Skip to content
This repository
Browse code

Adding test coverage and better logging to Rails::TemplateRunner [#1618

… state:resolved]

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
  • Loading branch information...
commit 9fd35fc2d892393386ca9f522d25ba0bcb9c6764 1 parent fdaa9ed
Aaron Quint authored December 27, 2008 lifo committed December 27, 2008
119  railties/lib/rails_generator/generators/applications/app/template_runner.rb
@@ -8,23 +8,24 @@
8 8
 module Rails
9 9
   class TemplateRunner
10 10
     attr_reader :root
  11
+    attr_writer :logger
11 12
 
12 13
     def initialize(template, root = '') # :nodoc:
13  
-      @root = File.join(Dir.pwd, root)
  14
+      @root = File.expand_path(File.directory?(root) ? root : File.join(Dir.pwd, root))
14 15
 
15  
-      puts "applying template: #{template}"
  16
+      log 'applying', "template: #{template}"
16 17
 
17 18
       load_template(template)
18 19
 
19  
-      puts "#{template} applied."
  20
+      log 'applied', "#{template}"
20 21
     end
21 22
 
22 23
     def load_template(template)
23 24
       begin
24 25
         code = open(template).read
25 26
         in_root { self.instance_eval(code) }
26  
-      rescue LoadError
27  
-        raise "The template [#{template}] could not be loaded."
  27
+      rescue LoadError, Errno::ENOENT => e
  28
+        raise "The template [#{template}] could not be loaded. Error: #{e}"
28 29
       end
29 30
     end
30 31
 
@@ -41,8 +42,8 @@ def load_template(template)
41 42
     #
42 43
     #   file("config/apach.conf", "your apache config")
43 44
     #
44  
-    def file(filename, data = nil, &block)
45  
-      puts "creating file #{filename}"
  45
+    def file(filename, data = nil, log_action = true, &block)
  46
+      log 'file', filename if log_action
46 47
       dir, file = [File.dirname(filename), File.basename(filename)]
47 48
 
48 49
       inside(dir) do
@@ -66,7 +67,7 @@ def file(filename, data = nil, &block)
66 67
     #   plugin 'restful-authentication', :svn => 'svn://svnhub.com/technoweenie/restful-authentication/trunk'
67 68
     #
68 69
     def plugin(name, options)
69  
-      puts "installing plugin #{name}"
  70
+      log 'plugin', name
70 71
 
71 72
       if options[:git] && options[:submodule]
72 73
         in_root do
@@ -74,18 +75,17 @@ def plugin(name, options)
74 75
         end
75 76
       elsif options[:git] || options[:svn]
76 77
         in_root do
77  
-          `script/plugin install #{options[:svn] || options[:git]}`
  78
+          run("script/plugin install #{options[:svn] || options[:git]}", false)
78 79
         end
79 80
       else
80  
-        puts "! no git or svn provided for #{name}.  skipping..."
  81
+        log "! no git or svn provided for #{name}.  skipping..."
81 82
       end
82 83
     end
83 84
 
84 85
     # Adds an entry into config/environment.rb for the supplied gem :
85 86
     def gem(name, options = {})
86  
-      puts "adding gem #{name}"
  87
+      log 'gem', name
87 88
 
88  
-      sentinel = 'Rails::Initializer.run do |config|'
89 89
       gems_code = "config.gem '#{name}'"
90 90
 
91 91
       if options.any?
@@ -93,9 +93,18 @@ def gem(name, options = {})
93 93
         gems_code << ", #{opts}"
94 94
       end
95 95
 
  96
+      environment gems_code
  97
+    end
  98
+
  99
+    # Adds a line inside the Initializer block for config/environment.rb. Used by #gem
  100
+    def environment(data = nil, &block)
  101
+      sentinel = 'Rails::Initializer.run do |config|'
  102
+
  103
+      data = block.call if !data && block_given?
  104
+
96 105
       in_root do
97 106
         gsub_file 'config/environment.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
98  
-          "#{match}\n  #{gems_code}"
  107
+          "#{match}\n " << data
99 108
         end
100 109
       end
101 110
     end
@@ -111,11 +120,11 @@ def gem(name, options = {})
111 120
     def git(command = {})
112 121
       in_root do
113 122
         if command.is_a?(Symbol)
114  
-          puts "running git #{command}"
  123
+          log 'running', "git #{command}"
115 124
           Git.run(command.to_s)
116 125
         else
117 126
           command.each do |command, options|
118  
-            puts "running git #{command} #{options}"
  127
+            log 'running', "git #{command} #{options}"
119 128
             Git.run("#{command} #{options}")
120 129
           end
121 130
         end
@@ -135,16 +144,8 @@ def git(command = {})
135 144
     #   vendor("foreign.rb", "# Foreign code is fun")
136 145
     #
137 146
     def vendor(filename, data = nil, &block)
138  
-      puts "vendoring file #{filename}"
139  
-      inside("vendor") do |folder|
140  
-        File.open("#{folder}/#{filename}", "w") do |f|
141  
-          if block_given?
142  
-            f.write(block.call)
143  
-          else
144  
-            f.write(data)
145  
-          end
146  
-        end
147  
-      end
  147
+      log 'vendoring', filename
  148
+      file("vendor/#{filename}", data, false, &block)
148 149
     end
149 150
 
150 151
     # Create a new file in the lib/ directory. Code can be specified
@@ -158,17 +159,9 @@ def vendor(filename, data = nil, &block)
158 159
     #
159 160
     #   lib("foreign.rb", "# Foreign code is fun")
160 161
     #
161  
-    def lib(filename, data = nil)
162  
-      puts "add lib file #{filename}"
163  
-      inside("lib") do |folder|
164  
-        File.open("#{folder}/#{filename}", "w") do |f|
165  
-          if block_given?
166  
-            f.write(block.call)
167  
-          else
168  
-            f.write(data)
169  
-          end
170  
-        end
171  
-      end
  162
+    def lib(filename, data = nil, &block)
  163
+      log 'lib', filename
  164
+      file("lib/#{filename}", data, false, &block)
172 165
     end
173 166
 
174 167
     # Create a new Rakefile with the provided code (either in a block or a string).
@@ -190,16 +183,8 @@ def lib(filename, data = nil)
190 183
     #   rakefile("seed.rake", "puts 'im plantin ur seedz'")
191 184
     #
192 185
     def rakefile(filename, data = nil, &block)
193  
-      puts "adding rakefile #{filename}"
194  
-      inside("lib/tasks") do |folder|
195  
-        File.open("#{folder}/#{filename}", "w") do |f|
196  
-          if block_given?
197  
-            f.write(block.call)
198  
-          else
199  
-            f.write(data)
200  
-          end
201  
-        end
202  
-      end
  186
+      log 'rakefile', filename
  187
+      file("lib/tasks/#{filename}", data, false, &block)
203 188
     end
204 189
 
205 190
     # Create a new initializer with the provided code (either in a block or a string).
@@ -219,16 +204,8 @@ def rakefile(filename, data = nil, &block)
219 204
     #   initializer("api.rb", "API_KEY = '123456'")
220 205
     #
221 206
     def initializer(filename, data = nil, &block)
222  
-      puts "adding initializer #{filename}"
223  
-      inside("config/initializers") do |folder|
224  
-        File.open("#{folder}/#{filename}", "w") do |f|
225  
-          if block_given?
226  
-            f.write(block.call)
227  
-          else
228  
-            f.write(data)
229  
-          end
230  
-        end
231  
-      end
  207
+      log 'initializer', filename
  208
+      file("config/initializers/#{filename}", data, false, &block)
232 209
     end
233 210
 
234 211
     # Generate something using a generator from Rails or a plugin.
@@ -240,10 +217,10 @@ def initializer(filename, data = nil, &block)
240 217
     #   generate(:authenticated, "user session")
241 218
     #
242 219
     def generate(what, *args)
243  
-      puts "generating #{what}"
  220
+      log 'generating', what
244 221
       argument = args.map(&:to_s).flatten.join(" ")
245 222
 
246  
-      in_root { `#{root}/script/generate #{what} #{argument}` }
  223
+      in_root { run("script/generate #{what} #{argument}", false) }
247 224
     end
248 225
 
249 226
     # Executes a command
@@ -254,8 +231,8 @@ def generate(what, *args)
254 231
     #     run('ln -s ~/edge rails)
255 232
     #   end
256 233
     #
257  
-    def run(command)
258  
-      puts "executing #{command} from #{Dir.pwd}"
  234
+    def run(command, log_action = true)
  235
+      log 'executing',  "#{command} from #{Dir.pwd}" if log_action
259 236
       `#{command}`
260 237
     end
261 238
 
@@ -268,10 +245,10 @@ def run(command)
268 245
     #   rake("gems:install", :sudo => true)
269 246
     #
270 247
     def rake(command, options = {})
271  
-      puts "running rake task #{command}"
  248
+      log 'rake', command
272 249
       env = options[:env] || 'development'
273 250
       sudo = options[:sudo] ? 'sudo ' : ''
274  
-      in_root { `#{sudo}rake #{command} RAILS_ENV=#{env}` }
  251
+      in_root { run("#{sudo}rake #{command} RAILS_ENV=#{env}", false) }
275 252
     end
276 253
 
277 254
     # Just run the capify command in root
@@ -281,7 +258,8 @@ def rake(command, options = {})
281 258
     #   capify!
282 259
     #
283 260
     def capify!
284  
-      in_root { `capify .` }
  261
+      log 'capifying'
  262
+      in_root { run('capify .', false) }
285 263
     end
286 264
 
287 265
     # Add Rails to /vendor/rails
@@ -291,8 +269,8 @@ def capify!
291 269
     #   freeze!
292 270
     #
293 271
     def freeze!(args = {})
294  
-      puts "vendoring rails edge"
295  
-      in_root { `rake rails:freeze:edge` }
  272
+      log 'vendor', 'rails edge'
  273
+      in_root { run('rake rails:freeze:edge', false) }
296 274
     end
297 275
 
298 276
     # Make an entry in Rails routing file conifg/routes.rb
@@ -302,6 +280,7 @@ def freeze!(args = {})
302 280
     #   route "map.root :controller => :welcome"
303 281
     #
304 282
     def route(routing_code)
  283
+      log 'route', routing_code
305 284
       sentinel = 'ActionController::Routing::Routes.draw do |map|'
306 285
 
307 286
       in_root do
@@ -321,7 +300,7 @@ def route(routing_code)
321 300
     #   freeze! if ask("Should I freeze the latest Rails?") == "yes"
322 301
     #
323 302
     def ask(string)
324  
-      puts string
  303
+      log '', string
325 304
       gets.strip
326 305
     end
327 306
 
@@ -368,5 +347,13 @@ def gsub_file(relative_destination, regexp, *args, &block)
368 347
     def destination_path(relative_destination)
369 348
       File.join(root, relative_destination)
370 349
     end
  350
+
  351
+    def log(action, message = '')
  352
+      logger.log(action, message)
  353
+    end
  354
+
  355
+    def logger
  356
+      @logger ||= Rails::Generator::Base.logger
  357
+    end
371 358
   end
372 359
 end
190  railties/test/generators/rails_template_runner_test.rb
... ...
@@ -0,0 +1,190 @@
  1
+require 'abstract_unit'
  2
+require 'generators/generator_test_helper'
  3
+
  4
+class RailsTemplateRunnerTest < GeneratorTestCase
  5
+  def setup
  6
+    Rails::Generator::Base.use_application_sources!
  7
+    run_generator('app', [RAILS_ROOT])
  8
+    # generate empty template
  9
+    @template_path = File.join(RAILS_ROOT, 'template.rb')
  10
+    File.open(File.join(@template_path), 'w') {|f| f << '' }
  11
+
  12
+    @git_plugin_uri = 'git://github.com/technoweenie/restful-authentication.git'
  13
+    @svn_plugin_uri = 'svn://svnhub.com/technoweenie/restful-authentication/trunk'
  14
+  end
  15
+
  16
+  def teardown
  17
+    super
  18
+    rm_rf "#{RAILS_ROOT}/README"
  19
+    rm_rf "#{RAILS_ROOT}/Rakefile"
  20
+    rm_rf "#{RAILS_ROOT}/doc"
  21
+    rm_rf "#{RAILS_ROOT}/lib"
  22
+    rm_rf "#{RAILS_ROOT}/log"
  23
+    rm_rf "#{RAILS_ROOT}/script"
  24
+    rm_rf "#{RAILS_ROOT}/vendor"
  25
+    rm_rf "#{RAILS_ROOT}/tmp"
  26
+    rm_rf "#{RAILS_ROOT}/Capfile"
  27
+    rm_rf @template_path
  28
+  end
  29
+
  30
+  def test_initialize_should_load_template
  31
+    Rails::TemplateRunner.any_instance.expects(:load_template).with(@template_path)
  32
+    silence_generator do
  33
+      Rails::TemplateRunner.new(@template_path, RAILS_ROOT)
  34
+    end
  35
+  end
  36
+
  37
+  def test_initialize_should_raise_error_on_missing_template_file
  38
+    assert_raise(RuntimeError) do
  39
+      silence_generator do
  40
+        Rails::TemplateRunner.new('non/existent/path/to/template.rb', RAILS_ROOT)
  41
+      end
  42
+    end
  43
+  end
  44
+
  45
+  def test_file_should_write_data_to_file_path
  46
+    run_template_method(:file, 'lib/test_file.rb', 'heres test data')
  47
+    assert_generated_file_with_data 'lib/test_file.rb', 'heres test data'
  48
+  end
  49
+
  50
+  def test_file_should_write_block_contents_to_file_path
  51
+    run_template_method(:file, 'lib/test_file.rb') { 'heres block data' }
  52
+    assert_generated_file_with_data 'lib/test_file.rb', 'heres block data'
  53
+  end
  54
+
  55
+  def test_plugin_with_git_option_should_run_plugin_install
  56
+    expects_run_with_command("script/plugin install #{@git_plugin_uri}")
  57
+    run_template_method(:plugin, 'restful-authentication', :git => @git_plugin_uri)
  58
+  end
  59
+
  60
+  def test_plugin_with_svn_option_should_run_plugin_install
  61
+    expects_run_with_command("script/plugin install #{@svn_plugin_uri}")
  62
+    run_template_method(:plugin, 'restful-authentication', :svn => @svn_plugin_uri)
  63
+  end
  64
+
  65
+  def test_plugin_with_git_option_and_submodule_should_use_git_scm
  66
+    Rails::Git.expects(:run).with("submodule add #{@git_plugin_uri} vendor/plugins/rest_auth")
  67
+    run_template_method(:plugin, 'rest_auth', :git => @git_plugin_uri, :submodule => true)
  68
+  end
  69
+
  70
+  def test_plugin_with_no_options_should_skip_method
  71
+    Rails::TemplateRunner.any_instance.expects(:run).never
  72
+    run_template_method(:plugin, 'rest_auth', {})
  73
+  end
  74
+
  75
+  def test_gem_should_put_gem_dependency_in_enviroment
  76
+    run_template_method(:gem, 'will-paginate')
  77
+    assert_rails_initializer_includes("config.gem 'will-paginate'")
  78
+  end
  79
+
  80
+  def test_gem_with_options_should_include_options_in_gem_dependency_in_environment
  81
+    run_template_method(:gem, 'mislav-will-paginate', :lib => 'will-paginate', :source => 'http://gems.github.com')
  82
+    assert_rails_initializer_includes("config.gem 'mislav-will-paginate', :source => 'http://gems.github.com', :lib => 'will-paginate'")
  83
+  end
  84
+
  85
+  def test_environment_should_include_data_in_environment_initializer_block
  86
+    load_paths = 'config.load_paths += %w["#{RAILS_ROOT}/app/extras"]'
  87
+    run_template_method(:environment, load_paths)
  88
+    assert_rails_initializer_includes(load_paths)
  89
+  end
  90
+
  91
+  def test_environment_with_block_should_include_block_contents_in_environment_initializer_block
  92
+    run_template_method(:environment) do
  93
+      '# This wont be added'
  94
+      '# This will be added'
  95
+    end
  96
+    assert_rails_initializer_includes('# This will be added')
  97
+  end
  98
+
  99
+  def test_git_with_symbol_should_run_command_using_git_scm
  100
+    Rails::Git.expects(:run).once.with('init')
  101
+    run_template_method(:git, :init)
  102
+  end
  103
+
  104
+  def test_git_with_hash_should_run_each_command_using_git_scm
  105
+    Rails::Git.expects(:run).times(2)
  106
+    run_template_method(:git, {:init => '', :add => '.'})
  107
+  end
  108
+
  109
+  def test_vendor_should_write_data_to_file_in_vendor
  110
+    run_template_method(:vendor, 'vendor_file.rb', '# vendor data')
  111
+    assert_generated_file_with_data('vendor/vendor_file.rb', '# vendor data')
  112
+  end
  113
+
  114
+  def test_lib_should_write_data_to_file_in_lib
  115
+    run_template_method(:lib, 'my_library.rb', 'class MyLibrary')
  116
+    assert_generated_file_with_data('lib/my_library.rb', 'class MyLibrary')
  117
+  end
  118
+
  119
+  def test_rakefile_should_write_date_to_file_in_lib_tasks
  120
+    run_template_method(:rakefile, 'myapp.rake', 'task :run => [:environment]')
  121
+    assert_generated_file_with_data('lib/tasks/myapp.rake', 'task :run => [:environment]')
  122
+  end
  123
+
  124
+  def test_initializer_should_write_date_to_file_in_config_initializers
  125
+    run_template_method(:initializer, 'constants.rb', 'MY_CONSTANT = 42')
  126
+    assert_generated_file_with_data('config/initializers/constants.rb', 'MY_CONSTANT = 42')
  127
+  end
  128
+
  129
+  def test_generate_should_run_script_generate_with_argument_and_options
  130
+    expects_run_with_command('script/generate model MyModel')
  131
+    run_template_method(:generate, 'model', 'MyModel')
  132
+  end
  133
+
  134
+  def test_rake_should_run_rake_command_with_development_env
  135
+    expects_run_with_command('rake log:clear RAILS_ENV=development')
  136
+    run_template_method(:rake, 'log:clear')
  137
+  end
  138
+
  139
+  def test_rake_with_env_option_should_run_rake_command_in_env
  140
+    expects_run_with_command('rake log:clear RAILS_ENV=production')
  141
+    run_template_method(:rake, 'log:clear', :env => 'production')
  142
+  end
  143
+
  144
+  def test_rake_with_sudo_option_should_run_rake_command_with_sudo
  145
+    expects_run_with_command('sudo rake log:clear RAILS_ENV=development')
  146
+    run_template_method(:rake, 'log:clear', :sudo => true)
  147
+  end
  148
+
  149
+  def test_capify_should_run_the_capify_command
  150
+    expects_run_with_command('capify .')
  151
+    run_template_method(:capify!)
  152
+  end
  153
+
  154
+  def test_freeze_should_freeze_rails_edge
  155
+    expects_run_with_command('rake rails:freeze:edge')
  156
+    run_template_method(:freeze!)
  157
+  end
  158
+
  159
+  def test_route_should_add_data_to_the_routes_block_in_config_routes
  160
+    route_command = "map.route '/login', :controller => 'sessions', :action => 'new'"
  161
+    run_template_method(:route, route_command)
  162
+    assert_generated_file_with_data 'config/routes.rb', route_command
  163
+  end
  164
+
  165
+  protected
  166
+  def run_template_method(method_name, *args, &block)
  167
+    silence_generator do
  168
+      @template_runner = Rails::TemplateRunner.new(@template_path, RAILS_ROOT)
  169
+      @template_runner.send(method_name, *args, &block)
  170
+    end
  171
+  end
  172
+
  173
+  def expects_run_with_command(command)
  174
+    Rails::TemplateRunner.any_instance.stubs(:run).once.with(command, false)
  175
+  end
  176
+
  177
+  def assert_rails_initializer_includes(data, message = nil)
  178
+    message ||= "Rails::Initializer should include #{data}"
  179
+    assert_generated_file 'config/environment.rb' do |body|
  180
+      assert_match(/#{Regexp.escape("Rails::Initializer.run do |config|")}.+#{Regexp.escape(data)}.+end/m, body, message)
  181
+    end
  182
+  end
  183
+
  184
+  def assert_generated_file_with_data(file, data, message = nil)
  185
+    message ||= "#{file} should include '#{data}'"
  186
+    assert_generated_file(file) do |file|
  187
+      assert_match(/#{Regexp.escape(data)}/,file, message)
  188
+    end
  189
+  end
  190
+end

4 notes on commit 9fd35fc

Andrew Timberlake

When running rake rails:template this breaks with uninitialized constant Rails::Generator

Aaron Quint

Its because of the logger – working on a fix right now.

Aaron Quint

Thanks for the catch @andrewtimberlake – I already put in a patch, should be picked up soon

Andrew Timberlake

Thanks, that helps

Please sign in to comment.
Something went wrong with that request. Please try again.