Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
@wycats wycats authored
View
247 railties/lib/rails/generators/rails/app/app_generator.rb
@@ -6,12 +6,152 @@
require 'uri'
module Rails
+ module ActionMethods
+ attr_reader :options
+
+ def initialize(generator)
+ @generator = generator
+ @options = generator.options
+ end
+
+ private
+ %w(template copy_file directory empty_directory inside
+ empty_directory_with_gitkeep create_file chmod shebang).each do |method|
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{method}(*args, &block)
+ @generator.send(:#{method}, *args, &block)
+ end
+ RUBY
+ end
+
+ # TODO: Remove once this is fully in place
+ def method_missing(meth, *args, &block)
+ STDERR.puts "Calling #{meth} with #{args.inspect} with #{block}"
+ @generator.send(meth, *args, &block)
+ end
+ end
+
+ class AppBuilder
+ def rakefile
+ template "Rakefile"
+ end
+
+ def readme
+ copy_file "README"
+ end
+
+ def gemfile
+ template "Gemfile"
+ end
+
+ def configru
+ template "config.ru"
+ end
+
+ def gitignore
+ copy_file "gitignore", ".gitignore"
+ end
+
+ def app
+ directory 'app'
+ end
+
+ def config
+ empty_directory "config"
+
+ inside "config" do
+ template "routes.rb"
+ template "application.rb"
+ template "environment.rb"
+
+ directory "environments"
+ directory "initializers"
+ directory "locales"
+ end
+ end
+
+ def database_yml
+ template "config/databases/#{@options[:database]}.yml", "config/database.yml"
+ end
+
+ def db
+ directory "db"
+ end
+
+ def doc
+ directory "doc"
+ end
+
+ def lib
+ empty_directory "lib"
+ empty_directory_with_gitkeep "lib/tasks"
+ end
+
+ def log
+ empty_directory "log"
+
+ inside "log" do
+ %w( server production development test ).each do |file|
+ create_file "#{file}.log"
+ chmod "#{file}.log", 0666, :verbose => false
+ end
+ end
+ end
+
+ def public_directory
+ directory "public", "public", :recursive => false
+ end
+
+ def images
+ directory "public/images"
+ end
+
+ def stylesheets
+ empty_directory_with_gitkeep "public/stylesheets"
+ end
+
+ def javascripts
+ unless options[:skip_prototype]
+ directory "public/javascripts"
+ else
+ empty_directory_with_gitkeep "public/javascripts"
+ create_file "public/javascripts/application.js"
+ end
+ end
+
+ def script
+ directory "script" do |content|
+ "#{shebang}\n" + content
+ end
+ chmod "script", 0755, :verbose => false
+ end
+
+ def test
+ directory "test"
+ end
+
+ def tmp
+ empty_directory "tmp"
+
+ inside "tmp" do
+ %w(sessions sockets cache pids).each do |dir|
+ empty_directory(dir)
+ end
+ end
+ end
+
+ def vendor_plugins
+ empty_directory_with_gitkeep "vendor/plugins"
+ end
+ end
+
module Generators
# We need to store the RAILS_DEV_PATH in a constant, otherwise the path
# can change in Ruby 1.8.7 when we FileUtils.cd.
RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__))
- RESERVED_NAMES = %w(application destroy benchmarker profiler plugin runner test)
+ RESERVED_NAMES = %w[application destroy benchmarker profiler
+ plugin runner test]
class AppGenerator < Base
DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db )
@@ -24,6 +164,9 @@ class AppGenerator < Base
class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3",
:desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})"
+ class_option :builder, :type => :string, :aliases => "-b",
+ :desc => "Path to an application builder (can be a filesystem path or URL)"
+
class_option :template, :type => :string, :aliases => "-m",
:desc => "Path to an application template (can be a filesystem path or URL)"
@@ -57,6 +200,7 @@ class AppGenerator < Base
def initialize(*args)
raise Error, "Options should be given after the application name. For details run: rails --help" if args[0].blank?
+
@original_wd = Dir.pwd
super
@@ -76,29 +220,19 @@ def create_root
end
def create_root_files
- copy_file "README"
- template "Rakefile"
- template "config.ru"
- copy_file "gitignore", ".gitignore" unless options[:skip_git]
- template "Gemfile" unless options[:skip_gemfile]
+ build(:readme)
+ build(:rakefile)
+ build(:configru)
+ build(:gitignore) unless options[:skip_git]
+ build(:gemfile) unless options[:skip_gemfile]
end
def create_app_files
- directory 'app'
+ build(:app)
end
def create_config_files
- empty_directory "config"
-
- inside "config" do
- template "routes.rb"
- template "application.rb"
- template "environment.rb"
-
- directory "environments"
- directory "initializers"
- directory "locales"
- end
+ build(:config)
end
def create_boot_file
@@ -107,77 +241,59 @@ def create_boot_file
def create_active_record_files
return if options[:skip_active_record]
- template "config/databases/#{@options[:database]}.yml", "config/database.yml"
+ build(:database_yml)
end
def create_db_files
- directory "db"
+ build(:db)
end
def create_doc_files
- directory "doc"
+ build(:doc)
end
def create_lib_files
- empty_directory "lib"
- empty_directory_with_gitkeep "lib/tasks"
+ build(:lib)
end
def create_log_files
- empty_directory "log"
-
- inside "log" do
- %w( server production development test ).each do |file|
- create_file "#{file}.log"
- chmod "#{file}.log", 0666, :verbose => false
- end
- end
+ build(:log)
end
def create_public_files
- directory "public", "public", :recursive => false
+ build(:public_directory)
end
def create_public_image_files
- directory "public/images"
+ build(:images)
end
def create_public_stylesheets_files
- empty_directory_with_gitkeep "public/stylesheets"
+ build(:stylesheets)
end
- def create_public_javascripts_files
- unless options[:skip_prototype]
- directory "public/javascripts"
- else
- empty_directory_with_gitkeep "public/javascripts"
- create_file "public/javascripts/application.js"
- end
+ def create_prototype_files
+ build(:javascripts)
end
def create_script_files
- directory "script" do |content|
- "#{shebang}\n" + content
- end
- chmod "script", 0755, :verbose => false
+ build(:script)
end
def create_test_files
- directory "test" unless options[:skip_test_unit]
+ build(:test) unless options[:skip_test_unit]
end
def create_tmp_files
- empty_directory "tmp"
-
- inside "tmp" do
- %w(sessions sockets cache pids).each do |dir|
- empty_directory(dir)
- end
- end
+ build(:tmp)
end
def create_vendor_files
- empty_directory_with_gitkeep "vendor/plugins"
+ build(:vendor_plugins)
+ end
+
+ def finish_template
+ build(:leftovers)
end
def apply_rails_template
@@ -197,6 +313,29 @@ def self.banner
"rails new #{self.arguments.map(&:usage).join(' ')} [options]"
end
+ def builder
+ @builder ||= begin
+ if path = options[:builder]
+ if URI(path).is_a?(URI::HTTP)
+ contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read }
+ else
+ contents = open(File.expand_path(path, @original_wd)) {|io| io.read }
+ end
+
+ prok = eval("proc { #{contents} }", TOPLEVEL_BINDING, path, 1)
+ instance_eval(&prok)
+ end
+
+ builder_class = defined?(::AppBuilder) ? ::AppBuilder : Rails::AppBuilder
+ builder_class.send(:include, ActionMethods)
+ builder_class.new(self)
+ end
+ end
+
+ def build(meth, *args)
+ builder.send(meth, *args) if builder.respond_to?(meth)
+ end
+
def set_default_accessors!
self.rails_template = case options[:template]
when /^http:\/\//
View
68 railties/test/generators/app_generator_test.rb
@@ -261,4 +261,70 @@ def action(*args, &block)
silence(:stdout){ generator.send(*args, &block) }
end
-end
+end
+
+class CustomAppGeneratorTest < Rails::Generators::TestCase
+ include GeneratorsTestHelper
+ tests Rails::Generators::AppGenerator
+
+ arguments [destination_root]
+
+ def setup
+ Rails.application = TestApp::Application
+ super
+ Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
+ @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
+ end
+
+ def teardown
+ super
+ Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
+ Object.class_eval { remove_const :AppBuilder if const_defined?(:AppBuilder) }
+ Rails.application = TestApp::Application.instance
+ end
+
+ def test_builder_option_with_empty_app_builder
+ FileUtils.cd(Rails.root)
+ run_generator([destination_root, "-b", "#{Rails.root}/lib/empty_builder.rb"])
+ DEFAULT_APP_FILES.each{ |path| assert_no_file path }
+ end
+
+ def test_builder_option_with_simple_app_builder
+ FileUtils.cd(Rails.root)
+ run_generator([destination_root, "-b", "#{Rails.root}/lib/simple_builder.rb"])
+ (DEFAULT_APP_FILES - ['config.ru']).each{ |path| assert_no_file path }
+ assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }]
+ end
+
+ def test_builder_option_with_relative_path
+ here = File.expand_path(File.dirname(__FILE__))
+ FileUtils.cd(here)
+ run_generator([destination_root, "-b", "../fixtures/lib/simple_builder.rb"])
+ (DEFAULT_APP_FILES - ['config.ru']).each{ |path| assert_no_file path }
+ assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }]
+ end
+
+ def test_builder_option_with_tweak_app_builder
+ FileUtils.cd(Rails.root)
+ run_generator([destination_root, "-b", "#{Rails.root}/lib/tweak_builder.rb"])
+ DEFAULT_APP_FILES.each{ |path| assert_file path }
+ assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }]
+ end
+
+ def test_builder_option_with_http
+ path = "http://gist.github.com/103208.txt"
+ template = "class AppBuilder; end"
+ template.instance_eval "def read; self; end" # Make the string respond to read
+
+ generator([destination_root], :builder => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
+ capture(:stdout) { generator.invoke_all }
+
+ DEFAULT_APP_FILES.each{ |path| assert_no_file path }
+ end
+
+protected
+
+ def action(*args, &block)
+ silence(:stdout){ generator.send(*args, &block) }
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.