erails 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. data/CHANGELOG +3 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +309 -0
  4. data/Rakefile +339 -0
  5. data/bin/about +4 -0
  6. data/bin/console +3 -0
  7. data/bin/dbconsole +3 -0
  8. data/bin/destroy +3 -0
  9. data/bin/erails +19 -0
  10. data/bin/generate +3 -0
  11. data/bin/performance/benchmarker +3 -0
  12. data/bin/performance/profiler +3 -0
  13. data/bin/performance/request +3 -0
  14. data/bin/plugin +3 -0
  15. data/bin/process/inspector +3 -0
  16. data/bin/process/reaper +3 -0
  17. data/bin/process/spawner +3 -0
  18. data/bin/runner +3 -0
  19. data/bin/server +3 -0
  20. data/builtin/rails_info/rails/info.rb +125 -0
  21. data/builtin/rails_info/rails/info_controller.rb +9 -0
  22. data/builtin/rails_info/rails/info_helper.rb +2 -0
  23. data/builtin/rails_info/rails_info_controller.rb +2 -0
  24. data/configs/apache.conf +40 -0
  25. data/configs/databases/frontbase.yml +28 -0
  26. data/configs/databases/mysql.yml +54 -0
  27. data/configs/databases/oracle.yml +39 -0
  28. data/configs/databases/postgresql.yml +48 -0
  29. data/configs/databases/sqlite2.yml +16 -0
  30. data/configs/databases/sqlite3.yml +19 -0
  31. data/configs/empty.log +0 -0
  32. data/configs/initializers/inflections.rb +10 -0
  33. data/configs/initializers/mime_types.rb +5 -0
  34. data/configs/initializers/new_rails_defaults.rb +17 -0
  35. data/configs/lighttpd.conf +54 -0
  36. data/configs/routes.rb +43 -0
  37. data/dispatches/dispatch.fcgi +24 -0
  38. data/dispatches/dispatch.rb +10 -0
  39. data/dispatches/gateway.cgi +97 -0
  40. data/doc/README_FOR_APP +2 -0
  41. data/environments/boot.rb +109 -0
  42. data/environments/development.rb +16 -0
  43. data/environments/environment.rb +71 -0
  44. data/environments/production.rb +22 -0
  45. data/environments/test.rb +22 -0
  46. data/fresh_rakefile +10 -0
  47. data/helpers/application.rb +15 -0
  48. data/helpers/application_helper.rb +3 -0
  49. data/helpers/test_helper.rb +38 -0
  50. data/html/404.html +30 -0
  51. data/html/422.html +30 -0
  52. data/html/500.html +30 -0
  53. data/html/favicon.ico +0 -0
  54. data/html/images/rails.png +0 -0
  55. data/html/index.html +274 -0
  56. data/html/javascripts/application.js +2 -0
  57. data/html/robots.txt +5 -0
  58. data/lib/code_statistics.rb +107 -0
  59. data/lib/commands/about.rb +3 -0
  60. data/lib/commands/console.rb +32 -0
  61. data/lib/commands/dbconsole.rb +67 -0
  62. data/lib/commands/destroy.rb +6 -0
  63. data/lib/commands/generate.rb +6 -0
  64. data/lib/commands/ncgi/listener +86 -0
  65. data/lib/commands/ncgi/tracker +69 -0
  66. data/lib/commands/performance/benchmarker.rb +24 -0
  67. data/lib/commands/performance/profiler.rb +50 -0
  68. data/lib/commands/performance/request.rb +6 -0
  69. data/lib/commands/plugin.rb +950 -0
  70. data/lib/commands/process/inspector.rb +68 -0
  71. data/lib/commands/process/reaper.rb +149 -0
  72. data/lib/commands/process/spawner.rb +219 -0
  73. data/lib/commands/process/spinner.rb +57 -0
  74. data/lib/commands/runner.rb +48 -0
  75. data/lib/commands/server.rb +39 -0
  76. data/lib/commands/servers/base.rb +31 -0
  77. data/lib/commands/servers/lighttpd.rb +94 -0
  78. data/lib/commands/servers/mongrel.rb +69 -0
  79. data/lib/commands/servers/new_mongrel.rb +16 -0
  80. data/lib/commands/servers/webrick.rb +66 -0
  81. data/lib/commands/update.rb +4 -0
  82. data/lib/commands.rb +17 -0
  83. data/lib/console_app.rb +30 -0
  84. data/lib/console_sandbox.rb +6 -0
  85. data/lib/console_with_helpers.rb +26 -0
  86. data/lib/dispatcher.rb +24 -0
  87. data/lib/fcgi_handler.rb +239 -0
  88. data/lib/initializer.rb +926 -0
  89. data/lib/rails/gem_builder.rb +21 -0
  90. data/lib/rails/gem_dependency.rb +129 -0
  91. data/lib/rails/mongrel_server/commands.rb +342 -0
  92. data/lib/rails/mongrel_server/handler.rb +55 -0
  93. data/lib/rails/plugin/loader.rb +152 -0
  94. data/lib/rails/plugin/locator.rb +100 -0
  95. data/lib/rails/plugin.rb +116 -0
  96. data/lib/rails/version.rb +9 -0
  97. data/lib/rails_generator/base.rb +263 -0
  98. data/lib/rails_generator/commands.rb +622 -0
  99. data/lib/rails_generator/generated_attribute.rb +42 -0
  100. data/lib/rails_generator/generators/applications/app/USAGE +9 -0
  101. data/lib/rails_generator/generators/applications/app/app_generator.rb +174 -0
  102. data/lib/rails_generator/generators/components/controller/USAGE +29 -0
  103. data/lib/rails_generator/generators/components/controller/controller_generator.rb +37 -0
  104. data/lib/rails_generator/generators/components/controller/templates/controller.rb +7 -0
  105. data/lib/rails_generator/generators/components/controller/templates/functional_test.rb +8 -0
  106. data/lib/rails_generator/generators/components/controller/templates/helper.rb +2 -0
  107. data/lib/rails_generator/generators/components/controller/templates/view.html.erb +2 -0
  108. data/lib/rails_generator/generators/components/integration_test/USAGE +8 -0
  109. data/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb +16 -0
  110. data/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb +10 -0
  111. data/lib/rails_generator/generators/components/mailer/USAGE +16 -0
  112. data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +30 -0
  113. data/lib/rails_generator/generators/components/mailer/templates/fixture.erb +3 -0
  114. data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +0 -0
  115. data/lib/rails_generator/generators/components/mailer/templates/mailer.rb +15 -0
  116. data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +21 -0
  117. data/lib/rails_generator/generators/components/mailer/templates/view.erb +3 -0
  118. data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +0 -0
  119. data/lib/rails_generator/generators/components/migration/USAGE +29 -0
  120. data/lib/rails_generator/generators/components/migration/migration_generator.rb +20 -0
  121. data/lib/rails_generator/generators/components/migration/templates/migration.rb +11 -0
  122. data/lib/rails_generator/generators/components/model/USAGE +27 -0
  123. data/lib/rails_generator/generators/components/model/model_generator.rb +45 -0
  124. data/lib/rails_generator/generators/components/model/templates/fixtures.yml +19 -0
  125. data/lib/rails_generator/generators/components/model/templates/migration.rb +16 -0
  126. data/lib/rails_generator/generators/components/model/templates/model.rb +2 -0
  127. data/lib/rails_generator/generators/components/model/templates/unit_test.rb +8 -0
  128. data/lib/rails_generator/generators/components/observer/USAGE +13 -0
  129. data/lib/rails_generator/generators/components/observer/observer_generator.rb +16 -0
  130. data/lib/rails_generator/generators/components/observer/templates/observer.rb +2 -0
  131. data/lib/rails_generator/generators/components/observer/templates/unit_test.rb +8 -0
  132. data/lib/rails_generator/generators/components/plugin/USAGE +25 -0
  133. data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +39 -0
  134. data/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE +20 -0
  135. data/lib/rails_generator/generators/components/plugin/templates/README +13 -0
  136. data/lib/rails_generator/generators/components/plugin/templates/Rakefile +22 -0
  137. data/lib/rails_generator/generators/components/plugin/templates/USAGE +8 -0
  138. data/lib/rails_generator/generators/components/plugin/templates/generator.rb +8 -0
  139. data/lib/rails_generator/generators/components/plugin/templates/init.rb +1 -0
  140. data/lib/rails_generator/generators/components/plugin/templates/install.rb +1 -0
  141. data/lib/rails_generator/generators/components/plugin/templates/plugin.rb +1 -0
  142. data/lib/rails_generator/generators/components/plugin/templates/tasks.rake +4 -0
  143. data/lib/rails_generator/generators/components/plugin/templates/uninstall.rb +1 -0
  144. data/lib/rails_generator/generators/components/plugin/templates/unit_test.rb +8 -0
  145. data/lib/rails_generator/generators/components/resource/USAGE +23 -0
  146. data/lib/rails_generator/generators/components/resource/resource_generator.rb +74 -0
  147. data/lib/rails_generator/generators/components/resource/templates/controller.rb +2 -0
  148. data/lib/rails_generator/generators/components/resource/templates/functional_test.rb +8 -0
  149. data/lib/rails_generator/generators/components/resource/templates/helper.rb +2 -0
  150. data/lib/rails_generator/generators/components/scaffold/USAGE +25 -0
  151. data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +93 -0
  152. data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +85 -0
  153. data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +45 -0
  154. data/lib/rails_generator/generators/components/scaffold/templates/helper.rb +2 -0
  155. data/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb +17 -0
  156. data/lib/rails_generator/generators/components/scaffold/templates/style.css +54 -0
  157. data/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb +18 -0
  158. data/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb +24 -0
  159. data/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb +17 -0
  160. data/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb +10 -0
  161. data/lib/rails_generator/generators/components/session_migration/USAGE +10 -0
  162. data/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb +18 -0
  163. data/lib/rails_generator/generators/components/session_migration/templates/migration.rb +16 -0
  164. data/lib/rails_generator/lookup.rb +249 -0
  165. data/lib/rails_generator/manifest.rb +53 -0
  166. data/lib/rails_generator/options.rb +150 -0
  167. data/lib/rails_generator/scripts/destroy.rb +30 -0
  168. data/lib/rails_generator/scripts/generate.rb +7 -0
  169. data/lib/rails_generator/scripts/update.rb +12 -0
  170. data/lib/rails_generator/scripts.rb +89 -0
  171. data/lib/rails_generator/secret_key_generator.rb +164 -0
  172. data/lib/rails_generator/simple_logger.rb +46 -0
  173. data/lib/rails_generator/spec.rb +44 -0
  174. data/lib/rails_generator.rb +43 -0
  175. data/lib/railties_path.rb +1 -0
  176. data/lib/ruby_version_check.rb +17 -0
  177. data/lib/rubyprof_ext.rb +35 -0
  178. data/lib/source_annotation_extractor.rb +102 -0
  179. data/lib/tasks/annotations.rake +23 -0
  180. data/lib/tasks/databases.rake +389 -0
  181. data/lib/tasks/documentation.rake +80 -0
  182. data/lib/tasks/framework.rake +105 -0
  183. data/lib/tasks/gems.rake +64 -0
  184. data/lib/tasks/log.rake +9 -0
  185. data/lib/tasks/misc.rake +57 -0
  186. data/lib/tasks/rails.rb +8 -0
  187. data/lib/tasks/routes.rake +17 -0
  188. data/lib/tasks/statistics.rake +18 -0
  189. data/lib/tasks/testing.rake +118 -0
  190. data/lib/tasks/tmp.rake +37 -0
  191. data/lib/test_help.rb +28 -0
  192. data/lib/webrick_server.rb +165 -0
  193. metadata +356 -0
@@ -0,0 +1,622 @@
1
+ require 'delegate'
2
+ require 'optparse'
3
+ require 'fileutils'
4
+ require 'tempfile'
5
+ require 'erb'
6
+
7
+ module Rails
8
+ module Generator
9
+ module Commands
10
+ # Here's a convenient way to get a handle on generator commands.
11
+ # Command.instance('destroy', my_generator) instantiates a Destroy
12
+ # delegate of my_generator ready to do your dirty work.
13
+ def self.instance(command, generator)
14
+ const_get(command.to_s.camelize).new(generator)
15
+ end
16
+
17
+ # Even more convenient access to commands. Include Commands in
18
+ # the generator Base class to get a nice #command instance method
19
+ # which returns a delegate for the requested command.
20
+ def self.included(base)
21
+ base.send(:define_method, :command) do |command|
22
+ Commands.instance(command, self)
23
+ end
24
+ end
25
+
26
+
27
+ # Generator commands delegate Rails::Generator::Base and implement
28
+ # a standard set of actions. Their behavior is defined by the way
29
+ # they respond to these actions: Create brings life; Destroy brings
30
+ # death; List passively observes.
31
+ #
32
+ # Commands are invoked by replaying (or rewinding) the generator's
33
+ # manifest of actions. See Rails::Generator::Manifest and
34
+ # Rails::Generator::Base#manifest method that generator subclasses
35
+ # are required to override.
36
+ #
37
+ # Commands allows generators to "plug in" invocation behavior, which
38
+ # corresponds to the GoF Strategy pattern.
39
+ class Base < DelegateClass(Rails::Generator::Base)
40
+ # Replay action manifest. RewindBase subclass rewinds manifest.
41
+ def invoke!
42
+ manifest.replay(self)
43
+ end
44
+
45
+ def dependency(generator_name, args, runtime_options = {})
46
+ logger.dependency(generator_name) do
47
+ self.class.new(instance(generator_name, args, full_options(runtime_options))).invoke!
48
+ end
49
+ end
50
+
51
+ # Does nothing for all commands except Create.
52
+ def class_collisions(*class_names)
53
+ end
54
+
55
+ # Does nothing for all commands except Create.
56
+ def readme(*args)
57
+ end
58
+
59
+ protected
60
+ def current_migration_number
61
+ Dir.glob("#{RAILS_ROOT}/#{@migration_directory}/[0-9]*_*.rb").inject(0) do |max, file_path|
62
+ n = File.basename(file_path).split('_', 2).first.to_i
63
+ if n > max then n else max end
64
+ end
65
+ end
66
+
67
+ def next_migration_number
68
+ current_migration_number + 1
69
+ end
70
+
71
+ def migration_directory(relative_path)
72
+ directory(@migration_directory = relative_path)
73
+ end
74
+
75
+ def existing_migrations(file_name)
76
+ Dir.glob("#{@migration_directory}/[0-9]*_*.rb").grep(/[0-9]+_#{file_name}.rb$/)
77
+ end
78
+
79
+ def migration_exists?(file_name)
80
+ not existing_migrations(file_name).empty?
81
+ end
82
+
83
+ def next_migration_string(padding = 3)
84
+ if ActiveRecord::Base.timestamped_migrations
85
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
86
+ else
87
+ "%.#{padding}d" % next_migration_number
88
+ end
89
+ end
90
+
91
+ def gsub_file(relative_destination, regexp, *args, &block)
92
+ path = destination_path(relative_destination)
93
+ content = File.read(path).gsub(regexp, *args, &block)
94
+ File.open(path, 'wb') { |file| file.write(content) }
95
+ end
96
+
97
+ private
98
+ # Ask the user interactively whether to force collision.
99
+ def force_file_collision?(destination, src, dst, file_options = {}, &block)
100
+ $stdout.print "overwrite #{destination}? (enter \"h\" for help) [Ynaqdh] "
101
+ case $stdin.gets.chomp
102
+ when /\Ad\z/i
103
+ Tempfile.open(File.basename(destination), File.dirname(dst)) do |temp|
104
+ temp.write render_file(src, file_options, &block)
105
+ temp.rewind
106
+ $stdout.puts `#{diff_cmd} "#{dst}" "#{temp.path}"`
107
+ end
108
+ puts "retrying"
109
+ raise 'retry diff'
110
+ when /\Aa\z/i
111
+ $stdout.puts "forcing #{spec.name}"
112
+ options[:collision] = :force
113
+ when /\Aq\z/i
114
+ $stdout.puts "aborting #{spec.name}"
115
+ raise SystemExit
116
+ when /\An\z/i then :skip
117
+ when /\Ay\z/i then :force
118
+ else
119
+ $stdout.puts <<-HELP
120
+ Y - yes, overwrite
121
+ n - no, do not overwrite
122
+ a - all, overwrite this and all others
123
+ q - quit, abort
124
+ d - diff, show the differences between the old and the new
125
+ h - help, show this help
126
+ HELP
127
+ raise 'retry'
128
+ end
129
+ rescue
130
+ retry
131
+ end
132
+
133
+ def diff_cmd
134
+ ENV['RAILS_DIFF'] || 'diff -u'
135
+ end
136
+
137
+ def render_template_part(template_options)
138
+ # Getting Sandbox to evaluate part template in it
139
+ part_binding = template_options[:sandbox].call.sandbox_binding
140
+ part_rel_path = template_options[:insert]
141
+ part_path = source_path(part_rel_path)
142
+
143
+ # Render inner template within Sandbox binding
144
+ rendered_part = ERB.new(File.readlines(part_path).join, nil, '-').result(part_binding)
145
+ begin_mark = template_part_mark(template_options[:begin_mark], template_options[:mark_id])
146
+ end_mark = template_part_mark(template_options[:end_mark], template_options[:mark_id])
147
+ begin_mark + rendered_part + end_mark
148
+ end
149
+
150
+ def template_part_mark(name, id)
151
+ "<!--[#{name}:#{id}]-->\n"
152
+ end
153
+ end
154
+
155
+ # Base class for commands which handle generator actions in reverse, such as Destroy.
156
+ class RewindBase < Base
157
+ # Rewind action manifest.
158
+ def invoke!
159
+ manifest.rewind(self)
160
+ end
161
+ end
162
+
163
+
164
+ # Create is the premier generator command. It copies files, creates
165
+ # directories, renders templates, and more.
166
+ class Create < Base
167
+
168
+ # Check whether the given class names are already taken by
169
+ # Ruby or Rails. In the future, expand to check other namespaces
170
+ # such as the rest of the user's app.
171
+ def class_collisions(*class_names)
172
+
173
+ # Initialize some check varibles
174
+ last_class = Object
175
+ current_class = nil
176
+ name = nil
177
+
178
+ class_names.flatten.each do |class_name|
179
+ # Convert to string to allow symbol arguments.
180
+ class_name = class_name.to_s
181
+
182
+ # Skip empty strings.
183
+ class_name.strip.empty? ? next : current_class = class_name
184
+
185
+ # Split the class from its module nesting.
186
+ nesting = class_name.split('::')
187
+ name = nesting.pop
188
+
189
+ # Extract the last Module in the nesting.
190
+ last = nesting.inject(last_class) { |last, nest|
191
+ break unless last_class.const_defined?(nest)
192
+ last_class = last_class.const_get(nest)
193
+ }
194
+
195
+ end
196
+ # If the last Module exists, check whether the given
197
+ # class exists and raise a collision if so.
198
+
199
+ if last_class and last_class.const_defined?(name.camelize)
200
+ raise_class_collision(current_class)
201
+ end
202
+ end
203
+
204
+ # Copy a file from source to destination with collision checking.
205
+ #
206
+ # The file_options hash accepts :chmod and :shebang and :collision options.
207
+ # :chmod sets the permissions of the destination file:
208
+ # file 'config/empty.log', 'log/test.log', :chmod => 0664
209
+ # :shebang sets the #!/usr/bin/ruby line for scripts
210
+ # file 'bin/generate.rb', 'script/generate', :chmod => 0755, :shebang => '/usr/bin/env ruby'
211
+ # :collision sets the collision option only for the destination file:
212
+ # file 'settings/server.yml', 'config/server.yml', :collision => :skip
213
+ #
214
+ # Collisions are handled by checking whether the destination file
215
+ # exists and either skipping the file, forcing overwrite, or asking
216
+ # the user what to do.
217
+ def file(relative_source, relative_destination, file_options = {}, &block)
218
+ # Determine full paths for source and destination files.
219
+ source = source_path(relative_source)
220
+ destination = destination_path(relative_destination)
221
+ destination_exists = File.exist?(destination)
222
+
223
+ # If source and destination are identical then we're done.
224
+ if destination_exists and identical?(source, destination, &block)
225
+ return logger.identical(relative_destination)
226
+ end
227
+
228
+ # Check for and resolve file collisions.
229
+ if destination_exists
230
+
231
+ # Make a choice whether to overwrite the file. :force and
232
+ # :skip already have their mind made up, but give :ask a shot.
233
+ choice = case (file_options[:collision] || options[:collision]).to_sym #|| :ask
234
+ when :ask then force_file_collision?(relative_destination, source, destination, file_options, &block)
235
+ when :force then :force
236
+ when :skip then :skip
237
+ else raise "Invalid collision option: #{options[:collision].inspect}"
238
+ end
239
+
240
+ # Take action based on our choice. Bail out if we chose to
241
+ # skip the file; otherwise, log our transgression and continue.
242
+ case choice
243
+ when :force then logger.force(relative_destination)
244
+ when :skip then return(logger.skip(relative_destination))
245
+ else raise "Invalid collision choice: #{choice}.inspect"
246
+ end
247
+
248
+ # File doesn't exist so log its unbesmirched creation.
249
+ else
250
+ logger.create relative_destination
251
+ end
252
+
253
+ # If we're pretending, back off now.
254
+ return if options[:pretend]
255
+
256
+ # Write destination file with optional shebang. Yield for content
257
+ # if block given so templaters may render the source file. If a
258
+ # shebang is requested, replace the existing shebang or insert a
259
+ # new one.
260
+ File.open(destination, 'wb') do |dest|
261
+ dest.write render_file(source, file_options, &block)
262
+ end
263
+
264
+ # Optionally change permissions.
265
+ if file_options[:chmod]
266
+ FileUtils.chmod(file_options[:chmod], destination)
267
+ end
268
+
269
+ # Optionally add file to subversion or git
270
+ system("svn add #{destination}") if options[:svn]
271
+ system("git add -v #{relative_destination}") if options[:git]
272
+ end
273
+
274
+ # Checks if the source and the destination file are identical. If
275
+ # passed a block then the source file is a template that needs to first
276
+ # be evaluated before being compared to the destination.
277
+ def identical?(source, destination, &block)
278
+ return false if File.directory? destination
279
+ source = block_given? ? File.open(source) {|sf| yield(sf)} : IO.read(source)
280
+ destination = IO.read(destination)
281
+ source == destination
282
+ end
283
+
284
+ # Generate a file for a Rails application using an ERuby template.
285
+ # Looks up and evaluates a template by name and writes the result.
286
+ #
287
+ # The ERB template uses explicit trim mode to best control the
288
+ # proliferation of whitespace in generated code. <%- trims leading
289
+ # whitespace; -%> trims trailing whitespace including one newline.
290
+ #
291
+ # A hash of template options may be passed as the last argument.
292
+ # The options accepted by the file are accepted as well as :assigns,
293
+ # a hash of variable bindings. Example:
294
+ # template 'foo', 'bar', :assigns => { :action => 'view' }
295
+ #
296
+ # Template is implemented in terms of file. It calls file with a
297
+ # block which takes a file handle and returns its rendered contents.
298
+ def template(relative_source, relative_destination, template_options = {})
299
+ file(relative_source, relative_destination, template_options) do |file|
300
+ # Evaluate any assignments in a temporary, throwaway binding.
301
+ vars = template_options[:assigns] || {}
302
+ b = binding
303
+ vars.each { |k,v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
304
+
305
+ # Render the source file with the temporary binding.
306
+ ERB.new(file.read, nil, '-').result(b)
307
+ end
308
+ end
309
+
310
+ def complex_template(relative_source, relative_destination, template_options = {})
311
+ options = template_options.dup
312
+ options[:assigns] ||= {}
313
+ options[:assigns]['template_for_inclusion'] = render_template_part(template_options)
314
+ template(relative_source, relative_destination, options)
315
+ end
316
+
317
+ # Create a directory including any missing parent directories.
318
+ # Always skips directories which exist.
319
+ def directory(relative_path)
320
+ path = destination_path(relative_path)
321
+ if File.exist?(path)
322
+ logger.exists relative_path
323
+ else
324
+ logger.create relative_path
325
+ unless options[:pretend]
326
+ FileUtils.mkdir_p(path)
327
+ # git doesn't require adding the paths, adding the files later will
328
+ # automatically do a path add.
329
+
330
+ # Subversion doesn't do path adds, so we need to add
331
+ # each directory individually.
332
+ # So stack up the directory tree and add the paths to
333
+ # subversion in order without recursion.
334
+ if options[:svn]
335
+ stack = [relative_path]
336
+ until File.dirname(stack.last) == stack.last # dirname('.') == '.'
337
+ stack.push File.dirname(stack.last)
338
+ end
339
+ stack.reverse_each do |rel_path|
340
+ svn_path = destination_path(rel_path)
341
+ system("svn add -N #{svn_path}") unless File.directory?(File.join(svn_path, '.svn'))
342
+ end
343
+ end
344
+ end
345
+ end
346
+ end
347
+
348
+ # Display a README.
349
+ def readme(*relative_sources)
350
+ relative_sources.flatten.each do |relative_source|
351
+ logger.readme relative_source
352
+ puts File.read(source_path(relative_source)) unless options[:pretend]
353
+ end
354
+ end
355
+
356
+ # When creating a migration, it knows to find the first available file in db/migrate and use the migration.rb template.
357
+ def migration_template(relative_source, relative_destination, template_options = {})
358
+ migration_directory relative_destination
359
+ migration_file_name = template_options[:migration_file_name] || file_name
360
+ raise "Another migration is already named #{migration_file_name}: #{existing_migrations(migration_file_name).first}" if migration_exists?(migration_file_name)
361
+ template(relative_source, "#{relative_destination}/#{next_migration_string}_#{migration_file_name}.rb", template_options)
362
+ end
363
+
364
+ def route_resources(*resources)
365
+ resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
366
+ sentinel = 'ActionController::Routing::Routes.draw do |map|'
367
+
368
+ logger.route "map.resources #{resource_list}"
369
+ unless options[:pretend]
370
+ gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
371
+ "#{match}\n map.resources #{resource_list}\n"
372
+ end
373
+ end
374
+ end
375
+
376
+ private
377
+ def render_file(path, options = {})
378
+ File.open(path, 'rb') do |file|
379
+ if block_given?
380
+ yield file
381
+ else
382
+ content = ''
383
+ if shebang = options[:shebang]
384
+ content << "#!#{shebang}\n"
385
+ if line = file.gets
386
+ content << "line\n" if line !~ /^#!/
387
+ end
388
+ end
389
+ content << file.read
390
+ end
391
+ end
392
+ end
393
+
394
+ # Raise a usage error with an informative WordNet suggestion.
395
+ # Thanks to Florian Gross (flgr).
396
+ def raise_class_collision(class_name)
397
+ message = <<end_message
398
+ The name '#{class_name}' is either already used in your application or reserved by Ruby on Rails.
399
+ Please choose an alternative and run this generator again.
400
+ end_message
401
+ if suggest = find_synonyms(class_name)
402
+ if suggest.any?
403
+ message << "\n Suggestions: \n\n"
404
+ message << suggest.join("\n")
405
+ end
406
+ end
407
+ raise UsageError, message
408
+ end
409
+
410
+ SYNONYM_LOOKUP_URI = "http://wordnet.princeton.edu/perl/webwn?s=%s"
411
+
412
+ # Look up synonyms on WordNet. Thanks to Florian Gross (flgr).
413
+ def find_synonyms(word)
414
+ require 'open-uri'
415
+ require 'timeout'
416
+ timeout(5) do
417
+ open(SYNONYM_LOOKUP_URI % word) do |stream|
418
+ # Grab words linked to dictionary entries as possible synonyms
419
+ data = stream.read.gsub("&nbsp;", " ").scan(/<a href="webwn.*?">([\w ]*?)<\/a>/s).uniq
420
+ end
421
+ end
422
+ rescue Exception
423
+ return nil
424
+ end
425
+ end
426
+
427
+
428
+ # Undo the actions performed by a generator. Rewind the action
429
+ # manifest and attempt to completely erase the results of each action.
430
+ class Destroy < RewindBase
431
+ # Remove a file if it exists and is a file.
432
+ def file(relative_source, relative_destination, file_options = {})
433
+ destination = destination_path(relative_destination)
434
+ if File.exist?(destination)
435
+ logger.rm relative_destination
436
+ unless options[:pretend]
437
+ if options[:svn]
438
+ # If the file has been marked to be added
439
+ # but has not yet been checked in, revert and delete
440
+ if options[:svn][relative_destination]
441
+ system("svn revert #{destination}")
442
+ FileUtils.rm(destination)
443
+ else
444
+ # If the directory is not in the status list, it
445
+ # has no modifications so we can simply remove it
446
+ system("svn rm #{destination}")
447
+ end
448
+ elsif options[:git]
449
+ if options[:git][:new][relative_destination]
450
+ # file has been added, but not committed
451
+ system("git reset HEAD #{relative_destination}")
452
+ FileUtils.rm(destination)
453
+ elsif options[:git][:modified][relative_destination]
454
+ # file is committed and modified
455
+ system("git rm -f #{relative_destination}")
456
+ else
457
+ # If the directory is not in the status list, it
458
+ # has no modifications so we can simply remove it
459
+ system("git rm #{relative_destination}")
460
+ end
461
+ else
462
+ FileUtils.rm(destination)
463
+ end
464
+ end
465
+ else
466
+ logger.missing relative_destination
467
+ return
468
+ end
469
+ end
470
+
471
+ # Templates are deleted just like files and the actions take the
472
+ # same parameters, so simply alias the file method.
473
+ alias_method :template, :file
474
+
475
+ # Remove each directory in the given path from right to left.
476
+ # Remove each subdirectory if it exists and is a directory.
477
+ def directory(relative_path)
478
+ parts = relative_path.split('/')
479
+ until parts.empty?
480
+ partial = File.join(parts)
481
+ path = destination_path(partial)
482
+ if File.exist?(path)
483
+ if Dir[File.join(path, '*')].empty?
484
+ logger.rmdir partial
485
+ unless options[:pretend]
486
+ if options[:svn]
487
+ # If the directory has been marked to be added
488
+ # but has not yet been checked in, revert and delete
489
+ if options[:svn][relative_path]
490
+ system("svn revert #{path}")
491
+ FileUtils.rmdir(path)
492
+ else
493
+ # If the directory is not in the status list, it
494
+ # has no modifications so we can simply remove it
495
+ system("svn rm #{path}")
496
+ end
497
+ # I don't think git needs to remove directories?..
498
+ # or maybe they have special consideration...
499
+ else
500
+ FileUtils.rmdir(path)
501
+ end
502
+ end
503
+ else
504
+ logger.notempty partial
505
+ end
506
+ else
507
+ logger.missing partial
508
+ end
509
+ parts.pop
510
+ end
511
+ end
512
+
513
+ def complex_template(*args)
514
+ # nothing should be done here
515
+ end
516
+
517
+ # When deleting a migration, it knows to delete every file named "[0-9]*_#{file_name}".
518
+ def migration_template(relative_source, relative_destination, template_options = {})
519
+ migration_directory relative_destination
520
+
521
+ migration_file_name = template_options[:migration_file_name] || file_name
522
+ unless migration_exists?(migration_file_name)
523
+ puts "There is no migration named #{migration_file_name}"
524
+ return
525
+ end
526
+
527
+
528
+ existing_migrations(migration_file_name).each do |file_path|
529
+ file(relative_source, file_path, template_options)
530
+ end
531
+ end
532
+
533
+ def route_resources(*resources)
534
+ resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
535
+ look_for = "\n map.resources #{resource_list}\n"
536
+ logger.route "map.resources #{resource_list}"
537
+ gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
538
+ end
539
+ end
540
+
541
+
542
+ # List a generator's action manifest.
543
+ class List < Base
544
+ def dependency(generator_name, args, options = {})
545
+ logger.dependency "#{generator_name}(#{args.join(', ')}, #{options.inspect})"
546
+ end
547
+
548
+ def class_collisions(*class_names)
549
+ logger.class_collisions class_names.join(', ')
550
+ end
551
+
552
+ def file(relative_source, relative_destination, options = {})
553
+ logger.file relative_destination
554
+ end
555
+
556
+ def template(relative_source, relative_destination, options = {})
557
+ logger.template relative_destination
558
+ end
559
+
560
+ def complex_template(relative_source, relative_destination, options = {})
561
+ logger.template "#{options[:insert]} inside #{relative_destination}"
562
+ end
563
+
564
+ def directory(relative_path)
565
+ logger.directory "#{destination_path(relative_path)}/"
566
+ end
567
+
568
+ def readme(*args)
569
+ logger.readme args.join(', ')
570
+ end
571
+
572
+ def migration_template(relative_source, relative_destination, options = {})
573
+ migration_directory relative_destination
574
+ logger.migration_template file_name
575
+ end
576
+
577
+ def route_resources(*resources)
578
+ resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
579
+ logger.route "map.resources #{resource_list}"
580
+ end
581
+ end
582
+
583
+ # Update generator's action manifest.
584
+ class Update < Create
585
+ def file(relative_source, relative_destination, options = {})
586
+ # logger.file relative_destination
587
+ end
588
+
589
+ def template(relative_source, relative_destination, options = {})
590
+ # logger.template relative_destination
591
+ end
592
+
593
+ def complex_template(relative_source, relative_destination, template_options = {})
594
+
595
+ begin
596
+ dest_file = destination_path(relative_destination)
597
+ source_to_update = File.readlines(dest_file).join
598
+ rescue Errno::ENOENT
599
+ logger.missing relative_destination
600
+ return
601
+ end
602
+
603
+ logger.refreshing "#{template_options[:insert].gsub(/\.erb/,'')} inside #{relative_destination}"
604
+
605
+ begin_mark = Regexp.quote(template_part_mark(template_options[:begin_mark], template_options[:mark_id]))
606
+ end_mark = Regexp.quote(template_part_mark(template_options[:end_mark], template_options[:mark_id]))
607
+
608
+ # Refreshing inner part of the template with freshly rendered part.
609
+ rendered_part = render_template_part(template_options)
610
+ source_to_update.gsub!(/#{begin_mark}.*?#{end_mark}/m, rendered_part)
611
+
612
+ File.open(dest_file, 'w') { |file| file.write(source_to_update) }
613
+ end
614
+
615
+ def directory(relative_path)
616
+ # logger.directory "#{destination_path(relative_path)}/"
617
+ end
618
+ end
619
+
620
+ end
621
+ end
622
+ end
@@ -0,0 +1,42 @@
1
+ require 'optparse'
2
+
3
+ module Rails
4
+ module Generator
5
+ class GeneratedAttribute
6
+ attr_accessor :name, :type, :column
7
+
8
+ def initialize(name, type)
9
+ @name, @type = name, type.to_sym
10
+ @column = ActiveRecord::ConnectionAdapters::Column.new(name, nil, @type)
11
+ end
12
+
13
+ def field_type
14
+ @field_type ||= case type
15
+ when :integer, :float, :decimal then :text_field
16
+ when :datetime, :timestamp, :time then :datetime_select
17
+ when :date then :date_select
18
+ when :string then :text_field
19
+ when :text then :text_area
20
+ when :boolean then :check_box
21
+ else
22
+ :text_field
23
+ end
24
+ end
25
+
26
+ def default
27
+ @default ||= case type
28
+ when :integer then 1
29
+ when :float then 1.5
30
+ when :decimal then "9.99"
31
+ when :datetime, :timestamp, :time then Time.now.to_s(:db)
32
+ when :date then Date.today.to_s(:db)
33
+ when :string then "MyString"
34
+ when :text then "MyText"
35
+ when :boolean then false
36
+ else
37
+ ""
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,9 @@
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.