cranky 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -29,14 +29,16 @@ You can create as many different factory files as you want, just require them in
29
29
 
30
30
  == In a Nutshell
31
31
 
32
- Cranky steals its core syntax from Factory Girl...
32
+ Cranky steals its core syntax from Factory Girl and can drop into tests already written for that framework...
33
33
 
34
34
  Factory.build(:user) # Build a user instance without saving
35
35
  Factory.create(:user) # Build and save a user instance
36
36
  Factory.build(:user, :name => "Ian") # Override a default attribute value
37
37
  Factory.attributes_for(:user) # Return a set of valid attributes rather than the object
38
38
 
39
- And has a nice debug option (rails only) to warn you when your factory is broken, recommend you do this for your first spec...
39
+ Or if you're coming from Machinist, you can make your Cranky factories drop into your existing tests by setting up make and make! methods as shown here.[http://gist.github.com/525653]
40
+
41
+ Cranky has a nice debug option (rails only) to warn you when your factory is broken, recommend you do this for your first spec...
40
42
 
41
43
  describe User do
42
44
  it "should have a working factory" do
@@ -48,7 +50,7 @@ And has a nice debug option (rails only) to warn you when your factory is broken
48
50
  Cranky allows you to build factories via std Ruby methods, like this...
49
51
 
50
52
  # factories/my_factories.rb
51
- class Cranky # Your factory must use the Cranky class
53
+ class Cranky::Factory # Your factory must extend Cranky::Factory
52
54
 
53
55
  # Simple factory method to create a user instance, you would call this via Factory.build(:user)
54
56
  def user
@@ -87,14 +89,14 @@ This is where Cranky really shines, if you can create Ruby methods you can prett
87
89
 
88
90
  The only rules are:
89
91
 
90
- 1. Your factory must use the +Cranky+ class
92
+ 1. Your factory must extend the Cranky::Factory class
91
93
  2. Your factory method must return the object you wanted to create
92
94
  3. You can access the overrides passed in via options[:key] (not really a rule!)
93
95
 
94
96
  So for example to create a simple user factory...
95
97
 
96
98
  # factories/my_factories.rb
97
- class Cranky
99
+ class Cranky::Factory
98
100
 
99
101
  # Simple factory method to create a user instance, you would call this via Factory.build(:user)
100
102
  def user
@@ -112,7 +114,7 @@ Now of course you are working in straight Ruby here, so you can extend this any
112
114
  For example here it is with the capability to automatically create a default address association...
113
115
 
114
116
  # factories/my_factories.rb
115
- class Cranky
117
+ class Cranky::Factory
116
118
 
117
119
  # Return the default address if it already exists, or call the address factory to make one
118
120
  def default_address
@@ -233,17 +235,8 @@ Clear all instance variables in the factory. This may be useful to run between t
233
235
 
234
236
  Sometimes it is useful to be warned that your factory is generating invalid instances (although quite often your tests may intentionally generate invalid instances, so use this with care). By turning on debug the Factory will raise an error if the generated instance is invalid...
235
237
 
236
- Factory.debug = true
237
-
238
- Or run within a block...
239
-
240
- Factory.debug do
241
- Factory.build(:user)
242
- end
243
-
244
- Or inline (runs the build method with debug enabled)...
245
-
246
- Factory.debug(:user)
238
+ Factory.debug(:user) # A replacement for Factory.build, with validation warnings enabled
239
+ Factory.debug!(:user) # Likewise for Factory.create
247
240
 
248
241
  Note that this relies on the instance having a valid? method, so in practice this may only work with Rails.
249
242
 
data/init.rb CHANGED
@@ -1,2 +1,2 @@
1
- require 'crank_it'
1
+ require 'cranky'
2
2
 
@@ -0,0 +1,99 @@
1
+ module Cranky
2
+ class Factory
3
+
4
+ attr_writer :debug
5
+
6
+ def initialize
7
+ # Factory jobs can be nested, i.e. a factory method can itself invoke another factory method to
8
+ # build a dependent object. In this case jobs the jobs are pushed into a pipeline and executed
9
+ # in a last in first out order.
10
+ @pipeline = []
11
+ @n = 0
12
+ @errors = []
13
+ end
14
+
15
+ def build(what, overrides={})
16
+ crank_it(what, overrides)
17
+ end
18
+
19
+ def create(what, overrides={})
20
+ item = build(what, overrides)
21
+ item.save
22
+ item
23
+ end
24
+
25
+ # Reset the factory instance, clear all instance variables
26
+ def reset
27
+ self.instance_variables.each do |var|
28
+ instance_variable_set(var, nil)
29
+ end
30
+ initialize
31
+ end
32
+
33
+ def attributes_for(what, attrs={})
34
+ build(what, attrs).attributes
35
+ end
36
+
37
+ # Can be left in your tests as an alternative to build and to warn if your factory method
38
+ # ever starts producing invalid instances
39
+ def debug(*args)
40
+ item = build(*args)
41
+ if !item.valid?
42
+ raise "Oops, the #{item.class} created by the Factory has the following errors: #{item.errors}"
43
+ end
44
+ item
45
+ end
46
+
47
+ # Same thing for create
48
+ def debug!(*args)
49
+ item = debug(*args)
50
+ item.save
51
+ item
52
+ end
53
+
54
+ private
55
+
56
+ def n
57
+ @n += 1
58
+ end
59
+
60
+ def inherit(what, overrides={})
61
+ build(what, overrides.merge(options))
62
+ end
63
+
64
+ # Execute the requested factory method, crank out the target object!
65
+ def crank_it(what, overrides)
66
+ item = "TBD"
67
+ new_job(what, overrides) do
68
+ item = self.send(what) # Invoke the factory method
69
+ end
70
+ item
71
+ end
72
+
73
+ # This method actually makes the required object instance, it gets called by the users factory
74
+ # method, where the name 'define' makes more sense than it does here!
75
+ def define(defaults={})
76
+ current_job.defaults = defaults
77
+ current_job.execute
78
+ end
79
+
80
+ def current_job
81
+ @pipeline.last
82
+ end
83
+
84
+ # Returns a hash containing any top-level overrides passed in when the current factory was invoked
85
+ def options
86
+ current_job.overrides
87
+ end
88
+
89
+ # Adds a new job to the pipeline then yields to the caller to execute it
90
+ def new_job(what, overrides)
91
+ @pipeline << Job.new(what, overrides)
92
+ yield
93
+ @pipeline.pop
94
+ end
95
+
96
+ end
97
+
98
+ end
99
+
data/lib/cranky/job.rb ADDED
@@ -0,0 +1,44 @@
1
+ module Cranky
2
+ class Job
3
+
4
+ attr_writer :defaults
5
+ attr_reader :overrides
6
+
7
+ def initialize(target, overrides={})
8
+ @defaults = {}
9
+ @target = target
10
+ @overrides = overrides
11
+ end
12
+
13
+ def attributes
14
+ @attributes ||= @defaults.merge(@overrides)
15
+ end
16
+
17
+ def defaults=(defs)
18
+ @attributes = nil # Needs to be re-calculated
19
+ @defaults = defs
20
+ end
21
+
22
+ def execute
23
+ item = get_constant(attributes[:class] ? attributes[:class] : @target).new
24
+ # Assign all explicit attributes first
25
+ attributes.each do |attribute, value|
26
+ item.send("#{attribute}=", value) if item.respond_to?("#{attribute}=") && !value.respond_to?("call")
27
+ end
28
+ # Then call any blocks
29
+ attributes.each do |attribute, value|
30
+ item.send("#{attribute}=", value.call(item)) if item.respond_to?("#{attribute}=") && value.respond_to?("call")
31
+ end
32
+ item
33
+ end
34
+
35
+ private
36
+
37
+ # Nicked from here: http://gist.github.com/301173
38
+ def get_constant(name_sym)
39
+ name = name_sym.to_s.split('_').collect {|s| s.capitalize }.join('')
40
+ Object.const_defined?(name) ? Object.const_get(name) : Object.const_missing(name)
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module Cranky
2
+ VERSION = "0.2.0"
3
+ end
data/lib/cranky.rb CHANGED
@@ -1,106 +1,18 @@
1
- class Cranky
2
-
3
- VERSION = "0.1.1"
4
-
5
- # Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/*.rb").each do |file|
6
- # require file
7
- # # Auto include all modules found in the directory
8
- # file =~ /.*[\/\\](.*)\.rb/
9
- # begin
10
- # include $1.to_s.camelcase.constantize
11
- # rescue
12
- # end
13
- # end
14
-
15
- attr_writer :debug
16
-
17
- def initialize
18
- @what = []
19
- @attrs = []
20
- @n = 0
21
- end
22
-
23
- def build(what, attrs={})
24
- crank_it(what, false, attrs)
25
- end
26
-
27
- def create(what, attrs={})
28
- crank_it(what, true, attrs)
29
- end
30
-
31
- def reset
32
- self.instance_variables.each do |var|
33
- instance_variable_set(var, nil)
34
- end
35
- initialize
36
- end
37
-
38
- def attributes_for(what, attrs={})
39
- build(what, attrs).attributes
40
- end
41
-
42
- def debug(what=nil)
43
- if block_given?
44
- @debug = true
45
- yield
46
- @debug = false
47
- elsif what
48
- @debug = true
49
- item = build(what)
50
- @debug = false
51
- item
52
- else
53
- @debug
54
- end
55
- end
56
-
57
- private
58
-
59
- def n
60
- @n += 1
61
- end
62
-
63
- def inherit(what, attrs={})
64
- build(what, attrs.merge(options))
65
- end
66
-
67
- def crank_it(what, save, attrs)
68
- @attrs << attrs; @what << what
69
- item = self.send(what)
70
- @attrs.pop; @what.pop
71
- if @debug && !item.valid?
72
- raise "Oops, the #{what} created by the Factory has the following errors: #{item.errors}"
73
- end
74
- item.save if save
75
- item
76
- end
77
-
78
- def define(attrs={})
79
- final_attrs = attrs.merge(@attrs.last)
80
- item = get_constant(attrs[:class] ? attrs[:class] : @what.last).new
81
- final_attrs.delete(:class)
82
- # Assign all explicit attributes first
83
- final_attrs.each do |attr, value|
84
- item.send("#{attr}=", value) if item.respond_to?("#{attr}=") && !value.respond_to?("call")
85
- end
86
- # Then call any blocks
87
- final_attrs.each do |attr, value|
88
- item.send("#{attr}=", value.call(item)) if item.respond_to?("#{attr}=") && value.respond_to?("call")
89
- end
90
- item
91
- end
92
-
93
- # Nicked from here: http://gist.github.com/301173
94
- def get_constant(name_sym)
95
- name = name_sym.to_s.split('_').collect {|s| s.capitalize }.join('')
96
- Object.const_defined?(name) ? Object.const_get(name) : Object.const_missing(name)
97
- end
98
-
99
- def options
100
- @attrs.last
101
- end
102
-
1
+ require 'cranky/version'
2
+ require 'cranky/job'
3
+ require 'cranky/factory'
4
+
5
+ # Instantiate a factory, this enables an easy drop in for tests written for Factory Girl
6
+ Factory = Cranky::Factory.new unless defined?(Factory)
7
+
8
+ # Alternative Cranky specific syntax:
9
+ # crank(:user) # equivalent to Factory.build(:user)
10
+ # crank!(:user) # equivalent to Factory.create(:user)
11
+ def crank(*args)
12
+ Factory.build(*args)
103
13
  end
104
14
 
105
- Factory = Cranky.new unless defined?(Factory)
15
+ def crank!(*args)
16
+ Factory.create(*args)
17
+ end
106
18
 
data/spec/cranky_spec.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Cranky do
3
+ describe "The Cranky factory" do
4
4
 
5
5
  before(:each) do
6
6
  end
@@ -54,6 +54,13 @@ describe Cranky do
54
54
  b.role.should == :admin
55
55
  end
56
56
 
57
+ it "should give top priority to attributes defined at the top level, even when inheriting" do
58
+ a = Factory.build(:admin_manually, :role => :something_else)
59
+ a.role.should == :something_else
60
+ b = Factory.build(:admin_by_define, :role => :something_else)
61
+ b.role.should == :something_else
62
+ end
63
+
57
64
  it "should create unique values using the n method" do
58
65
  a = Factory.build(:user)
59
66
  b = Factory.build(:user)
@@ -66,40 +73,19 @@ describe Cranky do
66
73
  describe "debugger" do
67
74
 
68
75
  it "should raise an error if the factory produces an invalid object when enabled (rails only)" do
69
- Factory.debug = true
70
76
  error = false
71
77
  begin
72
- Factory.build(:user)
78
+ Factory.debug(:user, :valid => false)
73
79
  rescue
74
80
  error = true
75
81
  end
76
82
  error.should == true
77
- Factory.debug = false
78
83
  end
79
84
 
80
- it "can be run as a block" do
81
- Factory.debug.should == false
82
- error = false
83
- Factory.debug do
84
- begin
85
- Factory.build(:user)
86
- rescue
87
- error = true
88
- end
89
- end
90
- error.should == true
91
- Factory.debug.should == false
92
- end
93
-
94
- it "can be run inline" do
95
- Factory.debug.should == false
96
- error = false
97
- begin
98
- Factory.debug(:user)
99
- rescue
100
- error = true
101
- end
102
- error.should == true
85
+ it "should have debug work like build and create when there are no errors" do
86
+ Factory.debug(:user).class.should == User
87
+ Factory.debug(:user).saved?.should == false
88
+ Factory.debug!(:user).saved?.should == true
103
89
  end
104
90
 
105
91
  end
@@ -115,6 +101,20 @@ describe Cranky do
115
101
  Factory.build(:user, :name => "jenny", :email => Proc.new{ |u| "#{u.name}@home.com" }).email.should == "jenny@home.com"
116
102
  Factory.build(:user, :name => Proc.new{"jimmy" + " cranky"}).name.should == "jimmy cranky"
117
103
  end
104
+
105
+ it "allows factories to call other factories" do
106
+ Factory.build(:user_manually).address.city.should == "New York"
107
+ Factory.create(:user_manually).address.city.should == "New York"
108
+ Factory.create(:user_manually).address.saved?.should == false
109
+ Factory.build(:user_by_define).address.city.should == "New York"
110
+ Factory.create(:user_by_define).address.city.should == "New York"
111
+ Factory.create(:user_by_define).address.saved?.should == true
112
+ end
113
+
114
+ it "should also have its own syntax" do
115
+ crank(:user).saved?.should == false
116
+ crank!(:address).saved?.should == true
117
+ end
118
118
 
119
119
  end
120
120
 
data/spec/spec_helper.rb CHANGED
@@ -2,13 +2,9 @@ require 'rubygems'
2
2
  require 'spec'
3
3
  require 'cranky'
4
4
 
5
- # A basic model to crank out
6
- class User
7
- attr_accessor :name
8
- attr_accessor :role
9
- attr_accessor :email
10
- attr_accessor :unique
11
- attr_accessor :argument_received
5
+
6
+ class TestClass
7
+ attr_accessor :valid
12
8
 
13
9
  def save
14
10
  @saved = true
@@ -19,7 +15,7 @@ class User
19
15
  end
20
16
 
21
17
  def valid?
22
- false
18
+ @valid
23
19
  end
24
20
 
25
21
  def errors
@@ -29,11 +25,26 @@ class User
29
25
  def attributes
30
26
  self.instance_variables
31
27
  end
28
+ end
32
29
 
30
+ # A basic model to crank out
31
+ class User < TestClass
32
+ attr_accessor :name
33
+ attr_accessor :role
34
+ attr_accessor :email
35
+ attr_accessor :unique
36
+ attr_accessor :argument_received
37
+ attr_accessor :address
38
+ end
39
+
40
+
41
+ class Address < TestClass
42
+ attr_accessor :address
43
+ attr_accessor :city
33
44
  end
34
45
 
35
46
  # Some basic factory methods
36
- class Cranky
47
+ class Cranky::Factory
37
48
 
38
49
  attr_accessor :some_instance_variable
39
50
 
@@ -43,6 +54,8 @@ class Cranky
43
54
  u.role = options[:role] || :user
44
55
  u.unique = "value#{n}"
45
56
  u.email = "fred@home.com"
57
+ u.address = Factory.build(:address)
58
+ u.valid = true
46
59
  u
47
60
  end
48
61
 
@@ -51,7 +64,9 @@ class Cranky
51
64
  :name => "Fred",
52
65
  :role => :user,
53
66
  :unique => "value#{n}",
54
- :email => "fred@home.com"
67
+ :email => "fred@home.com",
68
+ :address => Factory.create(:address),
69
+ :valid => true
55
70
  u.argument_received = true if options[:argument_supplied]
56
71
  u
57
72
  end
@@ -65,6 +80,12 @@ class Cranky
65
80
  inherit(:user_by_define, :role => :admin)
66
81
  end
67
82
 
83
+ def address
84
+ define :address => "25 Wisteria Lane",
85
+ :city => "New York",
86
+ :valid => true
87
+ end
88
+
68
89
  end
69
90
 
70
91
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cranky
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Stephen McGinty
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-08-14 00:00:00 -05:00
18
+ date: 2010-08-22 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -28,6 +28,9 @@ extensions: []
28
28
  extra_rdoc_files: []
29
29
 
30
30
  files:
31
+ - lib/cranky/job.rb
32
+ - lib/cranky/factory.rb
33
+ - lib/cranky/version.rb
31
34
  - lib/cranky.rb
32
35
  - spec/spec_helper.rb
33
36
  - spec/cranky_spec.rb