Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

`rails plugin new` generator #94

Closed
wants to merge 36 commits into from

5 participants

@drogus
Collaborator

I've prepared a generator for rails plugins, which generates basic structure for rails extension:

  • lib dir with
  • tests with dummy application at test/dummy (the easiest way to test rails extension is to run tests with real rails app)
  • gemspec

It's very similar to http://github.com/josevalim/enginex, but ported to rails with support for PluginBuilder (like AppBuilder) and templates (eg. rails plugin new foo -m some_template.rb).

There is also --full option which will generate integration tests, which is handy when you want to make a rails engine. To create mountable engine you can pass --mountable option, which will additionally create routes file and engine definition and automatically mount engine in dummy application.

drogus added some commits
@drogus drogus Added 'rails plugin new' generator which generates gem plugin skeleton.
This command is based on enginex gem by José Valim. It generates gem structure
and ads dummy application into test/dummy. This can be used to start developing
any kind of extension for rails 3.
cfcea1d
@drogus drogus Refactored AppGenerator and PluginNewGenerator to inherit from AppBase. b37938e
@drogus drogus Ensure that options for plugin new generator are not passed to applic…
…ation generator
b8a0fab
@drogus drogus Add support for templates for rails plugin new bcd414f
@drogus drogus That method is already declared at AppBase bbf02ff
@drogus drogus Added USAGE for rails plugin new 5c8b48a
@drogus drogus Add --dev and --edge options to rails plugin new e51e9e2
@drogus drogus Change // style regexp to %r{}, to not confuse editors code highlighting 59d5222
@drogus drogus Allow easy overriding of test framework in 'rake plugin new' generato…
…r, using PluginBuilder
b36fa51
@drogus drogus Ensure that tests run properly fd1562a
@drogus drogus Make tests for app and plugin generators more DRY ae1debd
@drogus drogus Builder should not be responsible for running store_application_defin…
…ition method
48fef64
@drogus drogus We don't need gem tasks, we have a gemspec ac8f927
@drogus drogus Remove integration tests and ActionModel/ActiveRecord calls from 'rak…
…e plugin new' generator, it shouldn't be available as default option
68295bc
@drogus drogus DRY up app generator and plugin new generator. Moved shared options t…
…o AppBase generator
d995953
@drogus drogus No need for say_step in 'plugin new' generator fdbd9df
@drogus drogus Add --full option to 'plugin new' generator, which generates rails en…
…gine
671d146
@drogus drogus Pass more options to test/dummy in 'plugin new' generator 46fdb31
@drogus drogus No need to require 'app_base', it's required in app_generator 013fc0a
@drogus drogus Don't be verbose while creating dummy application in plugin new gener…
…ator
489b279
@drogus drogus Do not create additional newline 9e86767
@drogus drogus Use application's generators defaults as engine defaults to not force…
… users to manually set it
cfbe595
@drogus drogus Added Hash#deep_dup function which performs deep duplication on given…
… hash
5071b72
@drogus drogus Make deep copy of application generators on engine initialization.
Otherwise nested hashes will be same objects for both application and engine,
which will result in overwriting each others values on changes.
a5311ee
@drogus drogus Refactor app and plugin generators to use new Thor API 9cb9713
@drogus drogus We don't need to configure ActionMailer in plugin's test helper, it's…
… configured by dummy app
4d108cb
@drogus drogus Use rails integration tests by default in 'plugin new' generator 57fae9b
@drogus drogus Skip active record properly in 'plugin new' generator b6497d3
@drogus drogus Properly handle other databases in 'plugin new' generator 2133495
@drogus drogus Properly skip test unit in 'plugin new' generator fadad11
@drogus drogus create_dummy_app method that allows to easily create dummy applicatio…
…n from template
f9e33fc
@drogus drogus Add example rake task to 'plugin new' generator c159b50
@drogus drogus Add --mountable option to 'plugin new' generator which generates full…
… mountable application (engine)
cbe391b
@drogus drogus Fix scaffold generator to be aware of namespace in isolated engine d0d30e7
@drogus drogus New version of thor was released no need to use the one from git 1fd4624
@drogus drogus Allow to set dummy application path through options cc135e3
@rafaelfranca

Then the original backtrace filter (or some equivalent) should be installed. There's no good reason to provide the full backtrace for the minitest runner.

https://github.com/rails/rails/blob/master/railties/lib/rails/test_help.rb#L15
https://github.com/seattlerb/minitest/blob/master/lib/minitest.rb#L750-L764

I suppose it would be better if we re-implement those rules with the AS backtrace cleaner rather than relying on the :nodoc:'ed one in minitest? (We already required it anyway..) @rafaelfranca, @zenspider?

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 2, 2010
  1. @drogus

    Added 'rails plugin new' generator which generates gem plugin skeleton.

    drogus authored
    This command is based on enginex gem by José Valim. It generates gem structure
    and ads dummy application into test/dummy. This can be used to start developing
    any kind of extension for rails 3.
  2. @drogus
  3. @drogus
  4. @drogus
  5. @drogus
  6. @drogus
  7. @drogus
  8. @drogus
  9. @drogus
  10. @drogus

    Ensure that tests run properly

    drogus authored
  11. @drogus
  12. @drogus
  13. @drogus
  14. @drogus

    Remove integration tests and ActionModel/ActiveRecord calls from 'rak…

    drogus authored
    …e plugin new' generator, it shouldn't be available as default option
  15. @drogus
  16. @drogus
  17. @drogus
  18. @drogus
  19. @drogus
  20. @drogus
  21. @drogus
  22. @drogus

    Use application's generators defaults as engine defaults to not force…

    drogus authored
    … users to manually set it
  23. @drogus
  24. @drogus

    Make deep copy of application generators on engine initialization.

    drogus authored
    Otherwise nested hashes will be same objects for both application and engine,
    which will result in overwriting each others values on changes.
  25. @drogus
  26. @drogus
  27. @drogus
  28. @drogus
  29. @drogus
  30. @drogus
  31. @drogus
  32. @drogus
  33. @drogus

    Add --mountable option to 'plugin new' generator which generates full…

    drogus authored
    … mountable application (engine)
Commits on Nov 3, 2010
  1. @drogus
Commits on Nov 4, 2010
  1. @drogus
Commits on Nov 8, 2010
  1. @drogus
This page is out of date. Refresh to see the latest.
Showing with 1,307 additions and 313 deletions.
  1. +1 −1  activerecord/lib/active_record/railtie.rb
  2. +1 −0  activesupport/lib/active_support/core_ext/hash.rb
  3. +11 −0 activesupport/lib/active_support/core_ext/hash/deep_dup.rb
  4. +15 −0 activesupport/test/core_ext/hash_ext_test.rb
  5. +6 −1 railties/lib/rails/cli.rb
  6. +16 −0 railties/lib/rails/commands/plugin_new.rb
  7. +8 −0 railties/lib/rails/configuration.rb
  8. +1 −0  railties/lib/rails/engine/configuration.rb
  9. +176 −0 railties/lib/rails/generators/app_base.rb
  10. +2 −0  railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb
  11. +2 −0  railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb
  12. +2 −0  railties/lib/rails/generators/erb/scaffold/templates/index.html.erb
  13. +2 −0  railties/lib/rails/generators/erb/scaffold/templates/new.html.erb
  14. +2 −0  railties/lib/rails/generators/erb/scaffold/templates/show.html.erb
  15. +7 −1 railties/lib/rails/generators/named_base.rb
  16. +10 −127 railties/lib/rails/generators/rails/app/app_generator.rb
  17. +2 −19 railties/lib/rails/generators/rails/app/templates/Gemfile
  18. +10 −0 railties/lib/rails/generators/rails/plugin_new/USAGE
  19. +246 −0 railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb
  20. +9 −0 railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec
  21. +11 −0 railties/lib/rails/generators/rails/plugin_new/templates/Gemfile
  22. +20 −0 railties/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE
  23. +3 −0  railties/lib/rails/generators/rails/plugin_new/templates/README.rdoc
  24. +18 −0 railties/lib/rails/generators/rails/plugin_new/templates/Rakefile
  25. +4 −0 railties/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt
  26. +4 −0 railties/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt
  27. +3 −0  railties/lib/rails/generators/rails/plugin_new/templates/config/routes.rb
  28. +6 −0 railties/lib/rails/generators/rails/plugin_new/templates/gitignore
  29. +6 −0 railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb
  30. +7 −0 railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb
  31. +4 −0 railties/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake
  32. +16 −0 railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb
  33. +10 −0 railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb
  34. +4 −0 railties/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb
  35. +5 −0 railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt
  36. +7 −0 railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb
  37. +11 −0 railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb
  38. +17 −0 railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb
  39. +2 −2 railties/lib/rails/generators/rails/resource/resource_generator.rb
  40. +2 −0  railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
  41. +2 −2 railties/lib/rails/generators/resource_helpers.rb
  42. +2 −0  railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
  43. 0  railties/test/fixtures/lib/{ → app_builders}/empty_builder.rb
  44. +7 −0 railties/test/fixtures/lib/app_builders/simple_builder.rb
  45. +7 −0 railties/test/fixtures/lib/app_builders/tweak_builder.rb
  46. +1 −0  railties/test/fixtures/lib/create_test_dummy_template.rb
  47. +2 −0  railties/test/fixtures/lib/plugin_builders/empty_builder.rb
  48. +7 −0 railties/test/fixtures/lib/plugin_builders/simple_builder.rb
  49. +19 −0 railties/test/fixtures/lib/plugin_builders/spec_builder.rb
  50. +7 −0 railties/test/fixtures/lib/plugin_builders/tweak_builder.rb
  51. +0 −7 railties/test/fixtures/lib/simple_builder.rb
  52. +0 −7 railties/test/fixtures/lib/tweak_builder.rb
  53. +12 −146 railties/test/generators/app_generator_test.rb
  54. +153 −0 railties/test/generators/namespaced_generators_test.rb
  55. +192 −0 railties/test/generators/plugin_new_generator_test.rb
  56. +187 −0 railties/test/generators/shared_generator_tests.rb
  57. +20 −0 railties/test/railties/engine_test.rb
View
2  activerecord/lib/active_record/railtie.rb
@@ -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"
View
1  activesupport/lib/active_support/core_ext/hash.rb
@@ -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'
View
11 activesupport/lib/active_support/core_ext/hash/deep_dup.rb
@@ -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
View
15 activesupport/test/core_ext/hash_ext_test.rb
@@ -316,6 +316,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)
View
7 railties/lib/rails/cli.rb
@@ -11,4 +11,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
View
16 railties/lib/rails/commands/plugin_new.rb
@@ -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
View
8 railties/lib/rails/configuration.rb
@@ -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
View
1  railties/lib/rails/engine/configuration.rb
@@ -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.
View
176 railties/lib/rails/generators/app_base.rb
@@ -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
View
2  railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb
@@ -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 -%>
View
2  railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb
@@ -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 -%>
View
2  railties/lib/rails/generators/erb/scaffold/templates/index.html.erb
@@ -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 -%>
View
2  railties/lib/rails/generators/erb/scaffold/templates/new.html.erb
@@ -1,5 +1,7 @@
+<% without_namespacing do -%>
<h1>New <%= singular_table_name %></h1>
<%%= render 'form' %>
<%%= link_to 'Back', <%= index_helper %>_path %>
+<% end -%>
View
2  railties/lib/rails/generators/erb/scaffold/templates/show.html.erb
@@ -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 -%>
View
8 railties/lib/rails/generators/named_base.rb
@@ -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)
View
137 railties/lib/rails/generators/rails/app/app_generator.rb
@@ -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
View
21 railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -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'
View
10 railties/lib/rails/generators/rails/plugin_new/USAGE
@@ -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.
View
246 railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb
@@ -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
View
9 railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec
@@ -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
View
11 railties/lib/rails/generators/rails/plugin_new/templates/Gemfile
@@ -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
View
20 railties/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE
@@ -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.
View
3  railties/lib/rails/generators/rails/plugin_new/templates/README.rdoc
@@ -0,0 +1,3 @@
+= <%= camelized %>
+
+This project rocks and uses MIT-LICENSE.
View
18 railties/lib/rails/generators/rails/plugin_new/templates/Rakefile
@@ -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
View
4 ...ties/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt
@@ -0,0 +1,4 @@
+module <%= camelized %>
+ class ApplicationController < ActiveController::Base
+ end
+end
View
4 railties/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt
@@ -0,0 +1,4 @@
+module <%= camelized %>
+ module ApplicationHelper
+ end
+end
View
3  railties/lib/rails/generators/rails/plugin_new/templates/config/routes.rb
@@ -0,0 +1,3 @@
+<%= camelized %>::Engine.routes.draw do
+
+end
View
6 railties/lib/rails/generators/rails/plugin_new/templates/gitignore
@@ -0,0 +1,6 @@
+.bundle/
+log/*.log
+pkg/
+test/dummy/db/*.sqlite3
+test/dummy/log/*.log
+test/dummy/tmp/
View
6 railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb
@@ -0,0 +1,6 @@
+<% if full? -%>
+require "<%= name %>/engine"
+
+<% end -%>
+module <%= camelized %>
+end
View
7 railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb
@@ -0,0 +1,7 @@
+module <%= camelized %>
+ class Engine < Rails::Engine
+<% if mountable? -%>
+ isolate_namespace <%= camelized %>
+<% end -%>
+ end
+end
View
4 railties/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake
@@ -0,0 +1,4 @@
+# desc "Explaining what the task does"
+# task :<%= name %> do
+# # Task goes here
+# end
View
16 railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb
@@ -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 %>
View
10 railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb
@@ -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__)
View
4 railties/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb
@@ -0,0 +1,4 @@
+Rails.application.routes.draw do
+
+ mount <%= camelized %>::Engine => "/<%= name %>"
+end
View
5 railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt
@@ -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__)
View
7 railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class <%= camelized %>Test < ActiveSupport::TestCase
+ test "truth" do
+ assert_kind_of Module, <%= camelized %>
+ end
+end
View
11 railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb
@@ -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
+
View
17 railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb
@@ -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 }
View
4 railties/lib/rails/generators/rails/resource/resource_generator.rb
@@ -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
View
2  railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
@@ -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 -%>
View
4 railties/lib/rails/generators/resource_helpers.rb
@@ -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
View
2  railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
@@ -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 -%>
View
0  railties/test/fixtures/lib/empty_builder.rb → ...s/test/fixtures/lib/app_builders/empty_builder.rb
File renamed without changes
View
7 railties/test/fixtures/lib/app_builders/simple_builder.rb
@@ -0,0 +1,7 @@
+class AppBuilder
+ def gitignore
+ create_file ".gitignore", <<-R.strip
+foobar
+ R
+ end
+end
View
7 railties/test/fixtures/lib/app_builders/tweak_builder.rb
@@ -0,0 +1,7 @@
+class AppBuilder < Rails::AppBuilder
+ def gitignore
+ create_file ".gitignore", <<-R.strip
+foobar
+ R
+ end
+end
View
1  railties/test/fixtures/lib/create_test_dummy_template.rb
@@ -0,0 +1 @@
+create_dummy_app("spec/dummy")
View
2  railties/test/fixtures/lib/plugin_builders/empty_builder.rb
@@ -0,0 +1,2 @@
+class PluginBuilder
+end
View
7 railties/test/fixtures/lib/plugin_builders/simple_builder.rb
@@ -0,0 +1,7 @@
+class PluginBuilder
+ def gitignore
+ create_file ".gitignore", <<-R.strip
+foobar
+ R
+ end
+end
View
19 railties/test/fixtures/lib/plugin_builders/spec_builder.rb
@@ -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
View
7 railties/test/fixtures/lib/plugin_builders/tweak_builder.rb
@@ -0,0 +1,7 @@
+class PluginBuilder < Rails::PluginBuilder
+ def gitignore
+ create_file ".gitignore", <<-R.strip
+foobar
+ R
+ end
+end
View
7 railties/test/fixtures/lib/simple_builder.rb
@@ -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
View
7 railties/test/fixtures/lib/tweak_builder.rb
@@ -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
View
158 railties/test/generators/app_generator_test.rb
@@ -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,11 +138,6 @@ def test_prototype_and_test_unit_are_added_by_default
assert_file "test"
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\(\)/
@@ -217,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
@@ -266,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)
@@ -292,62 +199,21 @@ class CustomAppGeneratorTest < Rails::Generators::TestCase
tests Rails::Generators::AppGenerator
arguments [destination_root]
+ include 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 { 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"]] }]
+protected
+ def default_files
+ ::DEFAULT_APP_FILES
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"]] }]
+ def builders_dir
+ "app_builders"
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 }
+ def builder_class
+ :AppBuilder
end
-protected
-
def action(*args, &block)
silence(:stdout){ generator.send(*args, &block) }
end
View
153 railties/test/generators/namespaced_generators_test.rb
@@ -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
View
192 railties/test/generators/plugin_new_generator_test.rb
@@ -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
View
187 railties/test/generators/shared_generator_tests.rb
@@ -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