pivotal-nested_scenarios 0.2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README +224 -0
- data/Rakefile +12 -0
- data/lib/nested_scenarios.rb +11 -0
- data/lib/nested_scenarios/builder.rb +171 -0
- data/lib/nested_scenarios/fixtures.rb +170 -0
- data/lib/nested_scenarios/join.rb +36 -0
- data/lib/nested_scenarios/nested_scenarios.rb +20 -0
- data/tasks/builder_tasks.rake +24 -0
- metadata +65 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Thomas Preston-Werner
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
NestedScenarios
|
2
|
+
License: MIT
|
3
|
+
Version: 0.2.2
|
4
|
+
|
5
|
+
Description
|
6
|
+
-----------
|
7
|
+
|
8
|
+
This plugin is based on FixtureScenarios and FixtureScenarioBuilder.
|
9
|
+
It includes both worlds in just one plugin with some fixes, new features
|
10
|
+
and Rails 2.2 and 2.3 support (check what's new session bellow).
|
11
|
+
|
12
|
+
You can check them at:
|
13
|
+
|
14
|
+
NestedScenarios
|
15
|
+
Info: http://josevalim.blogspot.com/
|
16
|
+
Git : http://github.com/josevalim/nested_scenarios
|
17
|
+
|
18
|
+
FixtureScenariosBuilder
|
19
|
+
Info: http://errtheblog.com/post/7708
|
20
|
+
SVN : svn://errtheblog.com/svn/plugins/fixture_scenarios_builder
|
21
|
+
|
22
|
+
FixtureScenarios
|
23
|
+
Info: http://code.google.com/p/fixture-scenarios/
|
24
|
+
SVN : http://fixture-scenarios.googlecode.com/svn/trunk/fixture_scenarios
|
25
|
+
|
26
|
+
|
27
|
+
Install
|
28
|
+
-------
|
29
|
+
|
30
|
+
Install Nested Scenarios is very easy. If you are using Rails 2.3.0, just do:
|
31
|
+
|
32
|
+
gem sources -a http://gems.github.com
|
33
|
+
sudo gem install josevalim-nested_scenarios
|
34
|
+
|
35
|
+
If you want it as plugin, just do:
|
36
|
+
|
37
|
+
script/plugin install git://github.com/josevalim/nested_scenarios.git
|
38
|
+
|
39
|
+
If you are running on Rails 2.2.x, you should use Nested Scenarios v0.1.1:
|
40
|
+
|
41
|
+
cd myapp
|
42
|
+
git clone git://github.com/josevalim/nested_scenarios.git
|
43
|
+
cd vendor/plugins/nested_scenarios
|
44
|
+
git checkout v0.1.1
|
45
|
+
rm -rf ./.git
|
46
|
+
|
47
|
+
|
48
|
+
Why?
|
49
|
+
----
|
50
|
+
|
51
|
+
You may, from time to time, wish to build your fixtures entirely in Ruby.
|
52
|
+
Doing so has its advantages, such as automatically created join tables
|
53
|
+
and default attributes. YAML files, however, bring with them some real
|
54
|
+
nice features in Rails which are difficult to abandon: transactional fixtures,
|
55
|
+
table_name(:key) helpers and auto-clearing between tests. This plugin allow to
|
56
|
+
get the best of both worlds.
|
57
|
+
|
58
|
+
|
59
|
+
What's new?
|
60
|
+
-----------
|
61
|
+
|
62
|
+
FixtureScenario is totally rewritten: it's lighter, smaller and faster.
|
63
|
+
|
64
|
+
FixtureScenarioBuilder was changed to expose some methods as API and it does
|
65
|
+
not try to guess anymore when you should rebuild your scenarios. You have to
|
66
|
+
call it explicitly using rake db:scenario:build.
|
67
|
+
|
68
|
+
Finally Rails 2.2 support was also added.
|
69
|
+
|
70
|
+
|
71
|
+
Usage
|
72
|
+
-----
|
73
|
+
|
74
|
+
Using the +scenario+ method within <tt>scenarios.rb</tt> file,
|
75
|
+
NestedScenarios can create your YAML fixtures automatically at run time.
|
76
|
+
|
77
|
+
Any file inside the +fixture_path+ called scenario.rb or scenarios.rb
|
78
|
+
is loaded to generating scenarios:
|
79
|
+
|
80
|
+
[RAILS_ROOT]
|
81
|
+
+-test/
|
82
|
+
+-fixtures/
|
83
|
+
+-scenarios.rb
|
84
|
+
|
85
|
+
Or:
|
86
|
+
|
87
|
+
[RAILS_ROOT]
|
88
|
+
+-spec/
|
89
|
+
+-fixtures/
|
90
|
+
+-models/
|
91
|
+
+-scenarios.rb
|
92
|
+
+-controllers/
|
93
|
+
+-scenarios.rb
|
94
|
+
+-helpers/
|
95
|
+
+-scenarios.rb
|
96
|
+
|
97
|
+
Now build your scenarios in those files, wrapping scenarios in the
|
98
|
+
+scenario+ method and providing it with the name of your scenario.
|
99
|
+
|
100
|
+
A brief example of a complete <tt>scenarios.rb</tt> file:
|
101
|
+
|
102
|
+
scenario :banned_users do
|
103
|
+
%w( Tom Chris Kevin ).each_with_index do |user, index|
|
104
|
+
User.create(:name => user, :banned => index.odd?)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
This will create a file for us:
|
109
|
+
|
110
|
+
[RAILS_ROOT]
|
111
|
+
+-test/
|
112
|
+
+-fixtures/
|
113
|
+
+-banned_users/
|
114
|
+
+-users.yml
|
115
|
+
|
116
|
+
Assuming that banned is a boolean field, our generated <tt>users.yml</tt>
|
117
|
+
file will look something like this:
|
118
|
+
|
119
|
+
chris:
|
120
|
+
name: Chris
|
121
|
+
id: "2"
|
122
|
+
banned: "1"
|
123
|
+
updated_at: 2007-05-09 09:08:04
|
124
|
+
created_at: 2007-05-09 09:08:04
|
125
|
+
kevin:
|
126
|
+
name: Kevin
|
127
|
+
id: "3"
|
128
|
+
banned: "0"
|
129
|
+
updated_at: 2007-05-09 09:08:04
|
130
|
+
created_at: 2007-05-09 09:08:04
|
131
|
+
tom:
|
132
|
+
name: Tom
|
133
|
+
id: "1"
|
134
|
+
banned: "0"
|
135
|
+
updated_at: 2007-05-09 09:08:04
|
136
|
+
created_at: 2007-05-09 09:08:04
|
137
|
+
|
138
|
+
Notice how the keys correspond to the user names. You can register fields that
|
139
|
+
can be used as fixtures names by:
|
140
|
+
|
141
|
+
NestedScenarios.record_name_fields += [ "nickname" ]
|
142
|
+
|
143
|
+
You can also assign your records to instance variables, then call +names_from_ivars!+
|
144
|
+
at the conclusion of your +scenario+ block.
|
145
|
+
|
146
|
+
scenario :foo do
|
147
|
+
@small_red_widget = Widget.create(:size => 'small', :color => 'red')
|
148
|
+
@big_blue_widget = Widget.create(:size => 'big', :color => 'blue')
|
149
|
+
|
150
|
+
names_from_ivars!
|
151
|
+
end
|
152
|
+
|
153
|
+
The above produces the following YAML:
|
154
|
+
|
155
|
+
small_red_widget:
|
156
|
+
size: small
|
157
|
+
color: red
|
158
|
+
updated_at: 2007-12-27 10:09:05
|
159
|
+
created_at: 2007-12-27 10:09:05
|
160
|
+
big_blue_widget:
|
161
|
+
size: big
|
162
|
+
color: blue
|
163
|
+
updated_at: 2007-12-27 10:19:23
|
164
|
+
created_at: 2007-12-27 10:19:23
|
165
|
+
|
166
|
+
To build the scenario you have to run:
|
167
|
+
|
168
|
+
rake db:scenario:build
|
169
|
+
|
170
|
+
NestedScenarios also allows you to nest scenarios:
|
171
|
+
|
172
|
+
scenario :models => { :users => :banned } do
|
173
|
+
User.create(:name => 'Kevin', :banned => true)
|
174
|
+
end
|
175
|
+
|
176
|
+
This will create an YAML in the following dir:
|
177
|
+
|
178
|
+
[RAILS_ROOT]
|
179
|
+
+-test/
|
180
|
+
+-fixtures/
|
181
|
+
+-models/
|
182
|
+
+-users/
|
183
|
+
+-banned/
|
184
|
+
+-users.yml
|
185
|
+
|
186
|
+
Finally, you can choose which scenario to use in your tests by:
|
187
|
+
|
188
|
+
scenario :users
|
189
|
+
|
190
|
+
Or, in the case of nested scenarios:
|
191
|
+
|
192
|
+
scenario :models => { :users => :banned }
|
193
|
+
|
194
|
+
If no scenario is sent after all, the default behaviour is adopted.
|
195
|
+
|
196
|
+
|
197
|
+
Fixtures path
|
198
|
+
-------------
|
199
|
+
|
200
|
+
If you have fixtures in your fixtures path root and you want those fixtures
|
201
|
+
to also be loaded, you can configure:
|
202
|
+
|
203
|
+
class ActiveSupport::TestCase
|
204
|
+
...
|
205
|
+
self.load_root_fixtures = true
|
206
|
+
...
|
207
|
+
end
|
208
|
+
|
209
|
+
You can disable such behaviour in your tests also, by doing:
|
210
|
+
|
211
|
+
scenario :models => { :users => :banned }, :root => false
|
212
|
+
|
213
|
+
You just have to remember if you have a scenario with fixtures for a specified
|
214
|
+
table, it will overwrite the fixtures in your root path for the same table.
|
215
|
+
|
216
|
+
Bugs and Feedback
|
217
|
+
-----------------
|
218
|
+
|
219
|
+
If you discover any bugs, please send an e-mail to jose.valim@gmail.com
|
220
|
+
If you just want to give some positive feedback or drop a line, that's fine too! =)
|
221
|
+
|
222
|
+
Copyright (c) 2009 José Valim
|
223
|
+
http://www.pagestacker.com/
|
224
|
+
http://josevalim.blogspot.com/
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Generate documentation for NestedScenarios plugin.'
|
6
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
7
|
+
rdoc.rdoc_dir = 'rdoc'
|
8
|
+
rdoc.title = 'NestedScenarios'
|
9
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
10
|
+
rdoc.rdoc_files.include('README')
|
11
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
if RAILS_ENV == 'test'
|
2
|
+
require 'test/unit/testcase'
|
3
|
+
require 'test/unit/testsuite'
|
4
|
+
require 'active_record/fixtures'
|
5
|
+
|
6
|
+
dir = File.dirname(__FILE__)
|
7
|
+
require File.join(dir, 'nested_scenarios', 'nested_scenarios')
|
8
|
+
require File.join(dir, 'nested_scenarios', 'builder')
|
9
|
+
require File.join(dir, 'nested_scenarios', 'fixtures')
|
10
|
+
require File.join(dir, 'nested_scenarios', 'join')
|
11
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
class Object
|
4
|
+
def scenario(scenario, &block)
|
5
|
+
if block.nil?
|
6
|
+
raise NoMethodError, "undefined method `scenario' for #{inspect}"
|
7
|
+
else
|
8
|
+
NestedScenarios::Builder.new(scenario, &block).build
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method :build_scenario, :scenario
|
13
|
+
end
|
14
|
+
|
15
|
+
class NestedScenarios::Builder
|
16
|
+
@@select_sql = "SELECT * FROM %s"
|
17
|
+
|
18
|
+
def initialize(scenario, &block)
|
19
|
+
case scenario
|
20
|
+
when Hash
|
21
|
+
@scenario = scenario.join('/')
|
22
|
+
when Symbol, String
|
23
|
+
@scenario = scenario.to_s
|
24
|
+
else
|
25
|
+
raise "I don't know how to build `#{scenario.inspect}'"
|
26
|
+
end
|
27
|
+
|
28
|
+
@block = block
|
29
|
+
@custom_names = {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def build
|
33
|
+
say "Building scenario `#{@scenario}'"
|
34
|
+
NestedScenarios.delete_tables
|
35
|
+
|
36
|
+
surface_errors { instance_eval(&@block) }
|
37
|
+
FileUtils.mkdir_p self.class.fixtures_dir(@scenario)
|
38
|
+
FileUtils.touch self.class.fixtures_dir(@scenario)
|
39
|
+
|
40
|
+
dump_tables
|
41
|
+
end
|
42
|
+
|
43
|
+
def names_from_ivars!
|
44
|
+
instance_values.each do |var, value|
|
45
|
+
name(var, value) if value.is_a? ActiveRecord::Base
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.fixtures_dir(*paths)
|
50
|
+
File.join(RAILS_ROOT, spec_or_test_dir, 'fixtures', *paths)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.spec_or_test_dir
|
54
|
+
File.exists?(File.join(RAILS_ROOT, 'spec')) ? 'spec' : 'test'
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.fixtures_dir_exists?(dir = @scenario)
|
58
|
+
File.exists? fixtures_dir(dir)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.fixture_file_exists?
|
62
|
+
File.exists? fixture_file
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.build_all
|
66
|
+
files = []
|
67
|
+
files += Dir.glob(NestedScenarios::Builder.fixtures_dir + '/**/scenario.rb')
|
68
|
+
files += Dir.glob(NestedScenarios::Builder.fixtures_dir + '/**/scenarios.rb')
|
69
|
+
|
70
|
+
files.each do |scenario_rb|
|
71
|
+
puts "Reading #{scenario_rb.gsub(RAILS_ROOT, '')} scenario file:"
|
72
|
+
require scenario_rb
|
73
|
+
puts
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.rebuild_all_if_needed(scenario)
|
78
|
+
@scenario = scenario
|
79
|
+
unless @automatic_build_checked
|
80
|
+
self.build_all if self.scenarios_file_changed?
|
81
|
+
@automatic_build_checked = true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.scenarios_file_changed?
|
86
|
+
can_trigger_rebuild = [
|
87
|
+
self.fixtures_dir('scenarios.rb'),
|
88
|
+
File.join(RAILS_ROOT, 'db', 'migrate')
|
89
|
+
]
|
90
|
+
|
91
|
+
can_trigger_rebuild.any? { |file| self.older_than_scenario? file }
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.older_than_scenario?(file)
|
95
|
+
scenario_dir = self.fixtures_dir(@scenario.to_s)
|
96
|
+
return true unless File.exists?(scenario_dir) # it has been deleted!
|
97
|
+
if File.exists?(file)
|
98
|
+
rebuild = File.mtime(file) > File.mtime(scenario_dir)
|
99
|
+
puts "Rebuilding Nested Scenarios: #{file} is newer than #{scenario_dir}" if rebuild
|
100
|
+
rebuild
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
protected
|
105
|
+
def say(*messages)
|
106
|
+
puts messages.map { |message| "=> #{message}" }
|
107
|
+
end
|
108
|
+
|
109
|
+
def write_fixture_file(fixture_data)
|
110
|
+
File.open(fixture_file, 'w') do |file|
|
111
|
+
file.write fixture_data.to_yaml
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def fixture_file
|
116
|
+
self.class.fixtures_dir(@scenario, "#{@table_name}.yml")
|
117
|
+
end
|
118
|
+
|
119
|
+
def surface_errors
|
120
|
+
yield
|
121
|
+
rescue Object => error
|
122
|
+
puts
|
123
|
+
say "There was an error building scenario `#{@scenario}'", error.inspect
|
124
|
+
puts
|
125
|
+
puts error.backtrace
|
126
|
+
puts
|
127
|
+
exit!
|
128
|
+
end
|
129
|
+
|
130
|
+
def name(custom_name, model_object)
|
131
|
+
key = [model_object.class.name, model_object.id]
|
132
|
+
@custom_names[key] = custom_name
|
133
|
+
model_object
|
134
|
+
end
|
135
|
+
|
136
|
+
def record_name(record_hash)
|
137
|
+
key = [@table_name.classify, record_hash['id'].to_i]
|
138
|
+
@record_names << (name = @custom_names[key] || inferred_record_name(record_hash) )
|
139
|
+
name
|
140
|
+
end
|
141
|
+
|
142
|
+
def inferred_record_name(record_hash)
|
143
|
+
NestedScenarios.record_name_fields.each do |try|
|
144
|
+
if name = record_hash[try]
|
145
|
+
inferred_name = name.underscore.gsub(/\W/, ' ').squeeze(' ').tr(' ', '_')
|
146
|
+
count = @record_names.select { |name| name == inferred_name }.size
|
147
|
+
return count.zero? ? inferred_name : "#{inferred_name}_#{count}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
"#{@table_name}_#{@row_index.succ!}"
|
152
|
+
end
|
153
|
+
|
154
|
+
def dump_tables
|
155
|
+
fixtures = NestedScenarios.tables.inject([]) do |files, @table_name|
|
156
|
+
rows = ActiveRecord::Base.connection.select_all(@@select_sql % @table_name)
|
157
|
+
next files if rows.empty?
|
158
|
+
|
159
|
+
@row_index = '000'
|
160
|
+
@record_names = []
|
161
|
+
fixture_data = rows.inject({}) do |hash, record|
|
162
|
+
hash.merge(record_name(record) => record)
|
163
|
+
end
|
164
|
+
|
165
|
+
write_fixture_file fixture_data
|
166
|
+
|
167
|
+
files + [File.basename(fixture_file)]
|
168
|
+
end
|
169
|
+
say "Built scenario `#{@scenario}' with #{fixtures.to_sentence}"
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
|
2
|
+
cattr_accessor :current_fixtures
|
3
|
+
cattr_accessor :current_test_class
|
4
|
+
|
5
|
+
def self.destroy_fixtures(table_names)
|
6
|
+
NestedScenarios.delete_tables(table_names)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Support for loading root-level fixtures: fixture cache keys based on fixture path + table name.
|
10
|
+
def self.create_fixtures(fixtures_directory, table_names, class_names = {})
|
11
|
+
table_names = [table_names].flatten.map { |n| n.to_s }
|
12
|
+
fixture_keys = table_names.inject({}){|collector, table_name| collector[table_name] = "#{fixtures_directory}/#{table_name}"; collector}
|
13
|
+
connection = block_given? ? yield : ActiveRecord::Base.connection
|
14
|
+
|
15
|
+
table_names_to_fetch = table_names.reject { |table_name| fixture_is_cached?(connection, fixture_keys[table_name]) }
|
16
|
+
unless table_names_to_fetch.empty?
|
17
|
+
ActiveRecord::Base.silence do
|
18
|
+
connection.disable_referential_integrity do
|
19
|
+
fixtures_map = {}
|
20
|
+
|
21
|
+
fixtures = table_names_to_fetch.map do |table_name|
|
22
|
+
fixtures_map[fixture_keys[table_name]] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s))
|
23
|
+
end
|
24
|
+
|
25
|
+
all_loaded_fixtures.update(fixtures_map)
|
26
|
+
|
27
|
+
connection.transaction(:requires_new => true) do
|
28
|
+
|
29
|
+
# fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures } # done elsewhere now
|
30
|
+
fixtures.each { |fixture| fixture.insert_fixtures }
|
31
|
+
|
32
|
+
# Cap primary key sequences to max(pk).
|
33
|
+
if connection.respond_to?(:reset_pk_sequence!)
|
34
|
+
table_names.each do |table_name|
|
35
|
+
connection.reset_pk_sequence!(table_name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
cache_fixtures(connection, fixtures_map)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
# cached_fixtures(connection, table_names)
|
45
|
+
cached_fixtures(connection, fixture_keys.values)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module ActiveRecord #:nodoc:
|
50
|
+
module TestFixtures #:nodoc:
|
51
|
+
|
52
|
+
def self.included(base)
|
53
|
+
base.class_eval do
|
54
|
+
setup :setup_fixtures
|
55
|
+
teardown :teardown_fixtures
|
56
|
+
|
57
|
+
superclass_delegating_accessor :fixture_path
|
58
|
+
superclass_delegating_accessor :fixture_table_names
|
59
|
+
superclass_delegating_accessor :fixture_class_names
|
60
|
+
superclass_delegating_accessor :use_transactional_fixtures
|
61
|
+
superclass_delegating_accessor :use_instantiated_fixtures # true, false, or :no_instances
|
62
|
+
superclass_delegating_accessor :pre_loaded_fixtures
|
63
|
+
|
64
|
+
self.fixture_table_names = []
|
65
|
+
self.use_transactional_fixtures = false
|
66
|
+
self.use_instantiated_fixtures = true
|
67
|
+
self.pre_loaded_fixtures = false
|
68
|
+
|
69
|
+
self.fixture_class_names = {}
|
70
|
+
|
71
|
+
superclass_delegating_accessor :scenario_path
|
72
|
+
superclass_delegating_accessor :load_root_fixtures
|
73
|
+
superclass_delegating_accessor :root_table_names
|
74
|
+
superclass_delegating_accessor :scenario_table_names
|
75
|
+
self.load_root_fixtures = false
|
76
|
+
end
|
77
|
+
|
78
|
+
base.extend ClassMethods
|
79
|
+
end
|
80
|
+
|
81
|
+
module ClassMethods
|
82
|
+
def scenario(scenario_name = nil, options = {})
|
83
|
+
NestedScenarios::Builder.rebuild_all_if_needed(scenario_name)
|
84
|
+
|
85
|
+
case scenario_name
|
86
|
+
when Hash
|
87
|
+
self.load_root_fixtures = scenario_name.delete(:root) if scenario_name.key? :root
|
88
|
+
scenario_name = scenario_name.join('/')
|
89
|
+
when Symbol, String
|
90
|
+
self.load_root_fixtures = options.delete(:root) if options.key? :root
|
91
|
+
scenario_name = scenario_name.to_s
|
92
|
+
else
|
93
|
+
raise ArgumentError, "Scenario must be a symbol, string or hash. You gave #{scenario_name.class}."
|
94
|
+
end
|
95
|
+
|
96
|
+
self.scenario_path = "#{self.fixture_path}/#{scenario_name}" if scenario_name
|
97
|
+
self.fixtures(:all)
|
98
|
+
end
|
99
|
+
|
100
|
+
def fixtures(*table_names)
|
101
|
+
if table_names.first == :all
|
102
|
+
self.root_table_names = load_table_names_in_path(self.fixture_path)
|
103
|
+
self.scenario_table_names = self.scenario_path ? load_table_names_in_path(self.scenario_path) : []
|
104
|
+
|
105
|
+
table_names = self.root_table_names + self.scenario_table_names
|
106
|
+
table_names.uniq!
|
107
|
+
else
|
108
|
+
table_names = table_names.flatten.map { |n| n.to_s }
|
109
|
+
end
|
110
|
+
|
111
|
+
self.fixture_table_names |= table_names
|
112
|
+
|
113
|
+
require_fixture_classes(table_names)
|
114
|
+
setup_fixture_accessors(table_names)
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
def load_table_names_in_path(path)
|
119
|
+
table_names = Dir["#{path}/*.yml"]# + Dir["#{path}/*.csv"] # no CSVs, please.
|
120
|
+
table_names.map! { |f| File.basename(f).split('.')[0..-2].join('.') }
|
121
|
+
return table_names
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
def load_fixtures
|
127
|
+
@loaded_fixtures = {}
|
128
|
+
current_fixtures = self.fixture_path.to_s + self.scenario_path.to_s
|
129
|
+
if Fixtures.current_fixtures != current_fixtures
|
130
|
+
Fixtures.current_fixtures = current_fixtures
|
131
|
+
Fixtures.reset_cache
|
132
|
+
end
|
133
|
+
if self.load_root_fixtures || self.scenario_path.blank?
|
134
|
+
root_fixtures = Fixtures.create_fixtures(self.fixture_path, self.root_table_names, fixture_class_names)
|
135
|
+
end
|
136
|
+
|
137
|
+
if self.scenario_path
|
138
|
+
scenario_fixtures = Fixtures.create_fixtures(self.scenario_path, self.scenario_table_names, fixture_class_names)
|
139
|
+
end
|
140
|
+
|
141
|
+
[root_fixtures, scenario_fixtures].each do |fixtures|
|
142
|
+
next if fixtures.nil?
|
143
|
+
|
144
|
+
if fixtures.instance_of?(Fixtures)
|
145
|
+
update_loaded_fixtures(fixtures)
|
146
|
+
else
|
147
|
+
fixtures.each { |f| update_loaded_fixtures(f) }
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def update_loaded_fixtures(fixtures)
|
153
|
+
if @loaded_fixtures[fixtures.table_name]
|
154
|
+
fixtures.each{|fixture| @loaded_fixtures[fixtures.table_name] << fixture }
|
155
|
+
else
|
156
|
+
@loaded_fixtures[fixtures.table_name] = fixtures
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def setup_fixtures_with_scenario_check
|
161
|
+
if (Fixtures.current_test_class != self.class || !self.use_transactional_fixtures)
|
162
|
+
Fixtures.destroy_fixtures self.root_table_names
|
163
|
+
Fixtures.reset_cache
|
164
|
+
end
|
165
|
+
Fixtures.current_test_class = self.class
|
166
|
+
setup_fixtures_without_scenario_check
|
167
|
+
end
|
168
|
+
alias_method_chain :setup_fixtures, :scenario_check
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActiveSupport #:nodoc:
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module Hash #:nodoc:
|
4
|
+
module Join
|
5
|
+
|
6
|
+
# Returns a string created by converting each element of the hash to
|
7
|
+
# a string, separated by <i>sep</i>.
|
8
|
+
#
|
9
|
+
# { :a => :b, :c => :d }.join #=> "abcd"
|
10
|
+
# { :a => :b, :c => :d }.join('-') #=> "a-b-c-d"
|
11
|
+
#
|
12
|
+
# If the hash has a key or value as a hash also, it's also joined
|
13
|
+
# (just as it works with arrays).
|
14
|
+
#
|
15
|
+
# { :a => { :b => :c } }.join(' ') #=> "a b c"
|
16
|
+
#
|
17
|
+
# Note: hash order is just preserved in Ruby 1.9
|
18
|
+
#
|
19
|
+
def join(sep = $,)
|
20
|
+
array = []
|
21
|
+
sep = sep.to_s
|
22
|
+
|
23
|
+
self.each_pair do |k, v|
|
24
|
+
array << (k.is_a?(Hash) ? k.join(sep) : k.to_s)
|
25
|
+
array << (v.is_a?(Hash) ? v.join(sep) : v.to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
array.join(sep)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Hash.send :include, ActiveSupport::CoreExtensions::Hash::Join
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class NestedScenarios
|
2
|
+
cattr_accessor :record_name_fields, :skip_tables
|
3
|
+
@@record_name_fields = %w( name username title )
|
4
|
+
@@skip_tables = %w( schema_migrations )
|
5
|
+
|
6
|
+
def self.delete_tables(table_names = self.tables)
|
7
|
+
connection = ActiveRecord::Base.connection
|
8
|
+
ActiveRecord::Base.silence do
|
9
|
+
connection.disable_referential_integrity do
|
10
|
+
(table_names - @@skip_tables).each do |table_name|
|
11
|
+
connection.delete "DELETE FROM #{table_name}", 'Fixture Delete'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.tables
|
18
|
+
ActiveRecord::Base.connection.tables - @@skip_tables
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
namespace :db do
|
2
|
+
namespace :scenario do
|
3
|
+
desc 'Build scenarios in test environment'
|
4
|
+
task :build do
|
5
|
+
# Load environment using test environment
|
6
|
+
ENV['RAILS_ENV'] = RAILS_ENV = 'test'
|
7
|
+
Rake::Task['environment'].invoke
|
8
|
+
|
9
|
+
# Force ActionMailer to delivery method :test
|
10
|
+
# while building scenarios
|
11
|
+
ActionMailer::Base.delivery_method = :test
|
12
|
+
|
13
|
+
files = []
|
14
|
+
files += Dir.glob(NestedScenarios::Builder.fixtures_dir + '/**/scenario.rb')
|
15
|
+
files += Dir.glob(NestedScenarios::Builder.fixtures_dir + '/**/scenarios.rb')
|
16
|
+
|
17
|
+
files.each do |scenario_rb|
|
18
|
+
puts "Reading #{scenario_rb.gsub(RAILS_ROOT, '')} scenario file:"
|
19
|
+
require scenario_rb
|
20
|
+
puts
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pivotal-nested_scenarios
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Jos\xC3\xA9 Valim"
|
8
|
+
- Tom Preston-Werner
|
9
|
+
- Chris Wanstrath
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2009-02-22 00:00:00 -08:00
|
15
|
+
default_executable:
|
16
|
+
dependencies: []
|
17
|
+
|
18
|
+
description: FixtureScenarios, FixtureScenariosBuilder, Yaml and Ruby in one big mix for Rails
|
19
|
+
email: jose.valim@gmail.com
|
20
|
+
executables: []
|
21
|
+
|
22
|
+
extensions: []
|
23
|
+
|
24
|
+
extra_rdoc_files:
|
25
|
+
- README
|
26
|
+
files:
|
27
|
+
- MIT-LICENSE
|
28
|
+
- README
|
29
|
+
- Rakefile
|
30
|
+
- lib/nested_scenarios.rb
|
31
|
+
- lib/nested_scenarios/builder.rb
|
32
|
+
- lib/nested_scenarios/fixtures.rb
|
33
|
+
- lib/nested_scenarios/join.rb
|
34
|
+
- lib/nested_scenarios/nested_scenarios.rb
|
35
|
+
- tasks/builder_tasks.rake
|
36
|
+
has_rdoc: true
|
37
|
+
homepage: http://github.com/josevalim/nested_scenarios
|
38
|
+
licenses:
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options:
|
41
|
+
- --main
|
42
|
+
- README
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.3.5
|
61
|
+
signing_key:
|
62
|
+
specification_version: 2
|
63
|
+
summary: FixtureScenarios, FixtureScenariosBuilder, Yaml and Ruby in one big mix for Rails
|
64
|
+
test_files: []
|
65
|
+
|