blueprints 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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