Froze rails gems
[depot.git] / vendor / rails / railties / lib / rails_generator / lookup.rb
1 require 'pathname'
2
3 require File.dirname(__FILE__) + '/spec'
4
5 class Object
6 class << self
7 # Lookup missing generators using const_missing. This allows any
8 # generator to reference another without having to know its location:
9 # RubyGems, ~/.rails/generators, and RAILS_ROOT/generators.
10 def lookup_missing_generator(class_id)
11 if md = /(.+)Generator$/.match(class_id.to_s)
12 name = md.captures.first.demodulize.underscore
13 Rails::Generator::Base.lookup(name).klass
14 else
15 const_missing_before_generators(class_id)
16 end
17 end
18
19 unless respond_to?(:const_missing_before_generators)
20 alias_method :const_missing_before_generators, :const_missing
21 alias_method :const_missing, :lookup_missing_generator
22 end
23 end
24 end
25
26 # User home directory lookup adapted from RubyGems.
27 def Dir.user_home
28 if ENV['HOME']
29 ENV['HOME']
30 elsif ENV['USERPROFILE']
31 ENV['USERPROFILE']
32 elsif ENV['HOMEDRIVE'] and ENV['HOMEPATH']
33 "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
34 else
35 File.expand_path '~'
36 end
37 end
38
39
40 module Rails
41 module Generator
42
43 # Generator lookup is managed by a list of sources which return specs
44 # describing where to find and how to create generators. This module
45 # provides class methods for manipulating the source list and looking up
46 # generator specs, and an #instance wrapper for quickly instantiating
47 # generators by name.
48 #
49 # A spec is not a generator: it's a description of where to find
50 # the generator and how to create it. A source is anything that
51 # yields generators from #each. PathSource and GemGeneratorSource are provided.
52 module Lookup
53 def self.included(base)
54 base.extend(ClassMethods)
55 base.use_component_sources!
56 end
57
58 # Convenience method to instantiate another generator.
59 def instance(generator_name, args, runtime_options = {})
60 self.class.instance(generator_name, args, runtime_options)
61 end
62
63 module ClassMethods
64 # The list of sources where we look, in order, for generators.
65 def sources
66 read_inheritable_attribute(:sources) or use_component_sources!
67 end
68
69 # Add a source to the end of the list.
70 def append_sources(*args)
71 sources.concat(args.flatten)
72 invalidate_cache!
73 end
74
75 # Add a source to the beginning of the list.
76 def prepend_sources(*args)
77 write_inheritable_array(:sources, args.flatten + sources)
78 invalidate_cache!
79 end
80
81 # Reset the source list.
82 def reset_sources
83 write_inheritable_attribute(:sources, [])
84 invalidate_cache!
85 end
86
87 # Use application generators (app, ?).
88 def use_application_sources!
89 reset_sources
90 sources << PathSource.new(:builtin, "#{File.dirname(__FILE__)}/generators/applications")
91 end
92
93 # Use component generators (model, controller, etc).
94 # 1. Rails application. If RAILS_ROOT is defined we know we're
95 # generating in the context of a Rails application, so search
96 # RAILS_ROOT/generators.
97 # 2. Look in plugins, either for generators/ or rails_generators/
98 # directories within each plugin
99 # 3. User home directory. Search ~/.rails/generators.
100 # 4. RubyGems. Search for gems named *_generator, and look for
101 # generators within any RubyGem's
102 # /rails_generators/<generator_name>_generator.rb file.
103 # 5. Builtins. Model, controller, mailer, scaffold, and so on.
104 def use_component_sources!
105 reset_sources
106 if defined? ::RAILS_ROOT
107 sources << PathSource.new(:lib, "#{::RAILS_ROOT}/lib/generators")
108 sources << PathSource.new(:vendor, "#{::RAILS_ROOT}/vendor/generators")
109 Rails.configuration.plugin_paths.each do |path|
110 relative_path = Pathname.new(File.expand_path(path)).relative_path_from(Pathname.new(::RAILS_ROOT))
111 sources << PathSource.new(:"plugins (#{relative_path})", "#{path}/*/**/{,rails_}generators")
112 end
113 end
114 sources << PathSource.new(:user, "#{Dir.user_home}/.rails/generators")
115 if Object.const_defined?(:Gem)
116 sources << GemGeneratorSource.new
117 sources << GemPathSource.new
118 end
119 sources << PathSource.new(:builtin, "#{File.dirname(__FILE__)}/generators/components")
120 end
121
122 # Lookup knows how to find generators' Specs from a list of Sources.
123 # Searches the sources, in order, for the first matching name.
124 def lookup(generator_name)
125 @found ||= {}
126 generator_name = generator_name.to_s.downcase
127 @found[generator_name] ||= cache.find { |spec| spec.name == generator_name }
128 unless @found[generator_name]
129 chars = generator_name.scan(/./).map{|c|"#{c}.*?"}
130 rx = /^#{chars}$/
131 gns = cache.select{|spec| spec.name =~ rx }
132 @found[generator_name] ||= gns.first if gns.length == 1
133 raise GeneratorError, "Pattern '#{generator_name}' matches more than one generator: #{gns.map{|sp|sp.name}.join(', ')}" if gns.length > 1
134 end
135 @found[generator_name] or raise GeneratorError, "Couldn't find '#{generator_name}' generator"
136 end
137
138 # Convenience method to lookup and instantiate a generator.
139 def instance(generator_name, args = [], runtime_options = {})
140 lookup(generator_name).klass.new(args, full_options(runtime_options))
141 end
142
143 private
144 # Lookup and cache every generator from the source list.
145 def cache
146 @cache ||= sources.inject([]) { |cache, source| cache + source.to_a }
147 end
148
149 # Clear the cache whenever the source list changes.
150 def invalidate_cache!
151 @cache = nil
152 end
153 end
154 end
155
156 # Sources enumerate (yield from #each) generator specs which describe
157 # where to find and how to create generators. Enumerable is mixed in so,
158 # for example, source.collect will retrieve every generator.
159 # Sources may be assigned a label to distinguish them.
160 class Source
161 include Enumerable
162
163 attr_reader :label
164 def initialize(label)
165 @label = label
166 end
167
168 # The each method must be implemented in subclasses.
169 # The base implementation raises an error.
170 def each
171 raise NotImplementedError
172 end
173
174 # Return a convenient sorted list of all generator names.
175 def names
176 map { |spec| spec.name }.sort
177 end
178 end
179
180
181 # PathSource looks for generators in a filesystem directory.
182 class PathSource < Source
183 attr_reader :path
184
185 def initialize(label, path)
186 super label
187 @path = path
188 end
189
190 # Yield each eligible subdirectory.
191 def each
192 Dir["#{path}/[a-z]*"].each do |dir|
193 if File.directory?(dir)
194 yield Spec.new(File.basename(dir), dir, label)
195 end
196 end
197 end
198 end
199
200 class AbstractGemSource < Source
201 def initialize
202 super :RubyGems
203 end
204 end
205
206 # GemGeneratorSource hits the mines to quarry for generators. The latest versions
207 # of gems named *_generator are selected.
208 class GemGeneratorSource < AbstractGemSource
209 # Yield latest versions of generator gems.
210 def each
211 dependency = Gem::Dependency.new(/_generator$/, Gem::Requirement.default)
212 Gem::cache.search(dependency).inject({}) { |latest, gem|
213 hem = latest[gem.name]
214 latest[gem.name] = gem if hem.nil? or gem.version > hem.version
215 latest
216 }.values.each { |gem|
217 yield Spec.new(gem.name.sub(/_generator$/, ''), gem.full_gem_path, label)
218 }
219 end
220 end
221
222 # GemPathSource looks for generators within any RubyGem's /rails_generators/<generator_name>_generator.rb file.
223 class GemPathSource < AbstractGemSource
224 # Yield each generator within rails_generator subdirectories.
225 def each
226 generator_full_paths.each do |generator|
227 yield Spec.new(File.basename(generator).sub(/_generator.rb$/, ''), File.dirname(generator), label)
228 end
229 end
230
231 private
232 def generator_full_paths
233 @generator_full_paths ||=
234 Gem::cache.inject({}) do |latest, name_gem|
235 name, gem = name_gem
236 hem = latest[gem.name]
237 latest[gem.name] = gem if hem.nil? or gem.version > hem.version
238 latest
239 end.values.inject([]) do |mem, gem|
240 Dir[gem.full_gem_path + '/{rails_,}generators/**/*_generator.rb'].each do |generator|
241 mem << generator
242 end
243 mem
244 end
245 end
246 end
247
248 end
249 end