aboutsummaryrefslogblamecommitdiffstats
path: root/railties/lib/generators.rb
blob: 91a0f5edca70fea7019c58518af5baf75d37d2b8 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                                                                        

                               
                                                                                           


                   



















































                                                                                   
     
                    

                                                                       

         
 





                                           



                                                                                
                                                       









                                                                                
                                           





                                                           

                                    




                                                                       

                      


                                                     
         
           
       





















                                                                               






                                                                                   










                                                         

     
 
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift(activesupport_path) if File.directory?(activesupport_path)
require 'active_support/all'

# TODO Use vendored Thor
require 'rubygems'
gem 'josevalim-thor'
require 'thor'

$:.unshift(File.dirname(__FILE__))
require 'rails/version' unless defined?(Rails::VERSION)

require 'generators/base'
require 'generators/named_base'
require 'generators/active_record' # We will need ActionORM from ActiveRecord, but just it.

module Rails
  module Generators
    mattr_accessor :load_path

    # Generators load paths. First search on generators in the RAILS_ROOT, then
    # look for them in rails generators.
    #
    def self.load_path
      @@load_path ||= begin
        paths = []
        paths << File.expand_path(File.join(File.dirname(__FILE__), "generators"))
        paths << File.join(RAILS_ROOT, "lib", "generators") if defined?(RAILS_ROOT)
        paths
      end
    end
    load_path # Cache load paths

    # Receives paths in an array and tries to find generators for it in the load
    # path.
    #
    def self.lookup(attempts)
      generators_path = []

      # Traverse attempts into directory lookups. For example:
      #
      #   rails:generators:model
      #
      # Becomes:
      #
      #   generators/rails/model/model_generator.rb
      #   generators/rails/model_generator.rb
      #   generators/model_generator.rb
      #
      attempts.each do |attempt|
        paths = attempt.gsub(':generators:', ':').split(':')
        paths << "#{paths.last}_generator.rb"

        until paths.empty?
          generators_path << File.join(*paths)
          paths.delete_at(-1) unless paths.delete_at(-2)
        end
      end

      generators_path.uniq!
      generators_path.each do |generator_path|
        self.load_path.each do |path|
          Dir[File.join(path, generator_path)].each do |file|
            require file
          end
        end
      end
    end

    # Keep builtin generators in an Array[Array[group, name]].
    #
    def self.builtin
      Dir[File.dirname(__FILE__) + '/generators/*/*'].collect do |file|
        file.split('/')[-2, 2]
      end
    end

    # Remove the color from output.
    #
    def self.no_color!
      Thor::Base.shell = Thor::Shell::Basic
    end

    # Receives a namespace and tries different combinations to find a generator.
    #
    # ==== Examples
    #
    #   find_by_namespace :webrat, :rails, :integration
    #
    # Will search for the following generators:
    #
    #   "rails:generators:webrat", "webrat:generators:integration", "webrat"
    #
    # If the namespace has ":" included we consider that a absolute namespace
    # was given and the lookup above does not happen. Just the name is searched.
    #
    # Finally, it deals with one kind of shortcut:
    #
    #   find_by_namespace "test_unit:model"
    #
    # It will search for generators at:
    #
    #   "test_unit:generators:model", "test_unit:model"
    #
    def self.find_by_namespace(name, base=nil, context=nil)
      name, attempts = name.to_s, []

      if name.count(':') == 0
        attempts << "#{base}:generators:#{name}"    if base
        attempts << "#{name}:generators:#{context}" if context
      end
      attempts << name.sub(':', ':generators:') if name.count(':') == 1
      attempts << name

      unless klass = find_many_by_namespace(attempts)
        lookup(attempts)
        klass = find_many_by_namespace(attempts)
      end
      klass
    end

    # Show help message with available generators.
    #
    def self.help
      rails = Rails::Generators.builtin.map do |group, name|
        name if group == "rails"
      end
      rails.compact!
      rails.sort!

      puts "Please select a generator."
      puts "Builtin: #{rails.join(', ')}."

      # TODO Show others after lookup is implemented
      # puts "Others: #{others.join(', ')}."
    end

    # Receives a namespace, arguments and the behavior to invoke the generator.
    # It's used as the default entry point for generate, destroy and update
    # commands.
    #
    def self.invoke(namespace, args=ARGV, behavior=:invoke)
      if klass = find_by_namespace(namespace, "rails")
        args << "--help" if klass.arguments.any? { |a| a.required? } && args.empty?
        klass.start args, :behavior => behavior
      else
        puts "Could not find generator #{namespace}."
      end
    end

    protected

      def self.find_many_by_namespace(attempts)
        attempts.each do |namespace|
          klass = Thor::Util.find_by_namespace(namespace)
          return klass if klass
        end
        nil
      end

  end
end