Fingertips-fakutori-san 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +9 -0
- data/Rakefile +42 -0
- data/VERSION.yml +4 -0
- data/lib/fakutori_san.rb +167 -0
- data/rails/init.rb +1 -0
- data/test/fakutori_san_test.rb +354 -0
- data/test/test_helper.rb +47 -0
- metadata +61 -0
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the fakutori-san plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the fakutori-san plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'Fakutori-san'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source' << '--charset=utf8'
|
20
|
+
rdoc.rdoc_files.include('README.rdoc')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'jeweler'
|
26
|
+
Jeweler::Tasks.new do |s|
|
27
|
+
s.name = "fakutori-san"
|
28
|
+
s.homepage = "http://github.com/Fingertips/fakutori-san"
|
29
|
+
s.email = "eloy.de.enige@gmail.com"
|
30
|
+
s.authors = ["Eloy Duran"]
|
31
|
+
s.summary = s.description = "FakutoriSan is a lean model factory plugin which uses vanilla Ruby to define the factories, allowing you to optimally use inheritance etc."
|
32
|
+
end
|
33
|
+
rescue LoadError
|
34
|
+
end
|
35
|
+
|
36
|
+
begin
|
37
|
+
require 'jewelry_portfolio/tasks'
|
38
|
+
JewelryPortfolio::Tasks.new do |p|
|
39
|
+
p.account = 'Fingertips'
|
40
|
+
end
|
41
|
+
rescue LoadError
|
42
|
+
end
|
data/VERSION.yml
ADDED
data/lib/fakutori_san.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# = FakutoriSan
|
2
|
+
#
|
3
|
+
# As its description, FakutoriSan aims to be a lean model factory. As it uses
|
4
|
+
# vanilla Ruby to define the factories, you can use class inheritance and all
|
5
|
+
# other standard Ruby practices.
|
6
|
+
module FakutoriSan
|
7
|
+
class FakutoriMissing < NameError; end
|
8
|
+
|
9
|
+
# Returns a hash of the available <tt>model => factory</tt> pairs.
|
10
|
+
def self.factories
|
11
|
+
@factories ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
module FakutoriExt
|
15
|
+
def associate_to(model, options = nil)
|
16
|
+
@__factory__.associate(self, model, options)
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def apply_scene(name, options = {})
|
21
|
+
@__factory__.scene(name, self, options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Collection < Array
|
26
|
+
include FakutoriExt
|
27
|
+
|
28
|
+
def initialize(factory, times)
|
29
|
+
@__factory__ = factory
|
30
|
+
super(times)
|
31
|
+
end
|
32
|
+
|
33
|
+
def factory
|
34
|
+
@__factory__
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Fakutori
|
39
|
+
class << self
|
40
|
+
def inherited(factory_klass)
|
41
|
+
model_klass = Object.const_get(factory_klass.name.gsub(/^FakutoriSan::|Fakutori$/, ''))
|
42
|
+
factory_klass.for_model model_klass
|
43
|
+
rescue NameError
|
44
|
+
end
|
45
|
+
|
46
|
+
def for_model(model)
|
47
|
+
FakutoriSan.factories[model] = new(model)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_reader :model
|
52
|
+
|
53
|
+
def initialize(model)
|
54
|
+
@model = model
|
55
|
+
end
|
56
|
+
|
57
|
+
def plan_one(*type_and_or_attributes)
|
58
|
+
attributes = type_and_or_attributes.extract_options!
|
59
|
+
type = type_and_or_attributes.pop || :valid
|
60
|
+
m = "#{type}_attrs"
|
61
|
+
|
62
|
+
if respond_to?(m)
|
63
|
+
plan = method(m).arity.zero? ? send(m) : send(m, attributes)
|
64
|
+
plan.merge(attributes)
|
65
|
+
else
|
66
|
+
raise NoMethodError, "#{self.class.name} has no attributes method for type `#{type}'"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def plan(*times_and_or_type_and_or_attributes)
|
71
|
+
multiple_times :plan, times_and_or_type_and_or_attributes
|
72
|
+
end
|
73
|
+
|
74
|
+
def build_one(*type_and_or_attributes)
|
75
|
+
make_chainable(@model.new(plan_one(*type_and_or_attributes)))
|
76
|
+
end
|
77
|
+
|
78
|
+
def build(*times_and_or_type_and_or_attributes)
|
79
|
+
multiple_times :build, times_and_or_type_and_or_attributes
|
80
|
+
end
|
81
|
+
|
82
|
+
def create_one(*type_and_or_attributes_and_or_validate)
|
83
|
+
args = type_and_or_attributes_and_or_validate
|
84
|
+
|
85
|
+
validate = args.pop if [true, false].include?(args.last)
|
86
|
+
instance = build_one(*args)
|
87
|
+
validate ? instance.save! : instance.save(false)
|
88
|
+
instance
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_one!(*type_and_or_attributes)
|
92
|
+
type_and_or_attributes << true
|
93
|
+
create_one(*type_and_or_attributes)
|
94
|
+
end
|
95
|
+
|
96
|
+
def create(*times_and_or_type_and_or_attributes)
|
97
|
+
multiple_times :create, times_and_or_type_and_or_attributes
|
98
|
+
end
|
99
|
+
|
100
|
+
def create!(*times_and_or_type_and_or_attributes)
|
101
|
+
times_and_or_type_and_or_attributes << true
|
102
|
+
create(*times_and_or_type_and_or_attributes)
|
103
|
+
end
|
104
|
+
|
105
|
+
def associate(record_or_collection, to_model, options = nil)
|
106
|
+
if builder = association_builder_for(to_model)
|
107
|
+
[*record_or_collection].each do |record|
|
108
|
+
send(*[builder, record, to_model, options].compact)
|
109
|
+
end
|
110
|
+
else
|
111
|
+
raise NoMethodError, "#{self.class.name} has no association builder method for model `#{to_model.inspect}'."
|
112
|
+
end
|
113
|
+
|
114
|
+
record_or_collection
|
115
|
+
end
|
116
|
+
|
117
|
+
def scene(name, record_or_collection, options = {})
|
118
|
+
method = "#{name}_scene"
|
119
|
+
unless respond_to?(method)
|
120
|
+
raise NoMethodError, "#{self.class.name} has no scene method for scene `#{name.inspect}'"
|
121
|
+
end
|
122
|
+
|
123
|
+
if record_or_collection.is_a?(Array)
|
124
|
+
record_or_collection.each_with_index do |record, index|
|
125
|
+
options[:index] = index
|
126
|
+
send(method, record, options)
|
127
|
+
end
|
128
|
+
else
|
129
|
+
send(method, record_or_collection, options)
|
130
|
+
end
|
131
|
+
|
132
|
+
record_or_collection
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def make_chainable(instance)
|
138
|
+
instance.extend(FakutoriExt)
|
139
|
+
instance.instance_variable_set(:@__factory__, self)
|
140
|
+
instance
|
141
|
+
end
|
142
|
+
|
143
|
+
def multiple_times(type, args)
|
144
|
+
m = "#{type}_one"
|
145
|
+
|
146
|
+
if args.first.is_a?(Numeric)
|
147
|
+
Collection.new(self, args.shift) { send(m, *args) }
|
148
|
+
else
|
149
|
+
send(m, *args)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def association_builder_for(model)
|
154
|
+
klass = model.is_a?(Class) ? model : model.class
|
155
|
+
name = "associate_to_#{klass.name.underscore.gsub('/', '_')}".to_sym
|
156
|
+
name if respond_to?(name)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
module Kernel
|
162
|
+
def Fakutori(model)
|
163
|
+
FakutoriSan.factories[model] || raise(FakutoriSan::FakutoriMissing, "No factory defined for model `#{model}'")
|
164
|
+
end
|
165
|
+
|
166
|
+
private :Fakutori
|
167
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'fakutori_san'
|
@@ -0,0 +1,354 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class Member < ActiveRecord::Base
|
4
|
+
validates_presence_of :name
|
5
|
+
end
|
6
|
+
|
7
|
+
class Article < ActiveRecord::Base
|
8
|
+
end
|
9
|
+
|
10
|
+
class Unrelated
|
11
|
+
end
|
12
|
+
|
13
|
+
module Namespaced
|
14
|
+
class Article
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module FakutoriSan
|
19
|
+
class MemberFakutori < Fakutori
|
20
|
+
def valid_attrs
|
21
|
+
{ 'name' => 'Eloy', 'email' => 'eloy@example.com', 'password' => 'secret' }
|
22
|
+
end
|
23
|
+
|
24
|
+
def minimal_attrs
|
25
|
+
{ 'name' => 'Eloy' }
|
26
|
+
end
|
27
|
+
|
28
|
+
def invalid_attrs
|
29
|
+
{}
|
30
|
+
end
|
31
|
+
|
32
|
+
def with_arg_attrs(arg)
|
33
|
+
{ 'arg' => arg }
|
34
|
+
end
|
35
|
+
|
36
|
+
def with_name_scene(member, options)
|
37
|
+
member.update_attribute :name, "#{options[:name]}#{options[:index]}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def associate_to_article(member, article, options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def associate_to_namespaced_article(member, article, options)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class FooFakutori < Fakutori
|
48
|
+
for_model Article
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module SharedSpecsHelper
|
53
|
+
def define_shared_specs_for(type)
|
54
|
+
it "should call ##{type}_one multiple times and return an array of the resulting attribute hashes" do
|
55
|
+
attributes = { 'name' => 'Eloy' }
|
56
|
+
|
57
|
+
@factory.expects("#{type}_one").with(attributes).times(2).returns({})
|
58
|
+
@factory.send(type, 2, attributes).should == [{}, {}]
|
59
|
+
|
60
|
+
@factory.expects("#{type}_one").with(:minimal, attributes).times(2).returns({})
|
61
|
+
@factory.send(type, 2, :minimal, attributes).should == [{}, {}]
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should not call ##{type}_one multiple times if no `times' argument is given" do
|
65
|
+
attributes = { 'name' => 'Eloy' }
|
66
|
+
|
67
|
+
@factory.expects("#{type}_one").with(attributes).times(1).returns({})
|
68
|
+
@factory.send(type, attributes).should == {}
|
69
|
+
|
70
|
+
@factory.expects("#{type}_one").with(:minimal, attributes).times(1).returns({})
|
71
|
+
@factory.send(type, :minimal, attributes).should == {}
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should return a FakutoriSan::Collection instance when a collection is created" do
|
75
|
+
collection = @factory.send(type, 2)
|
76
|
+
collection.should.be.instance_of FakutoriSan::Collection
|
77
|
+
collection.factory.should.be @factory
|
78
|
+
end
|
79
|
+
|
80
|
+
unless type == :plan
|
81
|
+
it "should extend each instance returned by FakutoriSan with the FakutoriSan::FakutoriExt module" do
|
82
|
+
instance = @factory.create_one
|
83
|
+
FakutoriSan::FakutoriExt.instance_methods.each do |method|
|
84
|
+
instance.should.respond_to method
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
Test::Unit::TestCase.send(:extend, SharedSpecsHelper)
|
91
|
+
|
92
|
+
describe "FakutoriSan::Fakutori, concerning setup" do
|
93
|
+
it "should automatically find the model class based on the factory class's name and initialize an instance the factory subclass" do
|
94
|
+
factory = FakutoriSan.factories[Member]
|
95
|
+
factory.should.be.instance_of FakutoriSan::MemberFakutori
|
96
|
+
factory.model.should.be Member
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should allow a user to explicitly define the model class when automatically finding the right class fails" do
|
100
|
+
factory = FakutoriSan.factories[Article]
|
101
|
+
factory.should.be.instance_of FakutoriSan::FooFakutori
|
102
|
+
factory.model.should.be Article
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "The top level Fakutori method" do
|
107
|
+
it "should return the factory belonging to the given model" do
|
108
|
+
Fakutori(Member).should.be FakutoriSan.factories[Member]
|
109
|
+
Fakutori(Article).should.be FakutoriSan.factories[Article]
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should raise a FakutoriSan::FakutoriMissing exception if no factory can be found" do
|
113
|
+
lambda {
|
114
|
+
Fakutori(Unrelated)
|
115
|
+
}.should.raise FakutoriSan::FakutoriMissing
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "FakutoriSan::Fakutori, concerning `planning'" do
|
120
|
+
before do
|
121
|
+
@factory = Fakutori(Member)
|
122
|
+
end
|
123
|
+
|
124
|
+
define_shared_specs_for :plan
|
125
|
+
|
126
|
+
it "should return a hash of attributes" do
|
127
|
+
@factory.plan_one.should == { 'name' => 'Eloy', 'email' => 'eloy@example.com', 'password' => 'secret' }
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should merge the given attributes onto the resulting attributes hash" do
|
131
|
+
@factory.plan_one('name' => 'Alloy', 'password' => 'supersecret').should ==
|
132
|
+
{ 'name' => 'Alloy', 'email' => 'eloy@example.com', 'password' => 'supersecret' }
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should pass the attributes hash to the `plan' method" do
|
136
|
+
@factory.plan_one(:with_arg, 'name' => 'Eloy').should ==
|
137
|
+
{ 'name' => 'Eloy', 'arg' => { 'name' => 'Eloy' } }
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should take an optional first plan `type', which invokes the method by the same name" do
|
141
|
+
@factory.plan_one(:minimal).should == { 'name' => 'Eloy' }
|
142
|
+
@factory.plan_one(:minimal, 'email' => 'eloy@example.com').should == { 'name' => 'Eloy', 'email' => 'eloy@example.com' }
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should raise a NoMethodError if given a attributes type for which no method exists" do
|
146
|
+
lambda { @factory.plan_one(:unexisting) }.should.raise NoMethodError
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "FakutoriSan::Fakutori, concerning `building'" do
|
151
|
+
before do
|
152
|
+
@factory = Fakutori(Member)
|
153
|
+
end
|
154
|
+
|
155
|
+
define_shared_specs_for :build
|
156
|
+
|
157
|
+
it "should build one instance with the default plan" do
|
158
|
+
instance = @factory.build_one
|
159
|
+
instance.should.be.new_record
|
160
|
+
instance.attributes.should == @factory.plan_one
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should take an optional first plan `type', which invokes the method by the same name" do
|
164
|
+
instance = @factory.build_one(:minimal)
|
165
|
+
instance.should.be.new_record
|
166
|
+
instance.attributes.except('password', 'email').should == @factory.plan_one(:minimal)
|
167
|
+
|
168
|
+
instance = @factory.build_one(:minimal, 'email' => 'eloy@example.com')
|
169
|
+
instance.should.be.new_record
|
170
|
+
instance.attributes.except('password').should == @factory.plan_one(:minimal, 'email' => 'eloy@example.com')
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "FakutoriSan::Fakutori, concerning `creating'" do
|
175
|
+
before do
|
176
|
+
@factory = Fakutori(Member)
|
177
|
+
end
|
178
|
+
|
179
|
+
define_shared_specs_for :create
|
180
|
+
|
181
|
+
it "should create one instance with the default plan" do
|
182
|
+
instance = @factory.create_one
|
183
|
+
instance.should.not.be.new_record
|
184
|
+
instance.attributes.except('id').should == @factory.plan_one
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should not perform validations by default" do
|
188
|
+
instance = @factory.create_one(:invalid)
|
189
|
+
instance.should.not.be.new_record
|
190
|
+
instance.should.not.be.valid
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should take an optional first plan `type', which invokes the method by the same name" do
|
194
|
+
instance = @factory.create_one(:minimal)
|
195
|
+
instance.should.not.be.new_record
|
196
|
+
instance.attributes.except('id', 'password', 'email').should == @factory.plan_one(:minimal)
|
197
|
+
|
198
|
+
instance = @factory.create_one(:minimal, 'email' => 'eloy@example.com')
|
199
|
+
instance.should.not.be.new_record
|
200
|
+
instance.attributes.except('id', 'password').should == @factory.plan_one(:minimal, 'email' => 'eloy@example.com')
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should perform validations and raise an exception if created with #create_one!" do
|
204
|
+
lambda {
|
205
|
+
@factory.create_one!(:invalid)
|
206
|
+
}.should.raise ActiveRecord::RecordInvalid
|
207
|
+
|
208
|
+
lambda {
|
209
|
+
instance = @factory.create_one!(:minimal, 'password' => '12345')
|
210
|
+
instance.attributes.except('id', 'email').should == @factory.plan_one(:minimal, 'password' => '12345')
|
211
|
+
}.should.not.raise ActiveRecord::RecordInvalid
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should call #create_one multiple times and perform validations, and return an array of the resulting record instances" do
|
215
|
+
attributes = { 'name' => 'Eloy' }
|
216
|
+
|
217
|
+
@factory.expects(:create_one).with(attributes, true).times(2).returns({})
|
218
|
+
@factory.create!(2, attributes)
|
219
|
+
|
220
|
+
@factory.expects(:create_one).with(:minimal, attributes, true).times(2).returns({})
|
221
|
+
@factory.create!(2, :minimal, attributes)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe "FakutoriSan::Fakutori, concerning associating records" do
|
226
|
+
before do
|
227
|
+
@factory = Fakutori(Member)
|
228
|
+
@record = @factory.create_one
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should return the association builder method if it exists for the given model" do
|
232
|
+
@factory.send(:association_builder_for, Article).should == :associate_to_article
|
233
|
+
@factory.send(:association_builder_for, Article.new).should == :associate_to_article
|
234
|
+
|
235
|
+
@factory.send(:association_builder_for, Namespaced::Article).should == :associate_to_namespaced_article
|
236
|
+
@factory.send(:association_builder_for, Namespaced::Article.new).should == :associate_to_namespaced_article
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should return nil if no association builder method can be found for the given model" do
|
240
|
+
@factory.send(:association_builder_for, Unrelated).should == nil
|
241
|
+
@factory.send(:association_builder_for, Unrelated.new).should == nil
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should call a builder method if it exists for the given model class" do
|
245
|
+
options = {}
|
246
|
+
@factory.expects(:associate_to_article).with(@record, Article, options)
|
247
|
+
@factory.associate(@record, Article, options).should.be @record
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should call a builder method for each member of a collection" do
|
251
|
+
options = {}
|
252
|
+
collection = @factory.create(2)
|
253
|
+
|
254
|
+
@factory.expects(:associate_to_article).with(collection.first, Article, options)
|
255
|
+
@factory.expects(:associate_to_article).with(collection.last, Article, options)
|
256
|
+
@factory.associate(collection, Article, options).should.be collection
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should raise an NoMethodError if an association builder method doesn't exist for a given model" do
|
260
|
+
lambda {
|
261
|
+
@factory.associate(@record, Unrelated, {})
|
262
|
+
}.should.raise NoMethodError
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should only forward the options hash if it's given by the user" do
|
266
|
+
@factory.expects(:associate_to_article).with(@record, Article)
|
267
|
+
@factory.associate(@record, Article)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "FakutoriSan::Collection, concerning associating records" do
|
272
|
+
before do
|
273
|
+
@factory = Fakutori(Member)
|
274
|
+
@collection = @factory.create!(2)
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should call #associate on each member and forward the given model and arguments" do
|
278
|
+
options = { 'name' => 'Eloy' }
|
279
|
+
@factory.expects(:associate).with(@collection, Article, options)
|
280
|
+
@collection.associate_to(Article, options)
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should return itself after associating so the user can chain calls" do
|
284
|
+
@collection.associate_to(Article, {}).should.be @collection
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should forward the options as `nil' by default" do
|
288
|
+
@factory.expects(:associate).with(@collection, Article, nil)
|
289
|
+
@collection.associate_to(Article)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
describe "FakutoriSan::Fakutori, concerning `scenes'" do
|
294
|
+
before do
|
295
|
+
@factory = Fakutori(Member)
|
296
|
+
end
|
297
|
+
|
298
|
+
it "should invoke a scene method if it exists and return self" do
|
299
|
+
instance = @factory.create_one
|
300
|
+
@factory.scene(:with_name, instance, :name => 'Alloy').should == instance
|
301
|
+
instance.name.should == 'Alloy'
|
302
|
+
end
|
303
|
+
|
304
|
+
it "should invoke a scene method for each record in a collection, assign the index to the options, and return self" do
|
305
|
+
collection = @factory.create!(2)
|
306
|
+
@factory.scene(:with_name, collection, :name => 'Alloy').should == collection
|
307
|
+
collection.each_with_index do |record, index|
|
308
|
+
record.reload.name.should == "Alloy#{index}"
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
it "should raise a NoMethodError if a requested scene does not exist" do
|
313
|
+
lambda {
|
314
|
+
@factory.scene(:does_not_exist, @factory.build_one)
|
315
|
+
}.should.raise NoMethodError
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
describe "FakutoriSan::Collection, concerning `scenes'" do
|
320
|
+
before do
|
321
|
+
@factory = Fakutori(Member)
|
322
|
+
@collection = @factory.create!(2)
|
323
|
+
end
|
324
|
+
|
325
|
+
it "should call Fakutori#scene with the given scene name, itself, and options" do
|
326
|
+
@collection.apply_scene(:with_name, :name => 'Alloy')
|
327
|
+
@collection.each do |record|
|
328
|
+
record.reload.name.should.match /^Alloy/
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
describe "FakutoriSan::FakutoriExt" do
|
334
|
+
before do
|
335
|
+
@factory = Fakutori(Member)
|
336
|
+
end
|
337
|
+
|
338
|
+
it "should call Fakutori#associate with the record and options given and return itself" do
|
339
|
+
instance = @factory.create_one
|
340
|
+
|
341
|
+
@factory.expects(:associate).with(instance, Article, nil)
|
342
|
+
instance.associate_to(Article).should.be instance
|
343
|
+
|
344
|
+
options = {}
|
345
|
+
@factory.expects(:associate).with(instance, Article, options)
|
346
|
+
instance.associate_to(Article, options).should.be instance
|
347
|
+
end
|
348
|
+
|
349
|
+
it "should call Fakutori#scene with the record and options given" do
|
350
|
+
instance = @factory.create_one
|
351
|
+
instance.apply_scene(:with_name).reload.name.should == ''
|
352
|
+
instance.apply_scene(:with_name, :name => 'Alloy').reload.name.should == 'Alloy'
|
353
|
+
end
|
354
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
TEST_ROOT_DIR = File.expand_path('..', __FILE__)
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
frameworks = %w(activesupport activerecord actionpack)
|
5
|
+
|
6
|
+
rails = [
|
7
|
+
File.expand_path('../../../rails', TEST_ROOT_DIR),
|
8
|
+
File.expand_path('../../rails', TEST_ROOT_DIR)
|
9
|
+
].detect do |possible_rails|
|
10
|
+
begin
|
11
|
+
entries = Dir.entries(possible_rails)
|
12
|
+
frameworks.all? { |framework| entries.include?(framework) }
|
13
|
+
rescue Errno::ENOENT
|
14
|
+
false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
frameworks.each { |framework| $:.unshift(File.join(rails, framework, 'lib')) }
|
19
|
+
$:.unshift File.join(TEST_ROOT_DIR, '/../lib')
|
20
|
+
$:.unshift File.join(TEST_ROOT_DIR, '/lib')
|
21
|
+
$:.unshift TEST_ROOT_DIR
|
22
|
+
|
23
|
+
ENV['RAILS_ENV'] = 'test'
|
24
|
+
|
25
|
+
# Rails libs
|
26
|
+
frameworks.each { |framework| require framework }
|
27
|
+
require File.expand_path('../../rails/init', __FILE__)
|
28
|
+
|
29
|
+
# Libraries for testing
|
30
|
+
require 'rubygems' rescue LoadError
|
31
|
+
require 'test/spec'
|
32
|
+
require 'mocha'
|
33
|
+
|
34
|
+
# Open a connection for ActiveRecord
|
35
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
36
|
+
ActiveRecord::Migration.verbose = false
|
37
|
+
|
38
|
+
ActiveRecord::Schema.define(:version => 1) do
|
39
|
+
create_table :members do |t|
|
40
|
+
t.string :name
|
41
|
+
t.string :email
|
42
|
+
t.string :password
|
43
|
+
end
|
44
|
+
|
45
|
+
create_table :articles do |t|
|
46
|
+
end
|
47
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Fingertips-fakutori-san
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eloy Duran
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-08-10 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: FakutoriSan is a lean model factory plugin which uses vanilla Ruby to define the factories, allowing you to optimally use inheritance etc.
|
17
|
+
email: eloy.de.enige@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- README.rdoc
|
26
|
+
- Rakefile
|
27
|
+
- VERSION.yml
|
28
|
+
- lib/fakutori_san.rb
|
29
|
+
- rails/init.rb
|
30
|
+
- test/fakutori_san_test.rb
|
31
|
+
- test/test_helper.rb
|
32
|
+
has_rdoc: false
|
33
|
+
homepage: http://github.com/Fingertips/fakutori-san
|
34
|
+
licenses:
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options:
|
37
|
+
- --charset=UTF-8
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: "0"
|
45
|
+
version:
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
requirements: []
|
53
|
+
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.3.5
|
56
|
+
signing_key:
|
57
|
+
specification_version: 3
|
58
|
+
summary: FakutoriSan is a lean model factory plugin which uses vanilla Ruby to define the factories, allowing you to optimally use inheritance etc.
|
59
|
+
test_files:
|
60
|
+
- test/fakutori_san_test.rb
|
61
|
+
- test/test_helper.rb
|