rails_product 0.5

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 (114) hide show
  1. data/CHANGELOG +619 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +195 -0
  4. data/Rakefile +413 -0
  5. data/bin/benchmarker +19 -0
  6. data/bin/breakpointer +3 -0
  7. data/bin/breakpointer_for_gem +4 -0
  8. data/bin/console +23 -0
  9. data/bin/console_sandbox +0 -0
  10. data/bin/destroy +7 -0
  11. data/bin/generate +7 -0
  12. data/bin/listener +86 -0
  13. data/bin/process/reaper +123 -0
  14. data/bin/process/spawner +54 -0
  15. data/bin/process/spinner +60 -0
  16. data/bin/profiler +34 -0
  17. data/bin/rails +17 -0
  18. data/bin/rails_product +17 -0
  19. data/bin/runner +28 -0
  20. data/bin/server +125 -0
  21. data/bin/tracker +69 -0
  22. data/bin/update +5 -0
  23. data/configs/apache/vhost.example.conf +42 -0
  24. data/configs/apache.conf +40 -0
  25. data/configs/database.yml +23 -0
  26. data/configs/empty.log +0 -0
  27. data/configs/routes.rb +19 -0
  28. data/dispatches/dispatch.fcgi +24 -0
  29. data/dispatches/dispatch.rb +10 -0
  30. data/dispatches/gateway.cgi +97 -0
  31. data/doc/README_FOR_APP +2 -0
  32. data/environments/development.rb +14 -0
  33. data/environments/environment.rb +101 -0
  34. data/environments/production.rb +8 -0
  35. data/environments/test.rb +17 -0
  36. data/fresh_rakefile +223 -0
  37. data/helpers/application.rb +4 -0
  38. data/helpers/application_helper.rb +3 -0
  39. data/helpers/test_helper.rb +26 -0
  40. data/html/404.html +8 -0
  41. data/html/500.html +8 -0
  42. data/html/favicon.ico +0 -0
  43. data/html/index.html +78 -0
  44. data/html/javascripts/controls.js +446 -0
  45. data/html/javascripts/dragdrop.js +537 -0
  46. data/html/javascripts/effects.js +612 -0
  47. data/html/javascripts/prototype.js +1038 -0
  48. data/html/robots.txt +1 -0
  49. data/lib/binding_of_caller.rb +83 -0
  50. data/lib/breakpoint.rb +523 -0
  51. data/lib/breakpoint_client.rb +196 -0
  52. data/lib/code_statistics.rb +104 -0
  53. data/lib/console_sandbox.rb +6 -0
  54. data/lib/dispatcher.rb +59 -0
  55. data/lib/fcgi_handler.rb +156 -0
  56. data/lib/productize.rb +116 -0
  57. data/lib/rails_generator/base.rb +203 -0
  58. data/lib/rails_generator/commands.rb +409 -0
  59. data/lib/rails_generator/generators/applications/app/USAGE +16 -0
  60. data/lib/rails_generator/generators/applications/app/app_generator.rb +126 -0
  61. data/lib/rails_generator/generators/applications/productized_app/USAGE +16 -0
  62. data/lib/rails_generator/generators/applications/productized_app/productized_app_generator.rb +133 -0
  63. data/lib/rails_generator/generators/components/controller/USAGE +30 -0
  64. data/lib/rails_generator/generators/components/controller/controller_generator.rb +38 -0
  65. data/lib/rails_generator/generators/components/controller/templates/controller.rb +10 -0
  66. data/lib/rails_generator/generators/components/controller/templates/functional_test.rb +18 -0
  67. data/lib/rails_generator/generators/components/controller/templates/helper.rb +2 -0
  68. data/lib/rails_generator/generators/components/controller/templates/view.rhtml +2 -0
  69. data/lib/rails_generator/generators/components/mailer/USAGE +19 -0
  70. data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +32 -0
  71. data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +3 -0
  72. data/lib/rails_generator/generators/components/mailer/templates/mailer.rb +13 -0
  73. data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +37 -0
  74. data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +3 -0
  75. data/lib/rails_generator/generators/components/migration/USAGE +14 -0
  76. data/lib/rails_generator/generators/components/migration/migration_generator.rb +9 -0
  77. data/lib/rails_generator/generators/components/migration/templates/migration.rb +7 -0
  78. data/lib/rails_generator/generators/components/model/USAGE +17 -0
  79. data/lib/rails_generator/generators/components/model/model_generator.rb +18 -0
  80. data/lib/rails_generator/generators/components/model/templates/fixtures.yml +5 -0
  81. data/lib/rails_generator/generators/components/model/templates/model.rb +2 -0
  82. data/lib/rails_generator/generators/components/model/templates/unit_test.rb +14 -0
  83. data/lib/rails_generator/generators/components/scaffold/USAGE +32 -0
  84. data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +178 -0
  85. data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +54 -0
  86. data/lib/rails_generator/generators/components/scaffold/templates/form.rhtml +3 -0
  87. data/lib/rails_generator/generators/components/scaffold/templates/form_scaffolding.rhtml +1 -0
  88. data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +98 -0
  89. data/lib/rails_generator/generators/components/scaffold/templates/helper.rb +2 -0
  90. data/lib/rails_generator/generators/components/scaffold/templates/layout.rhtml +13 -0
  91. data/lib/rails_generator/generators/components/scaffold/templates/style.css +74 -0
  92. data/lib/rails_generator/generators/components/scaffold/templates/view_edit.rhtml +9 -0
  93. data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +27 -0
  94. data/lib/rails_generator/generators/components/scaffold/templates/view_new.rhtml +8 -0
  95. data/lib/rails_generator/generators/components/scaffold/templates/view_show.rhtml +8 -0
  96. data/lib/rails_generator/generators/components/web_service/USAGE +28 -0
  97. data/lib/rails_generator/generators/components/web_service/templates/api_definition.rb +5 -0
  98. data/lib/rails_generator/generators/components/web_service/templates/controller.rb +8 -0
  99. data/lib/rails_generator/generators/components/web_service/templates/functional_test.rb +19 -0
  100. data/lib/rails_generator/generators/components/web_service/web_service_generator.rb +29 -0
  101. data/lib/rails_generator/lookup.rb +206 -0
  102. data/lib/rails_generator/manifest.rb +53 -0
  103. data/lib/rails_generator/options.rb +134 -0
  104. data/lib/rails_generator/scripts/destroy.rb +7 -0
  105. data/lib/rails_generator/scripts/generate.rb +7 -0
  106. data/lib/rails_generator/scripts/update.rb +12 -0
  107. data/lib/rails_generator/scripts.rb +83 -0
  108. data/lib/rails_generator/simple_logger.rb +46 -0
  109. data/lib/rails_generator/spec.rb +44 -0
  110. data/lib/rails_generator.rb +43 -0
  111. data/lib/rubyprof_ext.rb +35 -0
  112. data/lib/webrick_server.rb +148 -0
  113. data/sites/fresh_rakefile +176 -0
  114. metadata +250 -0
@@ -0,0 +1,203 @@
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? ::RAILS_ROOT
71
+ @destination_root = ::RAILS_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
148
+ attr_reader :class_path, :file_path, :class_nesting, :class_nesting_depth
149
+ alias_method :file_name, :singular_name
150
+ alias_method :table_name, :plural_name
151
+ alias_method :actions, :args
152
+
153
+ def initialize(runtime_args, runtime_options = {})
154
+ super
155
+
156
+ # Name argument is required.
157
+ usage if runtime_args.empty?
158
+
159
+ @args = runtime_args.dup
160
+ base_name = @args.shift
161
+ assign_names!(base_name)
162
+ end
163
+
164
+ protected
165
+ # Override with your own usage banner.
166
+ def banner
167
+ "Usage: #{$0} #{spec.name} #{spec.name.camelize}Name [options]"
168
+ end
169
+
170
+ private
171
+ def assign_names!(name)
172
+ @name = name
173
+ base_name, @class_path, @file_path, @class_nesting, @class_nesting_depth = extract_modules(@name)
174
+ @class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_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
@@ -0,0 +1,409 @@
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.append_features(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
+ private
59
+ # Ask the user interactively whether to force collision.
60
+ def force_file_collision?(destination)
61
+ $stdout.print "overwrite #{destination}? [Ynaq] "
62
+ case $stdin.gets
63
+ when /a/i
64
+ $stdout.puts "forcing #{spec.name}"
65
+ options[:collision] = :force
66
+ when /q/i
67
+ $stdout.puts "aborting #{spec.name}"
68
+ raise SystemExit
69
+ when /n/i then :skip
70
+ else :force
71
+ end
72
+ rescue
73
+ retry
74
+ end
75
+
76
+ def render_template_part(template_options)
77
+ # Getting Sandbox to evaluate part template in it
78
+ part_binding = template_options[:sandbox].call.sandbox_binding
79
+ part_rel_path = template_options[:insert]
80
+ part_path = source_path(part_rel_path)
81
+
82
+ # Render inner template within Sandbox binding
83
+ rendered_part = ERB.new(File.readlines(part_path).join, nil, '-').result(part_binding)
84
+ begin_mark = template_part_mark(template_options[:begin_mark], template_options[:mark_id])
85
+ end_mark = template_part_mark(template_options[:end_mark], template_options[:mark_id])
86
+ begin_mark + rendered_part + end_mark
87
+ end
88
+
89
+ def template_part_mark(name, id)
90
+ "<!--[#{name}:#{id}]-->\n"
91
+ end
92
+ end
93
+
94
+ # Base class for commands which handle generator actions in reverse, such as Destroy.
95
+ class RewindBase < Base
96
+ # Rewind action manifest.
97
+ def invoke!
98
+ manifest.rewind(self)
99
+ end
100
+ end
101
+
102
+
103
+ # Create is the premier generator command. It copies files, creates
104
+ # directories, renders templates, and more.
105
+ class Create < Base
106
+
107
+ # Check whether the given class names are already taken by
108
+ # Ruby or Rails. In the future, expand to check other namespaces
109
+ # such as the rest of the user's app.
110
+ def class_collisions(*class_names)
111
+ class_names.flatten.each do |class_name|
112
+ # Convert to string to allow symbol arguments.
113
+ class_name = class_name.to_s
114
+
115
+ # Skip empty strings.
116
+ next if class_name.strip.empty?
117
+
118
+ # Split the class from its module nesting.
119
+ nesting = class_name.split('::')
120
+ name = nesting.pop
121
+
122
+ # Extract the last Module in the nesting.
123
+ last = nesting.inject(Object) { |last, nest|
124
+ break unless last.const_defined?(nest)
125
+ last.const_get(nest)
126
+ }
127
+
128
+ # If the last Module exists, check whether the given
129
+ # class exists and raise a collision if so.
130
+ if last and last.const_defined?(name.camelize)
131
+ raise_class_collision(class_name)
132
+ end
133
+ end
134
+ end
135
+
136
+ # Copy a file from source to destination with collision checking.
137
+ #
138
+ # The file_options hash accepts :chmod and :shebang options.
139
+ # :chmod sets the permissions of the destination file:
140
+ # file 'config/empty.log', 'log/test.log', :chmod => 0664
141
+ # :shebang sets the #!/usr/bin/ruby line for scripts
142
+ # file 'bin/generate.rb', 'script/generate', :chmod => 0755, :shebang => '/usr/bin/env ruby'
143
+ #
144
+ # Collisions are handled by checking whether the destination file
145
+ # exists and either skipping the file, forcing overwrite, or asking
146
+ # the user what to do.
147
+ def file(relative_source, relative_destination, file_options = {})
148
+ # Determine full paths for source and destination files.
149
+ source = source_path(relative_source)
150
+ destination = destination_path(relative_destination)
151
+
152
+ # Check for and resolve file collisions.
153
+ if File.exists?(destination)
154
+
155
+ # Make a choice whether to overwrite the file. :force and
156
+ # :skip already have their mind made up, but give :ask a shot.
157
+ choice = case options[:collision].to_sym #|| :ask
158
+ when :ask then force_file_collision?(relative_destination)
159
+ when :force then :force
160
+ when :skip then :skip
161
+ else raise "Invalid collision option: #{options[:collision].inspect}"
162
+ end
163
+
164
+ # Take action based on our choice. Bail out if we chose to
165
+ # skip the file; otherwise, log our transgression and continue.
166
+ case choice
167
+ when :force then logger.force(relative_destination)
168
+ when :skip then return(logger.skip(relative_destination))
169
+ else raise "Invalid collision choice: #{choice}.inspect"
170
+ end
171
+
172
+ # File doesn't exist so log its unbesmirched creation.
173
+ else
174
+ logger.create relative_destination
175
+ end
176
+
177
+ # If we're pretending, back off now.
178
+ return if options[:pretend]
179
+
180
+ # Write destination file with optional shebang. Yield for content
181
+ # if block given so templaters may render the source file. If a
182
+ # shebang is requested, replace the existing shebang or insert a
183
+ # new one.
184
+ File.open(destination, 'w') do |df|
185
+ File.open(source) do |sf|
186
+ if block_given?
187
+ df.write(yield(sf))
188
+ else
189
+ line = sf.gets
190
+ if file_options[:shebang]
191
+ df.puts("#!#{file_options[:shebang]}")
192
+ df.puts(line) if line !~ /^#!/
193
+ else
194
+ df.puts(line)
195
+ end
196
+ df.write(sf.read)
197
+ end
198
+ end
199
+ end
200
+
201
+ # Optionally change permissions.
202
+ if file_options[:chmod]
203
+ FileUtils.chmod(file_options[:chmod], destination)
204
+ end
205
+ end
206
+
207
+ # Generate a file for a Rails application using an ERuby template.
208
+ # Looks up and evalutes a template by name and writes the result.
209
+ #
210
+ # The ERB template uses explicit trim mode to best control the
211
+ # proliferation of whitespace in generated code. <%- trims leading
212
+ # whitespace; -%> trims trailing whitespace including one newline.
213
+ #
214
+ # A hash of template options may be passed as the last argument.
215
+ # The options accepted by the file are accepted as well as :assigns,
216
+ # a hash of variable bindings. Example:
217
+ # template 'foo', 'bar', :assigns => { :action => 'view' }
218
+ #
219
+ # Template is implemented in terms of file. It calls file with a
220
+ # block which takes a file handle and returns its rendered contents.
221
+ def template(relative_source, relative_destination, template_options = {})
222
+ file(relative_source, relative_destination, template_options) do |file|
223
+ # Evaluate any assignments in a temporary, throwaway binding.
224
+ vars = template_options[:assigns] || {}
225
+ b = binding
226
+ vars.each { |k,v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
227
+
228
+ # Render the source file with the temporary binding.
229
+ ERB.new(file.read, nil, '-').result(b)
230
+ end
231
+ end
232
+
233
+ def complex_template(relative_source, relative_destination, template_options = {})
234
+ options = template_options.dup
235
+ options[:assigns] ||= {}
236
+ options[:assigns]['template_for_inclusion'] = render_template_part(template_options)
237
+ template(relative_source, relative_destination, options)
238
+ end
239
+
240
+ # Create a directory including any missing parent directories.
241
+ # Always directories which exist.
242
+ def directory(relative_path)
243
+ path = destination_path(relative_path)
244
+ if File.exists?(path)
245
+ logger.exists relative_path
246
+ else
247
+ logger.create relative_path
248
+ FileUtils.mkdir_p(path) unless options[:pretend]
249
+ end
250
+ end
251
+
252
+ # Display a README.
253
+ def readme(*relative_sources)
254
+ relative_sources.flatten.each do |relative_source|
255
+ logger.readme relative_source
256
+ puts File.read(source_path(relative_source)) unless options[:pretend]
257
+ end
258
+ end
259
+
260
+ private
261
+ # Raise a usage error with an informative WordNet suggestion.
262
+ # Thanks to Florian Gross (flgr).
263
+ def raise_class_collision(class_name)
264
+ message = <<end_message
265
+ The name '#{class_name}' is reserved by Ruby on Rails.
266
+ Please choose an alternative and run this generator again.
267
+ end_message
268
+ if suggest = find_synonyms(class_name)
269
+ message << "\n Suggestions: \n\n"
270
+ message << suggest.join("\n")
271
+ end
272
+ raise UsageError, message
273
+ end
274
+
275
+ SYNONYM_LOOKUP_URI = "http://wordnet.princeton.edu/cgi-bin/webwn2.0?stage=2&word=%s&posnumber=1&searchtypenumber=2&senses=&showglosses=1"
276
+
277
+ # Look up synonyms on WordNet. Thanks to Florian Gross (flgr).
278
+ def find_synonyms(word)
279
+ require 'open-uri'
280
+ require 'timeout'
281
+ timeout(5) do
282
+ open(SYNONYM_LOOKUP_URI % word) do |stream|
283
+ data = stream.read.gsub("&nbsp;", " ").gsub("<BR>", "")
284
+ data.scan(/^Sense \d+\n.+?\n\n/m)
285
+ end
286
+ end
287
+ rescue Exception
288
+ return nil
289
+ end
290
+ end
291
+
292
+
293
+ # Undo the actions performed by a generator. Rewind the action
294
+ # manifest and attempt to completely erase the results of each action.
295
+ class Destroy < RewindBase
296
+ # Remove a file if it exists and is a file.
297
+ def file(relative_source, relative_destination, options = {})
298
+ destination = destination_path(relative_destination)
299
+ if File.exists?(destination)
300
+ logger.rm relative_destination
301
+ FileUtils.rm(destination) unless options[:pretend]
302
+ else
303
+ logger.missing relative_destination
304
+ return
305
+ end
306
+ end
307
+
308
+ # Templates are deleted just like files and the actions take the
309
+ # same parameters, so simply alias the file method.
310
+ alias_method :template, :file
311
+
312
+ # Remove each directory in the given path from right to left.
313
+ # Remove each subdirectory if it exists and is a directory.
314
+ def directory(relative_path)
315
+ parts = relative_path.split('/')
316
+ until parts.empty?
317
+ partial = File.join(parts)
318
+ path = destination_path(partial)
319
+ if File.exists?(path)
320
+ if Dir[File.join(path, '*')].empty?
321
+ logger.rmdir partial
322
+ FileUtils.rmdir(path) unless options[:pretend]
323
+ else
324
+ logger.notempty partial
325
+ end
326
+ else
327
+ logger.missing partial
328
+ end
329
+ parts.pop
330
+ end
331
+ end
332
+
333
+ def complex_template(*args)
334
+ # nothing should be done here
335
+ end
336
+ end
337
+
338
+
339
+ # List a generator's action manifest.
340
+ class List < Base
341
+ def dependency(generator_name, args, options = {})
342
+ logger.dependency "#{generator_name}(#{args.join(', ')}, #{options.inspect})"
343
+ end
344
+
345
+ def class_collisions(*class_names)
346
+ logger.class_collisions class_names.join(', ')
347
+ end
348
+
349
+ def file(relative_source, relative_destination, options = {})
350
+ logger.file relative_destination
351
+ end
352
+
353
+ def template(relative_source, relative_destination, options = {})
354
+ logger.template relative_destination
355
+ end
356
+
357
+ def complex_template(relative_source, relative_destination, options = {})
358
+ logger.template "#{options[:insert]} inside #{relative_destination}"
359
+ end
360
+
361
+ def directory(relative_path)
362
+ logger.directory "#{destination_path(relative_path)}/"
363
+ end
364
+
365
+ def readme(*args)
366
+ logger.readme args.join(', ')
367
+ end
368
+ end
369
+
370
+ # Update generator's action manifest.
371
+ class Update < Create
372
+ def file(relative_source, relative_destination, options = {})
373
+ # logger.file relative_destination
374
+ end
375
+
376
+ def template(relative_source, relative_destination, options = {})
377
+ # logger.template relative_destination
378
+ end
379
+
380
+ def complex_template(relative_source, relative_destination, template_options = {})
381
+
382
+ begin
383
+ dest_file = destination_path(relative_destination)
384
+ source_to_update = File.readlines(dest_file).join
385
+ rescue Errno::ENOENT
386
+ logger.missing relative_destination
387
+ return
388
+ end
389
+
390
+ logger.refreshing "#{template_options[:insert].gsub(/\.rhtml/,'')} inside #{relative_destination}"
391
+
392
+ begin_mark = Regexp.quote(template_part_mark(template_options[:begin_mark], template_options[:mark_id]))
393
+ end_mark = Regexp.quote(template_part_mark(template_options[:end_mark], template_options[:mark_id]))
394
+
395
+ # Refreshing inner part of the template with freshly rendered part.
396
+ rendered_part = render_template_part(template_options)
397
+ source_to_update.gsub!(/#{begin_mark}.*?#{end_mark}/m, rendered_part)
398
+
399
+ File.open(dest_file, 'w') { |file| file.write(source_to_update) }
400
+ end
401
+
402
+ def directory(relative_path)
403
+ # logger.directory "#{destination_path(relative_path)}/"
404
+ end
405
+ end
406
+
407
+ end
408
+ end
409
+ end
@@ -0,0 +1,16 @@
1
+ Description:
2
+ The 'rails' command creates a new Rails application with a default
3
+ directory structure and configuration at the path you specify.
4
+
5
+ Example:
6
+ rails ~/Code/Ruby/weblog
7
+
8
+ This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
9
+ See the README in the newly created application to get going.
10
+
11
+ WARNING:
12
+ Only specify --without-gems if you did not use gems to install Rails.
13
+ Your application will expect to find activerecord, actionpack, and
14
+ actionmailer directories in the vendor directory. A popular way to track
15
+ the bleeding edge of Rails development is to checkout from source control
16
+ directly to the vendor directory. See http://dev.rubyonrails.com