shattered 0.4.0.1 → 0.5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. data/lib/game_loader.rb +89 -8
  2. data/lib/rails_generator.rb +1 -1
  3. data/lib/rails_generator/base.rb +3 -3
  4. data/lib/rails_generator/commands.rb +91 -17
  5. data/lib/rails_generator/generators/applications/shattered_app/shattered_app_generator.rb +12 -12
  6. data/lib/rails_generator/generators/components/state/templates/state.rb +17 -0
  7. data/lib/rails_generator/generators/components/view/templates/view.rb +5 -2
  8. data/lib/rails_generator/lookup.rb +18 -17
  9. data/lib/rails_generator/manifest.rb +1 -1
  10. data/lib/rails_generator/options.rb +18 -10
  11. data/lib/rails_generator/scripts.rb +4 -4
  12. data/lib/rails_generator/simple_logger.rb +2 -2
  13. data/lib/rails_generator/spec.rb +1 -1
  14. data/lib/shatter.rb +1 -1
  15. data/lib/tasks/documentation.rake +46 -0
  16. data/lib/tasks/framework.rake +84 -0
  17. data/lib/tasks/log.rake +9 -0
  18. data/lib/tasks/misc.rake +4 -0
  19. data/lib/tasks/pre_namespace_aliases.rake +28 -0
  20. data/lib/tasks/shattered.rb +6 -0
  21. data/lib/tasks/statistics.rake +17 -0
  22. data/lib/tasks/testing.rake +102 -0
  23. data/lib/templates/Rakefile +4 -8
  24. data/lib/templates/configs/ogre_plugins.windows.cfg +14 -0
  25. data/lib/templates/environments/environment.rb +5 -2
  26. metadata +44 -53
  27. data/lib/templates/configs/Mac/shattered.app/Contents/Info.plist +0 -22
  28. data/lib/templates/configs/Mac/shattered.app/Contents/MacOS/shattered_mac +0 -0
  29. data/lib/templates/configs/Mac/shattered.app/Contents/PkgInfo +0 -1
  30. data/lib/templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/InfoPlist.strings +0 -0
  31. data/lib/templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/classes.nib +0 -4
  32. data/lib/templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/info.nib +0 -20
  33. data/lib/templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/objects.nib +0 -0
  34. data/lib/templates/configs/Mac/shattered.app/Contents/Resources/rb_main.rb +0 -3
  35. data/lib/templates/configs/Mac/shattered.app/Contents/pbdevelopment.plist +0 -8
  36. data/lib/templates/configs/Mac/shattered.app/OgreLeaks.log +0 -144
  37. data/lib/templates/configs/Mac/shattered.app/OgreMemory.log +0 -29
  38. data/lib/templates/configs/ogre_plugins.rcfg +0 -16
@@ -10,6 +10,8 @@ module Shatter #:nodoc:all
10
10
  class GameLoader
11
11
  include Singleton
12
12
  attr_writer :environment
13
+ attr_reader :media_paths, :render_window, :input_manager, :key_manager, :key_converter
14
+ attr_accessor :current_state
13
15
 
14
16
  # This will recourse into the app/** directories and load all ruby files
15
17
  # inside those directories.
@@ -18,20 +20,99 @@ class GameLoader
18
20
  require(file)
19
21
  end
20
22
  end
23
+
24
+ # start the game
21
25
  def run
22
- load_environment
23
26
  load_all_sources(SHATTERED_ROOT)
27
+ load_environment
24
28
 
25
- eval("#{@environment[:start_state].to_s.camelize}State").new
29
+ # Create our initial state, as defined by the environment.
30
+ create_state(@environment[:start_state])
26
31
 
27
- @control.start_game(@environment)
32
+ start_game
33
+ end
34
+
35
+ # Create a state from the given name
36
+ # :sample creates a new SampleState object
37
+ def create_state(state_name)
38
+ state_class = eval("#{state_name.to_s.camelize}State")
39
+ raise Error, "#{state_class} is not a class" unless state_class.is_a? Class
40
+ state = state_class.new
41
+ unless state.is_a? ShatteredState::Base
42
+ raise Error, "#{state_class} is an invalid State object (not of ShatteredState::Base)"
43
+ end
44
+ return state
28
45
  end
46
+
29
47
  def load_environment
30
- view = ShatteredView::Runner.new @environment
31
- view.add_to_environment @environment
32
- @control = ShatteredState::Runner.new(@environment)
33
- ShatteredPack::Configuration.environment=@environment
34
- return @environment
48
+ #Setup Ogre and the scene for the state
49
+ raise Error, "Ogre failed to initialize" if !setup_ogre
50
+ setup_input
51
+
52
+ load_resources(@environment[:media])
53
+ end
54
+
55
+ # Given ['app/media', 'media'], searches those directories, recursively, for OGRE media
56
+ def load_resources(paths)
57
+ @media_paths = paths
58
+ # setup our resource paths specified in environment.rb
59
+ Resources.instance.add_resource_paths(*paths)
60
+ Resources.instance.setup
61
+ end
62
+
63
+ #Load the root, setup the render window
64
+ #TODO: allow for the user to specify whether the window dialogue pops up
65
+ #further TODO: allow the user to skin the render window dialogue
66
+ def setup_ogre
67
+ # TODO: create platform loader for other platforms
68
+ plugins = SHATTERED_ROOT + "/config/ogre_plugins.windows.cfg"
69
+ config_save=SHATTERED_ROOT + "/config/ogrerb_defaults.save"
70
+ log=SHATTERED_ROOT + "/log/ogrerb.log"
71
+ @root = ShatteredOgre.create_root(plugins, config_save, log)
72
+ return false if !@root.show_config_dialog
73
+ # TODO: allow application name to be set.
74
+ @render_window = @root.initialise(true)
75
+
76
+ return true
77
+ end
78
+
79
+ #Every time this exits, a game dies.
80
+ def start_game
81
+ each_frame do |time_elapsed|
82
+ current_state.update_timers(time_elapsed)
83
+ @keyboard.capture
84
+ #@@environment[:input].flush
85
+ end
86
+ end
87
+
88
+ # Main game loop
89
+ def each_frame
90
+ timer = Ogre::Timer.new
91
+ while !@environment[:quit] && Ogre::Root::instance.render_one_frame
92
+ seconds = timer.get_microseconds / 1000000.0
93
+ yield seconds
94
+ timer.reset
95
+ end
96
+ end
97
+
98
+ # Leave the game
99
+ def quit!
100
+ @environment[:quit]=true
101
+ end
102
+
103
+ # load the input manager, the key manager, etc
104
+ # TODO: Consider how to make input non-exclusive, as well as mouse, etc.
105
+ # TODO: Investigate any use cases for non-buffered input
106
+ def setup_input
107
+ windowHnd = render_window.get_custom_attribute_unsigned_long("WINDOW")
108
+ @input_manager = OIS::InputManager.create_input_system(
109
+ { "WINDOW" => "#{windowHnd}",
110
+ "w32_mouse" => ["DISCL_FOREGROUND", "DISCL_NONEXCLUSIVE"],
111
+ "w32_keyboard" => ["DISCL_FOREGROUND", "DISCL_NONEXCLUSIVE"]
112
+ })
113
+ @keyboard = @input_manager.create_input_object(OIS::OISKeyboard, true)
114
+ @key_manager = OIS::KeyManager.new(@keyboard)
115
+ @key_converter = ShatteredPack::KeyConverter.new(@key_manager)
35
116
  end
36
117
  end
37
118
  end
@@ -25,7 +25,7 @@ $:.unshift(File.dirname(__FILE__))
25
25
  $:.unshift(File.dirname(__FILE__) + "/../../shattered_support/lib")
26
26
 
27
27
  begin
28
- require 'shattered_support'
28
+ require 'shattered_support'
29
29
  rescue LoadError
30
30
  require 'rubygems'
31
31
  require_gem 'shattered_support'
@@ -14,7 +14,7 @@ require File.dirname(__FILE__) + '/spec'
14
14
  # generator and just replaces the code templates with its own.
15
15
  #
16
16
  # Now go forth and multiply^Wgenerate.
17
- module Rails #:nodoc:all
17
+ module Rails
18
18
  module Generator
19
19
  class GeneratorError < StandardError; end
20
20
  class UsageError < GeneratorError; end
@@ -144,10 +144,9 @@ module Rails #:nodoc:all
144
144
  #
145
145
  # See Rails::Generator::Base for a discussion of Manifests and Commands.
146
146
  class NamedBase < Base
147
- attr_reader :name, :class_name, :singular_name, :plural_name
147
+ attr_reader :name, :class_name, :singular_name, :plural_name, :table_name
148
148
  attr_reader :class_path, :file_path, :class_nesting, :class_nesting_depth
149
149
  alias_method :file_name, :singular_name
150
- alias_method :table_name, :plural_name
151
150
  alias_method :actions, :args
152
151
 
153
152
  def initialize(runtime_args, runtime_options = {})
@@ -172,6 +171,7 @@ module Rails #:nodoc:all
172
171
  @name = name
173
172
  base_name, @class_path, @file_path, @class_nesting, @class_nesting_depth = extract_modules(@name)
174
173
  @class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
174
+ @table_name = singular_name
175
175
  if @class_nesting.empty?
176
176
  @class_name = @class_name_without_nesting
177
177
  else
@@ -3,7 +3,7 @@ require 'optparse'
3
3
  require 'fileutils'
4
4
  require 'erb'
5
5
 
6
- module Rails #:nodoc:all
6
+ module Rails
7
7
  module Generator
8
8
  module Commands
9
9
  # Here's a convenient way to get a handle on generator commands.
@@ -16,7 +16,7 @@ module Rails #:nodoc:all
16
16
  # Even more convenient access to commands. Include Commands in
17
17
  # the generator Base class to get a nice #command instance method
18
18
  # which returns a delegate for the requested command.
19
- def self.append_features(base)
19
+ def self.included(base)
20
20
  base.send(:define_method, :command) do |command|
21
21
  Commands.instance(command, self)
22
22
  end
@@ -55,6 +55,34 @@ module Rails #:nodoc:all
55
55
  def readme(*args)
56
56
  end
57
57
 
58
+ protected
59
+ def migration_directory(relative_path)
60
+ directory(@migration_directory = relative_path)
61
+ end
62
+
63
+ def existing_migrations(file_name)
64
+ Dir.glob("#{@migration_directory}/[0-9]*_*.rb").grep(/[0-9]+_#{file_name}.rb$/)
65
+ end
66
+
67
+ def migration_exists?(file_name)
68
+ not existing_migrations(file_name).empty?
69
+ end
70
+
71
+ def current_migration_number
72
+ Dir.glob("#{@migration_directory}/[0-9]*.rb").inject(0) do |max, file_path|
73
+ n = File.basename(file_path).split('_', 2).first.to_i
74
+ if n > max then n else max end
75
+ end
76
+ end
77
+
78
+ def next_migration_number
79
+ current_migration_number + 1
80
+ end
81
+
82
+ def next_migration_string(padding = 3)
83
+ "%.#{padding}d" % next_migration_number
84
+ end
85
+
58
86
  private
59
87
  # Ask the user interactively whether to force collision.
60
88
  def force_file_collision?(destination)
@@ -84,10 +112,10 @@ module Rails #:nodoc:all
84
112
  begin_mark = template_part_mark(template_options[:begin_mark], template_options[:mark_id])
85
113
  end_mark = template_part_mark(template_options[:end_mark], template_options[:mark_id])
86
114
  begin_mark + rendered_part + end_mark
87
- end
115
+ end
88
116
 
89
- def template_part_mark(name, id)
90
- "<!--[#{name}:#{id}]-->\n"
117
+ def template_part_mark(name, id)
118
+ "<!--[#{name}:#{id}]-->\n"
91
119
  end
92
120
  end
93
121
 
@@ -135,26 +163,34 @@ module Rails #:nodoc:all
135
163
 
136
164
  # Copy a file from source to destination with collision checking.
137
165
  #
138
- # The file_options hash accepts :chmod and :shebang options.
166
+ # The file_options hash accepts :chmod and :shebang and :collision options.
139
167
  # :chmod sets the permissions of the destination file:
140
168
  # file 'config/empty.log', 'log/test.log', :chmod => 0664
141
169
  # :shebang sets the #!/usr/bin/ruby line for scripts
142
170
  # file 'bin/generate.rb', 'script/generate', :chmod => 0755, :shebang => '/usr/bin/env ruby'
171
+ # :collision sets the collision option only for the destination file:
172
+ # file 'settings/server.yml', 'config/server.yml', :collision => :skip
143
173
  #
144
174
  # Collisions are handled by checking whether the destination file
145
175
  # exists and either skipping the file, forcing overwrite, or asking
146
176
  # the user what to do.
147
- def file(relative_source, relative_destination, file_options = {})
177
+ def file(relative_source, relative_destination, file_options = {}, &block)
148
178
  # Determine full paths for source and destination files.
149
- source = source_path(relative_source)
150
- destination = destination_path(relative_destination)
179
+ source = source_path(relative_source)
180
+ destination = destination_path(relative_destination)
181
+ destination_exists = File.exists?(destination)
182
+
183
+ # If source and destination are identical then we're done.
184
+ if destination_exists and identical?(source, destination, &block)
185
+ return logger.identical(relative_destination)
186
+ end
151
187
 
152
188
  # Check for and resolve file collisions.
153
- if File.exists?(destination)
189
+ if destination_exists
154
190
 
155
191
  # Make a choice whether to overwrite the file. :force and
156
192
  # :skip already have their mind made up, but give :ask a shot.
157
- choice = case options[:collision].to_sym #|| :ask
193
+ choice = case (file_options[:collision] || options[:collision]).to_sym #|| :ask
158
194
  when :ask then force_file_collision?(relative_destination)
159
195
  when :force then :force
160
196
  when :skip then :skip
@@ -181,17 +217,16 @@ module Rails #:nodoc:all
181
217
  # if block given so templaters may render the source file. If a
182
218
  # shebang is requested, replace the existing shebang or insert a
183
219
  # new one.
184
- File.open(destination, 'w') do |df|
185
- File.open(source) do |sf|
220
+ File.open(destination, 'wb') do |df|
221
+ File.open(source, 'rb') do |sf|
186
222
  if block_given?
187
223
  df.write(yield(sf))
188
224
  else
189
- line = sf.gets
190
225
  if file_options[:shebang]
191
226
  df.puts("#!#{file_options[:shebang]}")
192
- df.puts(line) if line !~ /^#!/
193
- else
194
- df.puts(line)
227
+ if line = sf.gets
228
+ df.puts(line) if line !~ /^#!/
229
+ end
195
230
  end
196
231
  df.write(sf.read)
197
232
  end
@@ -207,6 +242,16 @@ module Rails #:nodoc:all
207
242
  system("svn add #{destination}") if options[:svn]
208
243
  end
209
244
 
245
+ # Checks if the source and the destination file are identical. If
246
+ # passed a block then the source file is a template that needs to first
247
+ # be evaluated before being compared to the destination.
248
+ def identical?(source, destination, &block)
249
+ return false if File.directory? destination
250
+ source = block_given? ? File.open(source) {|sf| yield(sf)} : IO.read(source)
251
+ destination = IO.read(destination)
252
+ source == destination
253
+ end
254
+
210
255
  # Generate a file for a Rails application using an ERuby template.
211
256
  # Looks up and evalutes a template by name and writes the result.
212
257
  #
@@ -263,6 +308,14 @@ module Rails #:nodoc:all
263
308
  end
264
309
  end
265
310
 
311
+ # When creating a migration, it knows to find the first available file in db/migrate and use the migration.rb template.
312
+ def migration_template(relative_source, relative_destination, template_options = {})
313
+ migration_directory relative_destination
314
+ migration_file_name = template_options[:migration_file_name] || file_name
315
+ raise "Another migration is already named #{migration_file_name}: #{existing_migrations(migration_file_name).first}" if migration_exists?(migration_file_name)
316
+ template(relative_source, "#{relative_destination}/#{next_migration_string}_#{migration_file_name}.rb", template_options)
317
+ end
318
+
266
319
  private
267
320
  # Raise a usage error with an informative WordNet suggestion.
268
321
  # Thanks to Florian Gross (flgr).
@@ -369,6 +422,22 @@ end_message
369
422
  def complex_template(*args)
370
423
  # nothing should be done here
371
424
  end
425
+
426
+ # When deleting a migration, it knows to delete every file named "[0-9]*_#{file_name}".
427
+ def migration_template(relative_source, relative_destination, template_options = {})
428
+ migration_directory relative_destination
429
+
430
+ migration_file_name = template_options[:migration_file_name] || file_name
431
+ unless migration_exists?(migration_file_name)
432
+ puts "There is no migration named #{migration_file_name}"
433
+ return
434
+ end
435
+
436
+
437
+ existing_migrations(migration_file_name).each do |file_path|
438
+ file(relative_source, file_path, template_options)
439
+ end
440
+ end
372
441
  end
373
442
 
374
443
 
@@ -401,6 +470,11 @@ end_message
401
470
  def readme(*args)
402
471
  logger.readme args.join(', ')
403
472
  end
473
+
474
+ def migration_template(relative_source, relative_destination, options = {})
475
+ migration_directory relative_destination
476
+ logger.migration_template file_name
477
+ end
404
478
  end
405
479
 
406
480
  # Update generator's action manifest.
@@ -26,7 +26,7 @@ class ShatteredAppGenerator < Rails::Generator::Base #:nodoc:all
26
26
  m.file "templates/README", "README"
27
27
 
28
28
  # ogre plugins and configuration
29
- m.file "templates/configs/ogre_plugins.rcfg", "config/ogre_plugins.rcfg"
29
+ m.file "templates/configs/ogre_plugins.windows.cfg", "config/ogre_plugins.windows.cfg"
30
30
  m.template "templates/configs/ogre.cfg", "config/ogre.cfg"
31
31
  m.template "templates/configs/boot.rb", "config/boot.rb"
32
32
 
@@ -37,15 +37,16 @@ class ShatteredAppGenerator < Rails::Generator::Base #:nodoc:all
37
37
  m.file "templates/test/test_helper.rb", "test/test_helper.rb"
38
38
 
39
39
  # Mac OSX
40
- m.file "templates/configs/Mac/shattered.app/Contents/Info.plist", "config/Mac/shattered.app/Contents/Info.plist"
41
- m.file "templates/configs/Mac/shattered.app/Contents/MacOS/shattered_mac", "config/Mac/shattered.app/Contents/MacOS/shattered_mac"
42
- m.file "templates/configs/Mac/shattered.app/Contents/pbdevelopment.plist", "config/Mac/shattered.app/Contents/pbdevelopment.plist"
43
- m.file "templates/configs/Mac/shattered.app/Contents/PkgInfo", "config/Mac/shattered.app/Contents/PkgInfo"
44
- m.file "templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/InfoPlist.strings", "config/Mac/shattered.app/Contents/Resources/English.lproj/InfoPlist.strings"
45
- m.file "templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/classes.nib", "config/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/classes.nib"
46
- m.file "templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/info.nib", "config/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/info.nib"
47
- m.file "templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/objects.nib", "config/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/objects.nib"
48
- m.file "templates/configs/Mac/shattered.app/Contents/Resources/rb_main.rb", "config/Mac/shattered.app/Contents/Resources/rb_main.rb"
40
+ # TODO: OSX support needs to be revisited.
41
+ #m.file "templates/configs/Mac/shattered.app/Contents/Info.plist", "config/Mac/shattered.app/Contents/Info.plist"
42
+ #m.file "templates/configs/Mac/shattered.app/Contents/MacOS/shattered_mac", "config/Mac/shattered.app/Contents/MacOS/shattered_mac"
43
+ #m.file "templates/configs/Mac/shattered.app/Contents/pbdevelopment.plist", "config/Mac/shattered.app/Contents/pbdevelopment.plist"
44
+ #m.file "templates/configs/Mac/shattered.app/Contents/PkgInfo", "config/Mac/shattered.app/Contents/PkgInfo"
45
+ #m.file "templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/InfoPlist.strings", "config/Mac/shattered.app/Contents/Resources/English.lproj/InfoPlist.strings"
46
+ #m.file "templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/classes.nib", "config/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/classes.nib"
47
+ #m.file "templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/info.nib", "config/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/info.nib"
48
+ #m.file "templates/configs/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/objects.nib", "config/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib/objects.nib"
49
+ #m.file "templates/configs/Mac/shattered.app/Contents/Resources/rb_main.rb", "config/Mac/shattered.app/Contents/Resources/rb_main.rb"
49
50
 
50
51
  # Scripts
51
52
  %w( generate runner console destroy ).each do |file|
@@ -91,9 +92,8 @@ class ShatteredAppGenerator < Rails::Generator::Base #:nodoc:all
91
92
  app/views
92
93
  app/media/common/programs
93
94
  app/media/common/templates
94
- config/Mac/shattered.app/Contents/MacOS
95
- config/Mac/shattered.app/Contents/Resources/English.lproj/MainMenu.nib
96
95
  doc
96
+ config
97
97
  log
98
98
  script
99
99
  test/unit
@@ -1,3 +1,20 @@
1
1
  class <%= class_name %>State < ShatteredState::Base
2
2
  key :pressed => :escape, :action => :quit
3
+
4
+ def initialize
5
+ # The different types of scene managers provided by Ogre are:
6
+ # :general
7
+ # :terrain
8
+ # :nature
9
+ # :paging
10
+ # :indoor
11
+ scene_manager = create_scene_manager :general
12
+
13
+ camera = scene_manager.create_camera("camera")
14
+ camera.position = v(0,0,-200)
15
+ camera.look_at v(0,0,0)
16
+
17
+ viewport = create_viewport(camera)
18
+ viewport.set_background_colour Ogre::ColourValue.new(0.8, 0.5, 0.5)
19
+ end
3
20
  end
@@ -1,4 +1,7 @@
1
1
  class <%= class_name %>View < ShatteredView::Base
2
- material "<%= file_name %>_material", :template => "basic", :texture => "<%= file_name %>.png"
3
- mesh "<%= file_name %>", :material => :<%= file_name %>_material
2
+ # View works by executing after any model event
3
+ # This initialize will work after the model's initialize
4
+ def initialize
5
+ mesh = create(:mesh, "<%= class_name %>")
6
+ end
4
7
  end
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/spec'
2
2
 
3
- class Object #:nodoc:all
3
+ class Object
4
4
  class << self
5
5
  # Lookup missing generators using const_missing. This allows any
6
6
  # generator to reference another without having to know its location:
@@ -21,23 +21,21 @@ class Object #:nodoc:all
21
21
  end
22
22
  end
23
23
 
24
- class Dir #:nodoc:all
25
- # User home directory lookup adapted from RubyGems.
26
- def self.user_home
27
- if ENV['HOME']
28
- ENV['HOME']
29
- elsif ENV['USERPROFILE']
30
- ENV['USERPROFILE']
31
- elsif ENV['HOMEDRIVE'] and ENV['HOMEPATH']
32
- "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
33
- else
34
- File.expand_path '~'
35
- end
24
+ # User home directory lookup adapted from RubyGems.
25
+ def Dir.user_home
26
+ if ENV['HOME']
27
+ ENV['HOME']
28
+ elsif ENV['USERPROFILE']
29
+ ENV['USERPROFILE']
30
+ elsif ENV['HOMEDRIVE'] and ENV['HOMEPATH']
31
+ "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
32
+ else
33
+ File.expand_path '~'
36
34
  end
37
35
  end
38
36
 
39
37
 
40
- module Rails #:nodoc:all
38
+ module Rails
41
39
  module Generator
42
40
 
43
41
  # Generator lookup is managed by a list of sources which return specs
@@ -50,8 +48,7 @@ module Rails #:nodoc:all
50
48
  # the generator and how to create it. A source is anything that
51
49
  # yields generators from #each. PathSource and GemSource are provided.
52
50
  module Lookup
53
- def self.append_features(base)
54
- super
51
+ def self.included(base)
55
52
  base.extend(ClassMethods)
56
53
  base.use_component_sources!
57
54
  end
@@ -100,7 +97,11 @@ module Rails #:nodoc:all
100
97
  # 4. Builtins. Model, controller, mailer, scaffold.
101
98
  def use_component_sources!
102
99
  reset_sources
103
- sources << PathSource.new(:app, "#{::SHATTERED_ROOT}/generators") if defined? ::SHATTERED_ROOT
100
+ if defined? ::SHATTERED_ROOT
101
+ sources << PathSource.new(:lib, "#{::SHATTERED_ROOT}/lib/generators")
102
+ sources << PathSource.new(:vendor, "#{::SHATTERED_ROOT}/vendor/generators")
103
+ sources << PathSource.new(:plugins, "#{::SHATTERED_ROOT}/vendor/plugins/**/generators")
104
+ end
104
105
  sources << PathSource.new(:user, "#{Dir.user_home}/.rails/generators")
105
106
  sources << GemSource.new if Object.const_defined?(:Gem)
106
107
  sources << PathSource.new(:builtin, "#{File.dirname(__FILE__)}/generators/components")