Froze rails gems
[depot.git] / vendor / rails / railties / lib / rails_generator / base.rb
1 require File.dirname(__FILE__) + '/options'
2 require File.dirname(__FILE__) + '/manifest'
3 require File.dirname(__FILE__) + '/spec'
4 require File.dirname(__FILE__) + '/generated_attribute'
5
6 module Rails
7 # Rails::Generator is a code generation platform tailored for the Rails
8 # web application framework. Generators are easily invoked within Rails
9 # applications to add and remove components such as models and controllers.
10 # New generators are easy to create and may be distributed as RubyGems,
11 # tarballs, or Rails plugins for inclusion system-wide, per-user,
12 # or per-application.
13 #
14 # For actual examples see the rails_generator/generators directory in the
15 # Rails source (or the +railties+ directory if you have frozen the Rails
16 # source in your application).
17 #
18 # Generators may subclass other generators to provide variations that
19 # require little or no new logic but replace the template files.
20 #
21 # For a RubyGem, put your generator class and templates in the +lib+
22 # directory. For a Rails plugin, make a +generators+ directory at the
23 # root of your plugin.
24 #
25 # The layout of generator files can be seen in the built-in
26 # +controller+ generator:
27 #
28 # generators/
29 # components/
30 # controller/
31 # controller_generator.rb
32 # templates/
33 # controller.rb
34 # functional_test.rb
35 # helper.rb
36 # view.html.erb
37 #
38 # The directory name (+controller+) matches the name of the generator file
39 # (controller_generator.rb) and class (ControllerGenerator). The files
40 # that will be copied or used as templates are stored in the +templates+
41 # directory.
42 #
43 # The filenames of the templates don't matter, but choose something that
44 # will be self-explanatory since you will be referencing these in the
45 # +manifest+ method inside your generator subclass.
46 #
47 #
48 module Generator
49 class GeneratorError < StandardError; end
50 class UsageError < GeneratorError; end
51
52
53 # The base code generator is bare-bones. It sets up the source and
54 # destination paths and tells the logger whether to keep its trap shut.
55 #
56 # It's useful for copying files such as stylesheets, images, or
57 # javascripts.
58 #
59 # For more comprehensive template-based passive code generation with
60 # arguments, you'll want Rails::Generator::NamedBase.
61 #
62 # Generators create a manifest of the actions they perform then hand
63 # the manifest to a command which replays the actions to do the heavy
64 # lifting (such as checking for existing files or creating directories
65 # if needed). Create, destroy, and list commands are included. Since a
66 # single manifest may be used by any command, creating new generators is
67 # as simple as writing some code templates and declaring what you'd like
68 # to do with them.
69 #
70 # The manifest method must be implemented by subclasses, returning a
71 # Rails::Generator::Manifest. The +record+ method is provided as a
72 # convenience for manifest creation. Example:
73 #
74 # class StylesheetGenerator < Rails::Generator::Base
75 # def manifest
76 # record do |m|
77 # m.directory('public/stylesheets')
78 # m.file('application.css', 'public/stylesheets/application.css')
79 # end
80 # end
81 # end
82 #
83 # See Rails::Generator::Commands::Create for a list of methods available
84 # to the manifest.
85 class Base
86 include Options
87
88 # Declare default options for the generator. These options
89 # are inherited to subclasses.
90 default_options :collision => :ask, :quiet => false
91
92 # A logger instance available everywhere in the generator.
93 cattr_accessor :logger
94
95 # Every generator that is dynamically looked up is tagged with a
96 # Spec describing where it was found.
97 class_inheritable_accessor :spec
98
99 attr_reader :source_root, :destination_root, :args
100
101 def initialize(runtime_args, runtime_options = {})
102 @args = runtime_args
103 parse!(@args, runtime_options)
104
105 # Derive source and destination paths.
106 @source_root = options[:source] || File.join(spec.path, 'templates')
107 if options[:destination]
108 @destination_root = options[:destination]
109 elsif defined? ::RAILS_ROOT
110 @destination_root = ::RAILS_ROOT
111 end
112
113 # Silence the logger if requested.
114 logger.quiet = options[:quiet]
115
116 # Raise usage error if help is requested.
117 usage if options[:help]
118 end
119
120 # Generators must provide a manifest. Use the +record+ method to create
121 # a new manifest and record your generator's actions.
122 def manifest
123 raise NotImplementedError, "No manifest for '#{spec.name}' generator."
124 end
125
126 # Return the full path from the source root for the given path.
127 # Example for source_root = '/source':
128 # source_path('some/path.rb') == '/source/some/path.rb'
129 #
130 # The given path may include a colon ':' character to indicate that
131 # the file belongs to another generator. This notation allows any
132 # generator to borrow files from another. Example:
133 # source_path('model:fixture.yml') = '/model/source/path/fixture.yml'
134 def source_path(relative_source)
135 # Check whether we're referring to another generator's file.
136 name, path = relative_source.split(':', 2)
137
138 # If not, return the full path to our source file.
139 if path.nil?
140 File.join(source_root, name)
141
142 # Otherwise, ask our referral for the file.
143 else
144 # FIXME: this is broken, though almost always true. Others'
145 # source_root are not necessarily the templates dir.
146 File.join(self.class.lookup(name).path, 'templates', path)
147 end
148 end
149
150 # Return the full path from the destination root for the given path.
151 # Example for destination_root = '/dest':
152 # destination_path('some/path.rb') == '/dest/some/path.rb'
153 def destination_path(relative_destination)
154 File.join(destination_root, relative_destination)
155 end
156
157 protected
158 # Convenience method for generator subclasses to record a manifest.
159 def record
160 Rails::Generator::Manifest.new(self) { |m| yield m }
161 end
162
163 # Override with your own usage banner.
164 def banner
165 "Usage: #{$0} #{spec.name} [options]"
166 end
167
168 # Read USAGE from file in generator base path.
169 def usage_message
170 File.read(File.join(spec.path, 'USAGE')) rescue ''
171 end
172 end
173
174
175 # The base generator for named components: models, controllers, mailers,
176 # etc. The target name is taken as the first argument and inflected to
177 # singular, plural, class, file, and table forms for your convenience.
178 # The remaining arguments are aliased to +actions+ as an array for
179 # controller and mailer convenience.
180 #
181 # Several useful local variables and methods are populated in the
182 # +initialize+ method. See below for a list of Attributes and
183 # External Aliases available to both the manifest and to all templates.
184 #
185 # If no name is provided, the generator raises a usage error with content
186 # optionally read from the USAGE file in the generator's base path.
187 #
188 # For example, the +controller+ generator takes the first argument as
189 # the name of the class and subsequent arguments as the names of
190 # actions to be generated:
191 #
192 # ./script/generate controller Article index new create
193 #
194 # See Rails::Generator::Base for a discussion of manifests,
195 # Rails::Generator::Commands::Create for methods available to the manifest,
196 # and Rails::Generator for a general discussion of generators.
197 class NamedBase < Base
198 attr_reader :name, :class_name, :singular_name, :plural_name, :table_name
199 attr_reader :class_path, :file_path, :class_nesting, :class_nesting_depth
200 alias_method :file_name, :singular_name
201 alias_method :actions, :args
202
203 def initialize(runtime_args, runtime_options = {})
204 super
205
206 # Name argument is required.
207 usage if runtime_args.empty?
208
209 @args = runtime_args.dup
210 base_name = @args.shift
211 assign_names!(base_name)
212 end
213
214 protected
215 # Override with your own usage banner.
216 def banner
217 "Usage: #{$0} #{spec.name} #{spec.name.camelize}Name [options]"
218 end
219
220 def attributes
221 @attributes ||= @args.collect do |attribute|
222 Rails::Generator::GeneratedAttribute.new(*attribute.split(":"))
223 end
224 end
225
226
227 private
228 def assign_names!(name)
229 @name = name
230 base_name, @class_path, @file_path, @class_nesting, @class_nesting_depth = extract_modules(@name)
231 @class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
232 @table_name = (!defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names) ? plural_name : singular_name
233 @table_name.gsub! '/', '_'
234 if @class_nesting.empty?
235 @class_name = @class_name_without_nesting
236 else
237 @table_name = @class_nesting.underscore << "_" << @table_name
238 @class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
239 end
240 end
241
242 # Extract modules from filesystem-style or ruby-style path:
243 # good/fun/stuff
244 # Good::Fun::Stuff
245 # produce the same results.
246 def extract_modules(name)
247 modules = name.include?('/') ? name.split('/') : name.split('::')
248 name = modules.pop
249 path = modules.map { |m| m.underscore }
250 file_path = (path + [name.underscore]).join('/')
251 nesting = modules.map { |m| m.camelize }.join('::')
252 [name, path, file_path, nesting, modules.size]
253 end
254
255 def inflect_names(name)
256 camel = name.camelize
257 under = camel.underscore
258 plural = under.pluralize
259 [camel, under, plural]
260 end
261 end
262 end
263 end