blueprints 0.8.2 → 0.9.0

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.
Files changed (61) hide show
  1. data/.gitignore +4 -1
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +82 -18
  4. data/LICENSE +1 -1
  5. data/README.rdoc +38 -8
  6. data/Rakefile +11 -35
  7. data/blueprints.gemspec +29 -123
  8. data/features/support/env.rb +7 -10
  9. data/lib/blueprints.rb +68 -12
  10. data/lib/blueprints/blueprint.rb +39 -19
  11. data/lib/blueprints/buildable.rb +92 -74
  12. data/lib/blueprints/configuration.rb +18 -4
  13. data/lib/blueprints/context.rb +148 -5
  14. data/lib/blueprints/database_cleaner_fix.rb +9 -0
  15. data/lib/blueprints/dependency.rb +32 -21
  16. data/lib/blueprints/eval_context.rb +51 -0
  17. data/lib/blueprints/extensions.rb +115 -0
  18. data/lib/blueprints/extensions/rspec.rb +3 -1
  19. data/lib/blueprints/helper.rb +52 -20
  20. data/lib/blueprints/namespace.rb +31 -12
  21. data/lib/blueprints/root_namespace.rb +24 -25
  22. data/lib/blueprints/version.rb +3 -0
  23. data/spec/{active_record/blueprint.rb → blueprint.rb} +14 -17
  24. data/spec/{active_record/blueprints_spec.rb → blueprints_spec.rb} +40 -59
  25. data/spec/spec_helper.rb +34 -0
  26. data/spec/support/active_record/database.yml.example +7 -0
  27. data/spec/support/active_record/initializer.rb +15 -0
  28. data/spec/{active_record/fixtures → support/active_record}/schema.rb +0 -0
  29. data/spec/support/dm-core/initializer.rb +31 -0
  30. data/spec/support/mongo_mapper/database.yml.example +2 -0
  31. data/spec/support/mongo_mapper/initializer.rb +20 -0
  32. data/spec/support/mongoid/database.yml.example +2 -0
  33. data/spec/support/mongoid/initializer.rb +23 -0
  34. data/spec/support/none/initializer.rb +63 -0
  35. data/spec/unit/active_record_spec.rb +1 -6
  36. data/spec/unit/blueprint_spec.rb +91 -20
  37. data/spec/unit/blueprints_spec.rb +44 -0
  38. data/spec/unit/buildable_spec.rb +37 -6
  39. data/spec/unit/configuration_spec.rb +11 -0
  40. data/spec/unit/context_spec.rb +100 -0
  41. data/spec/unit/dependency_spec.rb +24 -19
  42. data/spec/unit/eval_context_spec.rb +56 -0
  43. data/spec/unit/fixtures.rb +61 -0
  44. data/spec/unit/namespace_spec.rb +59 -11
  45. data/spec/unit/spec_helper.rb +8 -16
  46. data/test/blueprints_test.rb +40 -59
  47. data/test/test_helper.rb +6 -16
  48. data/test_all.sh +45 -0
  49. metadata +178 -61
  50. data/VERSION +0 -1
  51. data/lib/blueprints/core_ext.rb +0 -69
  52. data/lib/blueprints/file_context.rb +0 -37
  53. data/spec/active_record/fixtures/database.yml.example +0 -8
  54. data/spec/active_record/fixtures/fruit.rb +0 -3
  55. data/spec/active_record/fixtures/tree.rb +0 -4
  56. data/spec/active_record/spec_helper.rb +0 -37
  57. data/spec/no_db/blueprint.rb +0 -9
  58. data/spec/no_db/blueprints_spec.rb +0 -45
  59. data/spec/no_db/fixtures/fruit.rb +0 -15
  60. data/spec/no_db/spec_helper.rb +0 -14
  61. data/spec/test_all.sh +0 -39
@@ -1,10 +1,12 @@
1
1
  module DescribeHelper
2
2
  # Creates new before filter that builds blueprints before each spec.
3
+ # @param names (see Helper#build)
3
4
  def build_blueprint(*names)
4
5
  before { build_blueprint *names }
5
6
  end
6
7
 
7
- # Same as #build_blueprint except that you can use it to build same blueprint several times.
8
+ # Same as DescribeHelper#build_blueprint except that you can use it to build same blueprint several times.
9
+ # @param names (see Helper#build)
8
10
  def build_blueprint!(*names)
9
11
  before { build_blueprint! *names }
10
12
  end
@@ -2,42 +2,74 @@ module Blueprints
2
2
  # A helper module that should be included in test framework. Adds methods <tt>build</tt> and <tt>demolish</tt>
3
3
  module Helper
4
4
  # Builds one or more blueprints by their names. You can pass names as symbols or strings. You can also pass additional
5
- # options hash which will be available by calling <tt>options</tt> in blueprint block. Returns result of blueprint block.
6
- # # build :apple and orange blueprints
5
+ # options hash which will be available by calling <tt>options</tt> in blueprint block. Returns result of last blueprint block.
6
+ # @example build :apple and :orange blueprints.
7
7
  # build :apple, :orange
8
- #
9
- # # build :apple scenario with additional options
8
+ # @example build :apple blueprint with additional options.
10
9
  # build :apple => {:color => 'red'}
11
- #
12
- # # options can also be passed for several blueprints
10
+ # @example passing options to several blueprints.
13
11
  # build :pear, :apple => {:color => 'red'}, :orange => {:color => 'orange'}
14
- def build_blueprint(*names)
12
+ # @param [Array<Symbol, String, Hash>] names Names of blueprints/namespaces to build. Pass Hash if you want to pass additional options.
13
+ # @return Return value of last blueprint
14
+ def build(*names)
15
15
  Namespace.root.build(names, self, true)
16
16
  end
17
17
 
18
- # Same as #build_blueprint except that you can use it to build same blueprint several times.
19
- def build_blueprint!(*names)
20
- Namespace.root.build(names, self, false)
18
+ # Same as #build except that you can use it to build same blueprint several times.
19
+ # @overload build!(*names)
20
+ # @param [Array<Symbol, String, Hash>] names Names of blueprints/namespaces to build. Pass Hash if you want to pass additional options.
21
+ # @return Return value of last blueprint
22
+ # @overload build!(count, *names)
23
+ # @param [Integer] count Times to build passed blueprint
24
+ # @param [Array<Symbol, String, Hash>] names Names of blueprints/namespaces to build. Pass Hash if you want to pass additional options.
25
+ # @return [Array] Array of return values of last blueprint, which is same size as count that you pass
26
+ def build!(*names)
27
+ if names.first.is_a?(Integer)
28
+ (0...names.shift).collect { build! *names }
29
+ else
30
+ Namespace.root.build(names, self, false)
31
+ end
21
32
  end
22
33
 
23
- # Returns attributes that are used to build blueprint. To set what attributes are used you need to call attributes
24
- # method when defining blueprint like this:
25
- # blueprint :apple do
34
+ # Returns attributes that are used to build blueprint.
35
+ # @example Setting and retrieving attributes.
36
+ # # In blueprint.rb file
37
+ # attributes(:name => 'apple').blueprint :apple do
26
38
  # Fruit.build attributes
27
- # end.attributes(:name => 'apple')
39
+ # end
40
+ #
41
+ # # In spec/test file
42
+ # build_attributes :apple #=> {:name => 'apple'}
43
+ # @param [Symbol, String] name Name of blueprint/namespace.
44
+ # @return [Hash] Normalized attributes of blueprint/namespace
28
45
  def build_attributes(name)
29
- Namespace.root[name].build_parents
30
- Namespace.root[name].normalized_attributes.tap { Blueprints::Namespace.root.copy_ivars(self) }
46
+ blueprint = Namespace.root[name]
47
+ blueprint.build_parents(Namespace.root.eval_context)
48
+ Namespace.root.eval_context.normalize_hash(blueprint.attributes).tap { Namespace.root.eval_context.copy_instance_variables(self) }
31
49
  end
32
50
 
33
- alias :build :build_blueprint
34
- alias :build! :build_blueprint!
51
+ # Returns Blueprint::Dependency object that can be used to define dependencies on other blueprints.
52
+ # @example Building :post blueprint with different user.
53
+ # build :post => {:user => d(:admin)}
54
+ # @example Building :post blueprint by first building :user_profile with :name => 'John', then taking value of @profile and calling +user+ on it.
55
+ # build :post => {:user => d(:user_profile, :profile, :name => 'John').user}
56
+ # @see Blueprints::Dependency#initialize Blueprints::Dependency for accepted arguments.
57
+ # @return [Blueprints::Dependency] Dependency object that can be passed as option when building blueprint/namespace.
58
+ def d(*args)
59
+ Dependency.new(*args)
60
+ end
35
61
 
36
62
  # Demolishes built blueprints (by default simply calls destroy method on result of blueprint, but can be customized).
37
- #
63
+ # @example Demolish :apple and :pear blueprints
38
64
  # demolish :apple, :pear
65
+ # @param [Array<Symbol, String>] names Names of blueprints/namespaces to demolish.
39
66
  def demolish(*names)
40
- names.each { |name| Namespace.root[name].demolish }
67
+ names.each { |name| Namespace.root[name].demolish(Namespace.root.eval_context) }
41
68
  end
69
+
70
+ alias :build_blueprint :build
71
+ alias :build_blueprint! :build!
72
+ alias :blueprint_dependency :d
73
+ alias :blueprint_demolish :demolish
42
74
  end
43
75
  end
@@ -1,5 +1,5 @@
1
1
  module Blueprints
2
- # Namespace class, inherits from <tt>Buildable</tt>. Allows adding and finding child blueprints/namespaces and building
2
+ # Namespace class, inherits from Buildable. Allows adding and finding child blueprints/namespaces and building
3
3
  # all it's children.
4
4
  class Namespace < Buildable
5
5
  cattr_accessor :root
@@ -7,20 +7,27 @@ module Blueprints
7
7
  delegate :empty?, :size, :to => :@children
8
8
 
9
9
  # Creates namespace by name. See Buildable#new.
10
- def initialize(name)
11
- super(name)
10
+ # @param name (see Buildable#initialize)
11
+ # @param context (see Buildable#initialize)
12
+ def initialize(name, context)
12
13
  @children = {}
14
+ super(name, context)
13
15
  end
14
16
 
15
- # Adds child to namespaces children. Child should be instance of Buildable.
17
+ # Adds child to namespaces children. Warns if this will overwrite existing child.
18
+ # @param [Blueprints::Buildable] child Namespace or blueprint to add as a child.
16
19
  def add_child(child)
20
+ Blueprints.warn("Overwriting existing blueprint", child) if @children[child.name]
17
21
  @children[child.name] = child
18
- child.namespace = self
19
22
  end
20
23
 
21
- # Finds child by relative name. Raises BlueprintNotFoundError if child can't be found.
24
+ # Finds child by relative name.
25
+ # @param [String] path Path to child. Path parts should be joined with '.' symbol.
26
+ # @return [Blueprints::Buildable] Blueprint or namespace that matches path.
27
+ # @raise [BlueprintNotFoundError] If child can't be found.
22
28
  def [](path)
23
29
  child_name, path = path.to_s.split('.', 2)
30
+
24
31
  child = @children[child_name.to_sym] or raise BlueprintNotFoundError, child_name
25
32
  if path
26
33
  child[path]
@@ -29,14 +36,26 @@ module Blueprints
29
36
  end
30
37
  end
31
38
 
32
- # Builds all children and sets instance variable named by name of namespace with the results.
33
- def build_self(build_once = true)
34
- self.result = @children.collect {|p| p.last.build }.uniq
39
+ # Builds all children and sets an instance variable named by name of namespace with the results.
40
+ # @param eval_context (see Buildable#build)
41
+ # @param build_once (see Buildable#build)
42
+ # @param options (see Buildable#build)
43
+ # @return [Array] Results of all blueprints.
44
+ def build_self(eval_context, build_once, options)
45
+ result(eval_context) { @children.values.collect { |child| child.build(eval_context, build_once, options) }.uniq }
46
+ end
47
+
48
+ # Demolishes all child blueprints and namespaces.
49
+ # @param [Blueprints::EvalContext] eval_context Eval context that this namespace was built in.
50
+ def demolish(eval_context)
51
+ @children.each_value { |blueprint| blueprint.demolish(eval_context) }
35
52
  end
36
53
 
37
- # Demolished all child blueprints and namespaces
38
- def demolish
39
- @children.each_value(&:demolish)
54
+ protected
55
+
56
+ def update_context(options)
57
+ @children.each_value { |child| child.update_context(options) }
58
+ super
40
59
  end
41
60
  end
42
61
  end
@@ -1,68 +1,67 @@
1
+
1
2
  module Blueprints
2
3
  # Defines a root namespace that is used when no other namespace is. Apart from functionality in namespace it also allows
3
4
  # building blueprints/namespaces by name. Is also used for copying instance variables between blueprints/contexts/global
4
5
  # context.
5
6
  class RootNamespace < Namespace
6
- attr_reader :context, :executed_blueprints
7
+ # Lists of executed blueprints (to prevent executing twice). Cleared before each test.
8
+ attr_reader :executed_blueprints
9
+ # Context that blueprints/namespaces are built against. Reset before each test.
10
+ attr_writer :eval_context
7
11
 
12
+ # Initialized new root context.
8
13
  def initialize
9
14
  @executed_blueprints = @global_executed_blueprints = []
10
15
  @auto_iv_list = Set.new
11
16
 
12
- super ''
17
+ super '', Context.new
13
18
  end
14
19
 
15
- # Loads all instance variables from global context to current one.
20
+ # Loads all instance variables from global context to current one. Creates new eval context.
16
21
  def setup
22
+ @eval_context = EvalContext.new
17
23
  (@executed_blueprints - @global_executed_blueprints).each(&:undo!)
18
24
  @executed_blueprints = @global_executed_blueprints.clone
19
- @context = Blueprints::Context.new
20
25
 
21
26
  if Blueprints.config.transactions
22
- Marshal.load(@global_variables).each { |name, value| @context.instance_variable_set(name, value) }
27
+ Marshal.load(@global_variables).each { |name, value| eval_context.instance_variable_set(name, value) }
23
28
  else
24
29
  build(Blueprints.config.prebuild)
25
30
  end
26
31
  end
27
32
 
28
- # Copies all instance variables from current context to another one.
29
- def copy_ivars(to)
30
- @context.instance_variables.each do |iv|
31
- to.instance_variable_set(iv, @context.instance_variable_get(iv))
32
- end
33
- end
34
-
35
33
  # Sets up global context and executes prebuilt blueprints against it.
34
+ # @param [Array<Symbol, String>] blueprints Names of blueprints that are prebuilt.
36
35
  def prebuild(blueprints)
37
- @context = Blueprints::Context.new
38
36
  build(blueprints) if blueprints
39
37
 
40
38
  @global_executed_blueprints = @executed_blueprints
41
- @global_variables = Marshal.dump(@context.instance_variables.each_with_object({}) { |iv, hash| hash[iv] = @context.instance_variable_get(iv) })
39
+ @global_variables = Marshal.dump(eval_context.instance_variables.each_with_object({}) { |iv, hash| hash[iv] = eval_context.instance_variable_get(iv) })
42
40
  end
43
41
 
44
42
  # Builds blueprints that are passed against current context. Copies instance variables to context given if one is given.
45
- def build(names, context = nil, build_once = true)
43
+ # @param [Array<Symbol, String>] names List of blueprints/namespaces to build.
44
+ # @param current_context Object to copy instance variables from eval context after building to.
45
+ # @param build_once (see Buildable.build)
46
+ # @return Result of last blueprint/namespace.
47
+ def build(names, current_context = nil, build_once = true)
46
48
  names = [names] unless names.is_a?(Array)
47
49
  result = names.inject(nil) do |result, member|
48
50
  if member.is_a?(Hash)
49
- member.map { |name, options| self[name].build(build_once, options) }.last
51
+ member.map { |name, options| self[name].build(eval_context, build_once, options) }.last
50
52
  else
51
- self[member].build(build_once)
53
+ self[member].build(eval_context, build_once)
52
54
  end
53
55
  end
54
56
 
55
- copy_ivars(context) if context
57
+ eval_context.copy_instance_variables(current_context) if current_context
56
58
  result
57
59
  end
58
60
 
59
- # Sets instance variable in current context to passed value. If instance variable with same name already exists, it
60
- # is set only if it was set using this same method
61
- def add_variable(name, value)
62
- if not @context.instance_variable_defined?(name) or @auto_iv_list.include?(name)
63
- @auto_iv_list << name
64
- @context.instance_variable_set(name, value)
65
- end
61
+ # Return current eval context or creates a new one.
62
+ # @return [Blueprints::EvalContext] Eval context to be used to build blueprints.
63
+ def eval_context
64
+ @eval_context ||= EvalContext.new
66
65
  end
67
66
 
68
67
  @@root = RootNamespace.new
@@ -0,0 +1,3 @@
1
+ module Blueprints
2
+ VERSION = '0.9.0'
3
+ end
@@ -1,19 +1,15 @@
1
- blueprint :error do
2
- raise 'error'
3
- end
4
-
5
1
  blueprint :apple do
6
- Fruit.create! :species => 'apple'
2
+ Fruit.blueprint :species => 'apple'
7
3
  end
8
4
 
9
5
  blueprint :many_apples => [:apple, :apple, :apple]
10
6
 
11
7
  blueprint :bananas_and_apples => :apple do
12
- @banana = Fruit.create! :species => 'banana'
8
+ @banana = Fruit.blueprint :species => 'banana'
13
9
  end
14
10
 
15
11
  blueprint :orange do
16
- Fruit.create! :species => 'orange'
12
+ Fruit.blueprint :species => 'orange'
17
13
  end
18
14
 
19
15
  blueprint :fruit => [:apple, :orange] do
@@ -25,11 +21,11 @@ blueprint :bananas_and_apples_and_oranges => [:bananas_and_apples, :orange] do
25
21
  end
26
22
 
27
23
  blueprint :cherry do
28
- Fruit.create! :species => 'cherry', :average_diameter => 3
24
+ Fruit.blueprint :species => 'cherry', :average_diameter => 3
29
25
  end
30
26
 
31
27
  blueprint :big_cherry => :cherry do
32
- Fruit.create! options.reverse_merge(:species => @cherry.species, :average_diameter => 7)
28
+ Fruit.blueprint options.reverse_merge(:species => @cherry.species, :average_diameter => 7)
33
29
  end
34
30
 
35
31
  blueprint :cherry_basket => [:big_cherry, :cherry] do
@@ -49,15 +45,15 @@ end
49
45
 
50
46
  Fruit.blueprint(:acorn, :species => 'Acorn', :tree => d(:oak))
51
47
  blueprint :small_acorn do
52
- @small_acorn = build :acorn => {:average_diameter => 1}
53
48
  @small_acorn_options = options
49
+ build :acorn => {:average_diameter => 1}
54
50
  end
55
51
  blueprint(:huge_acorn => :huge_oak).extends(:acorn, :average_diameter => 100)
56
52
 
57
53
  namespace :pitted => :pine do
58
54
  Tree.blueprint :peach_tree, :name => 'pitted peach tree'
59
- Fruit.blueprint(:peach, :species => 'pitted peach', :tree => :@peach_tree).depends_on(:peach_tree)
60
- Fruit.blueprint(:acorn, :species => 'pitted acorn', :tree => :@oak).depends_on(:oak)
55
+ Fruit.blueprint :peach, :species => 'pitted peach', :tree => d(:'pitted.peach_tree')
56
+ Fruit.blueprint :acorn, :species => 'pitted acorn', :tree => d(:oak)
61
57
 
62
58
  namespace :red => :orange do
63
59
  Fruit.blueprint(:apple, :species => 'pitted red apple')
@@ -65,18 +61,19 @@ namespace :pitted => :pine do
65
61
  end
66
62
 
67
63
  blueprint :apple_with_params do
68
- Fruit.create! options.reverse_merge(:species => 'apple')
64
+ Fruit.blueprint options.reverse_merge(:species => 'apple')
69
65
  end
70
66
 
71
- namespace :attributes do
67
+ attributes(:average_diameter => 10, :species => 'fruit with attributes').namespace :attributes do
72
68
  blueprint :cherry do
73
69
  Fruit.blueprint attributes
74
70
  end.attributes(:species => 'cherry')
75
71
 
76
72
  Fruit.blueprint :shortened_cherry, :species => 'cherry'
77
73
 
78
- Fruit.blueprint :dependent_cherry1, :tree => d(:pine, :the_pine)
79
- Fruit.blueprint(:dependent_cherry2, :tree => :@the_pine).depends_on(:pine)
80
- end.attributes(:average_diameter => 10, :species => 'fruit with attributes')
74
+ Fruit.blueprint :dependent_cherry, :tree => d(:pine, :the_pine)
75
+ end
81
76
 
82
77
  blueprint :circular_reference => :circular_reference
78
+
79
+ Tree.blueprint :name => 'infered'
@@ -67,16 +67,30 @@ describe Blueprints do
67
67
  end
68
68
  end
69
69
 
70
+ describe "build per describe" do
71
+ unless File.dirname(__FILE__) =~ /test$/
72
+ build_blueprint :apple
73
+
74
+ it "should have cherry" do
75
+ @apple.should_not be_nil
76
+ end
77
+
78
+ it "should have correct cherry species" do
79
+ @apple.species.should == 'apple'
80
+ end
81
+ end
82
+ end
83
+
70
84
  describe 'with preloaded cherry scenario' do
71
85
  it "should have correct size after changed by second test" do
72
86
  @cherry.average_diameter.should == 3
73
- @cherry.update_attribute(:average_diameter, 1)
87
+ @cherry.blueprint(:average_diameter => 1)
74
88
  @cherry.average_diameter.should == 1
75
89
  end
76
90
 
77
91
  it "should have correct size" do
78
92
  @cherry.average_diameter.should == 3
79
- @cherry.update_attribute(:average_diameter, 5)
93
+ @cherry.blueprint(:average_diameter => 5)
80
94
  @cherry.average_diameter.should == 5
81
95
  end
82
96
 
@@ -94,7 +108,7 @@ describe Blueprints do
94
108
  demolish :apple
95
109
  Fruit.all.should_not include(@apple)
96
110
  build :apple
97
- Fruit.last.should == @apple
111
+ Fruit.all.should include(@apple)
98
112
  end
99
113
 
100
114
  it "should overwrite auto created instance variable with another auto created one" do
@@ -120,11 +134,11 @@ describe Blueprints do
120
134
  end
121
135
 
122
136
  it "should create only one apple" do
123
- Fruit.all(:conditions => 'species = "apple"').size.should == 1
137
+ Fruit.all(:conditions => {:species => "apple"}).size.should == 1
124
138
  end
125
139
 
126
140
  it "should create only two cherries even if they were preloaded" do
127
- Fruit.all(:conditions => 'species = "cherry"').size.should == 2
141
+ Fruit.all(:conditions => {:species => "cherry"}).size.should == 2
128
142
  end
129
143
 
130
144
  it "should contain cherries in basket if basket is loaded in test and cherries preloaded" do
@@ -132,26 +146,6 @@ describe Blueprints do
132
146
  end
133
147
  end
134
148
 
135
- describe 'transactions' do
136
- before do
137
- build :apple
138
- end
139
-
140
- it "should drop only inner transaction" do
141
- @apple.reload.should_not be_nil
142
- begin
143
- ActiveRecord::Base.transaction do
144
- f = Fruit.create(:species => 'orange')
145
- f.reload.should_not be_nil
146
- raise 'some error'
147
- end
148
- rescue
149
- end
150
- @apple.reload.should_not be_nil
151
- Fruit.find_by_species('orange').should be_nil
152
- end
153
- end
154
-
155
149
  describe 'errors' do
156
150
  it 'should raise ScenarioNotFoundError when scenario could not be found' do
157
151
  lambda {
@@ -164,12 +158,6 @@ describe Blueprints do
164
158
  build :parent_not_existing
165
159
  }.should raise_error(Blueprints::BlueprintNotFoundError)
166
160
  end
167
-
168
- it 'should raise TypeError when scenario name is not symbol or string' do
169
- lambda {
170
- Blueprints::Blueprint.new(1, __FILE__)
171
- }.should raise_error(TypeError, "Pass blueprint names as strings or symbols only, cannot define blueprint 1")
172
- end
173
161
  end
174
162
 
175
163
  describe 'with active record blueprints extensions' do
@@ -202,7 +190,7 @@ describe Blueprints do
202
190
 
203
191
  it "should normalize attributes when updating with blueprint method" do
204
192
  build :cherry, :oak
205
- @cherry.blueprint(:tree => :@oak)
193
+ build :cherry => {:tree => d(:oak)}
206
194
  @cherry.tree.should == @oak
207
195
  end
208
196
 
@@ -213,8 +201,7 @@ describe Blueprints do
213
201
  end
214
202
 
215
203
  it "should allow to pass array of hashes to blueprint method" do
216
- Fruit.create
217
- fruits = Fruit.blueprint([{:species => 'fruit1'}, {:species => 'fruit2'}])
204
+ fruits = Fruit.blueprint({:species => 'fruit1'}, {:species => 'fruit2'})
218
205
  fruits.collect(&:species).should == %w{fruit1 fruit2}
219
206
  end
220
207
 
@@ -331,23 +318,27 @@ describe Blueprints do
331
318
  end
332
319
  end
333
320
 
334
- it "should allow to build! without checking if it was already built" do
335
- build! :big_cherry, :big_cherry => {:species => 'not so big cherry'}
336
- Fruit.count.should == 4
337
- Fruit.find_by_species('not so big cherry').should_not be_nil
338
- end
321
+ describe "build!" do
322
+ it "should allow to building same blueprint again" do
323
+ build! :big_cherry, :big_cherry => {:species => 'not so big cherry'}
324
+ Fruit.count.should == 4
325
+ Fruit.first(:conditions => {:species => 'not so big cherry'}).should_not be_nil
326
+ end
339
327
 
340
- it "should warn when blueprint with same name exists" do
341
- STDERR.expects(:puts).with("**WARNING** Overwriting existing blueprint: 'overwritten'")
342
- STDERR.expects(:puts).with(regexp_matches(/blueprints_(spec|test)\.rb:\d+:in `new'/))
343
- Blueprints::Blueprint.new(:overwritten, __FILE__)
344
- Blueprints::Blueprint.new(:overwritten, __FILE__)
328
+ it "should allow building same blueprint n times" do
329
+ oaks = build! 5, :oak
330
+ oaks.should have(5).items
331
+ oaks.each do |oak|
332
+ oak.should be_instance_of(Tree)
333
+ oak.name.should == 'Oak'
334
+ end
335
+ end
345
336
  end
346
337
 
347
338
  describe 'attributes' do
348
339
  it "should allow to extract attributes from blueprint" do
349
- build_attributes('attributes.cherry').should == {:species => 'cherry'}
350
- build_attributes('attributes.shortened_cherry').should == {:species => 'cherry'}
340
+ build_attributes('attributes.cherry').should == {:species => 'cherry', :average_diameter => 10}
341
+ build_attributes('attributes.shortened_cherry').should == {:species => 'cherry', :average_diameter => 10}
351
342
  build_attributes(:big_cherry).should == {}
352
343
  end
353
344
 
@@ -367,13 +358,7 @@ describe Blueprints do
367
358
  end
368
359
 
369
360
  it "should return build attributes for dependencies" do
370
- attrs = build_attributes('attributes.dependent_cherry1')
371
- @the_pine.should_not be_nil
372
- attrs[:tree].should == @the_pine
373
- end
374
-
375
- it "should return build attributes for :@var" do
376
- attrs = build_attributes('attributes.dependent_cherry2')
361
+ attrs = build_attributes('attributes.dependent_cherry')
377
362
  @the_pine.should_not be_nil
378
363
  attrs[:tree].should == @the_pine
379
364
  end
@@ -383,11 +368,7 @@ describe Blueprints do
383
368
  build :circular_reference
384
369
  end
385
370
 
386
- it "should rewrite trace" do
387
- begin
388
- build :error
389
- rescue RuntimeError => e
390
- e.backtrace[0].should == "spec/active_record/blueprint.rb:2:in blueprint 'error'"
391
- end
371
+ it "should allow inferring blueprint name" do
372
+ build(:infered).name.should == 'infered'
392
373
  end
393
374
  end