shattered 0.5.0.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (223) hide show
  1. data/History.txt +6 -0
  2. data/INSTALL.txt +5 -0
  3. data/License.txt +18 -0
  4. data/Manifest.txt +175 -0
  5. data/README.txt +39 -0
  6. data/Rakefile +6 -0
  7. data/app_generators/actor/USAGE +6 -0
  8. data/app_generators/actor/actor_generator.rb +51 -0
  9. data/app_generators/actor/templates/actor.rb +4 -0
  10. data/app_generators/actor/templates/spec.rb +11 -0
  11. data/app_generators/actor/templates/unit_test.rb +9 -0
  12. data/app_generators/commands/console.rb +6 -0
  13. data/{lib/rails_generator/generators/applications/shattered_app → app_generators/shattered}/USAGE +1 -1
  14. data/app_generators/shattered/shattered_generator.rb +67 -0
  15. data/{lib → app_generators/shattered}/templates/Rakefile +4 -4
  16. data/app_generators/shattered/templates/configs/game.controls +16 -0
  17. data/app_generators/shattered/templates/configs/ogre_plugins.linux.cfg +12 -0
  18. data/app_generators/shattered/templates/configs/ogre_plugins.osx.cfg +12 -0
  19. data/{lib → app_generators/shattered}/templates/configs/ogre_plugins.windows.cfg +2 -2
  20. data/app_generators/shattered/templates/game.rb +50 -0
  21. data/{lib → app_generators/shattered}/templates/media/basic.rmaterial +0 -0
  22. data/app_generators/shattered/templates/spec/game_spec.rb +5 -0
  23. data/app_generators/shattered/templates/spec/spec_helper.rb +12 -0
  24. data/bin/shattered +39 -0
  25. data/config/hoe.rb +77 -0
  26. data/config/requirements.rb +15 -0
  27. data/lib/shattered.rb +40 -0
  28. data/lib/shattered_game/actor.rb +6 -0
  29. data/lib/shattered_game/game.rb +285 -0
  30. data/lib/{tasks → shattered_game/rake_tasks}/framework.rake +19 -24
  31. data/lib/{tasks → shattered_game/rake_tasks}/log.rake +0 -0
  32. data/lib/{tasks → shattered_game/rake_tasks}/misc.rake +1 -2
  33. data/lib/{tasks → shattered_game/rake_tasks}/pre_namespace_aliases.rake +0 -0
  34. data/lib/{tasks → shattered_game/rake_tasks}/shattered.rb +0 -0
  35. data/lib/shattered_game/rake_tasks/spec.rake +9 -0
  36. data/lib/{tasks → shattered_game/rake_tasks}/statistics.rake +0 -0
  37. data/lib/shattered_game/required.rb +2 -0
  38. data/lib/shattered_game/version.rb +9 -0
  39. data/lib/shattered_model/controls.rb +67 -0
  40. data/lib/shattered_model/input.rb +171 -0
  41. data/lib/shattered_model/key_converter.rb +44 -0
  42. data/lib/shattered_model/required.rb +4 -0
  43. data/lib/shattered_model/shattered_model.rb +28 -0
  44. data/lib/shattered_model/timed_event.rb +120 -0
  45. data/lib/shattered_model/timer.rb +78 -0
  46. data/lib/shattered_support/core_ext.rb +1 -0
  47. data/lib/shattered_support/core_ext/class.rb +3 -0
  48. data/lib/shattered_support/core_ext/class/attribute_accessors.rb +44 -0
  49. data/lib/shattered_support/core_ext/class/inheritable_attributes.rb +115 -0
  50. data/lib/shattered_support/core_ext/class/removal.rb +24 -0
  51. data/lib/shattered_support/core_ext/dir.rb +5 -0
  52. data/lib/shattered_support/core_ext/dir/search.rb +25 -0
  53. data/lib/shattered_support/core_ext/file.rb +5 -0
  54. data/lib/shattered_support/core_ext/file/search.rb +64 -0
  55. data/lib/shattered_support/core_ext/numeric.rb +5 -0
  56. data/lib/shattered_support/core_ext/numeric/time.rb +72 -0
  57. data/lib/shattered_support/core_ext/string.rb +13 -0
  58. data/lib/shattered_support/core_ext/string/access.rb +58 -0
  59. data/lib/shattered_support/core_ext/string/conversions.rb +19 -0
  60. data/lib/shattered_support/core_ext/string/inflections.rb +64 -0
  61. data/lib/shattered_support/core_ext/string/iterators.rb +17 -0
  62. data/lib/shattered_support/core_ext/string/starts_ends_with.rb +20 -0
  63. data/lib/shattered_support/error.rb +12 -0
  64. data/lib/shattered_support/inflections.rb +53 -0
  65. data/lib/shattered_support/inflector.rb +178 -0
  66. data/lib/shattered_support/pre_initialize.rb +153 -0
  67. data/lib/shattered_support/required.rb +9 -0
  68. data/lib/shattered_support/unload.rb +18 -0
  69. data/lib/shattered_view/camera.rb +7 -0
  70. data/lib/shattered_view/ogrerb/base.rb +28 -0
  71. data/lib/shattered_view/ogrerb/camera.rb +14 -0
  72. data/lib/shattered_view/ogrerb/key_manager.rb +54 -0
  73. data/lib/shattered_view/ogrerb/light.rb +25 -0
  74. data/lib/shattered_view/ogrerb/material.rb +5 -0
  75. data/lib/shattered_view/ogrerb/mesh_instance.rb +85 -0
  76. data/lib/shattered_view/ogrerb/mouse_manager.rb +109 -0
  77. data/lib/shattered_view/ogrerb/particle_system.rb +24 -0
  78. data/lib/shattered_view/ogrerb/rgb.rb +6 -0
  79. data/lib/shattered_view/ogrerb/rmaterial.rb +87 -0
  80. data/lib/shattered_view/ogrerb/scene_node.rb +76 -0
  81. data/lib/shattered_view/ogrerb/vector.rb +243 -0
  82. data/lib/shattered_view/ogrerb/window_event.rb +14 -0
  83. data/lib/shattered_view/resources.rb +64 -0
  84. data/lib/shattered_view/shattered_view.rb +248 -0
  85. data/script/destroy +14 -0
  86. data/script/generate +14 -0
  87. data/setup.rb +1585 -0
  88. data/tasks/deployment.rake +30 -0
  89. data/tasks/environment.rake +7 -0
  90. data/tasks/rcov.rake +7 -0
  91. data/tasks/testing.rake +46 -0
  92. data/tasks/website.rake +15 -0
  93. data/test/acceptance/Rakefile +10 -0
  94. data/test/acceptance/config/game.controls +17 -0
  95. data/test/acceptance/config/ogre_plugins.linux.cfg +12 -0
  96. data/test/acceptance/config/ogre_plugins.osx.cfg +12 -0
  97. data/test/acceptance/config/ogre_plugins.windows.cfg +14 -0
  98. data/test/acceptance/config/ogrerb_defaults.save +8 -0
  99. data/test/acceptance/game.rb +120 -0
  100. data/test/acceptance/lib/acceptance_test.rb +20 -0
  101. data/test/acceptance/lib/console.rb +54 -0
  102. data/test/acceptance/lib/input_test.rb +8 -0
  103. data/test/acceptance/lib/label.rb +30 -0
  104. data/test/acceptance/lib/light_test.rb +60 -0
  105. data/test/acceptance/lib/mesh_test.rb +69 -0
  106. data/test/acceptance/lib/particle_test.rb +9 -0
  107. data/test/acceptance/media/GreenSkin.jpg +0 -0
  108. data/test/acceptance/media/Ogre.material +86 -0
  109. data/test/acceptance/media/WeirdEye.png +0 -0
  110. data/test/acceptance/media/basic.rmaterial +18 -0
  111. data/test/acceptance/media/console.fontdef +7 -0
  112. data/test/acceptance/media/console.material +13 -0
  113. data/test/acceptance/media/console.png +0 -0
  114. data/test/acceptance/media/console.ttf +0 -0
  115. data/test/acceptance/media/dirt01.png +0 -0
  116. data/test/acceptance/media/fountain.material +19 -0
  117. data/test/acceptance/media/fountain.particle +40 -0
  118. data/test/acceptance/media/fountain.png +0 -0
  119. data/test/acceptance/media/fountaincolors.png +0 -0
  120. data/test/acceptance/media/ogre.mesh +0 -0
  121. data/test/acceptance/media/spheremap.png +0 -0
  122. data/test/acceptance/media/win.png +0 -0
  123. data/test/acceptance/spec/spec_helper.rb +7 -0
  124. data/test/integration/actor_generator_test.rb +43 -0
  125. data/test/integration/shattered_generator_test.rb +43 -0
  126. data/test/integration/test_helper.rb +20 -0
  127. data/test/ogre_test_defaults.save +8 -0
  128. data/test/ogre_test_plugins.linux.cfg +12 -0
  129. data/test/ogre_test_plugins.osx.cfg +12 -0
  130. data/test/ogre_test_plugins.windows.cfg +14 -0
  131. data/test/test_helper.rb +109 -0
  132. data/test/unit/shattered_game/actor_test.rb +9 -0
  133. data/test/unit/shattered_game/game_test.rb +49 -0
  134. data/test/unit/shattered_game/runner_test.rb +56 -0
  135. data/test/unit/shattered_model/controls/mouse.controls +4 -0
  136. data/test/unit/shattered_model/controls/player.controls +4 -0
  137. data/test/unit/shattered_model/controls/too_many_delims.controls +1 -0
  138. data/test/unit/shattered_model/key_controls_test.rb +89 -0
  139. data/test/unit/shattered_model/key_converter_test.rb +37 -0
  140. data/test/unit/shattered_model/keyboard_input_test.rb +32 -0
  141. data/test/unit/shattered_model/mouse_controls_test.rb +50 -0
  142. data/test/unit/shattered_model/mouse_input_test.rb +61 -0
  143. data/test/unit/shattered_model/shattered_model_test.rb +117 -0
  144. data/test/unit/shattered_model/timed_event_test.rb +79 -0
  145. data/test/unit/shattered_model/timer_test.rb +325 -0
  146. data/{lib/rails_generator/generators/components/actor/templates/actor.rb → test/unit/shattered_support/directory_test/file.test} +0 -0
  147. data/test/unit/shattered_support/numeric_ext_test.rb +38 -0
  148. data/test/unit/shattered_support/pre_initialize_test.rb +63 -0
  149. data/test/unit/shattered_support/shattered_support_test.rb +39 -0
  150. data/test/unit/shattered_support/unload_test.rb +17 -0
  151. data/test/unit/shattered_view/light_test.rb +38 -0
  152. data/test/unit/shattered_view/material_test.rb +41 -0
  153. data/test/unit/shattered_view/media_test/basic.rmaterial +18 -0
  154. data/{lib/templates/configs/empty.log → test/unit/shattered_view/media_test/beltch.ogg} +0 -0
  155. data/test/unit/shattered_view/media_test/test.mesh +0 -0
  156. data/test/unit/shattered_view/mesh_test.rb +59 -0
  157. data/test/unit/shattered_view/node_test.rb +11 -0
  158. data/test/unit/shattered_view/ogrerb/camera_test.rb +12 -0
  159. data/test/unit/shattered_view/ogrerb/key_manager_test.rb +42 -0
  160. data/test/unit/shattered_view/ogrerb/media/basic.rmaterial +18 -0
  161. data/test/unit/shattered_view/ogrerb/media/test.mesh +0 -0
  162. data/test/unit/shattered_view/ogrerb/media/test.rmaterial +1 -0
  163. data/test/unit/shattered_view/ogrerb/mesh_instance_test.rb +74 -0
  164. data/test/unit/shattered_view/ogrerb/mouse_manager_test.rb +104 -0
  165. data/test/unit/shattered_view/ogrerb/ogrerb.log +51 -0
  166. data/test/unit/shattered_view/ogrerb/resolve_ogrerb_test.rb +13 -0
  167. data/test/unit/shattered_view/ogrerb/rgb_test.rb +10 -0
  168. data/test/unit/shattered_view/ogrerb/rmaterial_test.rb +28 -0
  169. data/test/unit/shattered_view/ogrerb/scene_type_test.rb +12 -0
  170. data/test/unit/shattered_view/ogrerb/vector_test.rb +206 -0
  171. data/test/unit/shattered_view/particle_test.rb +23 -0
  172. data/test/unit/shattered_view/resources_test.rb +45 -0
  173. data/test/unit/shattered_view/test_helper.rb +1 -0
  174. data/test/unit/shattered_view/window_event_test.rb +19 -0
  175. data/test/unit/test_helper.rb +1 -0
  176. metadata +205 -121
  177. data/bin/console +0 -4
  178. data/bin/destroy +0 -9
  179. data/bin/generate +0 -7
  180. data/bin/runner +0 -9
  181. data/bin/shatter +0 -22
  182. data/lib/commands/console.rb +0 -23
  183. data/lib/game_loader.rb +0 -118
  184. data/lib/rails_generator.rb +0 -43
  185. data/lib/rails_generator/base.rb +0 -203
  186. data/lib/rails_generator/commands.rb +0 -519
  187. data/lib/rails_generator/generators/applications/shattered_app/shattered_app_generator.rb +0 -103
  188. data/lib/rails_generator/generators/components/actor/actor_generator.rb +0 -22
  189. data/lib/rails_generator/generators/components/model/USAGE +0 -17
  190. data/lib/rails_generator/generators/components/model/model_generator.rb +0 -22
  191. data/lib/rails_generator/generators/components/model/templates/fixtures.yml +0 -5
  192. data/lib/rails_generator/generators/components/model/templates/model.rb +0 -2
  193. data/lib/rails_generator/generators/components/model/templates/unit_test.rb +0 -11
  194. data/lib/rails_generator/generators/components/state/USAGE +0 -30
  195. data/lib/rails_generator/generators/components/state/state_generator.rb +0 -19
  196. data/lib/rails_generator/generators/components/state/templates/state.rb +0 -20
  197. data/lib/rails_generator/generators/components/view/USAGE +0 -30
  198. data/lib/rails_generator/generators/components/view/templates/material +0 -4
  199. data/lib/rails_generator/generators/components/view/templates/view.rb +0 -7
  200. data/lib/rails_generator/generators/components/view/view_generator.rb +0 -28
  201. data/lib/rails_generator/lookup.rb +0 -209
  202. data/lib/rails_generator/manifest.rb +0 -53
  203. data/lib/rails_generator/options.rb +0 -143
  204. data/lib/rails_generator/scripts.rb +0 -83
  205. data/lib/rails_generator/scripts/destroy.rb +0 -7
  206. data/lib/rails_generator/scripts/generate.rb +0 -7
  207. data/lib/rails_generator/scripts/update.rb +0 -12
  208. data/lib/rails_generator/simple_logger.rb +0 -46
  209. data/lib/rails_generator/spec.rb +0 -44
  210. data/lib/shatter.rb +0 -7
  211. data/lib/tasks/documentation.rake +0 -46
  212. data/lib/tasks/testing.rake +0 -102
  213. data/lib/templates/MIT-LICENSE +0 -20
  214. data/lib/templates/README +0 -35
  215. data/lib/templates/configs/boot.rb +0 -35
  216. data/lib/templates/configs/ogre.cfg +0 -4
  217. data/lib/templates/configs/runner.rb +0 -5
  218. data/lib/templates/doc/README_FOR_APP +0 -2
  219. data/lib/templates/environments/environment.rb +0 -10
  220. data/lib/templates/media/default.mesh +0 -0
  221. data/lib/templates/media/default.png +0 -0
  222. data/lib/templates/media/offset_map.rmaterial +0 -117
  223. data/lib/templates/test/test_helper.rb +0 -5
data/bin/runner DELETED
@@ -1,9 +0,0 @@
1
- #!/usr/local/bin/ruby
2
-
3
- if PLATFORM =~ /powerpc-darwin/
4
- path = File.dirname(__FILE__) + "/../config/Mac/"
5
- puts `(cd #{path}shattered.app; ./Contents/MacOS/shattered_mac)`
6
- else
7
- require File.dirname(__FILE__)+'/runner'
8
- start_game
9
- end
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #This file is adapted from the rails command.
3
-
4
- min_release = "1.8.2 (2004-12-25)"
5
- ruby_release = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
6
-
7
- if ruby_release < min_release
8
- abort <<-end_message
9
-
10
- Shattered requires Ruby version #{min_release} or later.
11
- You're running #{ruby_release}; please upgrade to continue.
12
-
13
- end_message
14
- end
15
-
16
- Signal.trap("INT") { puts; exit }
17
-
18
-
19
- require File.dirname(__FILE__) + '/../lib/rails_generator'
20
- require 'rails_generator/scripts/generate'
21
- Rails::Generator::Base.use_application_sources!
22
- Rails::Generator::Scripts::Generate.new.run(ARGV, :generator => 'shattered_app')
@@ -1,23 +0,0 @@
1
- irb = RUBY_PLATFORM =~ /mswin32/ ? 'irb.bat' : 'irb'
2
-
3
- require 'optparse'
4
- options = { :sandbox => false, :irb => irb }
5
- OptionParser.new do |opt|
6
- opt.banner = "Usage: console [environment] [options]"
7
- opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |options[:sandbox]| }
8
- opt.on("--irb=[#{irb}]", 'Invoke a different irb.') { |options[:irb]| }
9
- opt.parse!(ARGV)
10
- end
11
-
12
- libs = " -r irb/completion"
13
- libs << " -r #{SHATTERED_ROOT}/config/environment"
14
- libs << " -r console_sandbox" if options[:sandbox]
15
-
16
- ENV['SHATTERED_ENV'] = ARGV.first || ENV['SHATTERED_ENV'] || 'development'
17
- if options[:sandbox]
18
- puts "Loading #{ENV['SHATTER_ENV']} environment in sandbox."
19
- puts "Any modifications you make will be rolled back on exit."
20
- else
21
- puts "Loading #{ENV['SHATTER_ENV']} environment."
22
- end
23
- exec "#{options[:irb]} #{libs} --simple-prompt"
@@ -1,118 +0,0 @@
1
- require 'singleton'
2
-
3
- include ShatteredState
4
- include ShatteredView
5
- include ShatteredModel
6
-
7
- module Shatter #:nodoc:all
8
- #This class is loads the view, controller, and model. It then loads
9
- #and starts the game based on these.
10
- class GameLoader
11
- include Singleton
12
- attr_writer :environment
13
- attr_reader :media_paths, :render_window, :input_manager, :key_manager, :key_converter
14
- attr_accessor :current_state
15
-
16
- # This will recourse into the app/** directories and load all ruby files
17
- # inside those directories.
18
- def load_all_sources(shattered_root)
19
- File.find_by_extension(shattered_root+"/app", "rb").each do |file|
20
- require(file)
21
- end
22
- end
23
-
24
- # start the game
25
- def run
26
- load_all_sources(SHATTERED_ROOT)
27
- load_environment
28
-
29
- # Create our initial state, as defined by the environment.
30
- create_state(@environment[:start_state])
31
-
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
45
- end
46
-
47
- def load_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)
116
- end
117
- end
118
- end
@@ -1,43 +0,0 @@
1
- #--
2
- # Copyright (c) 2004 Jeremy Kemper
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining
5
- # a copy of this software and associated documentation files (the
6
- # "Software"), to deal in the Software without restriction, including
7
- # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
9
- # permit persons to whom the Software is furnished to do so, subject to
10
- # the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be
13
- # included in all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
- #++
23
-
24
- $:.unshift(File.dirname(__FILE__))
25
- $:.unshift(File.dirname(__FILE__) + "/../../shattered_support/lib")
26
-
27
- begin
28
- require 'shattered_support'
29
- rescue LoadError
30
- require 'rubygems'
31
- require_gem 'shattered_support'
32
- end
33
-
34
- require 'rails_generator/base'
35
- require 'rails_generator/lookup'
36
- require 'rails_generator/commands'
37
-
38
- Rails::Generator::Base.send(:include, Rails::Generator::Lookup)
39
- Rails::Generator::Base.send(:include, Rails::Generator::Commands)
40
-
41
- # Set up a default logger for convenience.
42
- require 'rails_generator/simple_logger'
43
- Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(STDOUT)
@@ -1,203 +0,0 @@
1
- require File.dirname(__FILE__) + '/options'
2
- require File.dirname(__FILE__) + '/manifest'
3
- require File.dirname(__FILE__) + '/spec'
4
-
5
- # Rails::Generator is a code generation platform tailored for the Rails
6
- # web application framework. Generators are easily invoked within Rails
7
- # applications to add and remove components such as models and controllers.
8
- # New generators are easy to create and may be distributed as RubyGems or
9
- # tarballs for inclusion system-wide, per-user, or per-application.
10
- #
11
- # Generators may subclass other generators to provide variations that
12
- # require little or no new logic but replace the template files.
13
- # The postback generator is an example: it subclasses the scaffold
14
- # generator and just replaces the code templates with its own.
15
- #
16
- # Now go forth and multiply^Wgenerate.
17
- module Rails
18
- module Generator
19
- class GeneratorError < StandardError; end
20
- class UsageError < GeneratorError; end
21
-
22
-
23
- # The base code generator is bare-bones. It sets up the source and
24
- # destination paths and tells the logger whether to keep its trap shut.
25
- # You're probably looking for NamedBase, a subclass meant for generating
26
- # "named" components such as models, controllers, and mailers.
27
- #
28
- # Generators create a manifest of the actions they perform then hand
29
- # the manifest to a command which replay the actions to do the heavy
30
- # lifting. Create, destroy, and list commands are included. Since a
31
- # single manifest may be used by any command, creating new generators is
32
- # as simple as writing some code templates and declaring what you'd like
33
- # to do with them.
34
- #
35
- # The manifest method must be implemented by subclasses, returning a
36
- # Rails::Generator::Manifest. The record method is provided as a
37
- # convenience for manifest creation. Example:
38
- # class EliteGenerator < Rails::Generator::Base
39
- # def manifest
40
- # record do |m|
41
- # m.do(some)
42
- # m.things(in) { here }
43
- # end
44
- # end
45
- # end
46
- class Base
47
- include Options
48
-
49
- # Declare default options for the generator. These options
50
- # are inherited to subclasses.
51
- default_options :collision => :ask, :quiet => false
52
-
53
- # A logger instance available everywhere in the generator.
54
- cattr_accessor :logger
55
-
56
- # Every generator that is dynamically looked up is tagged with a
57
- # Spec describing where it was found.
58
- class_inheritable_accessor :spec
59
-
60
- attr_reader :source_root, :destination_root, :args
61
-
62
- def initialize(runtime_args, runtime_options = {})
63
- @args = runtime_args
64
- parse!(@args, runtime_options)
65
-
66
- # Derive source and destination paths.
67
- @source_root = options[:source] || File.join(spec.path, 'templates')
68
- if options[:destination]
69
- @destination_root = options[:destination]
70
- elsif defined? ::SHATTERED_ROOT
71
- @destination_root = ::SHATTERED_ROOT
72
- end
73
-
74
- # Silence the logger if requested.
75
- logger.quiet = options[:quiet]
76
-
77
- # Raise usage error if help is requested.
78
- usage if options[:help]
79
- end
80
-
81
- # Generators must provide a manifest. Use the record method to create
82
- # a new manifest and record your generator's actions.
83
- def manifest
84
- raise NotImplementedError, "No manifest for '#{spec.name}' generator."
85
- end
86
-
87
- # Return the full path from the source root for the given path.
88
- # Example for source_root = '/source':
89
- # source_path('some/path.rb') == '/source/some/path.rb'
90
- #
91
- # The given path may include a colon ':' character to indicate that
92
- # the file belongs to another generator. This notation allows any
93
- # generator to borrow files from another. Example:
94
- # source_path('model:fixture.yml') = '/model/source/path/fixture.yml'
95
- def source_path(relative_source)
96
- # Check whether we're referring to another generator's file.
97
- name, path = relative_source.split(':', 2)
98
-
99
- # If not, return the full path to our source file.
100
- if path.nil?
101
- File.join(source_root, name)
102
-
103
- # Otherwise, ask our referral for the file.
104
- else
105
- # FIXME: this is broken, though almost always true. Others'
106
- # source_root are not necessarily the templates dir.
107
- File.join(self.class.lookup(name).path, 'templates', path)
108
- end
109
- end
110
-
111
- # Return the full path from the destination root for the given path.
112
- # Example for destination_root = '/dest':
113
- # destination_path('some/path.rb') == '/dest/some/path.rb'
114
- def destination_path(relative_destination)
115
- File.join(destination_root, relative_destination)
116
- end
117
-
118
- protected
119
- # Convenience method for generator subclasses to record a manifest.
120
- def record
121
- Rails::Generator::Manifest.new(self) { |m| yield m }
122
- end
123
-
124
- # Override with your own usage banner.
125
- def banner
126
- "Usage: #{$0} #{spec.name} [options]"
127
- end
128
-
129
- # Read USAGE from file in generator base path.
130
- def usage_message
131
- File.read(File.join(spec.path, 'USAGE')) rescue ''
132
- end
133
- end
134
-
135
-
136
- # The base generator for named components: models, controllers, mailers,
137
- # etc. The target name is taken as the first argument and inflected to
138
- # singular, plural, class, file, and table forms for your convenience.
139
- # The remaining arguments are aliased to actions for controller and
140
- # mailer convenience.
141
- #
142
- # If no name is provided, the generator raises a usage error with content
143
- # optionally read from the USAGE file in the generator's base path.
144
- #
145
- # See Rails::Generator::Base for a discussion of Manifests and Commands.
146
- class NamedBase < Base
147
- attr_reader :name, :class_name, :singular_name, :plural_name, :table_name
148
- attr_reader :class_path, :file_path, :class_nesting, :class_nesting_depth
149
- alias_method :file_name, :singular_name
150
- alias_method :actions, :args
151
-
152
- def initialize(runtime_args, runtime_options = {})
153
- super
154
-
155
- # Name argument is required.
156
- usage if runtime_args.empty?
157
-
158
- @args = runtime_args.dup
159
- base_name = @args.shift
160
- assign_names!(base_name)
161
- end
162
-
163
- protected
164
- # Override with your own usage banner.
165
- def banner
166
- "Usage: #{$0} #{spec.name} #{spec.name.camelize}Name [options]"
167
- end
168
-
169
- private
170
- def assign_names!(name)
171
- @name = name
172
- base_name, @class_path, @file_path, @class_nesting, @class_nesting_depth = extract_modules(@name)
173
- @class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
174
- @table_name = singular_name
175
- if @class_nesting.empty?
176
- @class_name = @class_name_without_nesting
177
- else
178
- @class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
179
- end
180
- end
181
-
182
- # Extract modules from filesystem-style or ruby-style path:
183
- # good/fun/stuff
184
- # Good::Fun::Stuff
185
- # produce the same results.
186
- def extract_modules(name)
187
- modules = name.include?('/') ? name.split('/') : name.split('::')
188
- name = modules.pop
189
- path = modules.map { |m| m.underscore }
190
- file_path = (path + [name.underscore]).join('/')
191
- nesting = modules.map { |m| m.camelize }.join('::')
192
- [name, path, file_path, nesting, modules.size]
193
- end
194
-
195
- def inflect_names(name)
196
- camel = name.camelize
197
- under = camel.underscore
198
- plural = under.pluralize
199
- [camel, under, plural]
200
- end
201
- end
202
- end
203
- end
@@ -1,519 +0,0 @@
1
- require 'delegate'
2
- require 'optparse'
3
- require 'fileutils'
4
- require 'erb'
5
-
6
- module Rails
7
- module Generator
8
- module Commands
9
- # Here's a convenient way to get a handle on generator commands.
10
- # Command.instance('destroy', my_generator) instantiates a Destroy
11
- # delegate of my_generator ready to do your dirty work.
12
- def self.instance(command, generator)
13
- const_get(command.to_s.camelize).new(generator)
14
- end
15
-
16
- # Even more convenient access to commands. Include Commands in
17
- # the generator Base class to get a nice #command instance method
18
- # which returns a delegate for the requested command.
19
- def self.included(base)
20
- base.send(:define_method, :command) do |command|
21
- Commands.instance(command, self)
22
- end
23
- end
24
-
25
-
26
- # Generator commands delegate Rails::Generator::Base and implement
27
- # a standard set of actions. Their behavior is defined by the way
28
- # they respond to these actions: Create brings life; Destroy brings
29
- # death; List passively observes.
30
- #
31
- # Commands are invoked by replaying (or rewinding) the generator's
32
- # manifest of actions. See Rails::Generator::Manifest and
33
- # Rails::Generator::Base#manifest method that generator subclasses
34
- # are required to override.
35
- #
36
- # Commands allows generators to "plug in" invocation behavior, which
37
- # corresponds to the GoF Strategy pattern.
38
- class Base < DelegateClass(Rails::Generator::Base)
39
- # Replay action manifest. RewindBase subclass rewinds manifest.
40
- def invoke!
41
- manifest.replay(self)
42
- end
43
-
44
- def dependency(generator_name, args, runtime_options = {})
45
- logger.dependency(generator_name) do
46
- self.class.new(instance(generator_name, args, full_options(runtime_options))).invoke!
47
- end
48
- end
49
-
50
- # Does nothing for all commands except Create.
51
- def class_collisions(*class_names)
52
- end
53
-
54
- # Does nothing for all commands except Create.
55
- def readme(*args)
56
- end
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
-
86
- private
87
- # Ask the user interactively whether to force collision.
88
- def force_file_collision?(destination)
89
- $stdout.print "overwrite #{destination}? [Ynaq] "
90
- case $stdin.gets
91
- when /a/i
92
- $stdout.puts "forcing #{spec.name}"
93
- options[:collision] = :force
94
- when /q/i
95
- $stdout.puts "aborting #{spec.name}"
96
- raise SystemExit
97
- when /n/i then :skip
98
- else :force
99
- end
100
- rescue
101
- retry
102
- end
103
-
104
- def render_template_part(template_options)
105
- # Getting Sandbox to evaluate part template in it
106
- part_binding = template_options[:sandbox].call.sandbox_binding
107
- part_rel_path = template_options[:insert]
108
- part_path = source_path(part_rel_path)
109
-
110
- # Render inner template within Sandbox binding
111
- rendered_part = ERB.new(File.readlines(part_path).join, nil, '-').result(part_binding)
112
- begin_mark = template_part_mark(template_options[:begin_mark], template_options[:mark_id])
113
- end_mark = template_part_mark(template_options[:end_mark], template_options[:mark_id])
114
- begin_mark + rendered_part + end_mark
115
- end
116
-
117
- def template_part_mark(name, id)
118
- "<!--[#{name}:#{id}]-->\n"
119
- end
120
- end
121
-
122
- # Base class for commands which handle generator actions in reverse, such as Destroy.
123
- class RewindBase < Base
124
- # Rewind action manifest.
125
- def invoke!
126
- manifest.rewind(self)
127
- end
128
- end
129
-
130
-
131
- # Create is the premier generator command. It copies files, creates
132
- # directories, renders templates, and more.
133
- class Create < Base
134
-
135
- # Check whether the given class names are already taken by
136
- # Ruby or Rails. In the future, expand to check other namespaces
137
- # such as the rest of the user's app.
138
- def class_collisions(*class_names)
139
- class_names.flatten.each do |class_name|
140
- # Convert to string to allow symbol arguments.
141
- class_name = class_name.to_s
142
-
143
- # Skip empty strings.
144
- next if class_name.strip.empty?
145
-
146
- # Split the class from its module nesting.
147
- nesting = class_name.split('::')
148
- name = nesting.pop
149
-
150
- # Extract the last Module in the nesting.
151
- last = nesting.inject(Object) { |last, nest|
152
- break unless last.const_defined?(nest)
153
- last.const_get(nest)
154
- }
155
-
156
- # If the last Module exists, check whether the given
157
- # class exists and raise a collision if so.
158
- if last and last.const_defined?(name.camelize)
159
- raise_class_collision(class_name)
160
- end
161
- end
162
- end
163
-
164
- # Copy a file from source to destination with collision checking.
165
- #
166
- # The file_options hash accepts :chmod and :shebang and :collision options.
167
- # :chmod sets the permissions of the destination file:
168
- # file 'config/empty.log', 'log/test.log', :chmod => 0664
169
- # :shebang sets the #!/usr/bin/ruby line for scripts
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
173
- #
174
- # Collisions are handled by checking whether the destination file
175
- # exists and either skipping the file, forcing overwrite, or asking
176
- # the user what to do.
177
- def file(relative_source, relative_destination, file_options = {}, &block)
178
- # Determine full paths for source and destination files.
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
187
-
188
- # Check for and resolve file collisions.
189
- if destination_exists
190
-
191
- # Make a choice whether to overwrite the file. :force and
192
- # :skip already have their mind made up, but give :ask a shot.
193
- choice = case (file_options[:collision] || options[:collision]).to_sym #|| :ask
194
- when :ask then force_file_collision?(relative_destination)
195
- when :force then :force
196
- when :skip then :skip
197
- else raise "Invalid collision option: #{options[:collision].inspect}"
198
- end
199
-
200
- # Take action based on our choice. Bail out if we chose to
201
- # skip the file; otherwise, log our transgression and continue.
202
- case choice
203
- when :force then logger.force(relative_destination)
204
- when :skip then return(logger.skip(relative_destination))
205
- else raise "Invalid collision choice: #{choice}.inspect"
206
- end
207
-
208
- # File doesn't exist so log its unbesmirched creation.
209
- else
210
- logger.create relative_destination
211
- end
212
-
213
- # If we're pretending, back off now.
214
- return if options[:pretend]
215
-
216
- # Write destination file with optional shebang. Yield for content
217
- # if block given so templaters may render the source file. If a
218
- # shebang is requested, replace the existing shebang or insert a
219
- # new one.
220
- File.open(destination, 'wb') do |df|
221
- File.open(source, 'rb') do |sf|
222
- if block_given?
223
- df.write(yield(sf))
224
- else
225
- if file_options[:shebang]
226
- df.puts("#!#{file_options[:shebang]}")
227
- if line = sf.gets
228
- df.puts(line) if line !~ /^#!/
229
- end
230
- end
231
- df.write(sf.read)
232
- end
233
- end
234
- end
235
-
236
- # Optionally change permissions.
237
- if file_options[:chmod]
238
- FileUtils.chmod(file_options[:chmod], destination)
239
- end
240
-
241
- # Optionally add file to subversion
242
- system("svn add #{destination}") if options[:svn]
243
- end
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
-
255
- # Generate a file for a Rails application using an ERuby template.
256
- # Looks up and evalutes a template by name and writes the result.
257
- #
258
- # The ERB template uses explicit trim mode to best control the
259
- # proliferation of whitespace in generated code. <%- trims leading
260
- # whitespace; -%> trims trailing whitespace including one newline.
261
- #
262
- # A hash of template options may be passed as the last argument.
263
- # The options accepted by the file are accepted as well as :assigns,
264
- # a hash of variable bindings. Example:
265
- # template 'foo', 'bar', :assigns => { :action => 'view' }
266
- #
267
- # Template is implemented in terms of file. It calls file with a
268
- # block which takes a file handle and returns its rendered contents.
269
- def template(relative_source, relative_destination, template_options = {})
270
- file(relative_source, relative_destination, template_options) do |file|
271
- # Evaluate any assignments in a temporary, throwaway binding.
272
- vars = template_options[:assigns] || {}
273
- b = binding
274
- vars.each { |k,v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
275
-
276
- # Render the source file with the temporary binding.
277
- ERB.new(file.read, nil, '-').result(b)
278
- end
279
- end
280
-
281
- def complex_template(relative_source, relative_destination, template_options = {})
282
- options = template_options.dup
283
- options[:assigns] ||= {}
284
- options[:assigns]['template_for_inclusion'] = render_template_part(template_options)
285
- template(relative_source, relative_destination, options)
286
- end
287
-
288
- # Create a directory including any missing parent directories.
289
- # Always directories which exist.
290
- def directory(relative_path)
291
- path = destination_path(relative_path)
292
- if File.exists?(path)
293
- logger.exists relative_path
294
- else
295
- logger.create relative_path
296
- FileUtils.mkdir_p(path) unless options[:pretend]
297
-
298
- # Optionally add file to subversion
299
- system("svn add #{path}") if options[:svn]
300
- end
301
- end
302
-
303
- # Display a README.
304
- def readme(*relative_sources)
305
- relative_sources.flatten.each do |relative_source|
306
- logger.readme relative_source
307
- puts File.read(source_path(relative_source)) unless options[:pretend]
308
- end
309
- end
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
-
319
- private
320
- # Raise a usage error with an informative WordNet suggestion.
321
- # Thanks to Florian Gross (flgr).
322
- def raise_class_collision(class_name)
323
- message = <<end_message
324
- The name '#{class_name}' is reserved by Ruby on Rails.
325
- Please choose an alternative and run this generator again.
326
- end_message
327
- if suggest = find_synonyms(class_name)
328
- message << "\n Suggestions: \n\n"
329
- message << suggest.join("\n")
330
- end
331
- raise UsageError, message
332
- end
333
-
334
- SYNONYM_LOOKUP_URI = "http://wordnet.princeton.edu/cgi-bin/webwn2.0?stage=2&word=%s&posnumber=1&searchtypenumber=2&senses=&showglosses=1"
335
-
336
- # Look up synonyms on WordNet. Thanks to Florian Gross (flgr).
337
- def find_synonyms(word)
338
- require 'open-uri'
339
- require 'timeout'
340
- timeout(5) do
341
- open(SYNONYM_LOOKUP_URI % word) do |stream|
342
- data = stream.read.gsub("&nbsp;", " ").gsub("<BR>", "")
343
- data.scan(/^Sense \d+\n.+?\n\n/m)
344
- end
345
- end
346
- rescue Exception
347
- return nil
348
- end
349
- end
350
-
351
-
352
- # Undo the actions performed by a generator. Rewind the action
353
- # manifest and attempt to completely erase the results of each action.
354
- class Destroy < RewindBase
355
- # Remove a file if it exists and is a file.
356
- def file(relative_source, relative_destination, file_options = {})
357
- destination = destination_path(relative_destination)
358
- if File.exists?(destination)
359
- logger.rm relative_destination
360
- unless options[:pretend]
361
- if options[:svn]
362
- # If the file has been marked to be added
363
- # but has not yet been checked in, revert and delete
364
- if options[:svn][relative_destination]
365
- system("svn revert #{destination}")
366
- FileUtils.rm(destination)
367
- else
368
- # If the directory is not in the status list, it
369
- # has no modifications so we can simply remove it
370
- system("svn rm #{destination}")
371
- end
372
- else
373
- FileUtils.rm(destination)
374
- end
375
- end
376
- else
377
- logger.missing relative_destination
378
- return
379
- end
380
- end
381
-
382
- # Templates are deleted just like files and the actions take the
383
- # same parameters, so simply alias the file method.
384
- alias_method :template, :file
385
-
386
- # Remove each directory in the given path from right to left.
387
- # Remove each subdirectory if it exists and is a directory.
388
- def directory(relative_path)
389
- parts = relative_path.split('/')
390
- until parts.empty?
391
- partial = File.join(parts)
392
- path = destination_path(partial)
393
- if File.exists?(path)
394
- if Dir[File.join(path, '*')].empty?
395
- logger.rmdir partial
396
- unless options[:pretend]
397
- if options[:svn]
398
- # If the directory has been marked to be added
399
- # but has not yet been checked in, revert and delete
400
- if options[:svn][relative_path]
401
- system("svn revert #{path}")
402
- FileUtils.rmdir(path)
403
- else
404
- # If the directory is not in the status list, it
405
- # has no modifications so we can simply remove it
406
- system("svn rm #{path}")
407
- end
408
- else
409
- FileUtils.rmdir(path)
410
- end
411
- end
412
- else
413
- logger.notempty partial
414
- end
415
- else
416
- logger.missing partial
417
- end
418
- parts.pop
419
- end
420
- end
421
-
422
- def complex_template(*args)
423
- # nothing should be done here
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
441
- end
442
-
443
-
444
- # List a generator's action manifest.
445
- class List < Base
446
- def dependency(generator_name, args, options = {})
447
- logger.dependency "#{generator_name}(#{args.join(', ')}, #{options.inspect})"
448
- end
449
-
450
- def class_collisions(*class_names)
451
- logger.class_collisions class_names.join(', ')
452
- end
453
-
454
- def file(relative_source, relative_destination, options = {})
455
- logger.file relative_destination
456
- end
457
-
458
- def template(relative_source, relative_destination, options = {})
459
- logger.template relative_destination
460
- end
461
-
462
- def complex_template(relative_source, relative_destination, options = {})
463
- logger.template "#{options[:insert]} inside #{relative_destination}"
464
- end
465
-
466
- def directory(relative_path)
467
- logger.directory "#{destination_path(relative_path)}/"
468
- end
469
-
470
- def readme(*args)
471
- logger.readme args.join(', ')
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
478
- end
479
-
480
- # Update generator's action manifest.
481
- class Update < Create
482
- def file(relative_source, relative_destination, options = {})
483
- # logger.file relative_destination
484
- end
485
-
486
- def template(relative_source, relative_destination, options = {})
487
- # logger.template relative_destination
488
- end
489
-
490
- def complex_template(relative_source, relative_destination, template_options = {})
491
-
492
- begin
493
- dest_file = destination_path(relative_destination)
494
- source_to_update = File.readlines(dest_file).join
495
- rescue Errno::ENOENT
496
- logger.missing relative_destination
497
- return
498
- end
499
-
500
- logger.refreshing "#{template_options[:insert].gsub(/\.rhtml/,'')} inside #{relative_destination}"
501
-
502
- begin_mark = Regexp.quote(template_part_mark(template_options[:begin_mark], template_options[:mark_id]))
503
- end_mark = Regexp.quote(template_part_mark(template_options[:end_mark], template_options[:mark_id]))
504
-
505
- # Refreshing inner part of the template with freshly rendered part.
506
- rendered_part = render_template_part(template_options)
507
- source_to_update.gsub!(/#{begin_mark}.*?#{end_mark}/m, rendered_part)
508
-
509
- File.open(dest_file, 'w') { |file| file.write(source_to_update) }
510
- end
511
-
512
- def directory(relative_path)
513
- # logger.directory "#{destination_path(relative_path)}/"
514
- end
515
- end
516
-
517
- end
518
- end
519
- end