stepford 0.9.3 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,32 +1,56 @@
1
1
  Stepford
2
2
  =====
3
3
 
4
- Stepford is an automatic required (non-null or presence validated) association resolving (creating/building/stubbing) wrapper and/or factory generator for [FactoryGirl][factory_girl].
4
+ Now getting started with FactoryGirl is even more simple and DRY!
5
5
 
6
- For example, with the rspec helper:
6
+ Stepford is an automatic required (non-null or presence validated) association resolver and factory generator for [FactoryGirl][factory_girl].
7
7
 
8
- create(:foo)
8
+ The Stepford CLI allows can generate a factories.rb or multiple files each defining a single factory, for every existing model or for those specified.
9
9
 
10
- Would take a :foo FactoryGirl factory that has no associations defined in it (only required attributes) and will travel the dependency tree of the models to create and create_list as needed. Or, you can build the same way:
10
+ The following would create/overwrite `test/factories.rb` with a factory for every model in `app/models`:
11
11
 
12
- build(:foo)
12
+ bundle exec stepford factories
13
+
14
+ If you use rspec, it would be:
15
+
16
+ bundle exec stepford factories --path spec
17
+
18
+ With our rspec helper, you can use this to create a bar and automatically create its dependencies and their dependencies, etc. providing ways to remedy circular dependencies:
19
+
20
+ deep_create(:bar)
13
21
 
14
- Need to just customize a few things? You can use the normal FactoryGirl behavior (args, options, block) but also specify options for each factory.
22
+ You can also `create_list`, `build`, `build_list`, and `build_stubbed`:
15
23
 
16
- e.g. maybe Bar has a required association called house_special which uses the :beer factory, and we have a block we want to send into it; oh, and Beer has specials that you want to build as a list of 3 using the :tuesday_special_offer factory. Just set it up like:
24
+ deep_build_list(:bar, 5)
17
25
 
18
- Stepford::FactoryGirl.create_list(:bar, with_factory_options: {
26
+ Need to customize it? You can use the normal FactoryGirl behavior (args, options, block), but in addition, you may specify options for each factories that would create direct or indirect associations.
27
+
28
+ e.g. maybe Bar has a required association called house_special which uses the beer factory, and we have a block we want to send into it, and Beer has specials that you want to build as a list of 3, using the tuesday_special_offer factory. In rspec, you'd do:
29
+
30
+ deep_create_list(:bar, with_factory_options: {
19
31
  house_special: [:create, :beer, {blk: ->(beer) do; beer.bubbles.create(attributes_for(:bubbles)); end}],
20
32
  specials: [:build_list, :tuesday_special_offer, 3]
21
33
  }) do
22
34
  # any block you would send to FactoryGirl.create_list(:bar) would go here
23
35
  end
24
36
 
25
- What if you have an existing schema, and you want to use FactoryGirl, but don't have any factories yet?
37
+ By default autogenerated factories just have required attributes, e.g.:
26
38
 
27
- The Stepford CLI allows you to generate your factories.rb or multiple factory files for you.
39
+ require 'factory_girl_rails'
40
+
41
+ FactoryGirl.define do
42
+
43
+ factory :post do
44
+ created_at { 2.weeks.ago }
45
+ name 'Test Name'
46
+ price 1.23
47
+ trait :with_summary do; template 'Test Summary'; end
48
+ updated_at { 2.weeks.ago }
49
+ end
50
+
51
+ end
28
52
 
29
- e.g. maybe one of your models is called post, then you could generate a factory for post and all of the other models with a one-liner, maybe with the following in the `some/path/factories/post.rb` file:
53
+ But you can have it autogenerate lots of the FactoryGirl bells and whistles:
30
54
 
31
55
  require 'factory_girl_rails'
32
56
 
@@ -48,6 +72,10 @@ e.g. maybe one of your models is called post, then you could generate a factory
48
72
 
49
73
  end
50
74
 
75
+ But, everything from author to with_notes may have association interdependency issues unless you hand edit the generated versions.
76
+
77
+ Stepford's FactoryGirl (and optionally its rspec helper) can help you avoid the heavy lifting.
78
+
51
79
  ### Setup
52
80
 
53
81
  In your Rails 3+ project, add this to your Gemfile:
@@ -95,9 +123,9 @@ Put this in your `spec/spec_helper.rb`:
95
123
 
96
124
  require 'stepford/factory_girl_rspec_helpers'
97
125
 
98
- Then you can just use `create`, `create_list`, `build`, `build_list`, or `build_stubbed` in your rspec tests (`create` becomes a shortcut for `::Stepford::FactoryGirl.create`, etc.), e.g.:
126
+ Then you can just use `deep_create`, `deep_create_list`, `deep_build`, `deep_build_list`, or `deep_build_stubbed` in your rspec tests (`deep_create` becomes a shortcut for `::Stepford::FactoryGirl.create`, etc.), e.g.:
99
127
 
100
- create(:foo)
128
+ deep_create(:foo)
101
129
 
102
130
  ##### Stopping Circular References
103
131
 
@@ -108,6 +136,14 @@ If you have a circular reference (A has NOT NULL foreign key to B that has NOT N
108
136
  [:waiter, :bar] => {on_loop: 2, set_to: Waiter.find(123)},
109
137
  }
110
138
 
139
+ Leave out :on_loop or set :on_loop to 0 to use the set instead of attempting to build/create.
140
+
141
+ ##### Debugging
142
+
143
+ Add somewhere after the require:
144
+
145
+ Stepford::FactoryGirl.debug = true
146
+
111
147
  #### CLI
112
148
 
113
149
  Stepford has a CLI with a circular reference checker and a generator to automatically create your factories file(s).
@@ -186,9 +222,9 @@ To generate traits for each association that would be included with `--associati
186
222
 
187
223
  ###### Associations
188
224
 
189
- If you use the (cache) wrapper to automatically generate factories, you may not need to generate associations. We had interdependence issues with factories. When there are NOT NULLs on foreign keys and/or presence validations, etc. you can't just use `after(:create)` or `after(:build)` to set associations, and without those you can have issues with "Trait not registered" or "Factory not registered" with interdependent factory associations.
225
+ If you use Stepford::FactoryGirl (or deep_* methods in rspec) to automatically generate factories, you may not need to generate associations, because that sets them for you. If you do choose to use associations, note that these will likely create factories with interdependence issues. When there are NOT NULLs on foreign keys and/or presence validations, etc. you can't just use `after(:create)` or `after(:build)` to set associations, and without those you can have issues with "Trait not registered" or "Factory not registered". Later versions of FactoryGirl may make this easier, and be sure to see notes from Josh down in the troubleshooting section.
190
226
 
191
- However, if you don't have anything that complex or don't mind hand-editing the factories to try to fix issues, these might help.
227
+ If you are ready to hand-edit to fix things, then copy paste stuff, rename it, etc. instead of just using Stepford::FactoryGirl (or deep_* methods in rspec), then keep reading.
192
228
 
193
229
  ####### Include Required Assocations
194
230
 
@@ -220,9 +256,39 @@ Currently uniqueness constraints are ignored and must be handled by FactoryGirl
220
256
 
221
257
  sequence(:username) {|n| "user#{n}" }
222
258
 
223
- ###### Testing Factories
259
+ ##### Testing Factories
260
+
261
+ See [Testing all Factories (with RSpec)][test_factories] in the FactoryGirl wiki.
262
+
263
+ Here are a few rspecs that test the FactoryGirl factories and the Stepford deep_builds:
264
+
265
+ require 'spec_helper'
266
+ require 'stepford/factory_girl_rspec_helpers'
267
+
268
+ describe 'validate factories build' do
269
+ FactoryGirl.factories.each do |factory|
270
+ context "with factory for :#{factory.name}" do
271
+ subject { build(factory.name) }
272
+
273
+ it "is valid" do
274
+ subject.valid?.should be, subject.errors.full_messages
275
+ end
276
+ end
277
+ end
278
+ end
279
+
280
+ describe 'validate factories deep build' do
281
+ FactoryGirl.factories.each do |factory|
282
+ context "with factory for :#{factory.name}" do
283
+ subject { deep_build(factory.name) }
284
+
285
+ it "is valid" do
286
+ subject.valid?.should be, subject.errors.full_messages
287
+ end
288
+ end
289
+ end
290
+ end
224
291
 
225
- See [Testing all Factories (with RSpec)][test_factories] in the FG wiki.
226
292
 
227
293
  ##### Troubleshooting
228
294
 
@@ -279,7 +345,13 @@ or referring to created objects through associations, though he said multiple ne
279
345
  comment = FactoryGirl.create(:comment, :authored_by_post_author)
280
346
  comment.author == comment.post.author # true
281
347
 
282
- This is the reason we wrote the Stepford Factory Girl Wrapper (see above). It automatically determines what needs to be set in what order and does create, create_list or build, build_list, etc. automatically.
348
+ This is the reason we wrote the Stepford's Factory Girl proxy and helper rspec methods (see above). It automatically determines what needs to be set in what order and does create, create_list or build, build_list, etc. automatically.
349
+
350
+ Unfortunately, it still has trouble with fkey constraints:
351
+
352
+ insert or update on table "foobars" violates foreign key constraint "some_foreign_key_contraint_name"
353
+
354
+ Working on that.
283
355
 
284
356
  ### License
285
357
 
@@ -67,19 +67,24 @@ module Stepford
67
67
 
68
68
  def self.check_associations(model_class, model_and_association_names = [])
69
69
  model_class.reflections.collect {|association_name, reflection|
70
- next unless reflection.macro == :belongs_to
71
70
  puts "warning: #{model_class}'s association #{reflection.name}'s foreign_key was nil. can't check." unless reflection.foreign_key
72
71
  assc_sym = reflection.name.to_sym
73
72
  clas_sym = reflection.class_name.underscore.to_sym
74
73
  next_class = clas_sym.to_s.camelize.constantize
75
74
 
76
- # if has a foreign key, then if NOT NULL or is a presence validate, the association is required and should be output. unfortunately this could mean a circular reference that will have to be manually fixed
77
75
  has_presence_validator = model_class.validators_on(assc_sym).collect{|v|v.class}.include?(ActiveModel::Validations::PresenceValidator)
78
- # note: supports composite_primary_keys gem which stores primary_key as an array
79
- foreign_key_is_also_primary_key = Array.wrap(model_class.primary_key).collect{|pk|pk.to_sym}.include?(reflection.foreign_key.to_sym)
80
- is_not_null_fkey_that_is_not_primary_key = model_class.columns.any?{|c| !c.null && c.name.to_sym == reflection.foreign_key.to_sym && !foreign_key_is_also_primary_key}
76
+ required = false
77
+ if reflection.macro == :belongs_to
78
+ # note: supports composite_primary_keys gem which stores primary_key as an array
79
+ foreign_key_is_also_primary_key = Array.wrap(model_class.primary_key).collect{|pk|pk.to_sym}.include?(reflection.foreign_key.to_sym)
80
+ is_not_null_fkey_that_is_not_primary_key = model_class.columns.any?{|c| !c.null && c.name.to_sym == reflection.foreign_key.to_sym && !foreign_key_is_also_primary_key}
81
+ required = is_not_null_fkey_that_is_not_primary_key || has_presence_validator
82
+ else
83
+ # no nullable metadata on column if no foreign key in this table. we'd figure out the null requirement on the column if inspecting the child model
84
+ required = has_presence_validator
85
+ end
81
86
 
82
- if is_not_null_fkey_that_is_not_primary_key || has_presence_validator
87
+ if required
83
88
  key = [model_class.table_name.to_sym, reflection.foreign_key.to_sym, next_class.table_name.to_sym]
84
89
  if model_and_association_names.include?(key)
85
90
  @@offenders << model_and_association_names.last unless @@offenders.include?(model_and_association_names.last)
@@ -1,7 +1,8 @@
1
1
  require 'factory_girl'
2
+ require 'bigdecimal'
2
3
 
3
4
  module Stepford
4
- # A wrapper for FactoryGirl that automatically recursively creates/builds/stubbed factories for null=false and/or presence validated associations.
5
+ # A proxy for FactoryGirl that automatically recursively creates/builds/stubbed factories for null=false and/or presence validated associations.
5
6
  #
6
7
  # Lets you specify method name and arguments/options to factory girl for associations.
7
8
  #
@@ -15,33 +16,24 @@ module Stepford
15
16
  # }) do
16
17
  # # the block you would send to FactoryGirl.create_list(:foo) would go here
17
18
  # end
18
- #
19
- # If you have a circular reference (A has NOT NULL foreign key to B that has NOT NULL foreign key to C that has NOT NULL foreign key to A) in the
20
- # schema, there is a workaround. First, prepopulate one of the models involved in the interdependency chain in the database as part of test setup,
21
- # or if the ids are NOT NULL but are not foreign key constrained (i.e. if you can enter an invalid ID into the foreign key column, which implies possible
22
- # referential integrity issues) then you may be able to set them with an invalid id. Take that foreign id and then use the following to ensure
23
- # that it will set that foreign id or instance. This is done at a global level which may not work for you, but it makes it convenient to put into
24
- # your spec/spec_helper.rb, etc. For example, let's say your bar has NOT NULL on bartender_id and waiter_id, and in turn bartender and waiter
25
- # both have a NOT NULL bar_id, and neither enforce foreign keys. Maybe you have preloaded data for waiter somehow as the id '123', but want to set bartender to
26
- # just use an invalid id '-1', and you want to do it when they are on their second loop. You could use:
27
- #
28
- # Stepford::FactoryGirl.stop_circular_refs = {
29
- # [:bartender, :bar] => {on_loop: 2, set_foreign_key_to: -1},
30
- # [:waiter, :bar] => {on_loop: 2, set_to: Waiter.find(123)},
31
- # }
32
19
  module FactoryGirl
33
20
  OPTIONS = [
21
+ :debug,
34
22
  :stop_circular_refs
35
23
  ]
36
24
 
37
25
  class << self
26
+ @@breadcrumbs = []
27
+
38
28
  OPTIONS.each{|o|attr_accessor o; define_method("#{o}?".to_sym){!!send("#{o}")}}
39
29
  def configure(&blk); class_eval(&blk); end
40
30
 
41
- def method_missing(m, *args, &block)
42
- puts "starting Stepford::FactoryGirl.#{m}(#{args.inspect})"
31
+ def handle_factory_girl_method(m, *args, &block)
32
+ @@breadcrumbs << [args[0]] if ::Stepford::FactoryGirl.debug?
33
+ #puts "#{' ' * @@indent}handling Stepford::FactoryGirl.#{m}(#{args.inspect})" if ::Stepford::FactoryGirl.debug?
34
+ puts "#{@@breadcrumbs.join('>')} start" if ::Stepford::FactoryGirl.debug?
43
35
 
44
- if [:build, :build_list, :build_stubbed, :create, :create_list].include?(m) && args && args.size > 0
36
+ if args && args.size > 0
45
37
  # call Stepford::FactoryGirl.* on any not null associations recursively
46
38
  model_sym = args[0].to_sym
47
39
  model_class = args[0].to_s.camelize.constantize
@@ -49,100 +41,68 @@ module Stepford
49
41
  args = args.dup # need local version because we'll be dup'ing the options hash to add things to set prior to create/build
50
42
  options = args.last
51
43
  if options.is_a?(Hash)
52
- options = options.dup
44
+ # keep them separate
45
+ orig_options = options
46
+ options = deep_dup(options)
53
47
  args[(args.size - 1)] = options # need to set the dup'd options
54
48
  else
49
+ # keep them separate
50
+ orig_options = {}
55
51
  options = {}
56
52
  args << options # need to add options to set associations
57
53
  end
58
54
 
55
+ if ::Stepford::FactoryGirl.debug?
56
+ print "#{@@breadcrumbs.join('>')} args="
57
+ debugargs(args)
58
+ puts
59
+ end
60
+
59
61
  options[:with_factory_options] = {} unless options[:with_factory_options]
60
62
  with_factory_options = options[:with_factory_options]
61
- with_factory_options[:circular_ref_counts] = {} unless with_factory_options[:circular_ref_counts]
63
+
62
64
  model_class.reflections.each do |association_name, reflection|
63
65
  assc_sym = reflection.name.to_sym
64
- next if options[assc_sym] || options[reflection.foreign_key.to_sym]
66
+ next if options[assc_sym] || options[reflection.foreign_key.to_sym] # || reflection.macro != :belongs_to
67
+
65
68
  clas_sym = reflection.class_name.underscore.to_sym
66
69
  has_presence_validator = model_class.validators_on(assc_sym).collect{|v|v.class}.include?(::ActiveModel::Validations::PresenceValidator)
67
70
  required = reflection.foreign_key ? (has_presence_validator || model_class.columns.any?{|c| !c.null && c.name.to_sym == reflection.foreign_key.to_sym}) : false
68
71
  orig_method_args_and_options = with_factory_options ? (with_factory_options[[clas_sym, assc_sym]] || with_factory_options[clas_sym]) : nil
69
- # if has a foreign key, then if NOT NULL or is a presence validate, the association is required and should be output. unfortunately this could mean a circular reference that will have to be manually fixed
72
+
70
73
  has_presence_validator = model_class.validators_on(assc_sym).collect{|v|v.class}.include?(ActiveModel::Validations::PresenceValidator)
71
- # note: supports composite_primary_keys gem which stores primary_key as an array
72
- foreign_key_is_also_primary_key = Array.wrap(model_class.primary_key).collect{|pk|pk.to_sym}.include?(reflection.foreign_key.to_sym)
73
- is_not_null_fkey_that_is_not_primary_key = model_class.columns.any?{|c| !c.null && c.name.to_sym == reflection.foreign_key.to_sym && !foreign_key_is_also_primary_key}
74
-
75
- if is_not_null_fkey_that_is_not_primary_key || has_presence_validator
76
- circular_ref_key = [model_sym, assc_sym]
77
- all_opts = ::Stepford::FactoryGirl.stop_circular_refs
78
- if all_opts.is_a?(Hash) && all_opts.size > 0
79
- circ_options = all_opts[circular_ref_key]
80
- if circ_options
81
- #puts "::Stepford::FactoryGirl.stop_circular_refs[circular_ref_key]=#{circ_options.inspect}"
82
- count = with_factory_options[:circular_ref_counts][circular_ref_key]
83
- if count
84
- count += 1
85
- else
86
- count = 0
87
- end
88
- with_factory_options[:circular_ref_counts][circular_ref_key] = count
89
- if count > 100
90
- puts "over 100 loops. need to add this to Stepford::FactoryGirl.stop_circular_refs: {#{circular_ref_key.inspect} => {on_loop: 2, set_foreign_key_to: -1}}"
91
- end
92
-
93
- if count >= (circ_options[:on_loop] || 1)
94
- if circ_options.has_key?(:set_to)
95
- puts "Circular dependency override enabled. Returning :set_to instance to set as #{model_sym}.#{assc_sym}. instance was #{circ_options[:set_to]}"
96
- return circ_options[:set_to]
97
- elsif circ_options.has_key?(:set_foreign_key_to)
98
- # (CHILD) return hash to set on parent
99
- puts "Circular dependency override enabled. Returning :set_foreign_key_to to set as #{model_sym}.#{reflection.foreign_key}. value was '#{circ_options[:set_foreign_key_to]}'"
100
- return {reflection.foreign_key.to_sym => circ_options[:set_foreign_key_to]}
101
- end
102
- end
103
- end
104
- end
74
+ required = false
75
+ if reflection.macro == :belongs_to
76
+ # note: supports composite_primary_keys gem which stores primary_key as an array
77
+ foreign_key_is_also_primary_key = Array.wrap(model_class.primary_key).collect{|pk|pk.to_sym}.include?(reflection.foreign_key.to_sym)
78
+ is_not_null_fkey_that_is_not_primary_key = model_class.columns.any?{|c| !c.null && c.name.to_sym == reflection.foreign_key.to_sym && !foreign_key_is_also_primary_key}
79
+ required = is_not_null_fkey_that_is_not_primary_key || has_presence_validator
80
+ else
81
+ # no nullable metadata on column if no foreign key in this table. we'd figure out the null requirement on the column if inspecting the child model
82
+ required = has_presence_validator
83
+ end
105
84
 
85
+ if required
86
+ @@breadcrumbs << ["a:#{assc_sym}"] if ::Stepford::FactoryGirl.debug?
106
87
  if orig_method_args_and_options
107
88
  method_args_and_options = orig_method_args_and_options.dup
108
89
  method_options = args.last
109
90
  blk = method_options.is_a?(Hash) ? method_args_and_options.delete(:blk) : nil
110
91
  if blk
111
- puts "FactoryGirl.__send__(#{method_args_and_options.inspect}, &blk)"
92
+ #puts "#{' ' * @@indent}FactoryGirl.__send__(#{method_args_and_options.inspect}, &blk)" if ::Stepford::FactoryGirl.debug?
112
93
  options[assc_sym] = ::FactoryGirl.__send__(*method_args_and_options, &blk)
113
94
  else
114
- puts "FactoryGirl.__send__(#{method_args_and_options.inspect})"
95
+ #puts "#{' ' * @@indent}FactoryGirl.__send__(#{method_args_and_options.inspect})" if ::Stepford::FactoryGirl.debug?
115
96
  options[assc_sym] = ::FactoryGirl.__send__(*method_args_and_options)
116
97
  end
117
98
  else
118
99
  if reflection.macro == :has_many
119
- case m
120
- when :create, :create_list
121
- options[assc_sym] = ::Stepford::FactoryGirl.create_list(clas_sym, 2, options)
122
- when :build, :build_list
123
- options[assc_sym] = ::Stepford::FactoryGirl.build_list(clas_sym, 2, options)
124
- when :build_stubbed
125
- #TODO: need to test building something stubbed that has a PresenceValidator on a has_many
126
- options[assc_sym] = ::Stepford::FactoryGirl.build_stubbed(clas_sym, options)
127
- end
100
+ options[assc_sym] = ::Stepford::FactoryGirl.create_list(clas_sym, 2, orig_options)
128
101
  else
129
- case m
130
- when :create, :create_list
131
- options[assc_sym] = ::Stepford::FactoryGirl.create(clas_sym, options)
132
- when :build, :build_list
133
- options[assc_sym] = ::Stepford::FactoryGirl.build(clas_sym, options)
134
- when :build_stubbed
135
- options[assc_sym] = ::Stepford::FactoryGirl.build_stubbed(clas_sym, options)
136
- end
137
-
138
- # (PARENT) we passed this back as a hash which means that the child model needed to set foreign key on the parent model
139
- if options[assc_sym].is_a?(Hash)
140
- value = options.delete(assc_sym)
141
- options.merge!()
142
- puts "Overrode foreign key #{model_sym}.#{assc_sym} = #{value}"
143
- end
102
+ options[assc_sym] = ::Stepford::FactoryGirl.create(clas_sym, orig_options)
144
103
  end
145
104
  end
105
+ @@breadcrumbs.pop if ::Stepford::FactoryGirl.debug?
146
106
  end
147
107
  end
148
108
  end
@@ -150,9 +110,69 @@ module Stepford
150
110
  # clean-up before sending to FactoryGirl
151
111
  (args.last).delete(:with_factory_options) if args.last.is_a?(Hash)
152
112
 
153
- puts "FactoryGirl.#{m}(#{args.inspect}) (via __send__)"
113
+ if ::Stepford::FactoryGirl.debug?
114
+ puts "#{@@breadcrumbs.join('>')} end"
115
+ puts
116
+ print "#{@@breadcrumbs.join('>')} FactoryGirl.#{m}("
117
+ debugargs(args)
118
+ puts ")"
119
+ puts
120
+ @@breadcrumbs.pop
121
+ end
122
+
154
123
  ::FactoryGirl.__send__(m, *args, &block)
155
124
  end
125
+
126
+ # switched to this from method_missing to avoid method trying to handle mistaken calls
127
+ def create(*args, &block); handle_factory_girl_method(:create, *args, &block); end
128
+ def create_list(*args, &block); handle_factory_girl_method(:create_list, *args, &block); end
129
+ def build(*args, &block); handle_factory_girl_method(:build, *args, &block); end
130
+ def build_list(*args, &block); handle_factory_girl_method(:build_list, *args, &block); end
131
+ def build_stubbed(*args, &block); handle_factory_girl_method(:build_stubbed, *args, &block); end
132
+ # pass everything else to FactoryGirl to try to handle (can't reflect in current version to find what it handles)
133
+ def method_missing(m, *args, &block); ::FactoryGirl.__send__(m, *args, &block); end
134
+
135
+ def deep_dup(o)
136
+ result = nil
137
+ if o.is_a?(Hash)
138
+ result = {}
139
+ o.keys.each do |key|
140
+ result[deep_dup(key)] = deep_dup(o[key])
141
+ end
142
+ elsif o.is_a?(Array)
143
+ result = []
144
+ o.each do |value|
145
+ result << deep_dup(value)
146
+ end
147
+ elsif [NilClass,FalseClass,TrueClass,Symbol,Numeric,Class,Module].any?{|c|o.is_a?(c)}
148
+ result = o
149
+ elsif o.is_a?(BigDecimal)
150
+ # ActiveSupport v3.2.8 checks duplicable? for BigDecimal by testing it, so we'll just try to dup the value itself
151
+ result = o
152
+ begin
153
+ result = o.dup
154
+ rescue TypeError
155
+ # can't dup
156
+ end
157
+ elsif o.is_a?(Object)
158
+ result = o.dup
159
+ else
160
+ result = o
161
+ end
162
+ result
163
+ end
164
+
165
+ def debugargs(args)
166
+ args.each do |arg|
167
+ if arg.is_a?(Hash)
168
+ print "{"
169
+ print arg.keys.collect{|key|"#{key} = (#{arg[key].class.name})"}.join(', ')
170
+ print "}"
171
+ else
172
+ print "#{arg.inspect},"
173
+ end
174
+ end
175
+ end
156
176
  end
157
177
  end
158
178
  end
@@ -4,7 +4,7 @@ module Stepford
4
4
  module FactoryGirlRspecHelpers
5
5
  [:create, :create_list, :build, :build_list, :build_stubbed].each do |s|
6
6
  class_eval %Q"
7
- def #{s}(*args, &block)
7
+ def deep_#{s}(*args, &block)
8
8
  ::Stepford::FactoryGirl.#{s}(*args, &block)
9
9
  end
10
10
  "
@@ -1,3 +1,3 @@
1
1
  module Stepford
2
- VERSION = '0.9.3'
2
+ VERSION = '0.11.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stepford
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.11.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-09 00:00:00.000000000 Z
12
+ date: 2012-11-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -43,7 +43,9 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
- description: A CLI to create starter FactoryGirl factories for all of your Rails models.
46
+ description: Has deep_* methods for automating FactoryGirl creation with required
47
+ association trees and small tweaks, ActiveRecord circular required reference checker
48
+ CLI, and a nice flexible FactoryGirl factories code generator CLI.
47
49
  email:
48
50
  - garysweaver@gmail.com
49
51
  executables:
@@ -86,5 +88,5 @@ rubyforge_project:
86
88
  rubygems_version: 1.8.24
87
89
  signing_key:
88
90
  specification_version: 3
89
- summary: Autocreate FactoryGirl factories from models.
91
+ summary: FactoryGirl becomes easier and automated.
90
92
  test_files: []