Permalink
Browse files

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.
  • Loading branch information...
1 parent d446392 commit cfcea1d53ae5ce38a7cbeb41e05958dc009988b0 @drogus drogus committed Oct 15, 2010
Showing with 607 additions and 1 deletion.
  1. +6 −1 railties/lib/rails/cli.rb
  2. +16 −0 railties/lib/rails/commands/plugin_new.rb
  3. +225 −0 railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb
  4. +9 −0 railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec
  5. +11 −0 railties/lib/rails/generators/rails/plugin_new/templates/Gemfile
  6. +20 −0 railties/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE
  7. +3 −0 railties/lib/rails/generators/rails/plugin_new/templates/README.rdoc
  8. +46 −0 railties/lib/rails/generators/rails/plugin_new/templates/Rakefile
  9. +6 −0 railties/lib/rails/generators/rails/plugin_new/templates/gitignore
  10. +2 −0 railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb.tt
  11. +12 −0 railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb
  12. +10 −0 railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb
  13. +5 −0 railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt
  14. +7 −0 railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb.tt
  15. +7 −0 railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb.tt
  16. +5 −0 railties/lib/rails/generators/rails/plugin_new/templates/test/support/integration_case.rb
  17. +22 −0 railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb
  18. +2 −0 railties/test/fixtures/lib/plugin_builders/empty_builder.rb
  19. +7 −0 railties/test/fixtures/lib/plugin_builders/simple_builder.rb
  20. +7 −0 railties/test/fixtures/lib/plugin_builders/tweak_builder.rb
  21. +179 −0 railties/test/generators/plugin_new_generator_test.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
@@ -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
@@ -0,0 +1,225 @@
+require "rails/generators/rails/app/app_generator"
+
+module Rails
+ class PluginBuilder
+ def rakefile
+ template "Rakefile"
+ 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
+ directory "lib"
+ end
+
+ def test
+ directory "test"
+ end
+
+ def test_dummy
+ invoke Rails::Generators::AppGenerator,
+ [ File.expand_path(dummy_path, destination_root) ]
+ end
+
+ def test_dummy_config
+ store_application_definition!
+ template "rails/boot.rb", "#{dummy_path}/config/boot.rb", :force => true
+ template "rails/application.rb", "#{dummy_path}/config/application.rb", :force => true
+ 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
+ directory "script" do |content|
+ "#{shebang}\n" + content
+ end
+ chmod "script", 0755, :verbose => false
+ end
+ end
+
+ module Generators
+ class PluginNewGenerator < Base
+ attr_accessor :rails_template
+
+ add_shebang_option!
+
+ argument :plugin_path, :type => :string
+
+ class_option :builder, :type => :string, :aliases => "-b",
+ :desc => "Path to a plugin builder (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 :help, :type => :boolean, :aliases => "-h", :group => :rails,
+ :desc => "Show this help message and quit"
+
+ def self.say_step(message)
+ @step = (@step || 0) + 1
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
+ def step_#{@step}
+ #{"puts" if @step > 1}
+ say_status "STEP #{@step}", #{message.inspect}
+ end
+ METHOD
+ end
+
+ def initialize(*args)
+ raise Error, "Options should be given after plugin name. For details run: rails plugin --help" if args[0].blank?
+
+ @original_wd = Dir.pwd
+
+ super
+ end
+
+ say_step "Creating gem skeleton"
+
+ def create_root
+ self.destination_root = File.expand_path(plugin_path, destination_root)
+ valid_plugin_const?
+
+ empty_directory '.'
+ FileUtils.cd(destination_root) unless options[:pretend]
+ end
+
+ 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_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
+
+ say_step "Vendoring Rails application at test/dummy"
+
+ def create_test_dummy_files
+ build(:test_dummy)
+ end
+
+ say_step "Configuring Rails application"
+
+ def change_config_files
+ build(:test_dummy_config)
+ end
+
+ say_step "Removing unneeded files"
+
+ def remove_uneeded_rails_files
+ build(:test_dummy_clean)
+ end
+
+ protected
+
+ def self.banner
+ "rails plugin 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?(::PluginBuilder) ? ::PluginBuilder : Rails::PluginBuilder
+ 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 name
+ @name ||= File.basename(destination_root)
+ end
+
+ def camelized
+ @camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize
+ end
+
+ def valid_plugin_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 dummy_path
+ "test/dummy"
+ end
+
+ def application_definition
+ @application_definition ||= begin
+ unless options[:pretend]
+ contents = File.read(File.expand_path("#{dummy_path}/config/application.rb", destination_root))
+ contents[(contents.index("module Dummy"))..-1]
+ end
+ end
+ end
+ alias :store_application_definition! :application_definition
+ 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"
+
+gem "rails", :git => "http://github.com/rails/rails.git"
+gem "arel" , :git => "http://github.com/rails/arel.git"
+gem "rack" , :git => "http://github.com/rack/rack.git"
+gem "capybara", ">= 0.3.9"
+gem "sqlite3-ruby", :require => "sqlite3"
+
+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,46 @@
+# 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'
+require 'rake/gempackagetask'
+
+require 'rake/testtask'
+
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.libs << 'test'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = false
+end
+
+task :default => :test
+
+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
+
+spec = Gem::Specification.new do |s|
+ s.name = "<%= name %>"
+ s.summary = "Insert <%= camelized %> summary."
+ s.description = "Insert <%= camelized %> description."
+ s.files = FileList["[A-Z]*", "lib/**/*"]
+ s.version = "0.0.1"
+end
+
+Rake::GemPackageTask.new(spec) do |pkg|
+end
+
+desc "Install the gem #{spec.name}-#{spec.version}.gem"
+task :install do
+ system("gem install pkg/#{spec.name}-#{spec.version}.gem --no-ri --no-rdoc")
+end
@@ -0,0 +1,6 @@
+.bundle/
+log/*.log
+pkg/
+test/dummy/db/*.sqlite3
+test/dummy/log/*.log
+test/dummy/tmp/
@@ -0,0 +1,2 @@
+module <%= camelized %>
+end
@@ -0,0 +1,12 @@
+require File.expand_path('../boot', __FILE__)
+
+require "active_model/railtie"
+require "active_record/railtie"
+require "action_controller/railtie"
+require "action_view/railtie"
+require "action_mailer/railtie"
+
+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,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('../../test/dummy/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
Oops, something went wrong.

0 comments on commit cfcea1d

Please sign in to comment.