sinsiliux-hornsby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,104 @@
1
+ = Hornsby
2
+
3
+ A Scenario Builder without the fixture pain.
4
+
5
+ == Usage
6
+
7
+ Scenarios look like:
8
+
9
+ scenario :apple do
10
+ @apple = Fruit.create! :species => 'apple'
11
+ end
12
+
13
+ scenario :orange do
14
+ @orange = Fruit.create! :species => 'orange'
15
+ end
16
+
17
+ scenario :fruitbowl => [:apple,:orange] do
18
+ @fruitbowl = FruitBowl.create! :fruit => [@apple,@orange]
19
+ end
20
+
21
+ scenario :kitchen => :fruitbowl do
22
+ @kitchen = Kitchen.create! :fruitbowl => @fruitbowl
23
+ end
24
+
25
+ ...and you use them in specs like:
26
+
27
+ describe Fruit, "@apple" do
28
+ before do
29
+ hornsby_scenario :apple
30
+ end
31
+
32
+ it "should be an apple" do
33
+ @apple.species.should == 'apple'
34
+ end
35
+ end
36
+
37
+ describe FruitBowl, "with and apple and an orange" do
38
+ before do
39
+ hornsby_scenario :fruitbowl
40
+ end
41
+
42
+ it "should have 2 fruits" do
43
+ @fruitbowl.should have(2).fruit
44
+ end
45
+ end
46
+
47
+ == Setup
48
+
49
+ Install the plugin:
50
+
51
+ ./script/plugin install git://github.com/lachie/hornsby.git
52
+
53
+ Add the following to spec_helper.rb
54
+
55
+ # by default this loads scenarios from RAILS_ROOT/spec/hornsby_scenarios.rb
56
+ Spec::Runner.configure do |config|
57
+ ...
58
+
59
+ Hornsby.configure_rspec(config, :filename => 'scenarios.rb', :scenarios => :preloaded_scenario)
60
+ end
61
+
62
+ configure_rspec supports two parameters:
63
+ * filename - file with hornsby scenarios
64
+ * scenarios - list of hornsby scenarios that should be preloaded (available in all tests, never reloaded so they're much faster)
65
+
66
+
67
+ == Advanced Usage
68
+
69
+ Its just ruby, right? So go nuts:
70
+
71
+ 1.upto(9) do |i|
72
+ scenario("user_#{i}") do
73
+ user = User.create! :name => "user#{i}"
74
+ instance_variable_set("@user_#{i}",user)
75
+ end
76
+ end
77
+
78
+ == Transactions
79
+
80
+ Hornsby scenarios is transactional, meaning that after every test transaction is dropped and database is reset to
81
+ starting point. Starting point is empty database + any scenarios that you specify in configure_rspec.
82
+
83
+ == Rake
84
+
85
+ If you'd like simply to load your scenarios into a database, use the rake task like so:
86
+
87
+ $ rake hornsby:scenario RAILS_ENV=test SCENARIO=fruitbowl
88
+
89
+ == TODO
90
+
91
+ * Add scenario namespaces for better organisation.
92
+ * Detect scenario cycles.
93
+
94
+ == Credits
95
+
96
+ Lachie Cox <lachie@smartbomb.com.au>
97
+
98
+ Andrius Chamentauskas <sinsiliux@gmail.com>
99
+
100
+ The code is based on Err's code found in this post: http://errtheblog.com/post/7708
101
+
102
+ == License
103
+
104
+ MIT, see LICENCE
data/lib/hornsby.rb ADDED
@@ -0,0 +1,167 @@
1
+ class Hornsby
2
+ @@record_name_fields = %w( name title username login )
3
+ @@delete_sql = "DELETE FROM %s"
4
+
5
+ def self.framework_root
6
+ if const_defined?(:RAILS_ROOT)
7
+ puts "rails root"
8
+ RAILS_ROOT
9
+ elsif const_defined?(:Merb)
10
+ puts "merb"
11
+ Merb.root
12
+ elsif const_defined?('Rails')
13
+ Rails.root
14
+ end
15
+ end
16
+
17
+ cattr_reader :scenarios
18
+ @@scenarios = {}
19
+ cattr_reader :global_scenarios
20
+ # @@namespaces = {}
21
+
22
+ def self.configure_rspec(config, options = {})
23
+ load(options[:filename])
24
+
25
+ @@global_scenarios = Hornsby.build(options[:scenarios]) if options[:scenarios]
26
+
27
+ config.include(HornsbySpecHelper)
28
+
29
+ config.before do
30
+ @@global_scenarios.each {|s| s.copy_ivars(self)} if @@global_scenarios
31
+ ActiveRecord::Base.connection.increment_open_transactions
32
+ ActiveRecord::Base.connection.transaction_joinable = false
33
+ ActiveRecord::Base.connection.begin_db_transaction
34
+ end
35
+
36
+ config.after do
37
+ ActiveRecord::Base.connection.rollback_db_transaction
38
+ ActiveRecord::Base.connection.decrement_open_transactions
39
+ end
40
+ end
41
+
42
+ def self.build(*names)
43
+ scenarios = names.map {|name| @@scenarios[name.to_sym] or raise "scenario #{name} not found"}
44
+
45
+ scenarios.each {|s| s.build}
46
+ end
47
+
48
+ def self.[](name)
49
+ end
50
+
51
+ def self.load(scenarios_file=nil)
52
+ delete_tables
53
+ return unless @@scenarios.empty?
54
+
55
+ scenarios_file ||= framework_root + '/spec/hornsby_scenarios.rb'
56
+ self.module_eval File.read(scenarios_file)
57
+ end
58
+
59
+ def self.scenario(scenario,&block)
60
+ self.new(scenario, &block)
61
+ end
62
+
63
+ def self.namespace(name,&block)
64
+ end
65
+
66
+ def self.reset!
67
+ @@scenarios = {}
68
+ end
69
+
70
+ def initialize(scenario, &block)
71
+ case scenario
72
+ when Hash
73
+ parents = scenario.values.first
74
+ @parents = Array === parents ? parents : [parents]
75
+ scenario = scenario.keys.first
76
+ when Symbol, String
77
+ @parents = []
78
+ else
79
+ raise "I don't know how to build `#{scenario.inspect}'"
80
+ end
81
+
82
+ @scenario = scenario.to_sym
83
+ @block = block
84
+
85
+ @@scenarios[@scenario] = self
86
+ end
87
+
88
+ def say(*messages)
89
+ puts messages.map { |message| "=> #{message}" }
90
+ end
91
+
92
+ def build
93
+ #say "Building scenario `#{@scenario}'"
94
+ @context = context = Module.new
95
+
96
+ # TODO move this elsewhere
97
+ context.module_eval do
98
+ def self.method_missing(meth_id,*args,&block)
99
+ begin
100
+ rec = meth_id.to_s.classify.constantize.send(:create!, *args)
101
+ yield(rec) if block_given?
102
+ rescue
103
+ super
104
+ end
105
+ end
106
+ end
107
+
108
+ ivars = context.instance_variables
109
+
110
+ build_parent_scenarios(context)
111
+ build_scenario(context)
112
+
113
+ @context_ivars = context.instance_variables - ivars
114
+
115
+ self
116
+ end
117
+
118
+ def build_scenario(context)
119
+ surface_errors { context.module_eval(&@block) }
120
+ end
121
+
122
+ def build_parent_scenarios(context)
123
+ @parents.each do |p|
124
+ parent = self.class.scenarios[p] or raise "parent scenario [#{p}] not found!"
125
+
126
+ parent.build_parent_scenarios(context)
127
+ parent.build_scenario(context)
128
+ end
129
+ end
130
+
131
+
132
+ def surface_errors
133
+ yield
134
+ rescue Object => error
135
+ puts
136
+ say "There was an error building scenario `#{@scenario}'", error.inspect
137
+ puts
138
+ puts error.backtrace
139
+ puts
140
+ raise error
141
+ end
142
+
143
+ def self.delete_tables
144
+ tables.each { |t| ActiveRecord::Base.connection.delete(@@delete_sql % t) }
145
+ end
146
+
147
+ def self.tables
148
+ ActiveRecord::Base.connection.tables - skip_tables
149
+ end
150
+
151
+ def self.skip_tables
152
+ %w( schema_info )
153
+ end
154
+
155
+ def copy_ivars(to)
156
+ @context_ivars.each do |iv|
157
+ to.instance_variable_set(iv, @context.instance_variable_get(iv))
158
+ end
159
+ end
160
+ end
161
+
162
+
163
+ module HornsbySpecHelper
164
+ def hornsby_scenario(*names)
165
+ Hornsby.build(*names).each {|s| s.copy_ivars(self)}
166
+ end
167
+ end
@@ -0,0 +1,103 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class Fruit < ActiveRecord::Base
4
+ end
5
+
6
+ Hornsby.scenario(:just_apple) do
7
+ @apple = Fruit.create! :species => 'apple'
8
+ end
9
+
10
+ Hornsby.scenario(:bananas_and_apples => :just_apple) do
11
+ @banana = Fruit.create! :species => 'banana'
12
+ end
13
+
14
+ Hornsby.scenario(:just_orange) do
15
+ @orange = Fruit.create! :species => 'orange'
16
+ end
17
+
18
+ Hornsby.scenario(:fruit => [:just_apple,:just_orange]) do
19
+ @fruit = [@orange,@apple]
20
+ end
21
+
22
+ Hornsby.scenario(:bananas_and_apples_and_oranges => [:bananas_and_apples,:just_orange]) do
23
+ @fruit = [@orange,@apple,@banana]
24
+ end
25
+
26
+
27
+ # Hornsby.namespace(:pitted_fruit) do
28
+ # scenario(:peach) do
29
+ # @peach = Fruit.create! :species => 'peach'
30
+ # end
31
+ #
32
+ # scenario(:nectarine) do
33
+ # @nectarine = Fruit.create! :species => 'nectarine'
34
+ # end
35
+ # end
36
+
37
+ describe Hornsby, "with just_apple scenario" do
38
+ before do
39
+ Hornsby.build(:just_apple).each {|s| s.copy_ivars(self)}
40
+ end
41
+
42
+ it "should create @apple" do
43
+ @apple.should_not be_nil
44
+ end
45
+
46
+ it "should create Fruit @apple" do
47
+ @apple.should be_instance_of(Fruit)
48
+ end
49
+
50
+ it "should not create @banana" do
51
+ @banana.should be_nil
52
+ end
53
+
54
+ it "should have correct species" do
55
+ @apple.species.should == 'apple'
56
+ end
57
+ end
58
+
59
+ describe Hornsby, "with bananas_and_apples scenario" do
60
+ before do
61
+ Hornsby.build(:bananas_and_apples).each {|s| s.copy_ivars(self)}
62
+ end
63
+
64
+ it "should have correct @apple species" do
65
+ @apple.species.should == 'apple'
66
+ end
67
+
68
+ it "should have correct @banana species" do
69
+ @banana.species.should == 'banana'
70
+ end
71
+ end
72
+
73
+ describe Hornsby, "with fruit scenario" do
74
+ before do
75
+ Hornsby.build(:fruit).each {|s| s.copy_ivars(self)}
76
+ end
77
+
78
+ it "should have 2 fruits" do
79
+ @fruit.should have(2).items
80
+ end
81
+
82
+ it "should have an @apple" do
83
+ @apple.species.should == 'apple'
84
+ end
85
+
86
+ it "should have an @orange" do
87
+ @orange.species.should == 'orange'
88
+ end
89
+
90
+ it "should have no @banana" do
91
+ @banana.should be_nil
92
+ end
93
+ end
94
+
95
+ #describe Hornsby, "with pitted namespace" do
96
+ # before do
97
+ # Hornsby.build('pitted:peach').copy_ivars(self)
98
+ # end
99
+
100
+ # it "should have @peach" do
101
+ # @peach.species.should == 'peach'
102
+ # end
103
+ #end
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
3
+
4
+ plugin_spec_dir = File.dirname(__FILE__)
5
+
6
+ ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log")
7
+
8
+ databases = YAML::load(IO.read(plugin_spec_dir + "/db/database.yml"))
9
+
10
+ db_info = databases[ENV["DB"] || "sqlite3"]
11
+
12
+ FileUtils::rm(RAILS_ROOT+"/"+db_info[:dbfile])
13
+
14
+ ActiveRecord::Base.establish_connection(db_info)
15
+
16
+ load(File.join(plugin_spec_dir, "db", "schema.rb"))
17
+
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__)+'/../lib/hornsby'
2
+
3
+ namespace :hornsby do
4
+
5
+ desc "Load the scenario named in the env var SCENARIO"
6
+ task :scenario => :environment do
7
+ raise "set SCENARIO to define which scenario to load" unless ENV['SCENARIO']
8
+ ::Hornsby.load
9
+ ::Hornsby.build(ENV['SCENARIO'])
10
+ end
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinsiliux-hornsby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrius Chamentauskas
8
+ - Lachie Cox
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-05-16 00:00:00 -07:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ type: :runtime
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 1.2.0
25
+ version:
26
+ - !ruby/object:Gem::Dependency
27
+ name: activerecord
28
+ type: :runtime
29
+ version_requirement:
30
+ version_requirements: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 2.0.0
35
+ version:
36
+ description:
37
+ email: sinsiliux@gmail.com
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - lib/hornsby.rb
46
+ - tasks/hornsby_tasks.rake
47
+ - README.rdoc
48
+ has_rdoc: false
49
+ homepage: http://github.com/sinsiliux/hornsby
50
+ post_install_message:
51
+ rdoc_options: []
52
+
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.2.0
71
+ signing_key:
72
+ specification_version: 2
73
+ summary: Fixtures replacement
74
+ test_files:
75
+ - spec/spec_helper.rb
76
+ - spec/hornsby_spec.rb