tap 0.7.9 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. data/History +28 -0
  2. data/MIT-LICENSE +1 -1
  3. data/README +71 -43
  4. data/Rakefile +81 -64
  5. data/Tutorial +235 -0
  6. data/bin/tap +80 -44
  7. data/lib/tap.rb +41 -12
  8. data/lib/tap/app.rb +243 -246
  9. data/lib/tap/file_task.rb +357 -118
  10. data/lib/tap/generator.rb +88 -29
  11. data/lib/tap/generator/generators/config/config_generator.rb +4 -2
  12. data/lib/tap/generator/generators/config/templates/config.erb +1 -2
  13. data/lib/tap/generator/generators/file_task/file_task_generator.rb +3 -18
  14. data/lib/tap/generator/generators/file_task/templates/task.erb +22 -15
  15. data/lib/tap/generator/generators/file_task/templates/test.erb +13 -2
  16. data/{test/test/inference_methods/test_assert_files_exist/input/input_1.txt → lib/tap/generator/generators/generator/USAGE} +0 -0
  17. data/lib/tap/generator/generators/generator/generator_generator.rb +21 -0
  18. data/lib/tap/generator/generators/generator/templates/generator.erb +23 -0
  19. data/lib/tap/generator/generators/generator/templates/usage.erb +1 -0
  20. data/{test/test/inference_methods/test_assert_files_exist/input/input_2.txt → lib/tap/generator/generators/package/USAGE} +0 -0
  21. data/lib/tap/generator/generators/package/package_generator.rb +38 -0
  22. data/lib/tap/generator/generators/package/templates/package.erb +186 -0
  23. data/lib/tap/generator/generators/root/root_generator.rb +14 -9
  24. data/lib/tap/generator/generators/root/templates/Rakefile +20 -14
  25. data/{test/test/inference_methods/test_infer_glob/expected/file.yml → lib/tap/generator/generators/root/templates/ReadMe.txt} +0 -0
  26. data/lib/tap/generator/generators/root/templates/tap.yml +82 -0
  27. data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +0 -1
  28. data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +2 -1
  29. data/{test/test/inference_methods/test_infer_glob/expected/file_1.txt → lib/tap/generator/generators/script/USAGE} +0 -0
  30. data/lib/tap/generator/generators/script/script_generator.rb +17 -0
  31. data/lib/tap/generator/generators/script/templates/script.erb +42 -0
  32. data/lib/tap/generator/generators/task/task_generator.rb +1 -1
  33. data/lib/tap/generator/generators/task/templates/task.erb +24 -16
  34. data/lib/tap/generator/generators/task/templates/test.erb +13 -17
  35. data/lib/tap/generator/generators/workflow/templates/task.erb +10 -10
  36. data/lib/tap/generator/generators/workflow/templates/test.erb +1 -1
  37. data/lib/tap/generator/generators/workflow/workflow_generator.rb +3 -18
  38. data/lib/tap/root.rb +108 -146
  39. data/lib/tap/script.rb +362 -0
  40. data/lib/tap/script/console.rb +28 -0
  41. data/lib/tap/script/destroy.rb +13 -1
  42. data/lib/tap/script/generate.rb +13 -1
  43. data/lib/tap/script/run.rb +100 -57
  44. data/lib/tap/support/batch_queue.rb +0 -3
  45. data/lib/tap/support/logger.rb +6 -3
  46. data/lib/tap/support/rake.rb +54 -0
  47. data/lib/tap/support/task_configuration.rb +169 -0
  48. data/lib/tap/support/tdoc.rb +198 -0
  49. data/lib/tap/support/tdoc/config_attr.rb +338 -0
  50. data/lib/tap/support/tdoc/tdoc_html_generator.rb +38 -0
  51. data/lib/tap/support/tdoc/tdoc_html_template.rb +42 -0
  52. data/lib/tap/support/versions.rb +33 -1
  53. data/lib/tap/task.rb +339 -227
  54. data/lib/tap/test.rb +86 -128
  55. data/lib/tap/test/env_vars.rb +16 -5
  56. data/lib/tap/test/file_methods.rb +373 -0
  57. data/lib/tap/test/subset_methods.rb +299 -180
  58. data/lib/tap/version.rb +2 -1
  59. data/lib/tap/workflow.rb +2 -0
  60. data/test/app/lib/app_test_task.rb +1 -0
  61. data/test/app_test.rb +327 -83
  62. data/test/check/binding_eval.rb +23 -0
  63. data/test/check/define_method_check.rb +22 -0
  64. data/test/check/dependencies_check.rb +175 -0
  65. data/test/check/inheritance_check.rb +22 -0
  66. data/test/file_task_test.rb +524 -291
  67. data/test/{test/inference_methods/test_infer_glob/expected/file_2.txt → root/glob/one.txt} +0 -0
  68. data/test/root/glob/two.txt +0 -0
  69. data/test/root_test.rb +330 -262
  70. data/test/script_test.rb +194 -0
  71. data/test/support/audit_test.rb +5 -2
  72. data/test/support/combinator_test.rb +10 -10
  73. data/test/support/rake_test.rb +35 -0
  74. data/test/support/task_configuration_test.rb +272 -0
  75. data/test/support/tdoc_test.rb +363 -0
  76. data/test/support/templater_test.rb +2 -2
  77. data/test/support/versions_test.rb +32 -0
  78. data/test/tap_test_helper.rb +39 -0
  79. data/test/task_base_test.rb +115 -0
  80. data/test/task_class_test.rb +56 -4
  81. data/test/task_execute_test.rb +29 -0
  82. data/test/task_test.rb +89 -70
  83. data/test/test/env_vars_test.rb +48 -0
  84. data/test/test/{inference_methods → file_methods}/test_assert_expected/expected/file.txt +0 -0
  85. data/test/test/{inference_methods → file_methods}/test_assert_expected/expected/folder/file.txt +0 -0
  86. data/test/test/{inference_methods → file_methods}/test_assert_expected/input/file.txt +0 -0
  87. data/test/test/{inference_methods → file_methods}/test_assert_expected/input/folder/file.txt +0 -0
  88. data/test/test/file_methods/test_assert_files_exist/input/input_1.txt +0 -0
  89. data/test/test/file_methods/test_assert_files_exist/input/input_2.txt +0 -0
  90. data/test/test/file_methods/test_assert_output_files_equal/expected/one.txt +1 -0
  91. data/test/test/file_methods/test_assert_output_files_equal/expected/two.txt +1 -0
  92. data/test/test/file_methods/test_assert_output_files_equal/input/one.txt +1 -0
  93. data/test/test/file_methods/test_assert_output_files_equal/input/two.txt +1 -0
  94. data/test/test/{inference_methods → file_methods}/test_file_compare/expected/output_1.txt +0 -0
  95. data/test/test/{inference_methods → file_methods}/test_file_compare/expected/output_2.txt +0 -0
  96. data/test/test/{inference_methods → file_methods}/test_file_compare/input/input_1.txt +0 -0
  97. data/test/test/{inference_methods → file_methods}/test_file_compare/input/input_2.txt +0 -0
  98. data/test/test/file_methods/test_infer_glob/expected/file.yml +0 -0
  99. data/test/test/file_methods/test_infer_glob/expected/file_1.txt +0 -0
  100. data/test/test/file_methods/test_infer_glob/expected/file_2.txt +0 -0
  101. data/test/test/file_methods/test_method_glob/expected/file.yml +0 -0
  102. data/test/test/file_methods/test_method_glob/expected/file_1.txt +0 -0
  103. data/test/test/file_methods/test_method_glob/expected/file_2.txt +0 -0
  104. data/test/test/{inference_methods → file_methods}/test_yml_compare/expected/output_1.yml +0 -0
  105. data/test/test/{inference_methods → file_methods}/test_yml_compare/expected/output_2.yml +0 -0
  106. data/test/test/{inference_methods → file_methods}/test_yml_compare/input/input_1.yml +0 -0
  107. data/test/test/{inference_methods → file_methods}/test_yml_compare/input/input_2.yml +0 -0
  108. data/test/test/file_methods_test.rb +204 -0
  109. data/test/test/subset_methods_test.rb +93 -33
  110. data/test/test/test_assert_expected_result_files/expected/task/name/a.txt +1 -0
  111. data/test/test/test_assert_expected_result_files/expected/task/name/b.txt +1 -0
  112. data/test/test/test_assert_expected_result_files/input/a.txt +1 -0
  113. data/test/test/test_assert_expected_result_files/input/b.txt +1 -0
  114. data/test/test/test_file_task_test/expected/one.txt +1 -0
  115. data/test/test/test_file_task_test/expected/two.txt +1 -0
  116. data/test/test/test_file_task_test/input/one.txt +1 -0
  117. data/test/test/test_file_task_test/input/two.txt +1 -0
  118. data/test/test_test.rb +143 -3
  119. data/test/workflow_test.rb +2 -0
  120. data/vendor/rails_generator.rb +56 -0
  121. data/vendor/rails_generator/base.rb +263 -0
  122. data/vendor/rails_generator/commands.rb +581 -0
  123. data/vendor/rails_generator/generated_attribute.rb +42 -0
  124. data/vendor/rails_generator/lookup.rb +209 -0
  125. data/vendor/rails_generator/manifest.rb +53 -0
  126. data/vendor/rails_generator/options.rb +143 -0
  127. data/vendor/rails_generator/scripts.rb +83 -0
  128. data/vendor/rails_generator/scripts/destroy.rb +7 -0
  129. data/vendor/rails_generator/scripts/generate.rb +7 -0
  130. data/vendor/rails_generator/scripts/update.rb +12 -0
  131. data/vendor/rails_generator/simple_logger.rb +46 -0
  132. data/vendor/rails_generator/spec.rb +44 -0
  133. metadata +180 -196
  134. data/lib/tap/generator/generators/root/templates/app.yml +0 -19
  135. data/lib/tap/generator/generators/root/templates/config/process_tap_request.yml +0 -4
  136. data/lib/tap/generator/generators/root/templates/lib/process_tap_request.rb +0 -26
  137. data/lib/tap/generator/generators/root/templates/public/images/nav.jpg +0 -0
  138. data/lib/tap/generator/generators/root/templates/public/stylesheets/color.css +0 -57
  139. data/lib/tap/generator/generators/root/templates/public/stylesheets/layout.css +0 -108
  140. data/lib/tap/generator/generators/root/templates/public/stylesheets/normalize.css +0 -40
  141. data/lib/tap/generator/generators/root/templates/public/stylesheets/typography.css +0 -21
  142. data/lib/tap/generator/generators/root/templates/server/config/environment.rb +0 -60
  143. data/lib/tap/generator/generators/root/templates/server/lib/tasks/clear_database_prerequisites.rake +0 -5
  144. data/lib/tap/generator/generators/root/templates/server/test/test_helper.rb +0 -53
  145. data/lib/tap/script/server.rb +0 -12
  146. data/lib/tap/support/rap.rb +0 -38
  147. data/lib/tap/test/inference_methods.rb +0 -298
  148. data/test/task/config/task_with_config.yml +0 -1
  149. data/test/test/inference_methods_test.rb +0 -311
@@ -0,0 +1 @@
1
+ processed file one
@@ -0,0 +1 @@
1
+ processed file two
@@ -0,0 +1 @@
1
+ file one
@@ -0,0 +1 @@
1
+ file two
data/test/test_test.rb CHANGED
@@ -11,7 +11,6 @@ class TestSetupTest < Test::Unit::TestCase
11
11
  #
12
12
 
13
13
  def test_setup_with_options
14
- assert runlist.empty?
15
14
  assert_equal @app, app
16
15
  assert_equal Tap::App.instance, app
17
16
  assert_equal File.expand_path("./alt/root"), File.expand_path(app[:root])
@@ -20,6 +19,7 @@ class TestSetupTest < Test::Unit::TestCase
20
19
  end
21
20
 
22
21
  class TestTest < Test::Unit::TestCase
22
+ include TapTestMethods
23
23
  acts_as_tap_test
24
24
 
25
25
  #
@@ -225,9 +225,149 @@ class TestTest < Test::Unit::TestCase
225
225
  # with options
226
226
  #
227
227
 
228
- def test_with_options_executes_block_having_set_options_for_app
229
- #app
228
+ def test_with_options_doc
229
+ app = Tap::App.new(:options => {:one => 1, :two => 2})
230
+
231
+ with_options({:one => 'one'}, app) do
232
+ assert_equal({:one => 'one', :two => 2}, app.options.marshal_dump)
233
+ end
234
+ assert_equal({:one => 1, :two => 2}, app.options.marshal_dump)
235
+ end
236
+
237
+ def test_with_options_merges_new_options_with_existing_for_block
238
+ app.options.one = 1
239
+ app.options.two = 2
240
+
241
+ assert_equal({:one => 1, :two => 2}, app.options.marshal_dump)
242
+ with_options(:one => 'one') do
243
+ assert_equal({:one => 'one', :two => 2}, app.options.marshal_dump)
244
+ end
245
+ assert_equal({:one => 1, :two => 2}, app.options.marshal_dump)
246
+ end
247
+
248
+ def test_with_options_does_not_merge_if_merge_with_existing_is_false
249
+ app.options.one = 1
250
+ app.options.two = 2
251
+
252
+ assert_equal({:one => 1, :two => 2}, app.options.marshal_dump)
253
+ with_options({:one => 'one'}, app, false) do
254
+ assert_equal({:one => 'one'}, app.options.marshal_dump)
255
+ end
256
+ assert_equal({:one => 1, :two => 2}, app.options.marshal_dump)
230
257
  end
231
258
 
259
+
260
+ #
261
+ # with config
262
+ #
263
+
264
+ def test_with_config_doc
265
+ app = Tap::App.new(:directories => {:dir => 'dir', :alt => 'alt_dir'})
266
+ tmp_config = {
267
+ :directories => {:alt => 'another', :new => 'new_dir'},
268
+ :options => {:one => 1}}
269
+
270
+ with_config(tmp_config, app) do
271
+ assert_equal({:dir => 'dir', :alt => 'another', :new => 'new_dir'}, app.directories)
272
+ assert_equal({:one => 1}, app.options.marshal_dump)
273
+ end
274
+ assert_equal({:dir => 'dir', :alt => 'alt_dir'}, app.directories)
275
+ assert_equal({}, app.options.marshal_dump)
276
+ end
277
+
278
+ def test_with_config_merges_new_config_with_existing_for_block
279
+ config = {
280
+ :root => File.expand_path("root"),
281
+ :directories => {:dir => 'dir', :alt => 'alt_dir'},
282
+ :options => {:one => 1, :two => 2}}
283
+ logger_config ={
284
+ :device => app.logger.logdev.dev,
285
+ :level => app.logger.level,
286
+ :datetime_format => app.logger.datetime_format}
287
+
288
+ full_config = config.merge(
289
+ :absolute_paths => {},
290
+ :logger => logger_config)
291
+ modified_config = {
292
+ :root => File.expand_path("root"),
293
+ :directories => {:dir => 'another', :new => 'new_dir', :alt => 'alt_dir'},
294
+ :options => {:one => 'one', :two => 2},
295
+ :absolute_paths => {:abs => File.expand_path('abs')},
296
+ :logger => logger_config}
297
+
298
+ app.reconfigure(full_config)
299
+
300
+ assert_equal(full_config, app.config)
301
+ with_config(
302
+ :directories => {:dir => 'another', :new => 'new_dir'},
303
+ :options => {:one => 'one'},
304
+ :absolute_paths => {:abs => 'abs'}
305
+ ) do
306
+ assert_equal(modified_config, app.config)
307
+ end
308
+ assert_equal(full_config, app.config)
309
+ end
310
+
311
+ def test_with_config_does_not_merge_if_merge_with_existing_is_false
312
+ config = {
313
+ :root => File.expand_path("root"),
314
+ :directories => {:dir => 'dir', :alt => 'alt_dir'},
315
+ :options => {:one => 1, :two => 2}}
316
+ logger_config ={
317
+ :device => app.logger.logdev.dev,
318
+ :level => app.logger.level,
319
+ :datetime_format => app.logger.datetime_format}
320
+
321
+ full_config = config.merge(
322
+ :absolute_paths => {},
323
+ :logger => logger_config)
324
+ modified_config = {
325
+ :root => File.expand_path("root"),
326
+ :directories => {:dir => 'another', :new => 'new_dir'},
327
+ :options => {:one => 'one'},
328
+ :absolute_paths => {:abs => File.expand_path('abs')},
329
+ :logger => logger_config}
330
+
331
+ app.reconfigure(full_config)
332
+
333
+ assert_equal(full_config, app.config)
334
+ with_config(
335
+ {:directories => {:dir => 'another', :new => 'new_dir'},
336
+ :options => {:one => 'one'},
337
+ :absolute_paths => {:abs => 'abs'}},
338
+ app,
339
+ false
340
+ ) do
341
+ assert_equal(modified_config, app.config)
342
+ end
343
+ assert_equal(full_config, app.config)
344
+ end
345
+
346
+ #
347
+ # assert_expected_result_files
348
+ #
349
+
350
+ def test_assert_expected_result_files
351
+ t = Tap::FileTask.new("task/name") do |task, input_file|
352
+ output_file = task.filepath(:data, File.basename(input_file))
353
+ content = "#{File.read(input_file)}content"
354
+
355
+ assert_equal method_filepath(:output, "task/name", File.basename(input_file)), output_file
356
+
357
+ task.prepare(output_file)
358
+ File.open(output_file, "wb") {|f| f << content}
359
+ output_file
360
+ end
361
+
362
+ was_in_block=false
363
+ assert_expected_result_files(t) do |output_files|
364
+ was_in_block = true
365
+ assert_equal [method_filepath(:output, "task/name/a.txt"), method_filepath(:output, "task/name/b.txt")], output_files
366
+ output_files
367
+ end
368
+
369
+ assert was_in_block
370
+ end
371
+
232
372
  end
233
373
 
@@ -2,6 +2,8 @@ require File.join(File.dirname(__FILE__), 'tap_test_helper')
2
2
  require 'tap/workflow'
3
3
 
4
4
  class WorkflowTest < Test::Unit::TestCase
5
+ include TapTestMethods
6
+
5
7
  acts_as_tap_test
6
8
 
7
9
  def test_workflow_raises_error_if_no_task_block_is_provided
@@ -0,0 +1,56 @@
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
+ #########################################################################
25
+ #--
26
+ # Added to Tap by Simon Chiang so that rails doesn't need to be installed
27
+ # for access to generators. A minor modification was required to remove
28
+ # a dependency on ActiveRecord, and the addition of the activesupport
29
+ # path was removed below. The default rails generators were also removed.
30
+ #
31
+ # Changes:
32
+ # commented out path addition below
33
+ # modified 'rails_generator/base' line 231
34
+ # removed 'rails_generator/generators'
35
+ #++
36
+
37
+ $:.unshift(File.dirname(__FILE__))
38
+ #$:.unshift(File.dirname(__FILE__) + "/../../activesupport/lib")
39
+
40
+ begin
41
+ require 'active_support'
42
+ rescue LoadError
43
+ require 'rubygems'
44
+ gem 'activesupport'
45
+ end
46
+
47
+ require 'rails_generator/base'
48
+ require 'rails_generator/lookup'
49
+ require 'rails_generator/commands'
50
+
51
+ Rails::Generator::Base.send(:include, Rails::Generator::Lookup)
52
+ Rails::Generator::Base.send(:include, Rails::Generator::Commands)
53
+
54
+ # Set up a default logger for convenience.
55
+ require 'rails_generator/simple_logger'
56
+ Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(STDOUT)
@@ -0,0 +1,263 @@
1
+ require File.dirname(__FILE__) + '/options'
2
+ require File.dirname(__FILE__) + '/manifest'
3
+ require File.dirname(__FILE__) + '/spec'
4
+ require File.dirname(__FILE__) + '/generated_attribute'
5
+
6
+ module Rails
7
+ # Rails::Generator is a code generation platform tailored for the Rails
8
+ # web application framework. Generators are easily invoked within Rails
9
+ # applications to add and remove components such as models and controllers.
10
+ # New generators are easy to create and may be distributed as RubyGems,
11
+ # tarballs, or Rails plugins for inclusion system-wide, per-user,
12
+ # or per-application.
13
+ #
14
+ # For actual examples see the rails_generator/generators directory in the
15
+ # Rails source (or the +railties+ directory if you have frozen the Rails
16
+ # source in your application).
17
+ #
18
+ # Generators may subclass other generators to provide variations that
19
+ # require little or no new logic but replace the template files.
20
+ #
21
+ # For a RubyGem, put your generator class and templates in the +lib+
22
+ # directory. For a Rails plugin, make a +generators+ directory at the
23
+ # root of your plugin.
24
+ #
25
+ # The layout of generator files can be seen in the built-in
26
+ # +controller+ generator:
27
+ #
28
+ # generators/
29
+ # controller/
30
+ # controller_generator.rb
31
+ # templates/
32
+ # controller.rb
33
+ # functional_test.rb
34
+ # helper.rb
35
+ # view.rhtml
36
+ #
37
+ # The directory name (+controller+) matches the name of the generator file
38
+ # (controller_generator.rb) and class (+ControllerGenerator+). The files
39
+ # that will be copied or used as templates are stored in the +templates+
40
+ # directory.
41
+ #
42
+ # The filenames of the templates don't matter, but choose something that
43
+ # will be self-explatatory since you will be referencing these in the
44
+ # +manifest+ method inside your generator subclass.
45
+ #
46
+ #
47
+ module Generator
48
+ class GeneratorError < StandardError; end
49
+ class UsageError < GeneratorError; end
50
+
51
+
52
+ # The base code generator is bare-bones. It sets up the source and
53
+ # destination paths and tells the logger whether to keep its trap shut.
54
+ #
55
+ # It's useful for copying files such as stylesheets, images, or
56
+ # javascripts.
57
+ #
58
+ # For more comprehensive template-based passive code generation with
59
+ # arguments, you'll want Rails::Generator::NamedBase.
60
+ #
61
+ # Generators create a manifest of the actions they perform then hand
62
+ # the manifest to a command which replays the actions to do the heavy
63
+ # lifting (such as checking for existing files or creating directories
64
+ # if needed). Create, destroy, and list commands are included. Since a
65
+ # single manifest may be used by any command, creating new generators is
66
+ # as simple as writing some code templates and declaring what you'd like
67
+ # to do with them.
68
+ #
69
+ # The manifest method must be implemented by subclasses, returning a
70
+ # Rails::Generator::Manifest. The +record+ method is provided as a
71
+ # convenience for manifest creation. Example:
72
+ #
73
+ # class StylesheetGenerator < Rails::Generator::Base
74
+ # def manifest
75
+ # record do |m|
76
+ # m.directory('public/stylesheets')
77
+ # m.file('application.css', 'public/stylesheets/application.css')
78
+ # end
79
+ # end
80
+ # end
81
+ #
82
+ # See Rails::Generator::Commands::Create for a list of methods available
83
+ # to the manifest.
84
+ class Base
85
+ include Options
86
+
87
+ # Declare default options for the generator. These options
88
+ # are inherited to subclasses.
89
+ default_options :collision => :ask, :quiet => false
90
+
91
+ # A logger instance available everywhere in the generator.
92
+ cattr_accessor :logger
93
+
94
+ # Every generator that is dynamically looked up is tagged with a
95
+ # Spec describing where it was found.
96
+ class_inheritable_accessor :spec
97
+
98
+ attr_reader :source_root, :destination_root, :args
99
+
100
+ def initialize(runtime_args, runtime_options = {})
101
+ @args = runtime_args
102
+ parse!(@args, runtime_options)
103
+
104
+ # Derive source and destination paths.
105
+ @source_root = options[:source] || File.join(spec.path, 'templates')
106
+ if options[:destination]
107
+ @destination_root = options[:destination]
108
+ elsif defined? ::RAILS_ROOT
109
+ @destination_root = ::RAILS_ROOT
110
+ end
111
+
112
+ # Silence the logger if requested.
113
+ logger.quiet = options[:quiet]
114
+
115
+ # Raise usage error if help is requested.
116
+ usage if options[:help]
117
+ end
118
+
119
+ # Generators must provide a manifest. Use the +record+ method to create
120
+ # a new manifest and record your generator's actions.
121
+ def manifest
122
+ raise NotImplementedError, "No manifest for '#{spec.name}' generator."
123
+ end
124
+
125
+ # Return the full path from the source root for the given path.
126
+ # Example for source_root = '/source':
127
+ # source_path('some/path.rb') == '/source/some/path.rb'
128
+ #
129
+ # The given path may include a colon ':' character to indicate that
130
+ # the file belongs to another generator. This notation allows any
131
+ # generator to borrow files from another. Example:
132
+ # source_path('model:fixture.yml') = '/model/source/path/fixture.yml'
133
+ def source_path(relative_source)
134
+ # Check whether we're referring to another generator's file.
135
+ name, path = relative_source.split(':', 2)
136
+
137
+ # If not, return the full path to our source file.
138
+ if path.nil?
139
+ File.join(source_root, name)
140
+
141
+ # Otherwise, ask our referral for the file.
142
+ else
143
+ # FIXME: this is broken, though almost always true. Others'
144
+ # source_root are not necessarily the templates dir.
145
+ File.join(self.class.lookup(name).path, 'templates', path)
146
+ end
147
+ end
148
+
149
+ # Return the full path from the destination root for the given path.
150
+ # Example for destination_root = '/dest':
151
+ # destination_path('some/path.rb') == '/dest/some/path.rb'
152
+ def destination_path(relative_destination)
153
+ File.join(destination_root, relative_destination)
154
+ end
155
+
156
+ protected
157
+ # Convenience method for generator subclasses to record a manifest.
158
+ def record
159
+ Rails::Generator::Manifest.new(self) { |m| yield m }
160
+ end
161
+
162
+ # Override with your own usage banner.
163
+ def banner
164
+ "Usage: #{$0} #{spec.name} [options]"
165
+ end
166
+
167
+ # Read USAGE from file in generator base path.
168
+ def usage_message
169
+ File.read(File.join(spec.path, 'USAGE')) rescue ''
170
+ end
171
+ end
172
+
173
+
174
+ # The base generator for named components: models, controllers, mailers,
175
+ # etc. The target name is taken as the first argument and inflected to
176
+ # singular, plural, class, file, and table forms for your convenience.
177
+ # The remaining arguments are aliased to +actions+ as an array for
178
+ # controller and mailer convenience.
179
+ #
180
+ # Several useful local variables and methods are populated in the
181
+ # +initialize+ method. See below for a list of Attributes and
182
+ # External Aliases available to both the manifest and to all templates.
183
+ #
184
+ # If no name is provided, the generator raises a usage error with content
185
+ # optionally read from the USAGE file in the generator's base path.
186
+ #
187
+ # For example, the +controller+ generator takes the first argument as
188
+ # the name of the class and subsequent arguments as the names of
189
+ # actions to be generated:
190
+ #
191
+ # ./script/generate controller Article index new create
192
+ #
193
+ # See Rails::Generator::Base for a discussion of manifests,
194
+ # Rails::Generator::Commands::Create for methods available to the manifest,
195
+ # and Rails::Generator for a general discussion of generators.
196
+ class NamedBase < Base
197
+ attr_reader :name, :class_name, :singular_name, :plural_name, :table_name
198
+ attr_reader :class_path, :file_path, :class_nesting, :class_nesting_depth
199
+ alias_method :file_name, :singular_name
200
+ alias_method :actions, :args
201
+
202
+ def initialize(runtime_args, runtime_options = {})
203
+ super
204
+
205
+ # Name argument is required.
206
+ usage if runtime_args.empty?
207
+
208
+ @args = runtime_args.dup
209
+ base_name = @args.shift
210
+ assign_names!(base_name)
211
+ end
212
+
213
+ protected
214
+ # Override with your own usage banner.
215
+ def banner
216
+ "Usage: #{$0} #{spec.name} #{spec.name.camelize}Name [options]"
217
+ end
218
+
219
+ def attributes
220
+ @attributes ||= @args.collect do |attribute|
221
+ Rails::Generator::GeneratedAttribute.new(*attribute.split(":"))
222
+ end
223
+ end
224
+
225
+
226
+ private
227
+ def assign_names!(name)
228
+ @name = name
229
+ base_name, @class_path, @file_path, @class_nesting, @class_nesting_depth = extract_modules(@name)
230
+ @class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
231
+ # Modified: such that ActiveRecord::Base is not needed. Default is plural_name.
232
+ #@table_name = ActiveRecord::Base.pluralize_table_names ? plural_name : singular_name
233
+ @table_name = plural_name
234
+ if @class_nesting.empty?
235
+ @class_name = @class_name_without_nesting
236
+ else
237
+ @table_name = @class_nesting.underscore << "_" << @table_name
238
+ @class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
239
+ end
240
+ end
241
+
242
+ # Extract modules from filesystem-style or ruby-style path:
243
+ # good/fun/stuff
244
+ # Good::Fun::Stuff
245
+ # produce the same results.
246
+ def extract_modules(name)
247
+ modules = name.include?('/') ? name.split('/') : name.split('::')
248
+ name = modules.pop
249
+ path = modules.map { |m| m.underscore }
250
+ file_path = (path + [name.underscore]).join('/')
251
+ nesting = modules.map { |m| m.camelize }.join('::')
252
+ [name, path, file_path, nesting, modules.size]
253
+ end
254
+
255
+ def inflect_names(name)
256
+ camel = name.camelize
257
+ under = camel.underscore
258
+ plural = under.pluralize
259
+ [camel, under, plural]
260
+ end
261
+ end
262
+ end
263
+ end