Merge remote branch 'drogus/plugin_new'

Conflicts:
	railties/test/generators/app_generator_test.rb
This commit is contained in:
José Valim 2010-11-11 19:39:21 +01:00
commit f912a359aa
57 changed files with 1311 additions and 324 deletions

@ -14,7 +14,7 @@ class Railtie < Rails::Railtie
config.active_record = ActiveSupport::OrderedOptions.new
config.app_generators.orm :active_record, :migration => true,
:timestamps => true
:timestamps => true
config.app_middleware.insert_after "::ActionDispatch::Callbacks",
"ActiveRecord::QueryCache"

@ -1,5 +1,6 @@
require 'active_support/core_ext/hash/conversions'
require 'active_support/core_ext/hash/deep_merge'
require 'active_support/core_ext/hash/deep_dup'
require 'active_support/core_ext/hash/diff'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/hash/indifferent_access'

@ -0,0 +1,11 @@
class Hash
# Returns a deep copy of hash.
def deep_dup
duplicate = self.dup
duplicate.each_pair do |k,v|
tv = duplicate[k]
duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_dup : v
end
duplicate
end
end

@ -329,6 +329,21 @@ def test_deep_merge_on_indifferent_access
assert_equal expected, hash_1
end
def test_deep_dup
hash = { :a => { :b => 'b' } }
dup = hash.deep_dup
dup[:a][:c] = 'c'
assert_equal nil, hash[:a][:c]
assert_equal 'c', dup[:a][:c]
end
def test_deep_dup_initialize
zero_hash = Hash.new 0
hash = { :a => zero_hash }
dup = hash.deep_dup
assert_equal 0, dup[:a][44]
end
def test_store_on_indifferent_access
hash = HashWithIndifferentAccess.new
hash.store(:test1, 1)

@ -8,4 +8,9 @@
require 'rails/ruby_version_check'
Signal.trap("INT") { puts; exit }
require 'rails/commands/application'
if ARGV.first == 'plugin'
ARGV.shift
require 'rails/commands/plugin_new'
else
require 'rails/commands/application'
end

@ -0,0 +1,16 @@
require 'rails/version'
if %w(--version -v).include? ARGV.first
puts "Rails #{Rails::VERSION::STRING}"
exit(0)
end
if ARGV.first != "new"
ARGV[0] = "--help"
else
ARGV.shift
end
require 'rails/generators'
require 'rails/generators/rails/plugin_new/plugin_new_generator'
Rails::Generators::PluginNewGenerator.start

@ -1,5 +1,6 @@
require 'active_support/deprecation'
require 'active_support/ordered_options'
require 'active_support/core_ext/hash/deep_dup'
require 'rails/paths'
require 'rails/rack'
@ -51,6 +52,13 @@ def initialize
@colorize_logging = true
end
def initialize_copy(source)
@aliases = @aliases.deep_dup
@options = @options.deep_dup
@fallbacks = @fallbacks.deep_dup
@templates = @templates.dup
end
def method_missing(method, *args)
method = method.to_s.sub(/=$/, '').to_sym

@ -10,6 +10,7 @@ class Configuration < ::Rails::Railtie::Configuration
def initialize(root=nil)
super()
@root = root
@generators = app_generators.dup
end
# Returns the middleware stack for the engine.

@ -0,0 +1,176 @@
require 'digest/md5'
require 'active_support/secure_random'
require 'rails/version' unless defined?(Rails::VERSION)
require 'rbconfig'
require 'open-uri'
require 'uri'
module Rails
module Generators
class AppBase < Base
DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db )
JAVASCRIPTS = %w( prototype jquery )
attr_accessor :rails_template
add_shebang_option!
argument :app_path, :type => :string
def self.add_shared_options_for(name)
class_option :builder, :type => :string, :aliases => "-b",
:desc => "Path to a #{name} builder (can be a filesystem path or URL)"
class_option :template, :type => :string, :aliases => "-m",
:desc => "Path to an #{name} template (can be a filesystem path or URL)"
class_option :skip_gemfile, :type => :boolean, :default => false,
:desc => "Don't create a Gemfile"
class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false,
:desc => "Skip Git ignores and keeps"
class_option :skip_active_record, :type => :boolean, :aliases => "-O", :default => false,
:desc => "Skip Active Record files"
class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3",
:desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})"
class_option :javascript, :type => :string, :aliases => "-j", :default => "prototype",
:desc => "Preconfigure for selected javascript library (options: #{JAVASCRIPTS.join('/')})"
class_option :skip_javascript, :type => :boolean, :aliases => "-J", :default => false,
:desc => "Skip javascript files"
class_option :dev, :type => :boolean, :default => false,
:desc => "Setup the #{name} with Gemfile pointing to your Rails checkout"
class_option :edge, :type => :boolean, :default => false,
:desc => "Setup the #{name} with Gemfile pointing to Rails repository"
class_option :skip_test_unit, :type => :boolean, :aliases => "-T", :default => false,
:desc => "Skip Test::Unit files"
class_option :help, :type => :boolean, :aliases => "-h", :group => :rails,
:desc => "Show this help message and quit"
end
def initialize(*args)
@original_wd = Dir.pwd
super
end
protected
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 = get_builder_class
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 create_root
self.destination_root = File.expand_path(app_path, destination_root)
valid_const?
empty_directory '.'
set_default_accessors!
FileUtils.cd(destination_root) unless options[:pretend]
end
def apply_rails_template
apply rails_template if rails_template
rescue Thor::Error, LoadError, Errno::ENOENT => e
raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}"
end
def set_default_accessors!
self.rails_template = case options[:template]
when /^http:\/\//
options[:template]
when String
File.expand_path(options[:template], Dir.pwd)
else
options[:template]
end
end
def database_gemfile_entry
entry = ""
unless options[:skip_active_record]
entry = "gem '#{gem_for_database}'"
entry << ", :require => '#{require_for_database}'" if require_for_database
end
entry
end
def rails_gemfile_entry
if options.dev?
<<-GEMFILE
gem 'rails', :path => '#{Rails::Generators::RAILS_DEV_PATH}'
gem 'arel', :git => 'git://github.com/rails/arel.git'
gem "rack", :git => "git://github.com/rack/rack.git"
GEMFILE
elsif options.edge?
<<-GEMFILE
gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'arel', :git => 'git://github.com/rails/arel.git'
gem "rack", :git => "git://github.com/rack/rack.git"
GEMFILE
else
<<-GEMFILE
gem 'rails', '#{Rails::VERSION::STRING}'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
# gem 'arel', :git => 'git://github.com/rails/arel.git'
# gem "rack", :git => "git://github.com/rack/rack.git"
GEMFILE
end
end
def gem_for_database
# %w( mysql oracle postgresql sqlite3 frontbase ibm_db )
case options[:database]
when "oracle" then "ruby-oci8"
when "postgresql" then "pg"
when "sqlite3" then "sqlite3-ruby"
when "frontbase" then "ruby-frontbase"
when "mysql" then "mysql2"
else options[:database]
end
end
def require_for_database
case options[:database]
when "sqlite3" then "sqlite3"
end
end
def bundle_if_dev_or_edge
bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
run "#{bundle_command} install" if dev_or_edge?
end
def dev_or_edge?
options.dev? || options.edge?
end
end
end
end

@ -1,3 +1,4 @@
<% without_namespacing do -%>
<%%= form_for(@<%= singular_table_name %>) do |f| %>
<%% if @<%= singular_table_name %>.errors.any? %>
<div id="error_explanation">
@ -21,3 +22,4 @@
<%%= f.submit %>
</div>
<%% end %>
<% end -%>

@ -1,6 +1,8 @@
<% without_namespacing do -%>
<h1>Editing <%= singular_table_name %></h1>
<%%= render 'form' %>
<%%= link_to 'Show', @<%= singular_table_name %> %> |
<%%= link_to 'Back', <%= index_helper %>_path %>
<% end -%>

@ -1,3 +1,4 @@
<% without_namespacing do -%>
<h1>Listing <%= plural_table_name %></h1>
<table>
@ -25,3 +26,4 @@
<br />
<%%= link_to 'New <%= human_name %>', new_<%= singular_table_name %>_path %>
<% end -%>

@ -1,5 +1,7 @@
<% without_namespacing do -%>
<h1>New <%= singular_table_name %></h1>
<%%= render 'form' %>
<%%= link_to 'Back', <%= index_helper %>_path %>
<% end -%>

@ -1,3 +1,4 @@
<% without_namespacing do -%>
<p id="notice"><%%= notice %></p>
<% for attribute in attributes -%>
@ -10,3 +11,4 @@
<%%= link_to 'Edit', edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> |
<%%= link_to 'Back', <%= index_helper %>_path %>
<% end -%>

@ -30,9 +30,15 @@ def module_namespacing(&block)
end
end
def without_namespacing(&block)
inside_namespace do
concat(capture(&block))
end
end
def indent(content, multiplier = 2)
spaces = " " * multiplier
content.each_line.map {|line| "#{spaces}#{line}" }.join("\n")
content = content.each_line.map {|line| "#{spaces}#{line}" }.join
end
def wrap_with_namespace(content)

@ -1,9 +1,4 @@
require 'digest/md5'
require 'active_support/secure_random'
require 'rails/version' unless defined?(Rails::VERSION)
require 'rbconfig'
require 'open-uri'
require 'uri'
require 'rails/generators/app_base'
module Rails
module ActionMethods
@ -158,60 +153,16 @@ module Generators
RESERVED_NAMES = %w[application destroy benchmarker profiler
plugin runner test]
class AppGenerator < Base
DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db )
JAVASCRIPTS = %w( prototype jquery )
attr_accessor :rails_template
add_shebang_option!
argument :app_path, :type => :string
class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3",
:desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})"
class_option :javascript, :type => :string, :aliases => "-j", :default => "prototype",
:desc => "Preconfigure for selected javascript library (options: #{JAVASCRIPTS.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)"
class_option :dev, :type => :boolean, :default => false,
:desc => "Setup the application with Gemfile pointing to your Rails checkout"
class_option :edge, :type => :boolean, :default => false,
:desc => "Setup the application with Gemfile pointing to Rails repository"
class_option :skip_gemfile, :type => :boolean, :default => false,
:desc => "Don't create a Gemfile"
class_option :skip_active_record, :type => :boolean, :aliases => "-O", :default => false,
:desc => "Skip Active Record files"
class_option :skip_test_unit, :type => :boolean, :aliases => "-T", :default => false,
:desc => "Skip Test::Unit files"
class_option :skip_javascript, :type => :boolean, :aliases => "-J", :default => false,
:desc => "Skip javascript files"
class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false,
:desc => "Skip Git ignores and keeps"
class AppGenerator < AppBase
add_shared_options_for "application"
# Add bin/rails options
class_option :version, :type => :boolean, :aliases => "-v", :group => :rails,
:desc => "Show Rails version number and quit"
class_option :help, :type => :boolean, :aliases => "-h", :group => :rails,
:desc => "Show this help message and quit"
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
if !options[:skip_active_record] && !DATABASES.include?(options[:database])
@ -223,14 +174,7 @@ def initialize(*args)
end
end
def create_root
self.destination_root = File.expand_path(app_path, destination_root)
valid_app_const?
empty_directory '.'
set_default_accessors!
FileUtils.cd(destination_root) unless options[:pretend]
end
public_task :create_root
def create_root_files
build(:readme)
@ -309,16 +253,7 @@ def finish_template
build(:leftovers)
end
def apply_rails_template
apply rails_template if rails_template
rescue Thor::Error, LoadError, Errno::ENOENT => e
raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}"
end
def bundle_if_dev_or_edge
bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
run "#{bundle_command} install" if dev_or_edge?
end
public_task :apply_rails_template, :bundle_if_dev_or_edge
protected
@ -326,40 +261,6 @@ 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:\/\//
options[:template]
when String
File.expand_path(options[:template], Dir.pwd)
else
options[:template]
end
end
# Define file as an alias to create_file for backwards compatibility.
def file(*args, &block)
create_file(*args, &block)
@ -388,7 +289,7 @@ def app_const
@app_const ||= "#{app_const_base}::Application"
end
def valid_app_const?
def valid_const?
if app_const =~ /^\d/
raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers."
elsif RESERVED_NAMES.include?(app_name)
@ -402,28 +303,6 @@ def app_secret
ActiveSupport::SecureRandom.hex(64)
end
def dev_or_edge?
options.dev? || options.edge?
end
def gem_for_database
# %w( mysql oracle postgresql sqlite3 frontbase ibm_db )
case options[:database]
when "oracle" then "ruby-oci8"
when "postgresql" then "pg"
when "sqlite3" then "sqlite3-ruby"
when "frontbase" then "ruby-frontbase"
when "mysql" then "mysql2"
else options[:database]
end
end
def require_for_database
case options[:database]
when "sqlite3" then "sqlite3"
end
end
def mysql_socket
@mysql_socket ||= [
"/tmp/mysql.sock", # default
@ -442,6 +321,10 @@ def empty_directory_with_gitkeep(destination, config = {})
empty_directory(destination, config)
create_file("#{destination}/.gitkeep") unless options[:skip_git]
end
def get_builder_class
defined?(::AppBuilder) ? ::AppBuilder : Rails::AppBuilder
end
end
end
end

@ -1,25 +1,8 @@
source 'http://rubygems.org'
<%- if options.dev? -%>
gem 'rails', :path => '<%= Rails::Generators::RAILS_DEV_PATH %>'
gem 'arel', :git => 'git://github.com/rails/arel.git'
gem "rack", :git => "git://github.com/rack/rack.git"
<%- elsif options.edge? -%>
gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'arel', :git => 'git://github.com/rails/arel.git'
gem "rack", :git => "git://github.com/rack/rack.git"
<%- else -%>
gem 'rails', '<%= Rails::VERSION::STRING %>'
<%= rails_gemfile_entry -%>
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
# gem 'arel', :git => 'git://github.com/rails/arel.git'
# gem "rack", :git => "git://github.com/rack/rack.git"
<%- end -%>
<% unless options[:skip_active_record] -%>
gem '<%= gem_for_database %>'<% if require_for_database %>, :require => '<%= require_for_database %>'<% end %>
<% end -%>
<%= database_gemfile_entry -%>
# Use unicorn as the web server
# gem 'unicorn'

@ -0,0 +1,10 @@
Description:
The 'rails plugin new' command creates a skeleton for developing any
kind of Rails extension with ability to run tests using dummy Rails
application.
Example:
rails plugin new ~/Code/Ruby/blog
This generates a skeletal Rails plugin in ~/Code/Ruby/blog.
See the README in the newly created plugin to get going.

@ -0,0 +1,246 @@
require 'active_support/core_ext/hash/slice'
require "rails/generators/rails/app/app_generator"
module Rails
class PluginBuilder
def rakefile
template "Rakefile"
end
def app
directory "app" if options[:mountable]
end
def readme
copy_file "README.rdoc"
end
def gemfile
template "Gemfile"
end
def license
template "MIT-LICENSE"
end
def gemspec
template "%name%.gemspec"
end
def gitignore
copy_file "gitignore", ".gitignore"
end
def lib
template "lib/%name%.rb"
template "lib/tasks/%name%_tasks.rake"
if full?
template "lib/%name%/engine.rb"
end
end
def config
template "config/routes.rb" if mountable?
end
def test
template "test/test_helper.rb"
template "test/%name%_test.rb"
append_file "Rakefile", <<-EOF
#{rakefile_test_tasks}
task :default => :test
EOF
if full?
template "test/integration/navigation_test.rb"
end
end
def generate_test_dummy(force = false)
opts = (options || {}).slice(:skip_active_record, :skip_javascript, :database, :javascript)
opts[:force] = force
invoke Rails::Generators::AppGenerator,
[ File.expand_path(dummy_path, destination_root) ], opts
end
def test_dummy_config
template "rails/boot.rb", "#{dummy_path}/config/boot.rb", :force => true
template "rails/application.rb", "#{dummy_path}/config/application.rb", :force => true
if mountable?
template "rails/routes.rb", "#{dummy_path}/config/routes.rb", :force => true
end
end
def test_dummy_clean
inside dummy_path do
remove_file ".gitignore"
remove_file "db/seeds.rb"
remove_file "doc"
remove_file "Gemfile"
remove_file "lib/tasks"
remove_file "public/images/rails.png"
remove_file "public/index.html"
remove_file "public/robots.txt"
remove_file "README"
remove_file "test"
remove_file "vendor"
end
end
def script(force = false)
directory "script", :force => force do |content|
"#{shebang}\n" + content
end
chmod "script", 0755, :verbose => false
end
end
module Generators
class PluginNewGenerator < AppBase
add_shared_options_for "plugin"
alias_method :plugin_path, :app_path
class_option :dummy_path, :type => :string, :default => "test/dummy",
:desc => "Create dummy application at given path"
class_option :full, :type => :boolean, :default => false,
:desc => "Generate rails engine with integration tests"
class_option :mountable, :type => :boolean, :default => false,
:desc => "Generate mountable isolated application"
def initialize(*args)
raise Error, "Options should be given after the plugin name. For details run: rails plugin --help" if args[0].blank?
super
end
public_task :create_root
def create_root_files
build(:readme)
build(:rakefile)
build(:gemspec)
build(:license)
build(:gitignore) unless options[:skip_git]
build(:gemfile) unless options[:skip_gemfile]
end
def create_app_files
build(:app)
end
def create_config_files
build(:config)
end
def create_lib_files
build(:lib)
end
def create_script_files
build(:script)
end
def create_test_files
build(:test) unless options[:skip_test_unit]
end
def create_test_dummy_files
return if options[:skip_test_unit]
create_dummy_app
end
def finish_template
build(:leftovers)
end
public_task :apply_rails_template, :bundle_if_dev_or_edge
protected
def create_dummy_app(path = nil)
dummy_path(path) if path
say_status :vendor_app, dummy_path
mute do
build(:generate_test_dummy)
store_application_definition!
build(:test_dummy_config)
build(:test_dummy_clean)
# ensure that script/rails has proper dummy_path
build(:script, true)
end
end
def full?
options[:full] || options[:mountable]
end
def mountable?
options[:mountable]
end
def self.banner
"rails plugin new #{self.arguments.map(&:usage).join(' ')} [options]"
end
def name
@name ||= File.basename(destination_root)
end
def camelized
@camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize
end
def valid_const?
if camelized =~ /^\d/
raise Error, "Invalid plugin name #{name}. Please give a name which does not start with numbers."
elsif RESERVED_NAMES.include?(name)
raise Error, "Invalid plugin name #{name}. Please give a name which does not match one of the reserved rails words."
elsif Object.const_defined?(camelized)
raise Error, "Invalid plugin name #{name}, constant #{camelized} is already in use. Please choose another application name."
end
end
def application_definition
@application_definition ||= begin
dummy_application_path = File.expand_path("#{dummy_path}/config/application.rb", destination_root)
unless options[:pretend] || !File.exists?(dummy_application_path)
contents = File.read(dummy_application_path)
contents[(contents.index("module Dummy"))..-1]
end
end
end
alias :store_application_definition! :application_definition
def get_builder_class
defined?(::PluginBuilder) ? ::PluginBuilder : Rails::PluginBuilder
end
def rakefile_test_tasks
<<-RUBY
require 'rake/testtask'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = false
end
RUBY
end
def dummy_path(path = nil)
@dummy_path = path if path
@dummy_path || options[:dummy_path]
end
def mute(&block)
shell.mute(&block)
end
end
end
end

@ -0,0 +1,9 @@
# Provide a simple gemspec so you can easily use your
# project in your rails apps through git.
Gem::Specification.new do |s|
s.name = "<%= name %>"
s.summary = "Insert <%= camelized %> summary."
s.description = "Insert <%= camelized %> description."
s.files = Dir["lib/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"]
s.version = "0.0.1"
end

@ -0,0 +1,11 @@
source "http://rubygems.org"
<%= rails_gemfile_entry -%>
<% if full? -%>
<%= database_gemfile_entry -%>
<% end -%>
if RUBY_VERSION < '1.9'
gem "ruby-debug", ">= 0.10.3"
end

@ -0,0 +1,20 @@
Copyright <%= Date.today.year %> YOURNAME
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -0,0 +1,3 @@
= <%= camelized %>
This project rocks and uses MIT-LICENSE.

@ -0,0 +1,18 @@
# encoding: UTF-8
require 'rubygems'
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
require 'rake'
require 'rake/rdoctask'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = '<%= camelized %>'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('lib/**/*.rb')
end

@ -0,0 +1,4 @@
module <%= camelized %>
class ApplicationController < ActiveController::Base
end
end

@ -0,0 +1,4 @@
module <%= camelized %>
module ApplicationHelper
end
end

@ -0,0 +1,3 @@
<%= camelized %>::Engine.routes.draw do
end

@ -0,0 +1,6 @@
.bundle/
log/*.log
pkg/
test/dummy/db/*.sqlite3
test/dummy/log/*.log
test/dummy/tmp/

@ -0,0 +1,6 @@
<% if full? -%>
require "<%= name %>/engine"
<% end -%>
module <%= camelized %>
end

@ -0,0 +1,7 @@
module <%= camelized %>
class Engine < Rails::Engine
<% if mountable? -%>
isolate_namespace <%= camelized %>
<% end -%>
end
end

@ -0,0 +1,4 @@
# desc "Explaining what the task does"
# task :<%= name %> do
# # Task goes here
# end

@ -0,0 +1,16 @@
require File.expand_path('../boot', __FILE__)
<% unless options[:skip_active_record] -%>
require 'rails/all'
<% else -%>
# require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "rails/test_unit/railtie"
<% end -%>
Bundler.require
require "<%= name %>"
<%= application_definition %>

@ -0,0 +1,10 @@
require 'rubygems'
gemfile = File.expand_path('../../../../Gemfile', __FILE__)
if File.exist?(gemfile)
ENV['BUNDLE_GEMFILE'] = gemfile
require 'bundler'
Bundler.setup
end
$:.unshift File.expand_path('../../../../lib', __FILE__)

@ -0,0 +1,4 @@
Rails.application.routes.draw do
mount <%= camelized %>::Engine => "/<%= name %>"
end

@ -0,0 +1,5 @@
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
ENGINE_PATH = File.expand_path('../..', __FILE__)
load File.expand_path('../../<%= dummy_path %>/script/rails', __FILE__)

@ -0,0 +1,7 @@
require 'test_helper'
class <%= camelized %>Test < ActiveSupport::TestCase
test "truth" do
assert_kind_of Module, <%= camelized %>
end
end

@ -0,0 +1,11 @@
require 'test_helper'
class NavigationTest < ActionDispatch::IntegrationTest
fixtures :all
# Replace this with your real tests.
test "the truth" do
assert true
end
end

@ -0,0 +1,17 @@
# Configure Rails Envinronment
ENV["RAILS_ENV"] = "test"
require File.expand_path("../dummy/config/environment.rb", __FILE__)
require "rails/test_help"
Rails.backtrace_cleaner.remove_silencers!
<% if full? && !options[:skip_active_record] -%>
# Run any available migration from application
ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
# and from engine
ActiveRecord::Migrator.migrate File.expand_path("../../db/migrate/", __FILE__)
<% end -%>
# Load support files
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }

@ -16,9 +16,9 @@ class ResourceGenerator < ModelGenerator #metagenerator
def add_resource_route
return if options[:actions].present?
route_config = class_path.collect{|namespace| "namespace :#{namespace} do " }.join(" ")
route_config = regular_class_path.collect{|namespace| "namespace :#{namespace} do " }.join(" ")
route_config << "resources :#{file_name.pluralize}"
route_config << " end" * class_path.size
route_config << " end" * regular_class_path.size
route route_config
end
end

@ -1,3 +1,4 @@
<% module_namespacing do -%>
class <%= controller_class_name %>Controller < ApplicationController
# GET <%= route_url %>
# GET <%= route_url %>.xml
@ -81,3 +82,4 @@ def destroy
end
end
end
<% end -%>

@ -34,7 +34,7 @@ def initialize(*args) #:nodoc:
attr_reader :controller_name
def controller_class_path
@class_path
class_path
end
def controller_file_name
@ -46,7 +46,7 @@ def controller_file_path
end
def controller_class_name
@controller_class_name ||= (controller_class_path + [controller_file_name]).map!{ |m| m.camelize }.join('::')
(controller_class_path + [controller_file_name]).map!{ |m| m.camelize }.join('::')
end
def controller_i18n_scope

@ -1,5 +1,6 @@
require 'test_helper'
<% module_namespacing do -%>
class <%= controller_class_name %>ControllerTest < ActionController::TestCase
setup do
@<%= singular_table_name %> = <%= table_name %>(:one)
@ -47,3 +48,4 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase
assert_redirected_to <%= index_helper %>_path
end
end
<% end -%>

@ -0,0 +1,7 @@
class AppBuilder
def gitignore
create_file ".gitignore", <<-R.strip
foobar
R
end
end

@ -0,0 +1,7 @@
class AppBuilder < Rails::AppBuilder
def gitignore
create_file ".gitignore", <<-R.strip
foobar
R
end
end

@ -0,0 +1 @@
create_dummy_app("spec/dummy")

@ -0,0 +1,2 @@
class PluginBuilder
end

@ -0,0 +1,7 @@
class PluginBuilder
def gitignore
create_file ".gitignore", <<-R.strip
foobar
R
end
end

@ -0,0 +1,19 @@
class PluginBuilder < Rails::PluginBuilder
def test
create_file "spec/spec_helper.rb"
append_file "Rakefile", <<-EOF
# spec tasks in rakefile
task :default => :spec
EOF
end
def generate_test_dummy
dummy_path("spec/dummy")
super
end
def skip_test_unit?
true
end
end

@ -0,0 +1,7 @@
class PluginBuilder < Rails::PluginBuilder
def gitignore
create_file ".gitignore", <<-R.strip
foobar
R
end
end

@ -1,7 +0,0 @@
class AppBuilder
def configru
create_file "config.ru", <<-R.strip
run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }
R
end
end

@ -1,7 +0,0 @@
class AppBuilder < Rails::AppBuilder
def configru
create_file "config.ru", <<-R.strip
run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }
R
end
end

@ -1,6 +1,7 @@
require 'abstract_unit'
require 'generators/generators_test_helper'
require 'rails/generators/rails/app/app_generator'
require 'generators/shared_generator_tests.rb'
DEFAULT_APP_FILES = %w(
.gitignore
@ -40,36 +41,10 @@
class AppGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
arguments [destination_root]
include SharedGeneratorTests
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')
Kernel::silence_warnings do
Thor::Base.shell.send(:attr_accessor, :always_force)
@shell = Thor::Base.shell.new
@shell.send(:always_force=, true)
end
end
def teardown
super
Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
Rails.application = TestApp::Application.instance
end
def test_application_skeleton_is_created
run_generator
DEFAULT_APP_FILES.each{ |path| assert_file path }
end
def test_application_generate_pretend
run_generator ["testapp", "--pretend"]
DEFAULT_APP_FILES.each{ |path| assert_no_file path }
def default_files
::DEFAULT_APP_FILES
end
def test_application_controller_and_layout_files
@ -78,36 +53,11 @@ def test_application_controller_and_layout_files
assert_no_file "public/stylesheets/application.css"
end
def test_options_before_application_name_raises_an_error
content = capture(:stderr){ run_generator(["--skip-active-record", destination_root]) }
assert_equal "Options should be given after the application name. For details run: rails --help\n", content
end
def test_name_collision_raises_an_error
reserved_words = %w[application destroy plugin runner test]
reserved_words.each do |reserved|
content = capture(:stderr){ run_generator [File.join(destination_root, reserved)] }
assert_equal "Invalid application name #{reserved}. Please give a name which does not match one of the reserved rails words.\n", content
end
end
def test_invalid_database_option_raises_an_error
content = capture(:stderr){ run_generator([destination_root, "-d", "unknown"]) }
assert_match /Invalid value for \-\-database option/, content
end
def test_invalid_application_name_raises_an_error
content = capture(:stderr){ run_generator [File.join(destination_root, "43-things")] }
assert_equal "Invalid application name 43-things. Please give a name which does not start with numbers.\n", content
end
def test_application_name_raises_an_error_if_name_already_used_constant
%w{ String Hash Class Module Set Symbol }.each do |ruby_class|
content = capture(:stderr){ run_generator [File.join(destination_root, ruby_class)] }
assert_equal "Invalid application name #{ruby_class}, constant #{ruby_class} is already in use. Please choose another application name.\n", content
end
end
def test_invalid_application_name_is_fixed
run_generator [File.join(destination_root, "things-43")]
assert_file "things-43/config/environment.rb", /Things43::Application\.initialize!/
@ -188,18 +138,6 @@ def test_prototype_and_test_unit_are_added_by_default
assert_file "test"
end
def test_test_unit_is_removed_from_frameworks_if_skip_test_unit_is_given
run_generator [destination_root, "--skip-test-unit"]
assert_file "config/application.rb" do |file|
assert_match /config.generators.test_framework = false/, file
end
end
def test_test_unit_is_skipped_if_required
run_generator [destination_root, "--skip-test-unit"]
assert_no_file "test"
end
def test_javascript_is_skipped_if_required
run_generator [destination_root, "--skip-javascript"]
assert_file "config/application.rb", /^\s+config\.action_view\.javascript_expansions\[:defaults\]\s+=\s+%w\(\)/
@ -224,36 +162,11 @@ def test_config_jquery_javascript_library
assert_file "public/javascripts/rails.js", /jQuery/
end
def test_shebang_is_added_to_rails_file
run_generator [destination_root, "--ruby", "foo/bar/baz"]
assert_file "script/rails", /#!foo\/bar\/baz/
end
def test_shebang_when_is_the_same_as_default_use_env
run_generator [destination_root, "--ruby", Thor::Util.ruby_command]
assert_file "script/rails", /#!\/usr\/bin\/env/
end
def test_template_from_dir_pwd
FileUtils.cd(Rails.root)
assert_match /It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"])
end
def test_template_raises_an_error_with_invalid_path
content = capture(:stderr){ run_generator([destination_root, "-m", "non/existant/path"]) }
assert_match /The template \[.*\] could not be loaded/, content
assert_match /non\/existant\/path/, content
end
def test_template_is_executed_when_supplied
path = "http://gist.github.com/103208.txt"
template = %{ say "It works!" }
template.instance_eval "def read; self; end" # Make the string respond to read
generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
assert_match /It works!/, silence(:stdout){ generator.invoke_all }
end
def test_usage_read_from_file
File.expects(:read).returns("USAGE FROM FILE")
assert_equal "USAGE FROM FILE", Rails::Generators::AppGenerator.desc
@ -273,19 +186,6 @@ def test_file_is_added_for_backwards_compatibility
assert_file 'lib/test_file.rb', 'heres test data'
end
def test_dev_option
generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install")
silence(:stdout){ generator.invoke_all }
rails_path = File.expand_path('../../..', Rails.root)
assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/
end
def test_edge_option
generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install")
silence(:stdout){ generator.invoke_all }
assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$/
end
protected
def action(*args, &block)
@ -299,61 +199,20 @@ class CustomAppGeneratorTest < Rails::Generators::TestCase
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
include SharedCustomGeneratorTests
protected
def default_files
::DEFAULT_APP_FILES
end
def builders_dir
"app_builders"
end
def builder_class
:AppBuilder
end
def action(*args, &block)
silence(:stdout){ generator.send(*args, &block) }

@ -3,6 +3,7 @@
require 'rails/generators/rails/model/model_generator'
require 'rails/generators/rails/observer/observer_generator'
require 'rails/generators/mailer/mailer_generator'
require 'rails/generators/rails/scaffold/scaffold_generator'
class NamespacedGeneratorTestCase < Rails::Generators::TestCase
def setup
@ -202,3 +203,155 @@ def test_invokes_default_template_engine_even_with_no_action
assert_file "app/views/test_app/notifier"
end
end
class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase
include GeneratorsTestHelper
arguments %w(product_line title:string price:integer)
tests Rails::Generators::ScaffoldGenerator
setup :copy_routes
def test_scaffold_on_invoke
run_generator
# Model
assert_file "app/models/test_app/product_line.rb", /module TestApp\n class ProductLine < ActiveRecord::Base/
assert_file "test/unit/test_app/product_line_test.rb", /module TestApp\n class ProductLineTest < ActiveSupport::TestCase/
assert_file "test/fixtures/test_app/product_lines.yml"
assert_migration "db/migrate/create_test_app_product_lines.rb"
# Route
assert_file "config/routes.rb" do |route|
assert_match(/resources :product_lines$/, route)
end
# Controller
assert_file "app/controllers/test_app/product_lines_controller.rb" do |content|
assert_match(/module TestApp\n class ProductLinesController < ApplicationController/, content)
end
assert_file "test/functional/test_app/product_lines_controller_test.rb",
/module TestApp\n class ProductLinesControllerTest < ActionController::TestCase/
# Views
%w(
index
edit
new
show
_form
).each { |view| assert_file "app/views/test_app/product_lines/#{view}.html.erb" }
assert_no_file "app/views/layouts/test_app/product_lines.html.erb"
# Helpers
assert_file "app/helpers/test_app/product_lines_helper.rb"
assert_file "test/unit/helpers/test_app/product_lines_helper_test.rb"
# Stylesheets
assert_file "public/stylesheets/scaffold.css"
end
def test_scaffold_on_revoke
run_generator
run_generator ["product_line"], :behavior => :revoke
# Model
assert_no_file "app/models/test_app/product_line.rb"
assert_no_file "test/unit/test_app/product_line_test.rb"
assert_no_file "test/fixtures/test_app/product_lines.yml"
assert_no_migration "db/migrate/create_test_app_product_lines.rb"
# Route
assert_file "config/routes.rb" do |route|
assert_no_match(/resources :product_lines$/, route)
end
# Controller
assert_no_file "app/controllers/test_app/product_lines_controller.rb"
assert_no_file "test/functional/test_app/product_lines_controller_test.rb"
# Views
assert_no_file "app/views/test_app/product_lines"
assert_no_file "app/views/test_app/layouts/product_lines.html.erb"
# Helpers
assert_no_file "app/helpers/test_app/product_lines_helper.rb"
assert_no_file "test/unit/helpers/test_app/product_lines_helper_test.rb"
# Stylesheets (should not be removed)
assert_file "public/stylesheets/scaffold.css"
end
def test_scaffold_with_namespace_on_invoke
run_generator [ "admin/role", "name:string", "description:string" ]
# Model
assert_file "app/models/test_app/admin.rb", /module TestApp\n module Admin/
assert_file "app/models/test_app/admin/role.rb", /module TestApp\n class Admin::Role < ActiveRecord::Base/
assert_file "test/unit/test_app/admin/role_test.rb", /module TestApp\n class Admin::RoleTest < ActiveSupport::TestCase/
assert_file "test/fixtures/test_app/admin/roles.yml"
assert_migration "db/migrate/create_test_app_admin_roles.rb"
# Route
assert_file "config/routes.rb" do |route|
assert_match(/namespace :admin do resources :roles end$/, route)
end
# Controller
assert_file "app/controllers/test_app/admin/roles_controller.rb" do |content|
assert_match(/module TestApp\n class Admin::RolesController < ApplicationController/, content)
end
assert_file "test/functional/test_app/admin/roles_controller_test.rb",
/module TestApp\n class Admin::RolesControllerTest < ActionController::TestCase/
# Views
%w(
index
edit
new
show
_form
).each { |view| assert_file "app/views/test_app/admin/roles/#{view}.html.erb" }
assert_no_file "app/views/layouts/admin/roles.html.erb"
# Helpers
assert_file "app/helpers/test_app/admin/roles_helper.rb"
assert_file "test/unit/helpers/test_app/admin/roles_helper_test.rb"
# Stylesheets
assert_file "public/stylesheets/scaffold.css"
end
def test_scaffold_with_namespace_on_revoke
run_generator [ "admin/role", "name:string", "description:string" ]
run_generator [ "admin/role" ], :behavior => :revoke
# Model
assert_file "app/models/test_app/admin.rb" # ( should not be remove )
assert_no_file "app/models/test_app/admin/role.rb"
assert_no_file "test/unit/test_app/admin/role_test.rb"
assert_no_file "test/fixtures/test_app/admin/roles.yml"
assert_no_migration "db/migrate/create_test_app_admin_roles.rb"
# Route
assert_file "config/routes.rb" do |route|
assert_no_match(/namespace :admin do resources :roles end$/, route)
end
# Controller
assert_no_file "app/controllers/test_app/admin/roles_controller.rb"
assert_no_file "test/functional/test_app/admin/roles_controller_test.rb"
# Views
assert_no_file "app/views/test_app/admin/roles"
assert_no_file "app/views/layouts/test_app/admin/roles.html.erb"
# Helpers
assert_no_file "app/helpers/test_app/admin/roles_helper.rb"
assert_no_file "test/unit/helpers/test_app/admin/roles_helper_test.rb"
# Stylesheets (should not be removed)
assert_file "public/stylesheets/scaffold.css"
end
end

@ -0,0 +1,192 @@
require 'abstract_unit'
require 'generators/generators_test_helper'
require 'rails/generators/rails/plugin_new/plugin_new_generator'
require 'generators/shared_generator_tests.rb'
DEFAULT_PLUGIN_FILES = %w(
.gitignore
Gemfile
Rakefile
bukkits.gemspec
MIT-LICENSE
lib
lib/bukkits.rb
lib/tasks/bukkits_tasks.rake
script/rails
test/bukkits_test.rb
test/test_helper.rb
test/dummy
)
class PluginNewGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
destination File.join(Rails.root, "tmp/bukkits")
arguments [destination_root]
include SharedGeneratorTests
def default_files
::DEFAULT_PLUGIN_FILES
end
def test_invalid_plugin_name_raises_an_error
content = capture(:stderr){ run_generator [File.join(destination_root, "43-things")] }
assert_equal "Invalid plugin name 43-things. Please give a name which does not start with numbers.\n", content
end
def test_invalid_plugin_name_is_fixed
run_generator [File.join(destination_root, "things-43")]
assert_file "things-43/lib/things-43.rb", /module Things43/
end
def test_generating_test_files
run_generator
assert_file "test/test_helper.rb"
assert_file "test/bukkits_test.rb", /assert_kind_of Module, Bukkits/
end
def test_generating_test_files_in_full_mode
run_generator [destination_root, "--full"]
assert_directory "test/integration/"
assert_file "test/integration/navigation_test.rb", /ActionDispatch::IntegrationTest/
end
def test_ensure_that_plugin_options_are_not_passed_to_app_generator
FileUtils.cd(Rails.root)
assert_no_match /It works from file!.*It works_from_file/, run_generator([destination_root, "-m", "lib/template.rb"])
end
def test_ensure_that_test_dummy_can_be_generated_from_a_template
FileUtils.cd(Rails.root)
run_generator([destination_root, "-m", "lib/create_test_dummy_template.rb", "--skip-test-unit"])
assert_file "spec/dummy"
assert_no_file "test"
end
def test_database_entry_is_assed_by_default_in_full_mode
run_generator([destination_root, "--full"])
assert_file "test/dummy/config/database.yml", /sqlite/
assert_file "Gemfile", /^gem\s+["']sqlite3-ruby["'],\s+:require\s+=>\s+["']sqlite3["']$/
end
def test_config_another_database
run_generator([destination_root, "-d", "mysql", "--full"])
assert_file "test/dummy/config/database.yml", /mysql/
assert_file "Gemfile", /^gem\s+["']mysql2["']$/
end
def test_active_record_is_removed_from_frameworks_if_skip_active_record_is_given
run_generator [destination_root, "--skip-active-record"]
assert_file "test/dummy/config/application.rb", /#\s+require\s+["']active_record\/railtie["']/
end
def test_ensure_that_skip_active_record_option_is_passed_to_app_generator
run_generator [destination_root, "--skip_active_record"]
assert_no_file "test/dummy/config/database.yml"
assert_no_match /ActiveRecord/, File.read(File.join(destination_root, "test/test_helper.rb"))
end
def test_ensure_that_database_option_is_passed_to_app_generator
run_generator [destination_root, "--database", "postgresql"]
assert_file "test/dummy/config/database.yml", /postgres/
end
def test_ensure_that_javascript_option_is_passed_to_app_generator
run_generator [destination_root, "--javascript", "jquery"]
assert_file "test/dummy/public/javascripts/jquery.js"
end
def test_ensure_that_skip_javascript_option_is_passed_to_app_generator
run_generator [destination_root, "--skip_javascript"]
assert_no_file "test/dummy/public/javascripts/prototype.js"
end
def test_template_from_dir_pwd
FileUtils.cd(Rails.root)
assert_match /It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"])
end
def test_ensure_that_tests_works
run_generator
FileUtils.cd destination_root
`bundle install`
assert_match /1 tests, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`
end
def test_ensure_that_tests_works_in_full_mode
run_generator [destination_root, "--full"]
FileUtils.cd destination_root
`bundle install`
assert_match /2 tests, 2 assertions, 0 failures, 0 errors/, `bundle exec rake test`
end
def test_creating_engine_in_full_mode
run_generator [destination_root, "--full"]
assert_file "lib/bukkits/engine.rb", /module Bukkits\n class Engine < Rails::Engine\n end\nend/
assert_file "lib/bukkits.rb", /require "bukkits\/engine"/
end
def test_being_quiet_while_creating_dummy_application
assert_no_match /create\s+config\/application.rb/, run_generator
end
def test_create_mountable_application_with_mountable_option
run_generator [destination_root, "--mountable"]
assert_file "config/routes.rb", /Bukkits::Engine.routes.draw do/
assert_file "lib/bukkits/engine.rb", /isolate_namespace Bukkits/
assert_file "test/dummy/config/routes.rb", /mount Bukkits::Engine => "\/bukkits"/
assert_file "app/controllers/bukkits/application_controller.rb", /module Bukkits\n class ApplicationController < ActiveController::Base/
assert_file "app/helpers/bukkits/application_helper.rb", /module Bukkits\n module ApplicationHelper/
end
def test_passing_dummy_path_as_a_parameter
run_generator [destination_root, "--dummy_path", "spec/dummy"]
assert_file "spec/dummy"
assert_file "spec/dummy/config/application.rb"
assert_no_file "test/dummy"
end
protected
def action(*args, &block)
silence(:stdout){ generator.send(*args, &block) }
end
end
class CustomPluginGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
tests Rails::Generators::PluginNewGenerator
destination File.join(Rails.root, "tmp/bukkits")
arguments [destination_root]
include SharedCustomGeneratorTests
def test_overriding_test_framework
FileUtils.cd(destination_root)
run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/spec_builder.rb"])
assert_file 'spec/spec_helper.rb'
assert_file 'spec/dummy'
assert_file 'Rakefile', /task :default => :spec/
assert_file 'Rakefile', /# spec tasks in rakefile/
assert_file 'script/rails', %r{spec/dummy}
end
protected
def default_files
::DEFAULT_PLUGIN_FILES
end
def builder_class
:PluginBuilder
end
def builders_dir
"plugin_builders"
end
def action(*args, &block)
silence(:stdout){ generator.send(*args, &block) }
end
end

@ -0,0 +1,187 @@
module SharedGeneratorTests
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')
Kernel::silence_warnings do
Thor::Base.shell.send(:attr_accessor, :always_force)
@shell = Thor::Base.shell.new
@shell.send(:always_force=, true)
end
end
def teardown
super
Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
Rails.application = TestApp::Application.instance
end
def test_skeleton_is_created
run_generator
default_files.each{ |path| assert_file path }
end
def test_plugin_new_generate_pretend
run_generator ["testapp", "--pretend"]
default_files.each{ |path| assert_no_file path }
end
def test_invalid_database_option_raises_an_error
content = capture(:stderr){ run_generator([destination_root, "-d", "unknown"]) }
assert_match /Invalid value for \-\-database option/, content
end
def test_test_unit_is_skipped_if_required
run_generator [destination_root, "--skip-test-unit"]
assert_no_file "test"
end
def test_options_before_application_name_raises_an_error
content = capture(:stderr){ run_generator(["--pretend", destination_root]) }
assert_match /Options should be given after the \w+ name. For details run: rails( plugin)? --help\n/, content
end
def test_name_collision_raises_an_error
reserved_words = %w[application destroy plugin runner test]
reserved_words.each do |reserved|
content = capture(:stderr){ run_generator [File.join(destination_root, reserved)] }
assert_match /Invalid \w+ name #{reserved}. Please give a name which does not match one of the reserved rails words.\n/, content
end
end
def test_name_raises_an_error_if_name_already_used_constant
%w{ String Hash Class Module Set Symbol }.each do |ruby_class|
content = capture(:stderr){ run_generator [File.join(destination_root, ruby_class)] }
assert_match /Invalid \w+ name #{ruby_class}, constant #{ruby_class} is already in use. Please choose another \w+ name.\n/, content
end
end
def test_shebang_is_added_to_rails_file
run_generator [destination_root, "--ruby", "foo/bar/baz"]
assert_file "script/rails", /#!foo\/bar\/baz/
end
def test_shebang_when_is_the_same_as_default_use_env
run_generator [destination_root, "--ruby", Thor::Util.ruby_command]
assert_file "script/rails", /#!\/usr\/bin\/env/
end
def test_template_raises_an_error_with_invalid_path
content = capture(:stderr){ run_generator([destination_root, "-m", "non/existant/path"]) }
assert_match /The template \[.*\] could not be loaded/, content
assert_match /non\/existant\/path/, content
end
def test_template_is_executed_when_supplied
path = "http://gist.github.com/103208.txt"
template = %{ say "It works!" }
template.instance_eval "def read; self; end" # Make the string respond to read
generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
assert_match /It works!/, silence(:stdout){ generator.invoke_all }
end
def test_dev_option
generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install")
silence(:stdout){ generator.invoke_all }
rails_path = File.expand_path('../../..', Rails.root)
assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/
end
def test_edge_option
generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install")
silence(:stdout){ generator.invoke_all }
assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$}
end
def test_template_raises_an_error_with_invalid_path
content = capture(:stderr){ run_generator([destination_root, "-m", "non/existant/path"]) }
assert_match /The template \[.*\] could not be loaded/, content
assert_match /non\/existant\/path/, content
end
def test_template_is_executed_when_supplied
path = "http://gist.github.com/103208.txt"
template = %{ say "It works!" }
template.instance_eval "def read; self; end" # Make the string respond to read
generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
assert_match /It works!/, silence(:stdout){ generator.invoke_all }
end
def test_dev_option
generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install")
silence(:stdout){ generator.invoke_all }
rails_path = File.expand_path('../../..', Rails.root)
assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/
end
def test_edge_option
generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install")
silence(:stdout){ generator.invoke_all }
assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$}
end
end
module SharedCustomGeneratorTests
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 do
remove_const :AppBuilder if const_defined?(:AppBuilder)
remove_const :PluginBuilder if const_defined?(:PluginBuilder)
end
Rails.application = TestApp::Application.instance
end
def test_builder_option_with_empty_app_builder
FileUtils.cd(destination_root)
run_generator([destination_root, "-b", "#{Rails.root}/lib/#{builders_dir}/empty_builder.rb"])
default_files.each{ |path| assert_no_file path }
end
def test_builder_option_with_simple_plugin_builder
FileUtils.cd(destination_root)
run_generator([destination_root, "-b", "#{Rails.root}/lib/#{builders_dir}/simple_builder.rb"])
(default_files - ['.gitignore']).each{ |path| assert_no_file path }
assert_file ".gitignore", "foobar"
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/#{builders_dir}/simple_builder.rb"])
FileUtils.cd(destination_root)
(default_files - ['.gitignore']).each{ |path| assert_no_file path }
assert_file ".gitignore", "foobar"
end
def test_builder_option_with_tweak_plugin_builder
FileUtils.cd(destination_root)
run_generator([destination_root, "-b", "#{Rails.root}/lib/#{builders_dir}/tweak_builder.rb"])
default_files.each{ |path| assert_file path }
assert_file ".gitignore", "foobar"
end
def test_builder_option_with_http
path = "http://gist.github.com/103208.txt"
template = "class #{builder_class}; 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_files.each{ |path| assert_no_file path }
end
end

@ -685,5 +685,25 @@ class Engine < ::Rails::Engine
assert_equal :haml , generators[:template_engine]
assert_equal :rspec , generators[:test_framework]
end
test "engine should get default generators with ability to overwrite them" do
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
class Engine < ::Rails::Engine
config.generators.test_framework :rspec
end
end
RUBY
boot_rails
require "#{rails_root}/config/environment"
generators = Bukkits::Engine.config.generators.options[:rails]
assert_equal :active_record, generators[:orm]
assert_equal :rspec , generators[:test_framework]
app_generators = Rails.application.config.generators.options[:rails]
assert_equal :test_unit , app_generators[:test_framework]
end
end
end