Skip to content
Browse files

features to verify spec'ing generators in a rails app OR a gem

* Generators in Rails apps have a rails application
* Generators in Gems do not so we create a "TestApp"
  • Loading branch information...
1 parent dfaab15 commit 096d562a858801970b5f2b6d4c3f50ca63c039d6 @alexrothenberg committed Jun 29, 2012
View
54 Rakefile
@@ -18,31 +18,63 @@ end
Cucumber::Rake::Task.new(:cucumber)
-# for cucumber features that create a sample project
-def in_example_app(command)
- Dir.chdir("./tmp/example_app/") do
- Bundler.clean_system command
+task :ensure_bundler_11 do
+ raise 'Bundler 1.1 is a development dependency to build ammeter. Please upgrade bundler.' unless Bundler::VERSION >= '1.1'
+end
+
+
+def create_gem(gem_name)
+ template_folder = "features/templates/#{gem_name}"
+
+ Dir.chdir("./tmp") do
+ sh "bundle gem #{gem_name}"
+ end
+ sh "cp '#{template_folder}/Gemfile' tmp/#{gem_name}"
+ sh "cp '#{template_folder}/#{gem_name}.gemspec' tmp/#{gem_name}"
+ sh "cp '#{template_folder}/Rakefile' tmp/#{gem_name}"
+ sh "mkdir tmp/#{gem_name}/spec"
+ sh "cp '#{template_folder}/spec/spec_helper.rb' tmp/#{gem_name}/spec"
+ Dir.chdir("./tmp/#{gem_name}") do
+ Bundler.clean_system 'bundle install'
end
end
+
namespace :generate do
desc "generate a fresh app with rspec installed"
- task :app do |t|
- raise 'Bundler 1.1 is a development dependency to build ammeter. Please upgrade bundler.' unless Bundler::VERSION >= '1.1'
-
+ task :app => :ensure_bundler_11 do |t|
sh "bundle exec rails new ./tmp/example_app -m 'features/templates/generate_example_app.rb' --skip-test-unit"
sh "cp 'features/templates/rspec.rake' ./tmp/example_app/lib/tasks"
- in_example_app 'rake db:migrate'
- in_example_app 'rails g rspec:install'
- in_example_app 'bundle install'
+ Dir.chdir("./tmp/example_app/") do
+ Bundler.clean_system 'rake db:migrate'
+ Bundler.clean_system 'rails g rspec:install'
+ Bundler.clean_system 'bundle install'
+ end
+ end
+
+ desc "generate a fresh gem that depends on railties"
+ task :railties_gem => :ensure_bundler_11 do |t|
+ create_gem('my_railties_gem')
+ end
+
+ desc "generate a fresh gem that depends on rails"
+ task :rails_gem => :ensure_bundler_11 do |t|
+ create_gem('my_rails_gem')
end
end
+task :generate => [:'generate:app', :'generate:railties_gem', :'generate:rails_gem']
+
namespace :clobber do
desc "clobber the generated app"
task :app do
rm_rf "tmp/example_app"
end
+ task :gem do
+ rm_rf "tmp/my_railties_gem"
+ rm_rf "tmp/my_rails_gem"
+ end
end
+task :clobber => [:'clobber:app', :'clobber:gem']
-task :ci => [:spec, :'clobber:app', :'generate:app', :cucumber]
+task :ci => [:spec, :clobber, :generate, :cucumber]
task :default => :ci
View
82 features/generator_in_a_gem.feature
@@ -0,0 +1,82 @@
+Feature: Gems can contain generators
+
+ Within a Gem Rails may often not be loaded (but railties is)
+ We should still be able to write a spec for these generators
+
+ @railties_gem
+ Scenario: A generator with "railties" dependency
+ Given a file named "lib/generators/awesome/awesome_generator.rb" with:
+ """
+ class AwesomeGenerator < Rails::Generators::NamedBase
+ source_root File.expand_path('../templates', __FILE__)
+ class_option :super, :type => :boolean, :default => false
+
+ def create_awesomeness
+ template 'awesome.html', File.join('public', name, "#{"super_" if options[:super]}awesome.html")
+ end
+ end
+ """
+ And a file named "lib/generators/awesome/templates/awesome.html" with:
+ """
+ This is an awesome file
+ """
+ And a file named "spec/generators/awesome_generator_spec.rb" with:
+ """
+ require "spec_helper"
+ require 'generators/awesome/awesome_generator'
+
+ describe AwesomeGenerator do
+ before { run_generator %w(my_dir) }
+ describe 'public/my_dir/awesome.html' do
+ subject { file('public/my_dir/awesome.html') }
+ it { should exist }
+ it { should contain 'This is an awesome file' }
+ it { should_not contain 'This text is not in the file' }
+ end
+ end
+ """
+ When I run `rake spec --trace`
+ Then the output should contain "3 examples, 0 failures"
+
+ @rails_gem
+ Scenario: A generator that uses "hook_for"
+ Given a file named "lib/generators/resourceful/resourceful_generator.rb" with:
+ """
+ class ResourcefulGenerator < Rails::Generators::NamedBase
+ source_root File.expand_path('../templates', __FILE__)
+ class_option :super, :type => :boolean, :default => false
+
+ hook_for :orm, :in => :rails, :as => :model, :required => true
+
+ def create_resourceful_controller
+ template 'controller.rb', File.join('app/controllers', "#{plural_file_name}_controller.rb")
+ end
+ end
+ """
+ And a file named "lib/generators/resourceful/templates/controller.rb" with:
+ """
+ class <%= class_name.pluralize %>Controller < ResourcefulController
+ end
+ """
+ And a file named "spec/generators/resourceful_generator_spec.rb" with:
+ """
+ require "spec_helper"
+ require 'generators/resourceful/resourceful_generator'
+
+ describe ResourcefulGenerator do
+ before { run_generator %w(post) }
+ describe 'app/controller/posts_controller.rb' do
+ subject { file('app/controllers/posts_controller.rb') }
+ it { should exist }
+ it { should contain 'class PostsController < ResourcefulController' }
+ end
+
+ describe 'app/models/post.rb' do
+ subject { file('app/models/post.rb') }
+ it { should exist }
+ it { should contain 'class Post < ActiveRecord::Base' }
+ end
+ end
+ """
+ When I run `rake spec`
+ Then the output should contain "4 examples, 0 failures"
View
1 features/generator_spec.feature
@@ -1,3 +1,4 @@
+@example_app
Feature: generator spec
Generator specs live in spec/generators. In order to access
View
1 features/hooking_into_other_generators.feature
@@ -1,3 +1,4 @@
+@example_app
Feature: generator spec
Generator specs live in spec/generators. In order to access
View
31 features/support/env.rb
@@ -4,32 +4,41 @@
@aruba_timeout_seconds = 10
end
-def aruba_path(file_or_dir)
- File.expand_path("../../../#{file_or_dir.sub('example_app','aruba')}", __FILE__)
+def aruba_path(file_or_dir, source_foldername)
+ File.expand_path("../../../#{file_or_dir.sub(source_foldername,'aruba')}", __FILE__)
end
def example_app_path(file_or_dir)
File.expand_path("../../../#{file_or_dir}", __FILE__)
end
-def write_symlink(file_or_dir)
+def write_symlink(file_or_dir, source_foldername)
source = example_app_path(file_or_dir)
- target = aruba_path(file_or_dir)
+ target = aruba_path(file_or_dir, source_foldername)
system "ln -s #{source} #{target}"
end
-Before do
+def copy_to_aruba_from(gem_or_app_name)
steps %Q{
Given a directory named "spec"
}
- Dir['tmp/example_app/*'].each do |file_or_dir|
- if !(file_or_dir =~ /spec$/)
- write_symlink(file_or_dir)
+ Dir["tmp/#{gem_or_app_name}/*"].each do |file_or_dir|
+ if !(file_or_dir =~ /\/spec$/)
+ write_symlink(file_or_dir, gem_or_app_name)
end
end
+ write_symlink("tmp/#{gem_or_app_name}/spec/spec_helper.rb", gem_or_app_name)
+end
- ["spec/spec_helper.rb"].each do |file_or_dir|
- write_symlink("tmp/example_app/#{file_or_dir}")
- end
+Before '@example_app' do
+ copy_to_aruba_from('example_app')
+end
+
+Before '@railties_gem' do
+ copy_to_aruba_from('my_railties_gem')
+end
+
+Before '@rails_gem' do
+ copy_to_aruba_from('my_rails_gem')
end
View
9 features/templates/my_rails_gem/Rakefile
@@ -0,0 +1,9 @@
+#!/usr/bin/env rake
+require "bundler/gem_tasks"
+
+require 'rspec'
+require 'rspec/core/rake_task'
+desc "Run all examples"
+RSpec::Core::RakeTask.new(:spec) do |t|
+ t.rspec_opts = %w[--color]
+end
View
20 features/templates/my_rails_gem/my_rails_gem.gemspec
@@ -0,0 +1,20 @@
+# -*- encoding: utf-8 -*-
+require File.expand_path('../lib/my_rails_gem/version', __FILE__)
+
+Gem::Specification.new do |gem|
+ gem.authors = ["Alex Rothenberg"]
+ gem.email = ["alex@alexrothenberg.com"]
+ gem.description = %q{TODO: Write a gem description}
+ gem.summary = %q{TODO: Write a gem summary}
+ gem.homepage = ""
+
+ gem.files = `git ls-files`.split($\)
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
+ gem.name = "my_gem"
+ gem.require_paths = ["lib"]
+ gem.version = MyRailsGem::VERSION
+
+ gem.add_runtime_dependency 'rails', '>= 3.1'
+ gem.add_development_dependency 'rspec-rails', '>= 2.2'
+end
View
5 features/templates/my_rails_gem/spec/spec_helper.rb
@@ -0,0 +1,5 @@
+require 'bundler/setup'
+require 'rails/all'
+require 'ammeter/init'
+
+Bundler.require
View
9 features/templates/my_railties_gem/Rakefile
@@ -0,0 +1,9 @@
+#!/usr/bin/env rake
+require "bundler/gem_tasks"
+
+require 'rspec'
+require 'rspec/core/rake_task'
+desc "Run all examples"
+RSpec::Core::RakeTask.new(:spec) do |t|
+ t.rspec_opts = %w[--color]
+end
View
20 features/templates/my_railties_gem/my_railties_gem.gemspec
@@ -0,0 +1,20 @@
+# -*- encoding: utf-8 -*-
+require File.expand_path('../lib/my_railties_gem/version', __FILE__)
+
+Gem::Specification.new do |gem|
+ gem.authors = ["Alex Rothenberg"]
+ gem.email = ["alex@alexrothenberg.com"]
+ gem.description = %q{TODO: Write a gem description}
+ gem.summary = %q{TODO: Write a gem summary}
+ gem.homepage = ""
+
+ gem.files = `git ls-files`.split($\)
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
+ gem.name = "my_gem"
+ gem.require_paths = ["lib"]
+ gem.version = MyRailtiesGem::VERSION
+
+ gem.add_runtime_dependency 'railties', '>= 3.1'
+ gem.add_development_dependency 'rspec-rails', '>= 2.2'
+end
View
5 features/templates/my_railties_gem/spec/spec_helper.rb
@@ -0,0 +1,5 @@
+require 'bundler/setup'
+require 'rails'
+require 'ammeter/init'
+
+Bundler.require
View
13 lib/ammeter/init.rb
@@ -1,6 +1,15 @@
require 'ammeter/rspec/generator/example.rb'
require 'ammeter/rspec/generator/matchers.rb'
-if Rails.respond_to?(:application) && Rails.application.respond_to?(:load_generators)
- Rails.application.load_generators
+if Rails.application.nil?
+ # We are in a gem so create test Rails app
+ module Ammeter
+ module TestApp
+ class Application < Rails::Application
+ config.root = File.dirname(__FILE__)
+ end
+ end
+ end
end
+
+Rails.application.load_generators

8 comments on commit 096d562

@twalpole

This commit brings back the back the issue from 0.2.6 of attempting to load_generators if Rails is not loaded

@alexrothenberg
Owner

Yes I seem to be having lots of trouble with this area :(

I think 3f448aa re-fixes it. Would you mind validating so I don't make the same mistake again (again).

@twalpole

With that change I'm getting an error in my use case (testing the formtastic gem)

1.9.3-p194/lib/ruby/gems/1.9.1/gems/railties-3.0.15/lib/rails/application.rb:63:in `inherited': You cannot have more than one Rails::Application (RuntimeError)

@alexrothenberg
Owner

I see. The problem is formtastic and ammeter are both creating the test Rails application. Ammeter does have an if Rails.application.nil? so it doesn't raise this error (https://github.com/alexrothenberg/ammeter/blob/v0.2.7/lib/ammeter/init.rb#L4) but formtastic requires ammeter and then creates its test app https://github.com/justinfrench/formtastic/blob/master/spec/spec_helper.rb#L13-17.

We could get rid of this by moving require 'ammeter/init' down below line 17 in Formtastic's spec_helper.rb

Do you think its too big a burden to put on gems using Ammeter to create their Rails.application before requiring "ammeter/init"?

@twalpole

I dont know that it would be too big of a burden as long as its documented, just wondering how many projects currently using ammeter it will affect, and maybe the change should go into a 0.3.0 or something

@alexrothenberg
Owner

Doing this in a 0.3.0 release is a good idea and yes usage documentation too. I'm learning that other people use your gem in unanticipated ways :)

I've reverted some of this and now the specs in formtastic head pass with ammeter head. I'd like to get back to a good 0.2.x release before moving on to 0.3.0.

@twalpole

@alexrothenberg sounds great - thanks

@alexrothenberg
Owner

Ok 0.2.8 is out and seems to work with formtastic.

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