Created
April 13, 2009 14:47
-
-
Save watersofoblivion/94476 to your computer and use it in GitHub Desktop.
My Generic Template for a Rails application
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Rails Application Template | |
# | |
# My personal template for Rails applications. Does a few things: | |
# - A few odds and ends (public/index.html, README => README.rdoc, etc.) | |
# - Sets up Rspec | |
# - Sets up Cucumber | |
# - Sets up Selenium | |
# - Stuffs everything into a git repository | |
# - Creates a project on Heroku and pushes the repo there | |
### | |
# Get some basic but important information from the user | |
### | |
heroku_name = ask "What Heroku name do you want for this application?" | |
### | |
# Clean up a bit | |
### | |
run "rm public/index.html" | |
run "rm README" | |
file "doc/README_FOR_APP", "" | |
file "config/template", "https://gist.github.com/94476.txt" | |
file "README.rdoc", <<EOF | |
= #{heroku_name} | |
About #{heroku_name} | |
== License | |
The MIT License | |
Copyright (c) <year> <copyright holders> | |
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. | |
EOF | |
### | |
# Setup git | |
### | |
git :init | |
file '.gitignore', <<EOF | |
log/*.log | |
tmp/* | |
db/*.sqlite3 | |
doc/app/* | |
coverage/* | |
config/database.yml | |
EOF | |
### | |
# Add a few plugins | |
### | |
plugin 'rspec', :git => 'git://github.com/dchelimsky/rspec.git' | |
plugin 'rspec-rails', :git => 'git://github.com/dchelimsky/rspec-rails.git' | |
plugin 'selenium-on-rails', :git => 'git://github.com/paytonrules/selenium-on-rails.git' | |
### | |
# Setup the testing environment | |
# | |
# This entails generating a bunch of files... | |
### | |
run "rm -rf test/" | |
# Do the initial Rspec and Cucumber setup | |
generate 'rspec' | |
generate 'cucumber' | |
run "mkdir features/regular features/ajax" | |
# A helper is always, well, helpful... | |
file 'features/support/helper.rb', "" | |
# A slight modifications of the Webrat code to work with Selenium | |
file 'features/step_definitions/selenium_steps.rb', <<EOF | |
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths")) | |
# Commonly used webrat steps modified to work with Selenium | |
Given /^I am on (.+)$/ do |page_name| | |
visit path_to(page_name) | |
end | |
When /^I go to (.+)$/ do |page_name| | |
visit path_to(page_name) | |
selenium.wait_for_page_to_load | |
end | |
When /^I press "([^\"]*)"$/ do |button| | |
click_button(button) | |
selenium.wait_for_page_to_load | |
end | |
When /^I follow "([^\"]*)"$/ do |link| | |
click_link(link) | |
selenium.wait_for_page_to_load | |
end | |
When /^I fill in "([^\"]*)" with "([^\"]*)"$/ do |field, value| | |
fill_in(field, :with => value) | |
end | |
When /^I select "([^\"]*)" from "([^\"]*)"$/ do |value, field| | |
select(value, :from => field) | |
end | |
# Use this step in conjunction with Rail's datetime_select helper. For example: | |
# When I select "December 25, 2008 10:00" as the date and time | |
When /^I select "([^\"]*)" as the date and time$/ do |time| | |
select_datetime(time) | |
end | |
# Use this step when using multiple datetime_select helpers on a page or | |
# you want to specify which datetime to select. Given the following view: | |
# <%= f.label :preferred %><br /> | |
# <%= f.datetime_select :preferred %> | |
# <%= f.label :alternative %><br /> | |
# <%= f.datetime_select :alternative %> | |
# The following steps would fill out the form: | |
# When I select "November 23, 2004 11:20" as the "Preferred" data and time | |
# And I select "November 25, 2004 10:30" as the "Alternative" data and time | |
When /^I select "([^\"]*)" as the "([^\"]*)" date and time$/ do |datetime, datetime_label| | |
select_datetime(datetime, :from => datetime_label) | |
end | |
# Use this step in conjunction with Rail's time_select helper. For example: | |
# When I select "2:20PM" as the time | |
# Note: Rail's default time helper provides 24-hour time-- not 12 hour time. Webrat | |
# will convert the 2:20PM to 14:20 and then select it. | |
When /^I select "([^\"]*)" as the time$/ do |time| | |
select_time(time) | |
end | |
# Use this step when using multiple time_select helpers on a page or you want to | |
# specify the name of the time on the form. For example: | |
# When I select "7:30AM" as the "Gym" time | |
When /^I select "([^\"]*)" as the "([^\"]*)" time$/ do |time, time_label| | |
select_time(time, :from => time_label) | |
end | |
# Use this step in conjunction with Rail's date_select helper. For example: | |
# When I select "February 20, 1981" as the date | |
When /^I select "([^\"]*)" as the date$/ do |date| | |
select_date(date) | |
end | |
# Use this step when using multiple date_select helpers on one page or | |
# you want to specify the name of the date on the form. For example: | |
# When I select "April 26, 1982" as the "Date of Birth" date | |
When /^I select "([^\"]*)" as the "([^\"]*)" date$/ do |date, date_label| | |
select_date(date, :from => date_label) | |
end | |
When /^I check "([^\"]*)"$/ do |field| | |
check(field) | |
end | |
When /^I uncheck "([^\"]*)"$/ do |field| | |
uncheck(field) | |
end | |
When /^I choose "([^\"]*)"$/ do |field| | |
choose(field) | |
end | |
When /^I attach the file at "([^\"]*)" to "([^\"]*)"$/ do |path, field| | |
attach_file(field, path) | |
end | |
Then /^I should see "([^\"]*)"$/ do |text| | |
response.should contain(text) | |
end | |
Then /^I should not see "([^\"]*)"$/ do |text| | |
response.should_not contain(text) | |
end | |
Then /^the "([^\"]*)" field should contain "([^\"]*)"$/ do |field, value| | |
field_labeled(field).value.should =~ /\#{value}/ | |
end | |
Then /^the "([^\"]*)" field should not contain "([^\"]*)"$/ do |field, value| | |
field_labeled(field).value.should_not =~ /\#{value}/ | |
end | |
Then /^the "([^\"]*)" checkbox should be checked$/ do |label| | |
field_labeled(label).should be_checked | |
end | |
Then /^I should be on (.+)$/ do |page_name| | |
URI.parse(selenium.get_location).path.should == path_to(page_name) | |
end | |
EOF | |
# Modify the Cucumber rake task to use the default profile | |
file 'lib/tasks/cucumber.rake', <<EOF | |
$LOAD_PATH.unshift(RAILS_ROOT + '/vendor/plugins/cucumber/lib') if File.directory?(RAILS_ROOT + '/vendor/plugins/cucumber/lib') | |
begin | |
require 'cucumber/rake/task' | |
Cucumber::Rake::Task.new(:features) do |t| | |
t.profile = "default" | |
t.cucumber_opts = "--format pretty" | |
end | |
task :features => 'db:test:prepare' | |
rescue LoadError | |
desc 'Cucumber rake task not available' | |
task :features do | |
abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' | |
end | |
end | |
EOF | |
# Create a selenium rake file which uses the ajax profile | |
file 'lib/tasks/selenium.rake', <<EOF | |
$LOAD_PATH.unshift(RAILS_ROOT + '/vendor/plugins/cucumber/lib') if File.directory?(RAILS_ROOT + '/vendor/plugins/cucumber/lib') | |
begin | |
require 'cucumber/rake/task' | |
Cucumber::Rake::Task.new(:selenium) do |t| | |
t.profile = "ajax" | |
t.cucumber_opts = "--format pretty" | |
end | |
task :features => 'db:test:prepare' | |
rescue LoadError | |
desc 'Cucumber rake task not available' | |
task :features do | |
abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' | |
end | |
end | |
EOF | |
# The shared environment | |
file "features/support/env.rb", <<EOF | |
ENV["RAILS_ENV"] = "test" | |
require File.expand_path(File.dirname(__FILE__) + "/../../config/environment") | |
require 'cucumber/rails/world' | |
require 'cucumber/formatters/unicode' | |
require 'webrat' | |
EOF | |
# The webrat environment | |
file "features/support/regular.rb", <<EOF | |
require 'spec/expectations' | |
require 'webrat' | |
Webrat.configure do |config| | |
config.mode = :rails | |
end | |
require 'database_cleaner' | |
require 'database_cleaner/cucumber' | |
DatabaseCleaner.clean_with :truncation | |
DatabaseCleaner.strategy = :transaction | |
EOF | |
# The selenium environment | |
file "features/support/ajax.rb", <<EOF | |
require 'spec/expectations' | |
require 'selenium' | |
require 'webrat' | |
Webrat.configure do |config| | |
config.mode = :selenium | |
config.application_environment = :test | |
end | |
require 'database_cleaner' | |
require 'database_cleaner/cucumber' | |
DatabaseCleaner.strategy = :truncation | |
EOF | |
# Configure the Cucumber profiles | |
file 'cucumber.yml', <<EOF | |
default: --require features/support/env.rb --require features/support/regular.rb --require features/support/helper.rb --require features/step_definitions/webrat_steps.rb features/regular | |
ajax: --require features/support/env.rb --require features/support/ajax.rb --require features/support/helper.rb --require features/step_definitions/selenium_steps.rb features/regular features/ajax | |
EOF | |
# An end to end testing Rake task. NOT IMPLEMENTED COMPLETELY (YET...) | |
rakefile "end_to_end.rake" do | |
<<EOF | |
# Run complete End-to-End testing in a test production environment | |
# | |
# I. Setup the tests | |
# 1. Clone the application repository into a temporary directory | |
# 2. Deploy the app to a new Heroku application | |
# 3. Copy the current production database to the testing app (via TAPS) | |
# 4. Run the pending migrations | |
# II. Run the tests | |
# 1. Run the specs | |
# 2. Run the features | |
# 3. Run the selenium tests | |
# III. Tear down the tests | |
# 1. Undeploy the application from Heroku | |
# 2. Delete the cloned repository | |
# Some helpful constants | |
PRODUCTION_APP = "#{heroku_name}" | |
CLONED_REPO = "\#{RAILS_ROOT}/tmp/e2et" | |
TESTING_APP = "\#{PRODUCTION_APP}-e2et" | |
namespace :test do | |
desc "Run complete end-to-end testing" | |
task :end_to_end => ["end_to_end:setup", "end_to_end:test", "end_to_end:teardown"] | |
namespace :end_to_end do | |
# Set up the testing environment | |
task :setup => ["setup:clone", "setup:deploy", "setup:copy", "setup:migrate"] | |
namespace :setup do | |
# Clone the application repository into a separate directory | |
task :clone do |t| | |
sh "git clone \#{RAILS_ROOT} \#{CLONED_REPO}" | |
end | |
# Deploy the cloned repository to a new Heroku application | |
task :deploy => :clone do |t| | |
FileUtils.cd CLONED_REPO do | |
sh "heroku create \#{TESTING_APP}" | |
sh "git push heroku master" | |
end | |
end | |
# Copy the current production database to the new Heroku application | |
task :copy => :deploy do |t| | |
sh "heroku db:pull" | |
sh "mkdir -p \#{CLONED_REPO}/db/" | |
sh "cp \#{RAILS_ROOT}/config/database.yml \#{CLONED_REPO}/config/database.yml" | |
sh "cp \#{RAILS_ROOT}/db/development.sqlite3 \#{CLONED_REPO}/db/" | |
FileUtils.cd CLONED_REPO do | |
sh "heroku db:push" | |
end | |
end | |
# Run the pending database migrations | |
task :migrate => :copy do |t| | |
FileUtils.cd CLONED_REPO do | |
sh "heroku rake db:migrate" | |
end | |
end | |
end | |
# Run all of the tests in the production environment | |
task :test => [:setup, "test:spec", "test:features", "test:selenium"] | |
namespace :test do | |
# Run the specs | |
task :spec do |t| | |
FileUtils.cd CLONED_REPO do | |
sh "heroku rake spec" | |
end | |
end | |
# Run the features | |
task :features do |t| | |
FileUtils.cd CLONED_REPO do | |
sh "heroku rake features" | |
end | |
end | |
# Run selenium | |
task :selenium do |t| | |
# TODO: Kick off selenium-grid | |
FileUtils.cd CLONED_REPO do | |
sh "rake test:acceptance" | |
end | |
end | |
end | |
# Tear down the testing environment | |
task :teardown => [:test, "teardown:undeploy", "teardown:unclone"] | |
namespace :teardown do | |
# Remove the application from Heroku | |
task :undeploy do |t| | |
FileUtils.cd CLONED_REPO do | |
sh "echo 'y' | heroku destroy --app \#{TESTING_APP}" | |
end | |
end | |
# Delete the cloned repository | |
task :unclone => :undeploy do |t| | |
sh "rm -rf \#{CLONED_REPO}" | |
end | |
end | |
end | |
end | |
EOF | |
end | |
### | |
# Add everything and commit it to a repository | |
### | |
git :add => "." | |
git :commit => "-a -m 'Initial import'" | |
### | |
# Create a Heroku app | |
### | |
run "heroku create #{heroku_name}" | |
git :push => "heroku master" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment