Skip to content
This repository
Browse code

Revert "Clean up the builder abstraction in AppGenerator."

The phrase "clean up" misrepresents the fact that this removes
a feature that ships with Rails 3.0.

This reverts commit 6774e12.
  • Loading branch information...
commit 848eb0d777d2f2907c399c2fe073fedffad14c63 1 parent 6774e12
Yehuda Katz authored October 06, 2010
247  railties/lib/rails/generators/rails/app/app_generator.rb
@@ -6,12 +6,152 @@
6 6
 require 'uri'
7 7
 
8 8
 module Rails
  9
+  module ActionMethods
  10
+    attr_reader :options
  11
+
  12
+    def initialize(generator)
  13
+      @generator = generator
  14
+      @options   = generator.options
  15
+    end
  16
+
  17
+    private
  18
+      %w(template copy_file directory empty_directory inside
  19
+         empty_directory_with_gitkeep create_file chmod shebang).each do |method|
  20
+        class_eval <<-RUBY, __FILE__, __LINE__ + 1
  21
+          def #{method}(*args, &block)
  22
+            @generator.send(:#{method}, *args, &block)
  23
+          end
  24
+        RUBY
  25
+      end
  26
+
  27
+      # TODO: Remove once this is fully in place
  28
+      def method_missing(meth, *args, &block)
  29
+        STDERR.puts "Calling #{meth} with #{args.inspect} with #{block}"
  30
+        @generator.send(meth, *args, &block)
  31
+      end
  32
+  end
  33
+
  34
+  class AppBuilder
  35
+    def rakefile
  36
+      template "Rakefile"
  37
+    end
  38
+
  39
+    def readme
  40
+      copy_file "README"
  41
+    end
  42
+
  43
+    def gemfile
  44
+      template "Gemfile"
  45
+    end
  46
+
  47
+    def configru
  48
+      template "config.ru"
  49
+    end
  50
+
  51
+    def gitignore
  52
+      copy_file "gitignore", ".gitignore"
  53
+    end
  54
+
  55
+    def app
  56
+      directory 'app'
  57
+    end
  58
+
  59
+    def config
  60
+      empty_directory "config"
  61
+
  62
+      inside "config" do
  63
+        template "routes.rb"
  64
+        template "application.rb"
  65
+        template "environment.rb"
  66
+
  67
+        directory "environments"
  68
+        directory "initializers"
  69
+        directory "locales"
  70
+      end
  71
+    end
  72
+
  73
+    def database_yml
  74
+      template "config/databases/#{@options[:database]}.yml", "config/database.yml"
  75
+    end
  76
+
  77
+    def db
  78
+      directory "db"
  79
+    end
  80
+
  81
+    def doc
  82
+      directory "doc"
  83
+    end
  84
+
  85
+    def lib
  86
+      empty_directory "lib"
  87
+      empty_directory_with_gitkeep "lib/tasks"
  88
+    end
  89
+
  90
+    def log
  91
+      empty_directory "log"
  92
+
  93
+      inside "log" do
  94
+        %w( server production development test ).each do |file|
  95
+          create_file "#{file}.log"
  96
+          chmod "#{file}.log", 0666, :verbose => false
  97
+        end
  98
+      end
  99
+    end
  100
+
  101
+    def public_directory
  102
+      directory "public", "public", :recursive => false
  103
+    end
  104
+
  105
+    def images
  106
+      directory "public/images"
  107
+    end
  108
+
  109
+    def stylesheets
  110
+      empty_directory_with_gitkeep "public/stylesheets"
  111
+    end
  112
+
  113
+    def javascripts
  114
+      unless options[:skip_prototype]
  115
+        directory "public/javascripts"
  116
+      else
  117
+        empty_directory_with_gitkeep "public/javascripts"
  118
+        create_file "public/javascripts/application.js"
  119
+      end
  120
+    end
  121
+
  122
+    def script
  123
+      directory "script" do |content|
  124
+        "#{shebang}\n" + content
  125
+      end
  126
+      chmod "script", 0755, :verbose => false
  127
+    end
  128
+
  129
+    def test
  130
+      directory "test"
  131
+    end
  132
+
  133
+    def tmp
  134
+      empty_directory "tmp"
  135
+
  136
+      inside "tmp" do
  137
+        %w(sessions sockets cache pids).each do |dir|
  138
+          empty_directory(dir)
  139
+        end
  140
+      end
  141
+    end
  142
+
  143
+    def vendor_plugins
  144
+      empty_directory_with_gitkeep "vendor/plugins"
  145
+    end
  146
+  end
  147
+
9 148
   module Generators
10 149
     # We need to store the RAILS_DEV_PATH in a constant, otherwise the path
11 150
     # can change in Ruby 1.8.7 when we FileUtils.cd.
12 151
     RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__))
13 152
 
14  
-    RESERVED_NAMES = %w(application destroy benchmarker profiler plugin runner test)
  153
+    RESERVED_NAMES = %w[application destroy benchmarker profiler
  154
+                        plugin runner test]
15 155
 
16 156
     class AppGenerator < Base
17 157
       DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db )
@@ -24,6 +164,9 @@ class AppGenerator < Base
24 164
       class_option :database,           :type => :string, :aliases => "-d", :default => "sqlite3",
25 165
                                         :desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})"
26 166
 
  167
+      class_option :builder,            :type => :string, :aliases => "-b",
  168
+                                        :desc => "Path to an application builder (can be a filesystem path or URL)"
  169
+
27 170
       class_option :template,           :type => :string, :aliases => "-m",
28 171
                                         :desc => "Path to an application template (can be a filesystem path or URL)"
29 172
 
@@ -57,6 +200,7 @@ class AppGenerator < Base
57 200
 
58 201
       def initialize(*args)
59 202
         raise Error, "Options should be given after the application name. For details run: rails --help" if args[0].blank?
  203
+
60 204
         @original_wd = Dir.pwd
61 205
 
62 206
         super
@@ -76,29 +220,19 @@ def create_root
76 220
       end
77 221
 
78 222
       def create_root_files
79  
-        copy_file "README"
80  
-        template "Rakefile"
81  
-        template "config.ru"
82  
-        copy_file "gitignore", ".gitignore" unless options[:skip_git]
83  
-        template "Gemfile" unless options[:skip_gemfile]
  223
+        build(:readme)
  224
+        build(:rakefile)
  225
+        build(:configru)
  226
+        build(:gitignore) unless options[:skip_git]
  227
+        build(:gemfile)   unless options[:skip_gemfile]
84 228
       end
85 229
 
86 230
       def create_app_files
87  
-        directory 'app'
  231
+        build(:app)
88 232
       end
89 233
 
90 234
       def create_config_files
91  
-        empty_directory "config"
92  
-
93  
-        inside "config" do
94  
-          template "routes.rb"
95  
-          template "application.rb"
96  
-          template "environment.rb"
97  
-
98  
-          directory "environments"
99  
-          directory "initializers"
100  
-          directory "locales"
101  
-        end
  235
+        build(:config)
102 236
       end
103 237
 
104 238
       def create_boot_file
@@ -107,77 +241,59 @@ def create_boot_file
107 241
 
108 242
       def create_active_record_files
109 243
         return if options[:skip_active_record]
110  
-        template "config/databases/#{@options[:database]}.yml", "config/database.yml"
  244
+        build(:database_yml)
111 245
       end
112 246
 
113 247
       def create_db_files
114  
-        directory "db"
  248
+        build(:db)
115 249
       end
116 250
 
117 251
       def create_doc_files
118  
-        directory "doc"
  252
+        build(:doc)
119 253
       end
120 254
 
121 255
       def create_lib_files
122  
-        empty_directory "lib"
123  
-        empty_directory_with_gitkeep "lib/tasks"
  256
+        build(:lib)
124 257
       end
125 258
 
126 259
       def create_log_files
127  
-        empty_directory "log"
128  
-
129  
-        inside "log" do
130  
-          %w( server production development test ).each do |file|
131  
-            create_file "#{file}.log"
132  
-            chmod "#{file}.log", 0666, :verbose => false
133  
-          end
134  
-        end
  260
+        build(:log)
135 261
       end
136 262
 
137 263
       def create_public_files
138  
-        directory "public", "public", :recursive => false
  264
+        build(:public_directory)
139 265
       end
140 266
 
141 267
       def create_public_image_files
142  
-        directory "public/images"
  268
+        build(:images)
143 269
       end
144 270
 
145 271
       def create_public_stylesheets_files
146  
-        empty_directory_with_gitkeep "public/stylesheets"
  272
+        build(:stylesheets)
147 273
       end
148 274
 
149  
-      def create_public_javascripts_files
150  
-        unless options[:skip_prototype]
151  
-          directory "public/javascripts"
152  
-        else
153  
-          empty_directory_with_gitkeep "public/javascripts"
154  
-          create_file "public/javascripts/application.js"
155  
-        end
  275
+      def create_prototype_files
  276
+        build(:javascripts)
156 277
       end
157 278
 
158 279
       def create_script_files
159  
-        directory "script" do |content|
160  
-          "#{shebang}\n" + content
161  
-        end
162  
-        chmod "script", 0755, :verbose => false
  280
+        build(:script)
163 281
       end
164 282
 
165 283
       def create_test_files
166  
-        directory "test" unless options[:skip_test_unit]
  284
+        build(:test) unless options[:skip_test_unit]
167 285
       end
168 286
 
169 287
       def create_tmp_files
170  
-        empty_directory "tmp"
171  
-
172  
-        inside "tmp" do
173  
-          %w(sessions sockets cache pids).each do |dir|
174  
-            empty_directory(dir)
175  
-          end
176  
-        end
  288
+        build(:tmp)
177 289
       end
178 290
 
179 291
       def create_vendor_files
180  
-        empty_directory_with_gitkeep "vendor/plugins"
  292
+        build(:vendor_plugins)
  293
+      end
  294
+
  295
+      def finish_template
  296
+        build(:leftovers)
181 297
       end
182 298
 
183 299
       def apply_rails_template
@@ -197,6 +313,29 @@ def self.banner
197 313
         "rails new #{self.arguments.map(&:usage).join(' ')} [options]"
198 314
       end
199 315
 
  316
+      def builder
  317
+        @builder ||= begin
  318
+          if path = options[:builder]
  319
+            if URI(path).is_a?(URI::HTTP)
  320
+              contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read }
  321
+            else
  322
+              contents = open(File.expand_path(path, @original_wd)) {|io| io.read }
  323
+            end
  324
+
  325
+            prok = eval("proc { #{contents} }", TOPLEVEL_BINDING, path, 1)
  326
+            instance_eval(&prok)
  327
+          end
  328
+
  329
+          builder_class = defined?(::AppBuilder) ? ::AppBuilder : Rails::AppBuilder
  330
+          builder_class.send(:include, ActionMethods)
  331
+          builder_class.new(self)
  332
+        end
  333
+      end
  334
+
  335
+      def build(meth, *args)
  336
+        builder.send(meth, *args) if builder.respond_to?(meth)
  337
+      end
  338
+
200 339
       def set_default_accessors!
201 340
         self.rails_template = case options[:template]
202 341
           when /^http:\/\//
68  railties/test/generators/app_generator_test.rb
@@ -261,4 +261,70 @@ def action(*args, &block)
261 261
     silence(:stdout){ generator.send(*args, &block) }
262 262
   end
263 263
 
264  
-end
  264
+end
  265
+
  266
+class CustomAppGeneratorTest < Rails::Generators::TestCase
  267
+  include GeneratorsTestHelper
  268
+  tests Rails::Generators::AppGenerator
  269
+
  270
+  arguments [destination_root]
  271
+
  272
+  def setup
  273
+    Rails.application = TestApp::Application
  274
+    super
  275
+    Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
  276
+    @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
  277
+  end
  278
+
  279
+  def teardown
  280
+    super
  281
+    Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
  282
+    Object.class_eval { remove_const :AppBuilder if const_defined?(:AppBuilder) }
  283
+    Rails.application = TestApp::Application.instance
  284
+  end
  285
+
  286
+  def test_builder_option_with_empty_app_builder
  287
+    FileUtils.cd(Rails.root)
  288
+    run_generator([destination_root, "-b", "#{Rails.root}/lib/empty_builder.rb"])
  289
+    DEFAULT_APP_FILES.each{ |path| assert_no_file path }
  290
+  end
  291
+
  292
+  def test_builder_option_with_simple_app_builder
  293
+    FileUtils.cd(Rails.root)
  294
+    run_generator([destination_root, "-b", "#{Rails.root}/lib/simple_builder.rb"])
  295
+    (DEFAULT_APP_FILES - ['config.ru']).each{ |path| assert_no_file path }
  296
+    assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }]
  297
+  end
  298
+
  299
+  def test_builder_option_with_relative_path
  300
+    here = File.expand_path(File.dirname(__FILE__))
  301
+    FileUtils.cd(here)
  302
+    run_generator([destination_root, "-b", "../fixtures/lib/simple_builder.rb"])
  303
+    (DEFAULT_APP_FILES - ['config.ru']).each{ |path| assert_no_file path }
  304
+    assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }]
  305
+  end
  306
+
  307
+  def test_builder_option_with_tweak_app_builder
  308
+    FileUtils.cd(Rails.root)
  309
+    run_generator([destination_root, "-b", "#{Rails.root}/lib/tweak_builder.rb"])
  310
+    DEFAULT_APP_FILES.each{ |path| assert_file path }
  311
+    assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }]
  312
+  end
  313
+
  314
+  def test_builder_option_with_http
  315
+    path = "http://gist.github.com/103208.txt"
  316
+    template = "class AppBuilder; end"
  317
+    template.instance_eval "def read; self; end" # Make the string respond to read
  318
+
  319
+    generator([destination_root], :builder => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
  320
+    capture(:stdout) { generator.invoke_all }
  321
+
  322
+    DEFAULT_APP_FILES.each{ |path| assert_no_file path }
  323
+  end
  324
+
  325
+protected
  326
+
  327
+  def action(*args, &block)
  328
+    silence(:stdout){ generator.send(*args, &block) }
  329
+  end
  330
+end

0 notes on commit 848eb0d

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