laurynasl-hornsby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,98 @@
1
+ Hornsby
2
+ =======
3
+ A Scenario Builder without the fixture pain.
4
+
5
+ Scenarios look like:
6
+
7
+ scenario :apple do
8
+ @apple = Fruit.create! :species => 'apple'
9
+ end
10
+
11
+ scenario :orange do
12
+ @orange = Fruit.create! :species => 'orange'
13
+ end
14
+
15
+ scenario :fruitbowl => [:apple,:orange] do
16
+ @fruitbowl = FruitBowl.create! :fruit => [@apple,@orange]
17
+ end
18
+
19
+ scenario :kitchen => :fruitbowl do
20
+ @kitchen = Kitchen.create! :fruitbowl => @fruitbowl
21
+ end
22
+
23
+ ...and you use them in specs like:
24
+
25
+ describe Fruit, "@apple" do
26
+ before do
27
+ hornsby_scenario :apple
28
+ end
29
+
30
+ it "should be an apple" do
31
+ @apple.species.should == 'apple'
32
+ end
33
+ end
34
+
35
+ describe FruitBowl, "with and apple and an orange" do
36
+ before do
37
+ hornsby_scenario :fruitbowl
38
+ end
39
+
40
+ it "should have 2 fruits" do
41
+ @fruitbowl.should have(2).fruit
42
+ end
43
+ end
44
+
45
+ Setup
46
+ =====
47
+ Install the plugin:
48
+
49
+ ./script/plugin install http://rails-oceania.googlecode.com/svn/lachiecox/hornsby
50
+
51
+ Or piston:
52
+
53
+ piston import http://rails-oceania.googlecode.com/svn/lachiecox/hornsby vendor/plugins/hornsby
54
+
55
+ Add the following to spec_helper.rb
56
+
57
+ # by default this loads scenarios from RAILS_ROOT/spec/hornsby_scenarios.rb
58
+ Hornsby.load
59
+
60
+ Spec::Runner.configure do |config|
61
+ ...
62
+
63
+ config.include(HornsbySpecHelper)
64
+ end
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
+ Rake
79
+ ====
80
+ If you'd like simply to load your scenarios into a database, use the rake task like so:
81
+
82
+ $ rake hornsby:scenario RAILS_ENV=test SCENARIO=fruitbowl
83
+
84
+ TODO
85
+ ====
86
+ * Make transactional for speed.
87
+ * Add scenario namespaces for better organisation.
88
+ * Detect scenario cycles.
89
+
90
+ Credits
91
+ =======
92
+ Lachie Cox <lachie@smartbomb.com.au>
93
+
94
+ The code is based on Err's code found in this post: http://errtheblog.com/post/7708
95
+
96
+ License
97
+ =======
98
+ MIT, see LICENCE
@@ -0,0 +1,179 @@
1
+ #require File.dirname(__FILE__) + '/detect_framework'
2
+ require 'yaml'
3
+
4
+ if defined?(Merb::Plugins)
5
+ Merb::Plugins.add_rakefiles "hornsby" / "tasks"
6
+ end
7
+
8
+ class Hornsby
9
+ @@record_name_fields = %w( name title username login )
10
+ @@delete_sql = "DELETE FROM %s"
11
+
12
+ cattr_reader :scenarios
13
+ cattr_accessor :tables_to_delete
14
+ cattr_accessor :orm
15
+ @@scenarios = {}
16
+
17
+ def self.build(names, receiver_context)
18
+ delete_tables
19
+
20
+ context = Module.new
21
+ ivars = context.instance_variables
22
+ @@completed_scenarios = []
23
+
24
+ names.each do |name|
25
+ scenario = @@scenarios[name.to_sym] or raise "scenario #{name} not found"
26
+ scenario.build(context)
27
+ end
28
+
29
+ context_ivars = context.instance_variables - ivars
30
+ context_ivars.each do |iv|
31
+ receiver_context.instance_variable_set(iv, context.instance_variable_get(iv))
32
+ end
33
+ end
34
+
35
+ def self.[](name)
36
+ end
37
+
38
+ #def self.load(scenarios_file=nil)
39
+ def self.load
40
+ return unless @@scenarios.empty?
41
+
42
+ root = RAILS_ROOT rescue Merb.root.to_s
43
+
44
+ if File.exists?('.hornsby')
45
+ config = YAML.load(IO.read('.hornsby'))
46
+ scenarios_file = config['filename']
47
+ @@orm = config['orm'].to_sym if config['orm']
48
+ @@tables_to_delete = config['tables_to_delete'].collect {|t| t.to_sym} if config['tables_to_delete']
49
+ else
50
+ #scenarios_file ||= root+'/spec/hornsby_scenarios.rb'
51
+ File.open('.hornsby', 'w') do |f|
52
+ f.write "orm: sequel\n"
53
+ f.write "filename: hornsby_scenarios.rb\n"
54
+ f.write "tables_to_delete: []\n"
55
+ end
56
+ puts "generated Hornsby configuration file at .hornsby"
57
+
58
+ if File.exists?('hornsby_scenarios.rb')
59
+ puts "looks like file hornsby_scenarios.rb exists"
60
+ else
61
+ File.open('hornsby_scenarios.rb', 'w') do |f|
62
+ f.write "# for more information, see http://github.com/laurynasl/hornsby/wikis/usage\n"
63
+ f.write "scenario :sample do\n"
64
+ f.write " \#@sample = SomeModel.create :name => \"Me\"\n"
65
+ f.write "end\n"
66
+ end
67
+ puts "created sample scenarios file at hornsby_scenarios.rb"
68
+ end
69
+ exit
70
+ end
71
+
72
+
73
+ self.module_eval File.read(scenarios_file)
74
+ end
75
+
76
+ def self.scenario(scenario,&block)
77
+ self.new(scenario, &block)
78
+ end
79
+
80
+ def self.namespace(name,&block)
81
+ end
82
+
83
+ def self.reset!
84
+ @@scenarios = {}
85
+ end
86
+
87
+ def initialize(scenario, &block)
88
+ case scenario
89
+ when Hash
90
+ parents = scenario.values.first
91
+ @parents = Array === parents ? parents : [parents]
92
+ scenario = scenario.keys.first
93
+ when Symbol, String
94
+ @parents = []
95
+ else
96
+ raise "I don't know how to build `#{scenario.inspect}'"
97
+ end
98
+
99
+ @scenario = scenario.to_sym
100
+ @block = block
101
+
102
+ @@scenarios[@scenario] = self
103
+ end
104
+
105
+ def say(*messages)
106
+ puts messages.map { |message| "=> #{message}" }
107
+ end
108
+
109
+ def build(context)
110
+ #say "Building scenario `#{@scenario}'"
111
+
112
+ build_parent_scenarios(context)
113
+ build_scenario(context)
114
+
115
+ self
116
+ end
117
+
118
+ def build_scenario(context)
119
+ return if @@completed_scenarios.include?(@scenario)
120
+ surface_errors { context.module_eval(&@block) }
121
+ @@completed_scenarios << @scenario
122
+ end
123
+
124
+ def build_parent_scenarios(context)
125
+ @parents.each do |p|
126
+ parent = self.class.scenarios[p] or raise "parent scenario [#{p}] not found!"
127
+
128
+ parent.build_parent_scenarios(context)
129
+ parent.build_scenario(context)
130
+ end
131
+ end
132
+
133
+
134
+ def surface_errors
135
+ yield
136
+ rescue Object => error
137
+ puts
138
+ say "There was an error building scenario `#{@scenario}'", error.inspect
139
+ puts
140
+ puts error.backtrace
141
+ puts
142
+ raise error
143
+ end
144
+
145
+ def self.delete_tables
146
+ if @@orm == :activerecord
147
+ tables.each { |t| ActiveRecord::Base.connection.delete(@@delete_sql % t) }
148
+ elsif @@orm == :datamapper
149
+ DataMapper::Resource.descendants.each do |klass|
150
+ #klass.auto_migrate!
151
+ klass.all.destroy!
152
+ end
153
+ elsif @@orm == :sequel
154
+ tables = (Sequel::Model.db.tables - [:schema_info])
155
+ tables = (@@tables_to_delete||[]) + (tables - (@@tables_to_delete||[]))
156
+ tables.each do |t|
157
+ Sequel::Model.db << (@@delete_sql % t)
158
+ end
159
+ else
160
+ raise "Hornsby.orm must be set to either :activerecord, :datamapper or :sequel"
161
+ end
162
+ end
163
+
164
+ def self.tables
165
+ ActiveRecord::Base.connection.tables - skip_tables
166
+ end
167
+
168
+ def self.skip_tables
169
+ %w( schema_info )
170
+ end
171
+ end
172
+
173
+
174
+ module HornsbySpecHelper
175
+ def hornsby_scenario(*names)
176
+ Hornsby.build(names, self)
177
+ end
178
+ end
179
+ Hornsby.orm = :activerecord
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__)+'/../hornsby'
2
+
3
+ env = []
4
+ if defined?(Merb)
5
+ env = :merb_env
6
+ elsif defined?(Rails)
7
+ env = :environment
8
+ end
9
+
10
+ namespace :hornsby do
11
+
12
+ desc "Load the scenario named in the env var SCENARIO"
13
+ task :scenario => env do
14
+ raise "set SCENARIO to define which scenario to load" unless ENV['SCENARIO']
15
+ ::Hornsby.load#(ENV['FILENAME'])
16
+ #::Hornsby.orm = ENV['ORM'].to_sym if ENV['ORM']
17
+ ::Hornsby.build(ENV['SCENARIO'].split(','), self)
18
+ end
19
+
20
+ end
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/hornsby.rb'
@@ -0,0 +1,130 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.dirname(__FILE__) + '/../lib/hornsby'
3
+
4
+ class Fruit < ActiveRecord::Base
5
+ end
6
+
7
+ Hornsby.scenario(:just_apple) do
8
+ @apple = Fruit.create! :species => 'apple'
9
+ end
10
+
11
+ Hornsby.scenario(:bananas_and_apples => :just_apple) do
12
+ @banana = Fruit.create! :species => 'banana'
13
+ end
14
+
15
+ Hornsby.scenario(:just_orange) do
16
+ @orange = Fruit.create! :species => 'orange'
17
+ end
18
+
19
+ Hornsby.scenario(:fruit => [:just_apple,:just_orange]) do
20
+ @fruit = [@orange,@apple]
21
+ end
22
+
23
+ Hornsby.scenario(:bananas_and_apples_and_oranges => [:bananas_and_apples,:just_orange]) do
24
+ @fruit = [@orange,@apple,@banana]
25
+ end
26
+
27
+ Hornsby.scenario(:bananas_and_more_apples => [:just_apple, :bananas_and_apples]) do
28
+ end
29
+
30
+
31
+ # Hornsby.namespace(:pitted_fruit) do
32
+ # scenario(:peach) do
33
+ # @peach = Fruit.create! :species => 'peach'
34
+ # end
35
+ #
36
+ # scenario(:nectarine) do
37
+ # @nectarine = Fruit.create! :species => 'nectarine'
38
+ # end
39
+ # end
40
+
41
+ describe Hornsby, "with just_apple scenario" do
42
+ before do
43
+ #Hornsby.build(:just_apple).copy_ivars(self)
44
+ hornsby_scenario :just_apple
45
+ end
46
+
47
+ it "should create @apple" do
48
+ @apple.should_not be_nil
49
+ end
50
+
51
+ it "should create Fruit @apple" do
52
+ @apple.should be_instance_of(Fruit)
53
+ end
54
+
55
+ it "should not create @banana" do
56
+ @banana.should be_nil
57
+ end
58
+
59
+ it "should have correct species" do
60
+ @apple.species.should == 'apple'
61
+ end
62
+ end
63
+
64
+ describe Hornsby, "with bananas_and_apples scenario" do
65
+ before do
66
+ #Hornsby.build(:bananas_and_apples).copy_ivars(self)
67
+ hornsby_scenario :bananas_and_apples
68
+ end
69
+
70
+ it "should have correct @apple species" do
71
+ @apple.species.should == 'apple'
72
+ end
73
+
74
+ it "should have correct @banana species" do
75
+ @banana.species.should == 'banana'
76
+ end
77
+ end
78
+
79
+ describe Hornsby, "with fruit scenario" do
80
+ before do
81
+ #Hornsby.build(:fruit).copy_ivars(self)
82
+ hornsby_scenario :fruit
83
+ end
84
+
85
+ it "should have 2 fruits" do
86
+ @fruit.should have(2).items
87
+ end
88
+
89
+ it "should have an @apple" do
90
+ @apple.species.should == 'apple'
91
+ end
92
+
93
+ it "should have an @orange" do
94
+ @orange.species.should == 'orange'
95
+ end
96
+
97
+ it "should have no @banana" do
98
+ @banana.should be_nil
99
+ end
100
+ end
101
+
102
+ describe Hornsby, "don't repeat completed scenario" do
103
+ before do
104
+ #Hornsby.build(:bananas_and_more_apples).copy_ivars(self)
105
+ hornsby_scenario :bananas_and_more_apples
106
+ end
107
+
108
+ it "should create only one apple" do
109
+ Fruit.find_all_by_species('apple').size.should == 1
110
+ end
111
+ end
112
+
113
+ describe Hornsby, "run multiple scenarios" do
114
+
115
+ it "should create both apple and orange" do
116
+ hornsby_scenario :just_apple, :just_orange
117
+ @apple.should_not be_nil
118
+ @orange.should_not be_nil
119
+ end
120
+ end
121
+
122
+ #describe Hornsby, "with pitted namespace" do
123
+ # before do
124
+ # Hornsby.build('pitted:peach').copy_ivars(self)
125
+ # end
126
+
127
+ # it "should have @peach" do
128
+ # @peach.species.should == 'peach'
129
+ # end
130
+ #end
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'fileutils'
3
+ require File.dirname(__FILE__) + '/../lib/detect_framework'
4
+
5
+
6
+ if FRAMEWORK == :rails
7
+ #ORM = :activerecord
8
+
9
+ require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
10
+
11
+
12
+ elsif FRAMEWORK == :merb
13
+ #ORM = :datamapper # just assumption for now...
14
+
15
+ require File.dirname(__FILE__) + '/../../../spec/spec_helper'
16
+ require 'activerecord'
17
+ end
18
+
19
+ plugin_spec_dir = File.dirname(__FILE__)
20
+
21
+ ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log")
22
+
23
+ databases = YAML::load(IO.read(plugin_spec_dir + "/db/database.yml"))
24
+
25
+ db_info = databases[ENV["DB"] || "sqlite3"]
26
+ puts db_info.inspect
27
+
28
+ #FileUtils::rm(RAILS_ROOT+"/"+db_info[:dbfile])
29
+
30
+ ActiveRecord::Base.establish_connection(db_info)
31
+
32
+ load(File.join(plugin_spec_dir, "db", "schema.rb"))
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: laurynasl-hornsby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Laurynas Liutkus
8
+ autorequire: name
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-08-13 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.1.4
23
+ version:
24
+ description:
25
+ email: laurynasl@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - README
32
+ files:
33
+ - lib/hornsby.rb
34
+ - lib/laurynasl-hornsby.rb
35
+ - lib/hornsby/tasks.rb
36
+ - README
37
+ has_rdoc: true
38
+ homepage: http://github.com/laurynasl/hornsby/
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.2.0
60
+ signing_key:
61
+ specification_version: 2
62
+ summary: Totally different fixtures replacement
63
+ test_files:
64
+ - spec/spec_helper.rb
65
+ - spec/hornsby_spec.rb