diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2005-02-07 13:14:05 +0000 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2005-02-07 13:14:05 +0000 |
commit | daee6fd92ac16878f6806c3382a9e74592aa9656 (patch) | |
tree | d477c6502960cb141403f8b4640dd483b487e5df /railties/lib/rails_generator.rb | |
parent | 838c5a3d82367977d13ced01f9e28c22ccff32ef (diff) | |
download | rails-daee6fd92ac16878f6806c3382a9e74592aa9656.tar.gz rails-daee6fd92ac16878f6806c3382a9e74592aa9656.tar.bz2 rails-daee6fd92ac16878f6806c3382a9e74592aa9656.zip |
Added new generator framework that informs about its doings on generation and enables updating and destruction of generated artifacts. See the new script/destroy and script/update for more details #487 [bitsweat]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@518 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'railties/lib/rails_generator.rb')
-rw-r--r-- | railties/lib/rails_generator.rb | 234 |
1 files changed, 33 insertions, 201 deletions
diff --git a/railties/lib/rails_generator.rb b/railties/lib/rails_generator.rb index 83a404fc0a..0875a22dee 100644 --- a/railties/lib/rails_generator.rb +++ b/railties/lib/rails_generator.rb @@ -1,201 +1,33 @@ -require 'fileutils' - -module Rails - module Generator - class GeneratorError < StandardError; end - class UsageError < GeneratorError; end - - CONTRIB_ROOT = "#{RAILS_ROOT}/script/generators" - BUILTIN_ROOT = "#{File.dirname(__FILE__)}/../generators" - DEFAULT_SEARCH_PATHS = [CONTRIB_ROOT, BUILTIN_ROOT] - - class << self - def instance(name, args = [], search_paths = DEFAULT_SEARCH_PATHS) - # RAILS_ROOT constant must be set. - unless Object.const_get(:RAILS_ROOT) - raise GeneratorError, "RAILS_ROOT must be set. Did you require 'config/environment'?" - end - - # Force canonical name. - name = Inflector.underscore(name.downcase) - - # Search for filesystem path to requested generator. - unless path = find_generator_path(name, search_paths) - raise GeneratorError, "#{name} generator not found." - end - - # Check for templates directory. - template_root = "#{path}/templates" - unless File.directory?(template_root) - raise GeneratorError, "missing template directory #{template_root}" - end - - # Require class file according to naming convention. - require "#{path}/#{name}_generator.rb" - - # Find class according to naming convention. Allow Nesting::In::Modules. - class_name = Inflector.classify("#{name}_generator") - unless klass = find_generator_class(name) - raise GeneratorError, "no #{class_name} class defined in #{path}/#{name}_generator.rb" - end - - # Instantiate and return generator. - klass.new(template_root, RAILS_ROOT, search_paths, args) - end - - - def builtin_generators - generators([BUILTIN_ROOT]) - end - - def contrib_generators - generators([CONTRIB_ROOT]) - end - - def generators(search_paths) - generator_paths(search_paths).keys.uniq.sort - end - - # Find all generator paths. - def generator_paths(search_paths) - @paths ||= {} - unless @paths[search_paths] - paths = Hash.new { |h,k| h[k] = [] } - search_paths.each do |path| - Dir["#{path}/[a-z]*"].each do |dir| - paths[File.basename(dir)] << dir if File.directory?(dir) - end - end - @paths[search_paths] = paths - end - @paths[search_paths] - end - - def find_generator_path(name, search_paths) - generator_paths(search_paths)[name].first - end - - # Find all generator classes. - def generator_classes - classes = Hash.new { |h,k| h[k] = [] } - class_re = /([^:]+)Generator$/ - ObjectSpace.each_object(Class) do |object| - if md = class_re.match(object.name) and object < Rails::Generator::Base - classes[Inflector.underscore(md.captures.first)] << object - end - end - classes - end - - def find_generator_class(name) - generator_classes[name].first - end - end - - - # Talk about generators. - class Base - attr_reader :template_root, :destination_root, :args, :options, - :class_name, :singular_name, :plural_name - - alias_method :file_name, :singular_name - alias_method :table_name, :plural_name - - def self.generator_name - Inflector.underscore(name.gsub('Generator', '')) - end - - def initialize(template_root, destination_root, search_paths, args) - @template_root, @destination_root = template_root, destination_root - usage if args.empty? - @search_paths, @original_args = search_paths, args.dup - @class_name, @singular_name, @plural_name = inflect_names(args.shift) - @options = extract_options!(args) - @args = args - end - - # Checks whether the class name that was assigned to this generator - # would cause a collision with a Class, Module or other constant - # that is already used up by Ruby or RubyOnRails. - def collision_with_builtin? - builtin = Object.const_get(full_class_name) rescue nil - type = case builtin - when Class: "Class" - when Module: "Module" - else "Constant" - end - - if builtin then - "Sorry, you can't have a #{self.class.generator_name} named " + - "'#{full_class_name}' because Ruby or Rails already has a #{type} with that name.\n" + - "Please rerun the generator with a different name." - end - end - - # Returns the complete name that the resulting Class would have. - # Used in collision_with_builtin(). The default guess is that it is - # the same as class_name. Override this in your generator in case - # it is wrong. - def full_class_name - class_name - end - - protected - # Look up another generator with the same arguments. - def generator(name) - Rails::Generator.instance(name, @original_args, @search_paths) - end - - # Generate a file for a Rails application using an ERuby template. - # Looks up and evalutes a template by name and writes the result - # to a file relative to +destination_root+. The template - # is evaluated in the context of the optional eval_binding argument. - # - # The ERB template uses explicit trim mode to best control the - # proliferation of whitespace in generated code. <%- trims leading - # whitespace; -%> trims trailing whitespace including one newline. - def template(template_name, destination_path, eval_binding = nil) - # Determine full paths for source and destination files. - template_path = find_template_path(template_name) - destination_path = File.join(destination_root, destination_path) - - # Create destination directories. - FileUtils.mkdir_p(File.dirname(destination_path)) - - # Render template and write result. - eval_binding ||= binding - contents = ERB.new(File.read(template_path), nil, '-').result(eval_binding) - File.open(destination_path, 'w') { |file| file.write(contents) } - end - - def usage - raise UsageError.new, File.read(usage_path) - end - - private - def find_template_path(template_name) - name, path = template_name.split('/', 2) - if path.nil? - File.join(template_root, name) - elsif generator_path = Rails::Generator.find_generator_path(name, @search_paths) - File.join(generator_path, 'templates', path) - end - end - - def inflect_names(name) - camel = Inflector.camelize(Inflector.underscore(name)) - under = Inflector.underscore(camel) - plural = Inflector.pluralize(under) - [camel, under, plural] - end - - def extract_options!(args) - if args.last.is_a?(Hash) then args.pop else {} end - end - - def usage_path - "#{template_root}/../USAGE" - end - end - end -end +#-- +# Copyright (c) 2004 Jeremy Kemper +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#++ + +$:.unshift(File.dirname(__FILE__)) + +require 'support/core_ext' + +require 'rails_generator/base' +require 'rails_generator/lookup' +require 'rails_generator/commands' + +Rails::Generator::Base.send(:include, Rails::Generator::Lookup) +Rails::Generator::Base.send(:include, Rails::Generator::Commands) |