Eliminated use of scenarios plugin

It doesn't work on Rails 2.3.5
This commit is contained in:
Eric Allen 2009-12-08 13:13:21 -05:00
parent d1fc119e2d
commit 6d3770c5fb
42 changed files with 24 additions and 1576 deletions

View file

@ -17,7 +17,7 @@ class Todo < ActiveRecord::Base
after_save :save_predecessors
named_scope :active, :conditions => { :state => 'active' }
named_scope :not_completed, :conditions => ['NOT (state = ? )', 'completed']
named_scope :not_completed, :conditions => ['NOT (todos.state = ? )', 'completed']
named_scope :are_due, :conditions => ['NOT (todos.due IS NULL)']
STARRED_TAG_NAME = "starred"

View file

@ -55,3 +55,14 @@ buymilk:
due: ~
completed_at: <%= today %>
user: admin_user
callmom:
id: 5
context_id: 3 # call
project_id: ~
description: Call mom
notes: Remember her birthday
state: active
due: ~
completed_at: ~
user: admin_user

View file

@ -51,37 +51,37 @@ describe Context do
end
describe 'when finding by namepart' do
scenario :todos
fixtures :todos, :contexts
it 'finds with exact match' do
Context.find_by_namepart('errand').should == contexts(:errand)
Context.find_by_namepart('agenda').should == contexts(:agenda)
end
it 'finds with partial match' do
Context.find_by_namepart('err').should == contexts(:errand)
Context.find_by_namepart('age').should == contexts(:agenda)
end
it 'deletes todos within context when context deleted' do
contexts(:call).should have(2).todos
call_todos = contexts(:call).todos
contexts(:call).destroy
contexts(:agenda).should have(3).todos
call_todos = contexts(:agenda).todos
contexts(:agenda).destroy
Todo.find(:all).should_not include(call_todos)
end
end
describe 'when counting todos' do
scenario :todos
fixtures :todos, :contexts, :users, :preferences
it 'returns correct number of completed todos' do
contexts(:call).should_not have(:any).done_todos
contexts(:call).done_todos.should_not have(:any).items
contexts(:call).todos.first.complete!
contexts(:call).should have(1).done_todos
Context.find(contexts(:call).id).done_todos.should have(1).items
end
it 'returns correct number of not done todos' do
contexts(:call).should have(2).not_done_todos
contexts(:call).todos.last.complete!
contexts(:call).should have(1).not_done_todos
contexts(:agenda).todos.not_completed.should have(2).items
contexts(:agenda).todos.last.complete!
contexts(:agenda).todos.not_completed.should have(1).items
end
end
end

View file

@ -1,19 +0,0 @@
class ContextsScenario < Scenario::Base
uses :users
def load
%w(Call Email Errand Someday).each_with_index do |context, index|
create_context context, index+1
end
end
def create_context(name, position)
create_model :context, name.downcase.to_sym,
:name => name,
:position => position,
:hide => name == 'Someday' ? true : false,
:created_at => Time.now,
:updated_at => Time.now,
:user_id => user_id(:sean)
end
end

View file

@ -1,20 +0,0 @@
class ProjectsScenario < Scenario::Base
def load
create_project :build_time_machine, 'Build a working time machine'
create_project :make_more_money, 'Make more money than Billy Gates'
create_project :evict_dinosaurs, 'Evict dinosaurs from the garden'
create_project :attend_railsconf, 'Attend RailsConf'
end
def create_project(identifier, name)
attributes = {
:name => name,
:state => 'active',
:created_at => 4.day.ago,
:updated_at => 1.minute.ago
}
create_model :project,
identifier || attributes[:name].split.first.downcase.to_sym,
attributes
end
end

View file

@ -1,30 +0,0 @@
class TodosScenario < Scenario::Base
uses :contexts, :projects, :users
def load
create_todo :bill,
:description => 'Call Bill Gates to find out how much he makes per day',
:user => :sean,
:context => :call,
:project => :make_more_money
create_todo :bank,
:description => 'Call my bank',
:user => :sean,
:context => :call,
:project => :make_more_money
end
def create_todo(identifier, options={})
context = options.delete(:context)
project = options.delete(:project)
user = options.delete(:user)
attributes = {
:state => 'active',
:created_at => 1.week.ago,
:context_id => context_id(context),
:project_id => project_id(project),
:user_id => user_id(user)
}.merge(options)
create_model :todo, identifier, attributes
end
end

View file

@ -1,19 +0,0 @@
class UsersScenario < Scenario::Base
def load
create_user :login => 'johnny', :first_name => 'Johnny', :last_name => 'Smith'
create_user :login => 'jane', :first_name => 'Jane', :last_name => 'Pilbeam'
create_user :login => 'sean', :first_name => 'Sean', :last_name => 'Pallmer'
end
def create_user(attributes={})
password = attributes[:login] + Time.now.to_s
attributes = {
:password => password,
:password_confirmation => password,
:is_admin => attributes[:is_admin] || false,
}.merge(attributes)
identifier = attributes[:login].downcase.to_sym
user = create_model :user, identifier, attributes
Preference.create(:show_number_completed => 5, :user => user)
end
end

View file

@ -5,7 +5,6 @@ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'spec'
require 'spec/rails'
require 'skinny_spec'
require 'scenarios'
module LuckySneaks
module ModelSpecHelpers

View file

@ -1,4 +0,0 @@
environments
*.log
tmp
vendor

View file

@ -1,19 +0,0 @@
Copyright (c) 2007, Adam Williams and John W. Long.
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 file

@ -1,262 +0,0 @@
== Rails Scenarios Plugin
Who hasn't experienced the pain of dozens of YAML files filled with hundreds
of inter-related data structures? When do you look at People of an
Organization and not have to look at the organization_id, open the
organizations.yml file, and search for 'id: X'?
In a nutshell, scenarios are a drop in replacement for YAML fixtures. Instead
of encouraging you to create a mindless amount of raw data in the form of
YAML, scenarios encourage you to create code that populates your tables with
the appropriate records.
How is it different from other solutions? A few things:
* It continues to provide a fundamental, fast insertion method using attributes
written directly to a table. This is the
Scenarios::TableMethods#create_record method.
* It allows you to create records using validations if you prefer, or if it's
important to have all your callbacks be invoked. See
Scenarios::TableMethods#create_model. Both create_record and create_model
allow you to name your instances for retrieval by the instance and id reader
methods (more below).
* Nothing stops you from simply invoking YouModel.create!, etc. We'll still
keep track of the tables the scenario modifies and clean things up afterward.
* It allows you to create re-usable scenarios as classes. These classes are
like any other class - they may include modules, subclass, and be composed of
other scenarios. See Scenarios::Base.uses. This also means that you can load
any scenario into any Rails environment. That's what the 'rake
db:scenario:load' task is good for (more below). Very handy for re-using all
that test support code to create populated demos!
=== Quick Start
Since Scenarios is a Rails plugin at this time, you should get it installed,
using the appropriate method (script/plugin, svn, piston) into your
vendor/plugins directory. Once you have this, in your spec_helper.rb or
test_helper.rb, add the following line after the spec requires:
require 'scenarios'
The Scenarios you write should be placed in the spec/scenarios directory of your
Rails project if you're using RSpec, or the test/scenarios directory of your
Rails project if you're using Test::Unit. Scenario file names always end in
"_scenario.rb" and classes end in "Scenario".
A simple scenario looks like this:
# in spec/scenarios/users_scenario.rb or test/scenarios/users_scenario.rb
class UsersScenario < Scenario::Base
def load
create_record :user, :john, :name => 'John', :password => 'doodaht'
create_record :user, :cindy, :name => 'Cindy', :password => 'whoot!'
end
end
In the example above, I'm using the <tt>create_record</tt> instance method to
create two users: John and Cindy. Notice the calls to <tt>create_record</tt>.
There are three parameters. The first is the singular name of the table to
insert the record into, the second is the symbolic name of the record (more on
that later), and the third is a hash of the attributes of the record.
To use the UsersScenario in a description, you should declare it using
the <tt>scenario</tt> method. Here it is within a spec file (RSpec):
# in spec/models/user_spec.rb
describe User do
scenario :users
it "should allow me to do something with John" do
user = users(:john)
user.password.should == "doodaht"
end
end
and here it is within a standard Test::Unit test:
# in test/unit/user_test.rb
class UserTest < Test::Unit::TestCase
scenario :users
def test_do_something
user = users(:john)
assert_equal "doodaht", user.password
end
end
Notice that it is easy to load an instance of a model object using its
symbolic name with a reader method, similar to that of Rails' fixtures. In the
example above, I loaded John with the reader method <tt>users</tt> and the
symbolic name <tt>:john</tt>. (Remember that in the Users scenario I declared
that John should be accessible through the symbolic name <tt>:john</tt>.)
I could also have retrieved an array of user fixtures by passing in
multiple symbolic names to the reader method:
# in spec/models/user_spec.rb
describe User do
scenario :users
it "should allow me to get all admins" do
admins = users(:john, :ryan)
User.admins.should eql(admins)
end
end
=== Composition
In real life your scenarios will probably grow quite complicated. The
scenarios plugin allows you to deal with this complexity through composition.
Here's a simple example:
# in spec/scenarios/posts_scenario.rb or test/scenarios/posts_scenario.rb
class PostsScenario < Scenario::Base
def load
create_record :post, :first, :title => "First Post"
create_record :post, :second, :title => "Second Post"
end
end
# in spec/scenarios/comments_scenario.rb or test/scenarios/comments_scenario.rb
class CommentsScenario < Scenario::Base
uses :posts
def load
create_record :comment, :first, :body => "Nice post!", :post_id => post_id(:first)
create_record :comment, :second, :body => "I like it.", :post_id => post_id(:first)
create_record :comment, :third, :body => "I thoroughly disagree.", :post_id => post_id(:second)
end
end
In the example above, the CommentsScenario declares that it depends on the
Posts scenario with the <tt>uses</tt> class method. This means that if you
load the CommentsScenario, the PostsScenario will be loaded first and the
CommentsScenario will have access to all the data loaded by the PostsScenario
in its own <tt>load</tt> method. Note that inside the load method I'm using
another form of reader methed which simply gives you the id for a symbolic
name (in this case: <tt>post_id</tt>). This is most useful for making
associations, as done here with comments and posts.
=== Helper Methods
Another way of simplifying your scenarios and specs/tests is through helper
methods. The Scenarios plugin provides a handy way to declare helper methods
that are accessible from inside the scenario and also from inside related
RSpec/Test::Unit examples:
# in spec/scenarios/users_scenario.rb or test/scenarios/users_scenario.rb
class UsersScenario < Scenario::Base
def load
create_user :name => "John"
end
helpers do
def create_user(attributes={})
create_record :user, attributes[:name].downcase.intern, attributes
end
def login_as(user)
@request.session[:user_id] = user.id
end
end
end
Helper methods declared inside the helpers block are mixed into the scenario
when it is instantiated and mixed into examples that declare that they are using
the scenario. Also, in the case where one scenario <tt>uses</tt> another, the
using scenario will have the helper methods of the used scenario.
# in spec/controllers/projects_controller_spec.rb
describe "Projects screen" do
scenario :users
it "should show active projects" do
login_as(users(:john))
get :projects
@response.should have_tag('#active_projects')
end
end
# in test/functional/projects_controller_test.rb
class PeopleControllerTest < Test::Unit::TestCase
scenario :users
def test_index
login_as(users(:john))
get :projects
assert_tag('#active_projects')
end
end
Notice that within my specs/tests I have access to the login_as helper method
declared inside the <tt>helpers</tt> block of the UsersScenario. Scenario
helpers are a great way to share helper methods between specs/tests that use a
specific scenario.
=== Built-in Scenario
There is a scenario named 'blank' that comes with the plugin. This scenario is
useful when you want to express, and guarantee, that the database is empty. It
works by using your db/schema.rb, so if the table isn't created in there, it
won't be cleaned up.
Scenario.load_paths is an array of the locations to look for scenario
definitions. The built-in scenarios directory is consulted last, so if you'd
like to re-define, for instance, the 'blank' scenario, simply create
'blank_scenario.rb' in your spec/scenarios or test/scenarios directory.
=== Load Rake Task
The Scenarios plugin provides a single Rake task, <tt>db:scenario:load</tt>,
which you may use in a fashion similar to Rails fixtures'
<tt>db:fixtures:load</tt>.
rake db:scenario:load SCENARIO=comments
When invoked, this task will populate the development database with the named
scenario.
If you do not specify SCENARIO, the task will expect to find a default scenario
(a file 'default_scenario.rb' having DefaultScenario defined in it). It is our
practice to have it such that this scenario <tt>uses</tt> a number of our other
scenarios, thereby:
* encouraging us to use test data that looks good in the running development
application
* allowing us to troubleshoot failing tests in the running development
application
=== More Information
For more information, be sure to look through the documentation over at RubyForge:
* http://faithfulcode.rubyforge.org/docs/scenarios
You might also enjoy taking a look at the specs for the plugin and the example
scenarios:
* http://faithfulcode.rubyforge.org/svn/plugins/trunk/scenarios/spec/scenarios_spec.rb
* http://faithfulcode.rubyforge.org/svn/plugins/trunk/scenarios/spec/scenarios
Browse the complete source code:
* http://faithfulcode.rubyforge.org/svn/plugins/trunk/scenarios
=== Running Tests
You should be able to simply run rake. Notice in testing/environment.rb the
revisions under which this project will work. If you intend to test against
HEAD, you will need to delete the directory testing/tmp/trunk/HEAD. At some
point, it would be nice to have the script track the revision of HEAD that we
have, and update the directory automatically.
=== License
The Scenarios plugin is released under the MIT-License and is Copyright (c)
2007, Adam Williams and John W. Long. Special thanks to Chris Redinger for his
part in helping us get this plugin ready for the public.

View file

@ -1,10 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + '/testing/plugit_descriptor')
require 'rake/rdoctask'
Rake::RDocTask.new(:doc) do |r|
r.title = "Rails Scenarios Plugin"
r.main = "README"
r.options << "--line-numbers"
r.rdoc_files.include("README", "LICENSE", "lib/**/*.rb")
r.rdoc_dir = "doc"
end

View file

@ -1 +0,0 @@
Make sure before :all's that use scenario methods work. They don't right now.

View file

@ -1,127 +0,0 @@
Only in /Users/aiwilliams/Workspaces/faithfulcode/scenarios/: .git
Only in scenarios/: .svn
Only in scenarios/: .tm_last_run_ruby
diff -r scenarios/Rakefile /Users/aiwilliams/Workspaces/faithfulcode/scenarios/Rakefile
3c3
< TESTING_ENVIRONMENTS["rspec_3317_rails_8956"].load
---
> TESTING_ENVIRONMENTS["rspec_3119_rails_8375"].load
Only in /Users/aiwilliams/Workspaces/faithfulcode/scenarios/: helpers.diff
Only in scenarios/lib: .svn
Only in scenarios/lib/scenarios: .svn
diff -r scenarios/lib/scenarios/base.rb /Users/aiwilliams/Workspaces/faithfulcode/scenarios/lib/scenarios/base.rb
11,14c11,12
< # be included into the scenario and all specs that include the scenario.
< # You may also provide names of helpers from your scenarios/helpers
< # directory, or any other module you'd like included in your Scenario.
< def helpers(helper_names_or_modules = [], &block)
---
> # be included into the scenario and all specs that include the scenario
> def helpers(&block)
17,19d14
< mod.module_eval do
< [helper_names_or_modules].flatten.each {|h| include h.is_a?(Module) ? h : h.to_scenario_helper}
< end
Only in scenarios/lib/scenarios/builtin: .svn
Only in scenarios/lib/scenarios/extensions: .svn
diff -r scenarios/lib/scenarios/extensions/string.rb /Users/aiwilliams/Workspaces/faithfulcode/scenarios/lib/scenarios/extensions/string.rb
22,39d21
< # Convert a string into the associated scenario helper module:
< #
< # "basic".to_scenario_helper #=> BasicScenarioHelper
< # "basic_scenario".to_scenario_helper #=> BasicScenarioHelper
< #
< # Raises Scenario::NameError if the the helper cannot be loacated as
< # 'helpers/<name>_helper' in Scenario.load_paths.
< def to_scenario_helper
< class_name = "#{self.strip.camelize.sub(/ScenarioHelper$/, '')}ScenarioHelper"
< Scenario.load_paths.each do |path|
< filename = "#{path}/#{class_name.underscore}.rb"
< if File.file?(filename)
< require filename
< break
< end
< end
< class_name.constantize rescue raise Scenario::NameError, "Expected to find #{class_name} in #{Scenario.load_paths.inspect}"
< end
diff -r scenarios/lib/scenarios/extensions/symbol.rb /Users/aiwilliams/Workspaces/faithfulcode/scenarios/lib/scenarios/extensions/symbol.rb
14,23d13
< # Convert a symbol into the associated scenario helper module:
< #
< # :basic.to_scenario_helper #=> BasicScenarioHelper
< # :basic_scenario.to_scenario_helper #=> BasicScenarioHelper
< #
< # Raises Scenario::NameError if the the helper cannot be loacated as
< # 'helpers/<name>_helper' in Scenario.load_paths.
< def to_scenario_helper
< to_s.to_scenario_helper
< end
Only in scenarios/spec: .svn
Only in scenarios/spec: environments.rb
Only in scenarios/spec/scenarios: .svn
Only in scenarios/spec/scenarios: helpers
diff -r scenarios/spec/scenarios_spec.rb /Users/aiwilliams/Workspaces/faithfulcode/scenarios/spec/scenarios_spec.rb
23,27d22
< it 'should allow us to have helpers in scenarios/helpers directory which we can get through the helpers class method' do
< klass = :empty.to_scenario
< klass.helpers :myown
< end
<
diff -r scenarios/spec/spec_helper.rb /Users/aiwilliams/Workspaces/faithfulcode/scenarios/spec/spec_helper.rb
1,20c1,6
< $LOAD_PATH << File.dirname(__FILE__) + '/../testing'
<
< require File.dirname(__FILE__) + "/environments"
<
< require 'active_support'
< require 'active_record'
< require 'action_controller'
< require 'action_view'
<
< module Spec
< module Rails
< module Example
< end
< end
< end
<
< require 'spec/rails'
< require 'scenarios'
<
< require 'models'
\ No newline at end of file
---
> require File.expand_path(File.dirname(__FILE__) + "/../testing/environment")
> TESTING_ENVIRONMENTS[TESTING_ENVIRONMENT].load(DATABASE_ADAPTER)
> require "models"
> require "spec"
> require "spec/rails"
> require "scenarios"
Only in scenarios/tasks: .svn
Only in scenarios/test: .svn
Only in scenarios/testing: .svn
diff -r scenarios/testing/environment.rb /Users/aiwilliams/Workspaces/faithfulcode/scenarios/testing/environment.rb
15c15
< TESTING_ENVIRONMENT = "rspec_3317_rails_8956" unless defined?(TESTING_ENVIRONMENT)
---
> TESTING_ENVIRONMENT = "rspec_3119_rails_8375" unless defined?(TESTING_ENVIRONMENT)
31c31
< # system "cd #{lib.support_directory} && patch -p0 < #{File.join(TESTING_ROOT, "rspec_on_rails_3119.patch")}"
---
> system "cd #{lib.support_directory} && patch -p0 < #{File.join(TESTING_ROOT, "rspec_on_rails_3119.patch")}"
36,38c36,38
< TESTING_ENVIRONMENTS << TestingLibrary::Environment.new("rspec_3317_rails_8956", SUPPORT_TEMP, DB_CONFIG_FILE, DB_SCHEMA_FILE) do |env|
< env.package "rails", "http://svn.rubyonrails.org/rails", "trunk", "8956", &rails_package
< env.package "rspec", "http://rspec.rubyforge.org/svn", "trunk", "3317", &rspec_package
---
> TESTING_ENVIRONMENTS << TestingLibrary::Environment.new("rspec_3119_rails_8375", SUPPORT_TEMP, DB_CONFIG_FILE, DB_SCHEMA_FILE) do |env|
> env.package "rails", "http://svn.rubyonrails.org/rails", "trunk", "8375", &rails_package
> env.package "rspec", "http://rspec.rubyforge.org/svn", "trunk", "3119", &rspec_package
40c40
< TESTING_ENVIRONMENTS << TestingLibrary::Environment.new("rspec_3317_rails_1_2_6", SUPPORT_TEMP, DB_CONFIG_FILE, DB_SCHEMA_FILE) do |env|
---
> TESTING_ENVIRONMENTS << TestingLibrary::Environment.new("rspec_3119_rails_1_2_6", SUPPORT_TEMP, DB_CONFIG_FILE, DB_SCHEMA_FILE) do |env|
42c42
< env.package "rspec", "http://rspec.rubyforge.org/svn", "trunk", "3317", &rspec_package
---
> env.package "rspec", "http://rspec.rubyforge.org/svn", "trunk", "3119", &rspec_package

View file

@ -1,34 +0,0 @@
module Scenarios
# Thrown by Scenario.load when it cannot find a specific senario.
class NameError < ::NameError; end
class << self
# The locations from which scenarios will be loaded.
mattr_accessor :load_paths
self.load_paths = ["#{RAILS_ROOT}/spec/scenarios", "#{RAILS_ROOT}/test/scenarios", "#{File.dirname(__FILE__)}/scenarios/builtin"]
# Load a scenario by name. <tt>scenario_name</tt> can be a string, symbol,
# or the scenario class.
def load(scenario_name)
klass = scenario_name.to_scenario
klass.load
klass
end
end
end
# The Scenario namespace makes for Scenario::Base
Scenario = Scenarios
# For Rails 1.2 compatibility
unless Class.instance_methods.include?(:superclass_delegating_reader)
require File.dirname(__FILE__) + "/scenarios/extensions/delegating_attributes"
end
require 'active_record/fixtures'
require 'scenarios/configuration'
require 'scenarios/table_blasting'
require 'scenarios/table_methods'
require 'scenarios/loading'
require 'scenarios/base'
require 'scenarios/extensions'

View file

@ -1,73 +0,0 @@
module Scenarios
class Base
class << self
# Class method to load the scenario. Used internally by the Scenarios
# plugin.
def load
new.load_scenarios(used_scenarios + [self])
end
# Class method for your own scenario to define helper methods that will
# be included into the scenario and all specs that include the scenario
def helpers(&block)
mod = (const_get(:Helpers) rescue const_set(:Helpers, Module.new))
mod.module_eval(&block) if block_given?
mod
end
# Class method for your own scenario to define the scenarios that it
# depends on. If your scenario depends on other scenarios those
# scenarios will be loaded before the load method on your scenario is
# executed.
def uses(*scenarios)
names = scenarios.map(&:to_scenario).reject { |n| used_scenarios.include?(n) }
used_scenarios.concat(names)
end
# Class method that returns the scenarios used by your scenario.
def used_scenarios # :nodoc:
@used_scenarios ||= []
@used_scenarios = (@used_scenarios.collect(&:used_scenarios) + @used_scenarios).flatten.uniq
end
# Returns the scenario class.
def to_scenario
self
end
end
include TableMethods
include Loading
attr_reader :table_config
# Initialize a scenario with a Configuration. Used internally by the
# Scenarios plugin.
def initialize(config = Configuration.new)
@table_config = config
table_config.update_scenario_helpers self.class
self.extend table_config.table_readers
self.extend table_config.scenario_helpers
end
# This method should be implemented in your scenarios. You may also have
# scenarios that simply use other scenarios, so it is not required that
# this be overridden.
def load
end
# Unload a scenario, sort of. This really only deletes the records, all of
# them, of every table this scenario modified. The goal is to maintain a
# clean database for successive runs. Used internally by the Scenarios
# plugin.
def unload
return if unloaded?
record_metas.each_value { |meta| blast_table(meta.table_name) }
@unloaded = true
end
def unloaded?
@unloaded == true
end
end
end

View file

@ -1,18 +0,0 @@
class BlankScenario < Scenarios::Base
def load
table_names.each do |table|
blast_table(table)
end
end
def table_names
self.class.table_names
end
def self.table_names
@table_names ||= begin
schema = (open(RAILS_ROOT + '/db/schema.rb') { |f| f.read } rescue '')
schema.grep(/create_table\s+(['"])(.+?)\1/m) { $2 }
end
end
end

View file

@ -1,55 +0,0 @@
module Scenarios
class Configuration # :nodoc:
attr_reader :blasted_tables, :loaded_scenarios, :record_metas, :table_readers, :scenario_helpers, :symbolic_names_to_id
def initialize
@blasted_tables = Set.new
@record_metas = Hash.new
@table_readers = Module.new
@scenario_helpers = Module.new
@symbolic_names_to_id = Hash.new {|h,k| h[k] = Hash.new}
@loaded_scenarios = Array.new
end
# Given a created record (currently ScenarioModel or ScenarioRecord),
# update the table readers module appropriately such that this record and
# it's id are findable via methods like 'people(symbolic_name)' and
# 'person_id(symbolic_name)'.
def update_table_readers(record)
ids, record_meta = symbolic_names_to_id, record.record_meta # scoping assignments
ids[record_meta.table_name][record.symbolic_name] = record.id
table_readers.send :define_method, record_meta.id_reader do |*symbolic_names|
record_ids = symbolic_names.flatten.collect do |symbolic_name|
if symbolic_name.kind_of?(ActiveRecord::Base)
symbolic_name.id
else
record_id = ids[record_meta.table_name][symbolic_name.to_sym]
raise ActiveRecord::RecordNotFound, "No object is associated with #{record_meta.table_name}(:#{symbolic_name})" unless record_id
record_id
end
end
record_ids.size > 1 ? record_ids : record_ids.first
end
table_readers.send :define_method, record_meta.record_reader do |*symbolic_names|
results = symbolic_names.flatten.collect do |symbolic_name|
symbolic_name.kind_of?(ActiveRecord::Base) ?
symbolic_name :
record_meta.record_class.find(send(record_meta.id_reader, symbolic_name))
end
results.size > 1 ? results : results.first
end
end
def update_scenario_helpers(scenario_class)
scenario_helpers.module_eval do
include scenario_class.helpers
end
end
def scenarios_loaded?
!loaded_scenarios.blank?
end
end
end

View file

@ -1,5 +0,0 @@
require File.dirname(__FILE__) + "/extensions/object"
require File.dirname(__FILE__) + "/extensions/string"
require File.dirname(__FILE__) + "/extensions/symbol"
require File.dirname(__FILE__) + "/extensions/active_record"
require File.dirname(__FILE__) + "/extensions/test_case" rescue nil

View file

@ -1,14 +0,0 @@
module ActiveRecord
class Base
cattr_accessor :table_config
include Scenarios::TableBlasting
# In order to guarantee that tables are tracked when _create_model_ is
# used, and those models cause other models to be created...
def create_with_table_blasting
prepare_table(self.class.table_name)
create_without_table_blasting
end
alias_method_chain :create, :table_blasting
end
end

View file

@ -1,40 +0,0 @@
# These class attributes behave something like the class
# inheritable accessors. But instead of copying the hash over at
# the time the subclass is first defined, the accessors simply
# delegate to their superclass unless they have been given a
# specific value. This stops the strange situation where values
# set after class definition don't get applied to subclasses.
class Class
def superclass_delegating_reader(*names)
class_name_to_stop_searching_on = self.superclass.name.blank? ? "Object" : self.superclass.name
names.each do |name|
class_eval <<-EOS
def self.#{name}
if defined?(@#{name})
@#{name}
elsif superclass < #{class_name_to_stop_searching_on} && superclass.respond_to?(:#{name})
superclass.#{name}
end
end
def #{name}
self.class.#{name}
end
EOS
end
end
def superclass_delegating_writer(*names)
names.each do |name|
class_eval <<-EOS
def self.#{name}=(value)
@#{name} = value
end
EOS
end
end
def superclass_delegating_accessor(*names)
superclass_delegating_reader(*names)
superclass_delegating_writer(*names)
end
end

View file

@ -1,5 +0,0 @@
class Object
def metaclass
(class << self; self; end)
end unless method_defined?(:metaclass)
end

View file

@ -1,22 +0,0 @@
class String
# Convert a string into the associated scenario class:
#
# "basic".to_scenario #=> BasicScenario
# "basic_scenario".to_scenario #=> BasicScenario
#
# Raises Scenario::NameError if the the scenario cannot be loacated in
# Scenario.load_paths.
def to_scenario
class_name = "#{self.strip.camelize.sub(/Scenario$/, '')}Scenario"
Scenario.load_paths.each do |path|
filename = "#{path}/#{class_name.underscore}.rb"
if File.file?(filename)
require filename
break
end
end
class_name.constantize rescue raise Scenario::NameError, "Expected to find #{class_name} in #{Scenario.load_paths.inspect}"
end
end

View file

@ -1,14 +0,0 @@
class Symbol
# Convert a symbol into the associated scenario class:
#
# :basic.to_scenario #=> BasicScenario
# :basic_scenario.to_scenario #=> BasicScenario
#
# Raises Scenario::NameError if the the scenario cannot be located in
# Scenario.load_paths.
def to_scenario
to_s.to_scenario
end
end

View file

@ -1,77 +0,0 @@
module Test #:nodoc:
module Unit #:nodoc:
class TestCase #:nodoc:
superclass_delegating_accessor :scenario_classes
superclass_delegating_accessor :table_config
# Changing either of these is not supported at this time.
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
include Scenarios::TableMethods
include Scenarios::Loading
class << self
# This class method is mixed into RSpec and allows you to declare that
# you are using a given scenario or set of scenarios within a spec:
#
# scenario :basic # loads BasicScenario and any dependencies
# scenario :posts, :comments # loads PostsScenario and CommentsScenario
#
# It accepts an array of scenarios (strings, symbols, or classes) and
# will load them roughly in the order that they are specified.
def scenario(*names)
self.scenario_classes = []
names.each do |name|
scenario_class = name.to_scenario
scenario_classes.concat(scenario_class.used_scenarios + [scenario_class])
end
scenario_classes.uniq!
end
# Overridden to provide before all and after all code which sets up and
# tears down scenarios
def suite_with_scenarios
suite = suite_without_scenarios
class << suite
attr_accessor :test_class
def run_with_scenarios(*args, &block)
debugger
run_without_scenarios(*args, &block)
test_class.table_config.loaded_scenarios.each { |s| s.unload } if test_class.table_config
end
alias_method_chain :run, :scenarios
end
suite.test_class = self
suite
end
alias_method_chain :suite, :scenarios
end
# Hook into fixtures loading lifecycle to instead load scenarios. This
# is expected to be called in a fashion respective of
# use_transactional_fixtures. I feel like a leech.
def load_fixtures
if !scenarios_loaded? || !use_transactional_fixtures?
self.class.table_config = Scenarios::Configuration.new if !use_transactional_fixtures? || table_config.nil?
load_scenarios(scenario_classes)
end
self.extend scenario_helpers
self.extend table_readers
end
# Here we are counting on existing logic to allow teardown method
# overriding as done in fixtures.rb. Only if transaction fixtures are
# not being used do we unload scenarios after a test. Otherwise, we wait
# until the end of the run of all tests on this test_case (collection of
# tests, right!). See the TestSuite extension done in _suite_ for
# behaviour when using transaction fixtures.
def teardown_with_scenarios
teardown_without_scenarios
loaded_scenarios.each { |s| s.unload } unless use_transactional_fixtures?
end
alias_method_chain :teardown, :scenarios
end
end
end

View file

@ -1,51 +0,0 @@
module Scenarios
# Provides scenario loading and convenience methods around the Configuration
# that must be made available through a method _table_config_.
module Loading # :nodoc:
def load_scenarios(scenario_classes)
install_active_record_tracking_hook
scenario_classes.each do |scenario_class|
scenario = scenario_class.new(table_config)
scenario.load
table_config.loaded_scenarios << scenario
end if scenario_classes
end
def loaded_scenarios
table_config.loaded_scenarios
end
def scenarios_loaded?
table_config && table_config.scenarios_loaded?
end
# The sum of all the loaded scenario's helper methods. These can be mixed
# into anything you like to gain access to them.
def scenario_helpers
table_config.scenario_helpers
end
# The sum of all the available table reading methods. These will only
# include readers for which data has been placed into the table. These can
# be mixed into anything you like to gain access to them.
def table_readers
table_config.table_readers
end
# # This understand nesting descriptions one deep
# def table_config
# on_my_class = self.class.instance_variable_get("@table_config")
# return on_my_class if on_my_class
#
# if self.class.superclass
# on_super_class = self.class.superclass.instance_variable_get("@table_config")
# return on_super_class if on_super_class
# end
# end
private
def install_active_record_tracking_hook
ActiveRecord::Base.table_config = table_config
end
end
end

View file

@ -1,20 +0,0 @@
module Scenarios
module TableBlasting
def self.included(base)
base.module_eval do
delegate :blasted_tables, :to => :table_config
end
end
def blast_table(name) # :nodoc:
ActiveRecord::Base.silence do
ActiveRecord::Base.connection.delete "DELETE FROM #{name}", "Scenario Delete"
end
blasted_tables << name
end
def prepare_table(name)
blast_table(name) unless blasted_tables.include?(name)
end
end
end

View file

@ -1,205 +0,0 @@
module Scenarios
# This helper module contains the #create_record method. It is made
# available to all Scenario instances, test and example classes, and test
# and example instances.
module TableMethods
include TableBlasting
delegate :record_metas, :to => :table_config
# Insert a record into the database, add the appropriate helper methods
# into the scenario and spec, and return the ID of the inserted record:
#
# create_record :event, :name => "Ruby Hoedown"
# create_record Event, :hoedown, :name => "Ruby Hoedown"
#
# The first form will create a new record in the given class identifier
# and no symbolic name (essentially).
#
# The second form is exactly like the first, except for that it provides a
# symbolic name as the second parameter. The symbolic name will allow you
# to access the record through a couple of helper methods:
#
# events(:hoedown) # The hoedown event
# event_id(:hoedown) # The ID of the hoedown event
#
# These helper methods are only accessible for a particular table after
# you have inserted a record into that table using <tt>create_record</tt>.
def create_record(class_identifier, *args)
insert(ScenarioRecord, class_identifier, *args) do |record|
meta = record.record_meta
fixture = record.to_fixture
begin
meta.connection.insert_fixture(fixture, record.record_meta.table_name)
rescue # Rails 1.2 compatible!
meta.connection.execute "INSERT INTO #{meta.table_name} (#{fixture.key_list}) VALUES (#{fixture.value_list})"
end
record.id
end
end
# Instantiate and save! a model, add the appropriate helper methods into
# the scenario and spec, and return the new model instance:
#
# create_model :event, :name => "Ruby Hoedown"
# create_model Event, :hoedown, :name => "Ruby Hoedown"
#
# The first form will create a new model with no symbolic name
# (essentially).
#
# The second form is exactly like the first, except for that it provides a
# symbolic name as the second parameter. The symbolic name will allow you
# to access the record through a couple of helper methods:
#
# events(:hoedown) # The hoedown event
# event_id(:hoedown) # The ID of the hoedown event
#
# These helper methods are only accessible for a particular table after
# you have inserted a record into that table using <tt>create_model</tt>.
def create_model(class_identifier, *args)
insert(ScenarioModel, class_identifier, *args) do |record|
model = record.to_model
model.save!
model
end
end
private
def insert(record_or_model, class_identifier, *args, &insertion)
symbolic_name, attributes = extract_creation_arguments(args)
record_meta = (record_metas[class_identifier] ||= RecordMeta.new(class_identifier))
record = record_or_model.new(record_meta, attributes, symbolic_name)
return_value = nil
ActiveRecord::Base.silence do
prepare_table(record_meta.table_name)
return_value = insertion.call record
table_config.update_table_readers(record)
self.extend table_config.table_readers
end
return_value
end
def extract_creation_arguments(arguments)
if arguments.size == 2 && arguments.last.kind_of?(Hash)
arguments
elsif arguments.size == 1 && arguments.last.kind_of?(Hash)
[nil, arguments[0]]
else
[nil, Hash.new]
end
end
class RecordMeta # :nodoc:
attr_reader :class_name, :record_class, :table_name
def initialize(class_identifier)
@class_identifier = class_identifier
@class_name = resolve_class_name(class_identifier)
@record_class = class_name.constantize
@table_name = record_class.table_name
end
def timestamp_columns
@timestamp_columns ||= begin
timestamps = %w(created_at created_on updated_at updated_on)
columns.select do |column|
timestamps.include?(column.name)
end
end
end
def columns
@columns ||= connection.columns(table_name)
end
def connection
record_class.connection
end
def id_reader
@id_reader ||= begin
reader = ActiveRecord::Base.pluralize_table_names ? table_name.singularize : table_name
"#{reader}_id".to_sym
end
end
def record_reader
table_name.to_sym
end
def resolve_class_name(class_identifier)
case class_identifier
when Symbol
class_identifier.to_s.singularize.camelize
when Class
class_identifier.name
when String
class_identifier
end
end
def to_s
"#<RecordMeta: #{table_name}>"
end
end
class ScenarioModel # :nodoc:
attr_reader :attributes, :model, :record_meta, :symbolic_name
delegate :id, :to => :model
def initialize(record_meta, attributes, symbolic_name = nil)
@record_meta = record_meta
@attributes = attributes.stringify_keys
@symbolic_name = symbolic_name || object_id
end
def to_hash
to_model.attributes
end
def to_model
@model ||= record_meta.record_class.new(attributes)
end
end
class ScenarioRecord # :nodoc:
attr_reader :record_meta, :symbolic_name
def initialize(record_meta, attributes, symbolic_name = nil)
@record_meta = record_meta
@attributes = attributes.stringify_keys
@symbolic_name = symbolic_name || object_id
install_default_attributes!
end
def id
@attributes['id']
end
def to_hash
@attributes
end
def to_fixture
Fixture.new(to_hash, record_meta.class_name)
end
def install_default_attributes!
@attributes['id'] ||= symbolic_name.to_s.hash.abs
install_timestamps!
end
def install_timestamps!
record_meta.timestamp_columns.each do |column|
@attributes[column.name] = now(column) unless @attributes.key?(column.name)
end
end
def now(column)
now = ActiveRecord::Base.default_timezone == :utc ? column.klass.now.utc : column.klass.now
now.to_s(:db)
end
end
end
end

View file

@ -1,9 +0,0 @@
class ComplexCompositeScenario < Scenario::Base
uses :composite, :places
helpers do
def method_from_complex_composite_scenario
:method_from_complex_composite_scenario
end
end
end

View file

@ -1,9 +0,0 @@
class CompositeScenario < Scenario::Base
uses :people, :things
helpers do
def method_from_composite_scenario
:method_from_composite_scenario
end
end
end

View file

@ -1,4 +0,0 @@
class EmptyScenario < Scenario::Base
def load
end
end

View file

@ -1,26 +0,0 @@
class PeopleScenario < Scenario::Base
def load
create_person "John Long"
create_person "Adam Williams"
end
helpers do
def create_person(attributes = {})
if attributes.kind_of?(String)
first, last = attributes.split(/\s+/)
attributes = { :first_name => first, :last_name => last }
end
attributes = person_params(attributes)
create_record(:person, attributes[:first_name].strip.gsub(' ', '_').underscore.to_sym, attributes)
end
def person_params(attributes = {})
attributes = {
:first_name => "John",
:last_name => "Q."
}.update(attributes)
end
end
end

View file

@ -1,22 +0,0 @@
class PlacesScenario < Scenario::Base
def load
create_place "Taj Mahal", "India"
create_place "Whitehouse", "Washington DC"
end
helpers do
def create_place(name, location)
attributes = place_params(:name => name, :location => location)
create_record(:place, name.strip.gsub(' ', '_').underscore.to_sym, attributes)
end
def place_params(attributes = {})
attributes = {
:name => "Noplace",
:location => "Nowhere"
}.update(attributes)
end
end
end

View file

@ -1,22 +0,0 @@
class ThingsScenario < Scenario::Base
def load
create_thing "one"
create_thing "two"
end
helpers do
def create_thing(attributes = {})
attributes = { :name => attributes } if attributes.kind_of?(String)
attributes = thing_params(attributes)
create_record(:thing, attributes[:name].strip.gsub(' ', '_').underscore.to_sym, attributes)
end
def thing_params(attributes = {})
attributes = {
:name => "Unnamed Thing",
:description => "I'm not sure what this is."
}.update(attributes)
end
end
end

View file

@ -1,185 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
class ExplodesOnSecondInstantiationScenario < Scenario::Base
cattr_accessor :instance
def initialize(*args)
raise "Should only be created once" if self.class.instance
self.class.instance = super(*args)
end
end
describe "Scenario loading" do
scenario :explodes_on_second_instantiation
it "should work" do
end
it 'should work again' do
end
end
describe "Scenario loading" do
it "should load from configured directories" do
Scenario.load(:empty)
EmptyScenario
end
it "should raise Scenario::NameError when the scenario does not exist" do
lambda { Scenario.load(:whatcha_talkin_bout) }.should raise_error(Scenario::NameError)
end
it "should allow us to add helper methods through the helpers class method" do
klass = :empty.to_scenario
klass.helpers do
def hello
"Hello World"
end
end
klass.new.methods.should include('hello')
end
it "should provide a built-in scenario named :blank which clears all tables found in schema.rb" do
Scenario.load(:blank)
BlankScenario
end
end
describe Scenarios::TableMethods do
scenario :things
it "should understand namespaced models" do
create_record "ModelModule::Model", :raking, :name => "Raking", :description => "Moving leaves around"
models(:raking).should_not be_nil
end
it "should include record creation methods" do
create_record(:thing, :three, :name => "Three")
things(:three).name.should == "Three"
end
it "should include other example helper methods" do
create_thing("The Thing")
things(:the_thing).name.should == "The Thing"
end
describe "for retrieving objects" do
it "should have a pluralized name" do
should respond_to("things")
should_not respond_to("thing")
end
it "should answer a single object given a single name" do
things(:one).should be_kind_of(Thing)
things("one").should be_kind_of(Thing)
things(:two).name.should == "two"
end
it "should answer an array of objects given multiple names" do
things(:one, :two).should be_kind_of(Array)
things(:one, :two).should eql([things(:one), things(:two)])
end
it "should just return the argument if an AR instance is given" do
thing = things(:one)
things(thing).should eql(thing)
end
end
describe "for retrieving ids" do
it "should have a singular name" do
should respond_to("thing_id")
should_not respond_to("thing_ids")
should_not respond_to("things_id")
end
it "should answer a single id given a single name" do
thing_id(:one).should be_kind_of(Fixnum)
thing_id("one").should be_kind_of(Fixnum)
end
it "should answer an array of ids given multiple names" do
thing_id(:one, :two).should be_kind_of(Array)
thing_id(:one, :two).should eql([thing_id(:one), thing_id(:two)])
thing_id("one", "two").should eql([thing_id(:one), thing_id(:two)])
end
it "should answer the id of the argument if an AR instance id given" do
thing = things(:one)
thing_id(thing).should == thing.id
end
end
end
describe "it uses people and things scenarios", :shared => true do
it "should have reader helper methods for each used scenario" do
should respond_to(:things)
should respond_to(:people)
end
it "should allow us to use helper methods from each scenario inside an example" do
should respond_to(:create_thing)
should respond_to(:create_person)
end
end
describe "A composite scenario" do
scenario :composite
it_should_behave_like "it uses people and things scenarios"
it "should allow us to use helper methods scenario" do
should respond_to(:method_from_composite_scenario)
end
end
describe "Multiple scenarios" do
scenario :things, :people
it_should_behave_like "it uses people and things scenarios"
end
describe "A complex composite scenario" do
scenario :complex_composite
it_should_behave_like "it uses people and things scenarios"
it "should have correct reader helper methods" do
should respond_to(:places)
end
it "should allow us to use correct helper methods" do
should respond_to(:create_place)
end
end
describe "Overlapping scenarios" do
scenario :composite, :things, :people
it "should not cause scenarios to be loaded twice" do
Person.find_all_by_first_name("John").size.should == 1
end
end
describe "create_record table method" do
scenario :empty
it "should automatically set timestamps" do
create_record :note, :first, :content => "first note"
note = notes(:first)
note.created_at.should be_instance_of(Time)
end
end
describe "create_model table method" do
scenario :empty
it "should support symbolic names" do
thing = create_model Thing, :mything, :name => "My Thing", :description => "For testing"
things(:mything).should == thing
end
it "should blast any table touched as a side effect of creating a model (callbacks, observers, etc.)" do
create_model SideEffectyThing
blasted_tables.should include(Thing.table_name)
end
end

View file

@ -1,7 +0,0 @@
--colour
--format
progress
--loadby
mtime
--reverse
--backtrace

View file

@ -1,24 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + '/../testing/plugit_descriptor')
TESTING_ROOT = File.expand_path("#{File.dirname(__FILE__)}/../testing")
TESTING_TMP = "#{TESTING_ROOT}/tmp"
require 'fileutils'
FileUtils.mkdir_p(TESTING_TMP)
FileUtils.touch("#{TESTING_TMP}/test.log")
require 'logger'
RAILS_DEFAULT_LOGGER = Logger.new("#{TESTING_TMP}/test.log")
RAILS_DEFAULT_LOGGER.level = Logger::DEBUG
ActiveRecord::Base.silence do
ActiveRecord::Base.configurations = {'sqlite3' => {
'adapter' => 'sqlite3',
'database' => "#{TESTING_TMP}/sqlite3.db"
}}
ActiveRecord::Base.establish_connection 'sqlite3'
load "#{TESTING_ROOT}/schema.rb"
end
require "models"
require "scenarios"

View file

@ -1,19 +0,0 @@
namespace :db do
namespace :scenario do
desc "Load a scenario into the current environment's database using SCENARIO=scenario_name"
task :load => 'db:reset' do
scenario_name = ENV['SCENARIO'] || 'default'
begin
klass = Scenarios.load(scenario_name)
puts "Loaded #{klass.name.underscore.gsub('_', ' ')}."
rescue Scenarios::NameError => e
if scenario_name == 'default'
puts "Error! Set the SCENARIO environment variable or define a DefaultScenario class."
else
puts "Error! Invalid scenario name [#{scenario_name}]."
end
exit(1)
end
end
end
end

View file

@ -1,2 +0,0 @@
class ApplicationController < ActionController::Base
end

View file

@ -1,14 +0,0 @@
class Person < ActiveRecord::Base; end
class Place < ActiveRecord::Base; end
class Thing < ActiveRecord::Base; end
class Note < ActiveRecord::Base; end
class SideEffectyThing < ActiveRecord::Base
after_create do
Thing.create!
end
end
module ModelModule
class Model < ActiveRecord::Base; end
end

View file

@ -1,44 +0,0 @@
require 'rubygems'
gem 'plugit'
require 'plugit'
$LOAD_PATH << File.expand_path("#{File.dirname(__FILE__)}/../lib")
$LOAD_PATH << File.expand_path(File.dirname(__FILE__))
RAILS_ROOT = File.expand_path("#{File.dirname(__FILE__)}/..")
Plugit.describe do |scenarios|
scenarios.environments_root_path = File.dirname(__FILE__) + '/environments'
vendor_directory = File.expand_path(File.dirname(__FILE__) + '/../vendor/plugins')
scenarios.environment :default, 'Released versions of Rails and RSpec' do |env|
env.library :rails, :export => "git clone git://github.com/rails/rails.git" do |rails|
rails.after_update { `git co v2.1.0_RC1` }
rails.load_paths = %w{/activesupport/lib /activerecord/lib /actionpack/lib}
rails.requires = %w{active_support active_record action_controller action_view}
end
env.library :rspec, :export => "git clone git://github.com/dchelimsky/rspec.git" do |rspec|
rspec.after_update { `git co 1.1.4 && mkdir -p #{vendor_directory} && ln -sF #{File.expand_path('.')} #{vendor_directory + '/rspec'}` }
rspec.requires = %w{spec}
end
env.library :rspec_rails, :export => "git clone git://github.com/dchelimsky/rspec-rails.git" do |rspec_rails|
rspec_rails.after_update { `git co 1.1.4` }
rspec_rails.requires = %w{spec/rails}
end
end
scenarios.environment :edge, 'Edge versions of Rails and RSpec' do |env|
env.library :rails, :export => "git clone git://github.com/rails/rails.git --depth 1" do |rails|
rails.before_install { `git pull` }
rails.load_paths = %w{/activesupport/lib /activerecord/lib /actionpack/lib}
rails.requires = %w{active_support active_record action_controller action_view}
end
env.library :rspec, :export => "git clone git://github.com/dchelimsky/rspec.git --depth 1" do |rspec|
rspec.after_update { `git pull && mkdir -p #{vendor_directory} && ln -sF #{File.expand_path('.')} #{vendor_directory + '/rspec'}` }
rspec.requires = %w{spec}
end
env.library :rspec_rails, :export => "git clone git://github.com/dchelimsky/rspec-rails.git --depth 1" do |rspec_rails|
rspec_rails.after_update { `git pull` }
rspec_rails.requires = %w{spec/rails}
end
end
end

View file

@ -1,31 +0,0 @@
ActiveRecord::Schema.define do
create_table :people, :force => true do |t|
t.column :first_name, :string
t.column :last_name, :string
end
create_table :places, :force => true do |t|
t.column :name, :string
t.column :location, :string
end
create_table :things, :force => true do |t|
t.column :name, :string
t.column :description, :string
end
create_table :side_effecty_things, :force => true do |t|
end
create_table :models, :force => true do |t|
t.column :name, :string
t.column :description, :string
end
create_table :notes, :force => true do |t|
t.column :content, :string
t.column :created_at, :datetime
t.column :updated_at, :datetime
end
end