blueprints 0.7.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +6 -11
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/blueprints.gemspec +14 -4
- data/lib/blueprints/blueprint.rb +31 -2
- data/lib/blueprints/buildable.rb +18 -20
- data/lib/blueprints/configuration.rb +0 -11
- data/lib/blueprints/core_ext.rb +69 -0
- data/lib/blueprints/dependency.rb +35 -0
- data/lib/blueprints/errors.rb +17 -5
- data/lib/blueprints/extensions/rspec.rb +16 -0
- data/lib/blueprints/file_context.rb +3 -4
- data/lib/blueprints/helper.rb +4 -18
- data/lib/blueprints/namespace.rb +5 -0
- data/lib/blueprints/root_namespace.rb +9 -9
- data/lib/blueprints.rb +22 -14
- data/spec/active_record/blueprint.rb +2 -1
- data/spec/active_record/blueprints_spec.rb +15 -48
- data/spec/active_record/spec_helper.rb +0 -1
- data/spec/no_db/blueprint.rb +3 -1
- data/spec/no_db/blueprints_spec.rb +20 -1
- data/spec/no_db/fixtures/fruit.rb +7 -0
- data/spec/no_db/spec_helper.rb +0 -1
- data/spec/test_all.sh +6 -3
- data/spec/unit/active_record_spec.rb +17 -0
- data/spec/unit/blueprint_spec.rb +58 -0
- data/spec/unit/buildable_spec.rb +14 -0
- data/spec/unit/configuration_spec.rb +1 -12
- data/spec/unit/dependency_spec.rb +39 -0
- data/spec/unit/namespace_spec.rb +23 -0
- data/spec/unit/spec_helper.rb +9 -0
- data/test/blueprints_test.rb +46 -49
- metadata +17 -7
- data/lib/blueprints/database_backends/active_record.rb +0 -48
- data/lib/blueprints/extensions/deprecated.rb +0 -22
data/README.rdoc
CHANGED
@@ -113,19 +113,15 @@ You can just type:
|
|
113
113
|
|
114
114
|
If you need to make associations then:
|
115
115
|
|
116
|
-
SomeModel.blueprint
|
116
|
+
SomeModel.blueprint(:something, :associated_column => d(:some_blueprint))
|
117
117
|
|
118
|
-
|
118
|
+
...or if the name of blueprint and the name of instance variable are not the same:
|
119
119
|
|
120
|
-
|
120
|
+
SomeModel.blueprint(:something, :associated_column => d(:some_blueprint, :some_instance_variable))
|
121
121
|
|
122
|
-
...
|
122
|
+
...and when you need to pass options to associated blueprint:
|
123
123
|
|
124
|
-
|
125
|
-
|
126
|
-
...or if name of blueprint that this one depends on and instance variable association uses are the same...
|
127
|
-
|
128
|
-
SomeModel.blueprint(:something, :associated_column => d(:some_blueprint)) # I prefer this one
|
124
|
+
SomeModel.blueprint(:something, :associated_column => d(:some_blueprint, :option => 'value'))
|
129
125
|
|
130
126
|
You can learn more about blueprint method in http://wiki.github.com/sinsiliux/blueprints/method-blueprint
|
131
127
|
|
@@ -148,11 +144,10 @@ which resets database to the state before the test. This state is empty database
|
|
148
144
|
|
149
145
|
== TODO
|
150
146
|
|
151
|
-
* Add ability to revert one blueprint.
|
152
147
|
* Add preloading blueprints for whole block of tests.
|
153
148
|
* Fix rake tasks
|
154
149
|
* Add merb support
|
155
|
-
* Add support for other test frameworks
|
150
|
+
* Add support for other test frameworks
|
156
151
|
|
157
152
|
== Credits
|
158
153
|
|
data/Rakefile
CHANGED
@@ -56,6 +56,8 @@ task :rspec_to_test do
|
|
56
56
|
data.gsub!(/(\s+)lambda \{\n(.*)\n(\s+)\}.should raise_error\((.*)\)/, "\\1assert_raise(\\4) do\n\\2\n\\3end")
|
57
57
|
# should =~ => assert_similar
|
58
58
|
data.gsub!(/^(\s+)(.*)\.should\s*=~\s*(.*)/, '\1assert_similar(\2, \3)')
|
59
|
+
# A.should_not include(B) => assert_false(A.include?(B))
|
60
|
+
data.gsub!(/^(\s+)(.*)\.should_not\s*include\((.*)\)/, '\1assert(!\2.include?(\3))')
|
59
61
|
|
60
62
|
# .should_not => assert(!())
|
61
63
|
data.gsub!(/^(\s+)(.*)\.should_not(.*)/, '\1assert(!(\2\3))')
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.0
|
data/blueprints.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{blueprints}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.8.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andrius Chamentauskas"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-08-13}
|
13
13
|
s.default_executable = %q{blueprintify}
|
14
14
|
s.description = %q{Another replacement for factories and fixtures. The library that lazy typists will love}
|
15
15
|
s.email = %q{sinsiliux@gmail.com}
|
@@ -38,10 +38,10 @@ Gem::Specification.new do |s|
|
|
38
38
|
"lib/blueprints/context.rb",
|
39
39
|
"lib/blueprints/convertable.rb",
|
40
40
|
"lib/blueprints/convertable/fixtures.rb",
|
41
|
-
"lib/blueprints/
|
41
|
+
"lib/blueprints/core_ext.rb",
|
42
|
+
"lib/blueprints/dependency.rb",
|
42
43
|
"lib/blueprints/errors.rb",
|
43
44
|
"lib/blueprints/extensions/cucumber.rb",
|
44
|
-
"lib/blueprints/extensions/deprecated.rb",
|
45
45
|
"lib/blueprints/extensions/rspec.rb",
|
46
46
|
"lib/blueprints/extensions/test_unit.rb",
|
47
47
|
"lib/blueprints/file_context.rb",
|
@@ -60,7 +60,12 @@ Gem::Specification.new do |s|
|
|
60
60
|
"spec/no_db/fixtures/fruit.rb",
|
61
61
|
"spec/no_db/spec_helper.rb",
|
62
62
|
"spec/test_all.sh",
|
63
|
+
"spec/unit/active_record_spec.rb",
|
64
|
+
"spec/unit/blueprint_spec.rb",
|
65
|
+
"spec/unit/buildable_spec.rb",
|
63
66
|
"spec/unit/configuration_spec.rb",
|
67
|
+
"spec/unit/dependency_spec.rb",
|
68
|
+
"spec/unit/namespace_spec.rb",
|
64
69
|
"spec/unit/spec_helper.rb",
|
65
70
|
"test/blueprints_test.rb",
|
66
71
|
"test/test_helper.rb",
|
@@ -76,8 +81,13 @@ Gem::Specification.new do |s|
|
|
76
81
|
"spec/no_db/spec_helper.rb",
|
77
82
|
"spec/no_db/blueprints_spec.rb",
|
78
83
|
"spec/no_db/blueprint.rb",
|
84
|
+
"spec/unit/active_record_spec.rb",
|
85
|
+
"spec/unit/blueprint_spec.rb",
|
79
86
|
"spec/unit/spec_helper.rb",
|
80
87
|
"spec/unit/configuration_spec.rb",
|
88
|
+
"spec/unit/namespace_spec.rb",
|
89
|
+
"spec/unit/buildable_spec.rb",
|
90
|
+
"spec/unit/dependency_spec.rb",
|
81
91
|
"spec/active_record/fixtures/fruit.rb",
|
82
92
|
"spec/active_record/fixtures/tree.rb",
|
83
93
|
"spec/active_record/fixtures/schema.rb",
|
data/lib/blueprints/blueprint.rb
CHANGED
@@ -6,12 +6,22 @@ module Blueprints
|
|
6
6
|
def initialize(name, file, &block)
|
7
7
|
@file = file
|
8
8
|
super(name)
|
9
|
+
|
10
|
+
ivname = :"@#{path}"
|
9
11
|
@block = block
|
12
|
+
@demolish_block = lambda { instance_variable_get(ivname).destroy }
|
13
|
+
@update_block = lambda { instance_variable_get(ivname).blueprint(options) }
|
10
14
|
end
|
11
15
|
|
12
16
|
# Builds blueprint and adds it to executed blueprint hash. Setups instance variable with same name as blueprint if it is not defined yet.
|
13
17
|
def build_self(build_once = true)
|
14
|
-
surface_errors
|
18
|
+
surface_errors do
|
19
|
+
if built? and build_once
|
20
|
+
Namespace.root.context.instance_eval(&@update_block) if RootNamespace.root.context.options.present?
|
21
|
+
elsif @block
|
22
|
+
@result = Namespace.root.context.instance_eval(&@block)
|
23
|
+
end
|
24
|
+
end
|
15
25
|
end
|
16
26
|
|
17
27
|
# Changes blueprint block to build another blueprint by passing additional options to it. Usually used to dry up
|
@@ -22,7 +32,26 @@ module Blueprints
|
|
22
32
|
end
|
23
33
|
|
24
34
|
def backtrace(trace)
|
25
|
-
trace.collect {|line| line.sub(/^\(eval\):(\d+).*/, "#{@file}:\\1:in blueprint '#{@name}'") }
|
35
|
+
trace.collect { |line| line.sub(/^\(eval\):(\d+).*/, "#{@file}:\\1:in blueprint '#{@name}'") }
|
36
|
+
end
|
37
|
+
|
38
|
+
# If block is passed then sets custom demolish block for this blueprint.
|
39
|
+
# If no block is passed then calls demolish block and marks blueprint as not built.
|
40
|
+
# Raises DemolishError if blueprints has not been built.
|
41
|
+
def demolish(&block)
|
42
|
+
if block
|
43
|
+
@demolish_block = block
|
44
|
+
elsif built?
|
45
|
+
Namespace.root.context.instance_eval(&@demolish_block)
|
46
|
+
undo!
|
47
|
+
else
|
48
|
+
raise DemolishError, @name
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Allows customizing what happens when blueprint is already built and it's being built again.
|
53
|
+
def update(&block)
|
54
|
+
@update_block = block
|
26
55
|
end
|
27
56
|
|
28
57
|
private
|
data/lib/blueprints/buildable.rb
CHANGED
@@ -1,13 +1,5 @@
|
|
1
1
|
module Blueprints
|
2
2
|
class Buildable
|
3
|
-
class Dependency < Struct.new(:name) # :nodoc:
|
4
|
-
alias :to_sym :name
|
5
|
-
|
6
|
-
def iv_name
|
7
|
-
:"@#{name}"
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
3
|
attr_reader :name
|
12
4
|
attr_accessor :namespace
|
13
5
|
|
@@ -31,15 +23,12 @@ module Blueprints
|
|
31
23
|
|
32
24
|
# Builds dependencies of blueprint and then blueprint itself.
|
33
25
|
#
|
34
|
-
# +build_once+ - pass false if you want to build
|
26
|
+
# +build_once+ - pass false if you want to build blueprint again instead of updating old one.
|
35
27
|
#
|
36
28
|
# +options+ - list of options to be accessible in the body of a blueprint. Defaults to empty Hash.
|
37
29
|
def build(build_once = true, options = {})
|
38
|
-
if
|
39
|
-
|
40
|
-
return @result
|
41
|
-
end
|
42
|
-
Namespace.root.executed_blueprints << path
|
30
|
+
return @result if (built? or Namespace.root.executed_blueprints.include? self) and build_once and options.blank?
|
31
|
+
Namespace.root.executed_blueprints << self
|
43
32
|
|
44
33
|
each_namespace {|namespace| namespace.build_parents }
|
45
34
|
build_parents
|
@@ -53,6 +42,17 @@ module Blueprints
|
|
53
42
|
Namespace.root.add_variable(path, @result)
|
54
43
|
end
|
55
44
|
|
45
|
+
# Returns if blueprint has been built
|
46
|
+
def built?
|
47
|
+
instance_variable_defined?(:@result)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Marks blueprint as not built
|
51
|
+
def undo!
|
52
|
+
remove_instance_variable(:@result) if built?
|
53
|
+
Namespace.root.executed_blueprints.delete self
|
54
|
+
end
|
55
|
+
|
56
56
|
# If value is passed then it sets attributes for this buildable object.
|
57
57
|
# Otherwise returns attributes (defaulting to empty Hash)
|
58
58
|
def attributes(value)
|
@@ -69,13 +69,11 @@ module Blueprints
|
|
69
69
|
def self.normalize_attributes(attributes)
|
70
70
|
attributes = attributes.dup
|
71
71
|
attributes.each do |attr, value|
|
72
|
-
if value.is_a?(Blueprints::
|
73
|
-
|
74
|
-
|
72
|
+
attributes[attr] = value.value if value.is_a?(Blueprints::Dependency)
|
73
|
+
if value.is_a? Symbol and value.to_s =~ /^@.+$/
|
74
|
+
STDERR.puts "DEPRECATION WARNING: :@variables are deprecated in favor of `d` method"
|
75
|
+
attributes[attr] = Blueprints::Namespace.root.context.instance_variable_get(value)
|
75
76
|
end
|
76
|
-
iv_name = value if value.is_a? Symbol and value.to_s =~ /^@.+$/
|
77
|
-
|
78
|
-
attributes[attr] = Blueprints::Namespace.root.context.instance_variable_get(iv_name) if iv_name
|
79
77
|
end
|
80
78
|
end
|
81
79
|
|
@@ -9,8 +9,6 @@ module Blueprints
|
|
9
9
|
attr_reader :root
|
10
10
|
# By default blueprints runs each test in it's own transaction. This may sometimes be not desirable so this options allows to turn this off.
|
11
11
|
attr_accessor :transactions
|
12
|
-
# Returns ORM that is used, default is :active_record
|
13
|
-
attr_reader :orm
|
14
12
|
|
15
13
|
# Sets default attributes for all attributes
|
16
14
|
def initialize
|
@@ -26,15 +24,6 @@ module Blueprints
|
|
26
24
|
@root = defined?(Rails) ? Rails.root : Pathname.pwd
|
27
25
|
end
|
28
26
|
|
29
|
-
# Allows specifying what ORM should be used. See SUPPORTED_ORMS to check what values it can contain.
|
30
|
-
def orm=(value)
|
31
|
-
if SUPPORTED_ORMS.include?(value)
|
32
|
-
@orm = value
|
33
|
-
else
|
34
|
-
raise ArgumentError, "Unsupported ORM #{value.inspect}. Blueprints supports only #{SUPPORTED_ORMS.collect(&:inspect).join(', ')}"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
27
|
def filename=(value)
|
39
28
|
@filename = Array(value).flatten.collect {|path| Pathname.new(path) }
|
40
29
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Include this module into your class if you need klass.blueprint and object.blueprint methods.
|
2
|
+
module Blueprints::Blueprintable
|
3
|
+
module ClassMethods
|
4
|
+
# Two forms of this method can be used. First one is typically used inside blueprint block. Essentially it does
|
5
|
+
# same as <tt>create!</tt>, except it does bypass attr_protected and attr_accessible. It accepts only a hash or attributes,
|
6
|
+
# same as <tt>create!</tt> does.
|
7
|
+
# blueprint :post => [:user, :board] do
|
8
|
+
# @user.posts.blueprint(:title => 'first post', :text => 'My first post')
|
9
|
+
# end
|
10
|
+
# The second form is used when you want to define new blueprint. It takes first argument as name of blueprint
|
11
|
+
# and second one as hash of attributes. As you cannot use instance variables outside of blueprint block, you need
|
12
|
+
# to prefix them with colon. So the example above could be rewritten like this:
|
13
|
+
# Post.blueprint(:post, :title => 'first post', :text => 'My first post', :user => d(:user)).depends_on(:board)
|
14
|
+
def blueprint(name_or_attrs, attrs = {})
|
15
|
+
if Blueprints::FileContext.current
|
16
|
+
define_blueprint(name_or_attrs, attrs)
|
17
|
+
else
|
18
|
+
if name_or_attrs.is_a?(Array)
|
19
|
+
name_or_attrs.collect { |attrs| blueprint(attrs) }
|
20
|
+
else
|
21
|
+
blueprint_object(name_or_attrs)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def define_blueprint(name, attrs)
|
29
|
+
klass = self
|
30
|
+
blueprint = Blueprints::Blueprint.new(name, Blueprints::FileContext.current.file) { klass.blueprint attributes }
|
31
|
+
blueprint.attributes(attrs)
|
32
|
+
blueprint
|
33
|
+
end
|
34
|
+
|
35
|
+
def blueprint_object(attrs)
|
36
|
+
object = new
|
37
|
+
object.blueprint(attrs)
|
38
|
+
object
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.included(mod)
|
43
|
+
mod.extend Blueprints::Blueprintable::ClassMethods
|
44
|
+
end
|
45
|
+
|
46
|
+
# Updates attributes of object by calling setter methods.
|
47
|
+
def blueprint(attributes)
|
48
|
+
Blueprints::Blueprint.normalize_attributes(attributes).each do |attr, val|
|
49
|
+
send(:"#{attr}=", val)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Include this instead of Blueprints::Blueprintable if record needs to persist, includes Blueprints::Blueprintable
|
55
|
+
module Blueprints::Saveable
|
56
|
+
include Blueprints::Blueprintable
|
57
|
+
|
58
|
+
def self.included(mod)
|
59
|
+
mod.extend Blueprints::Blueprintable::ClassMethods
|
60
|
+
end
|
61
|
+
|
62
|
+
# Overrides object.blueprint to also call save!
|
63
|
+
def blueprint(attributes)
|
64
|
+
super(attributes)
|
65
|
+
save!
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
::ActiveRecord::Base.send(:include, Blueprints::Saveable) if defined?(ActiveRecord)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Class for defining blueprint dependencies. Accepts up to 3 params:
|
2
|
+
# * name - pass the name of blueprint to build when trying to access value of this dependency.
|
3
|
+
# * iv_name (optional) - pass the name of instance variable to use for value. Defaults to same name as blueprint name.
|
4
|
+
# * options (optional) - pass options that are then passed to blueprint when building.
|
5
|
+
# Examples:
|
6
|
+
# Blueprints::Dependency.new(:blueprint).value # Builds blueprint 'blueprint' and returns value of @blueprint instance variable
|
7
|
+
# Blueprints::Dependency.new(:blueprint, value).value # Builds blueprint 'blueprint' and returns value of @value instance variable
|
8
|
+
# Blueprints::Dependency.new(:blueprint, :option => true).value # Builds blueprint 'blueprint' with options and returns value of @value instance variable
|
9
|
+
#
|
10
|
+
# Blueprints::Dependency objects also catch all missing methods. They are later replayed on instance variable when getting value. Example:
|
11
|
+
# d = Blueprints::Dependency.new(:blueprint).name.size
|
12
|
+
# d.value # => 4 when @blueprint.name == 'John'
|
13
|
+
class Blueprints::Dependency
|
14
|
+
# Initializes new copy of Blueprints::Dependency with name, iv_name and options.
|
15
|
+
def initialize(name, *args)
|
16
|
+
@name = name
|
17
|
+
@options = args.extract_options!
|
18
|
+
@iv_name = args.first || @name
|
19
|
+
@registry = []
|
20
|
+
end
|
21
|
+
|
22
|
+
# Builds blueprint (if necessary) and returns the value of instance variable.
|
23
|
+
def value
|
24
|
+
Blueprints::RootNamespace.root.build @name => @options
|
25
|
+
@registry.inject(Blueprints::RootNamespace.root.context.instance_variable_get(:"@#{@iv_name}")) do |value, (method, args, block)|
|
26
|
+
value.send(method, *args, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Catches all missing methods to later replay when asking for value.
|
31
|
+
def method_missing(method, *args, &block)
|
32
|
+
@registry << [method, args, block]
|
33
|
+
self
|
34
|
+
end
|
35
|
+
end
|
data/lib/blueprints/errors.rb
CHANGED
@@ -1,12 +1,24 @@
|
|
1
1
|
module Blueprints
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
@blueprints = args
|
2
|
+
class Error < StandardError
|
3
|
+
def initialize(blueprint)
|
4
|
+
@name = blueprint
|
6
5
|
end
|
7
6
|
|
8
7
|
def to_s
|
9
|
-
"Blueprint
|
8
|
+
"Blueprint '#{@name}' #{message_append}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class DemolishError < Error
|
13
|
+
def message_append
|
14
|
+
'must be built before demolishing'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Is raised when blueprint or namespace is not found.
|
19
|
+
class BlueprintNotFoundError < Error
|
20
|
+
def message_append
|
21
|
+
'not found'
|
10
22
|
end
|
11
23
|
end
|
12
24
|
end
|
@@ -1,6 +1,22 @@
|
|
1
|
+
module DescribeHelper
|
2
|
+
# Creates new before filter that builds blueprints before each spec.
|
3
|
+
def build_blueprint(*names)
|
4
|
+
before { build_blueprint *names }
|
5
|
+
end
|
6
|
+
|
7
|
+
# Same as #build_blueprint except that you can use it to build same blueprint several times.
|
8
|
+
def build_blueprint!(*names)
|
9
|
+
before { build_blueprint! *names }
|
10
|
+
end
|
11
|
+
|
12
|
+
alias :build :build_blueprint
|
13
|
+
alias :build! :build_blueprint!
|
14
|
+
end
|
15
|
+
|
1
16
|
config_class = defined?(RSpec) ? RSpec : Spec::Runner
|
2
17
|
config_class.configure do |config|
|
3
18
|
config.include(Blueprints::Helper)
|
19
|
+
config.extend(DescribeHelper)
|
4
20
|
config.before do
|
5
21
|
Blueprints.setup(self)
|
6
22
|
end
|
@@ -29,10 +29,9 @@ module Blueprints
|
|
29
29
|
namespace
|
30
30
|
end
|
31
31
|
|
32
|
-
#
|
33
|
-
|
34
|
-
|
35
|
-
Buildable::Dependency.new(name)
|
32
|
+
# Wrapper around Blueprints::Dependency.new. See Blueprints::Dependency for more information.
|
33
|
+
def d(*args)
|
34
|
+
Dependency.new(*args)
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
data/lib/blueprints/helper.rb
CHANGED
@@ -33,25 +33,11 @@ module Blueprints
|
|
33
33
|
alias :build :build_blueprint
|
34
34
|
alias :build! :build_blueprint!
|
35
35
|
|
36
|
-
#
|
37
|
-
# to remove scenarios from built scenarios cache.
|
36
|
+
# Demolishes built blueprints (by default simply calls destroy method on result of blueprint, but can be customized).
|
38
37
|
#
|
39
|
-
#
|
40
|
-
def demolish(*
|
41
|
-
|
42
|
-
options = args.extract_options!
|
43
|
-
args = (ActiveRecord::Base.connection.tables - ['schema_migrations']) if args.blank?
|
44
|
-
args.each {|table| ActiveRecord::Base.connection.execute("DELETE FROM #{table}") }
|
45
|
-
|
46
|
-
if options[:undo] == :all
|
47
|
-
Namespace.root.executed_blueprints.clear
|
48
|
-
else
|
49
|
-
undo = [options[:undo]].flatten.compact.collect(&:to_s)
|
50
|
-
unless (not_found = undo - Namespace.root.executed_blueprints.to_a).blank?
|
51
|
-
raise(BlueprintNotFoundError, not_found)
|
52
|
-
end
|
53
|
-
Namespace.root.executed_blueprints -= undo
|
54
|
-
end
|
38
|
+
# demolish :apple, :pear
|
39
|
+
def demolish(*names)
|
40
|
+
names.each { |name| Namespace.root[name].demolish }
|
55
41
|
end
|
56
42
|
end
|
57
43
|
end
|
data/lib/blueprints/namespace.rb
CHANGED
@@ -3,12 +3,10 @@ module Blueprints
|
|
3
3
|
# building blueprints/namespaces by name. Is also used for copying instance variables between blueprints/contexts/global
|
4
4
|
# context.
|
5
5
|
class RootNamespace < Namespace
|
6
|
-
attr_reader :context, :
|
7
|
-
attr_accessor :executed_blueprints
|
6
|
+
attr_reader :context, :executed_blueprints
|
8
7
|
|
9
8
|
def initialize
|
10
|
-
@executed_blueprints =
|
11
|
-
@global_executed_blueprints = Set.new
|
9
|
+
@executed_blueprints = @global_executed_blueprints = []
|
12
10
|
@auto_iv_list = Set.new
|
13
11
|
|
14
12
|
super ''
|
@@ -16,8 +14,10 @@ module Blueprints
|
|
16
14
|
|
17
15
|
# Loads all instance variables from global context to current one.
|
18
16
|
def setup
|
19
|
-
@
|
17
|
+
(@executed_blueprints - @global_executed_blueprints).each(&:undo!)
|
20
18
|
@executed_blueprints = @global_executed_blueprints.clone
|
19
|
+
@context = Blueprints::Context.new
|
20
|
+
|
21
21
|
if Blueprints.config.transactions
|
22
22
|
Marshal.load(@global_variables).each { |name, value| @context.instance_variable_set(name, value) }
|
23
23
|
else
|
@@ -35,10 +35,10 @@ module Blueprints
|
|
35
35
|
# Sets up global context and executes prebuilt blueprints against it.
|
36
36
|
def prebuild(blueprints)
|
37
37
|
@context = Blueprints::Context.new
|
38
|
-
|
39
|
-
@global_executed_blueprints = @executed_blueprints
|
38
|
+
build(blueprints) if blueprints
|
40
39
|
|
41
|
-
@
|
40
|
+
@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) })
|
42
42
|
end
|
43
43
|
|
44
44
|
# Builds blueprints that are passed against current context. Copies instance variables to context given if one is given.
|
@@ -46,7 +46,7 @@ module Blueprints
|
|
46
46
|
names = [names] unless names.is_a?(Array)
|
47
47
|
result = names.inject(nil) do |result, member|
|
48
48
|
if member.is_a?(Hash)
|
49
|
-
member.map {|name, options| self[name].build(build_once, options) }.last
|
49
|
+
member.map { |name, options| self[name].build(build_once, options) }.last
|
50
50
|
else
|
51
51
|
self[member].build(build_once)
|
52
52
|
end
|
data/lib/blueprints.rb
CHANGED
@@ -4,9 +4,9 @@ require 'database_cleaner'
|
|
4
4
|
require 'set'
|
5
5
|
|
6
6
|
files = %w{
|
7
|
-
configuration context buildable namespace root_namespace blueprint file_context helper errors
|
7
|
+
configuration context buildable namespace root_namespace blueprint file_context helper errors dependency core_ext
|
8
8
|
}
|
9
|
-
files.each {|f| require File.join(File.dirname(__FILE__), 'blueprints', f) }
|
9
|
+
files.each { |f| require File.join(File.dirname(__FILE__), 'blueprints', f) }
|
10
10
|
|
11
11
|
module Blueprints
|
12
12
|
# Contains current configuration of blueprints
|
@@ -18,12 +18,12 @@ module Blueprints
|
|
18
18
|
def self.setup(current_context)
|
19
19
|
Namespace.root.setup
|
20
20
|
Namespace.root.copy_ivars(current_context)
|
21
|
-
DatabaseCleaner.start
|
21
|
+
if_orm { DatabaseCleaner.start }
|
22
22
|
end
|
23
23
|
|
24
24
|
# Rollbacks transaction returning everything to state before test. Should be called after every test case.
|
25
25
|
def self.teardown
|
26
|
-
DatabaseCleaner.clean
|
26
|
+
if_orm { DatabaseCleaner.clean }
|
27
27
|
end
|
28
28
|
|
29
29
|
# Enables blueprints support for RSpec or Test::Unit depending on whether (R)Spec is defined or not. Yields
|
@@ -36,7 +36,7 @@ module Blueprints
|
|
36
36
|
elsif defined? Spec or defined? RSpec
|
37
37
|
'rspec'
|
38
38
|
else
|
39
|
-
|
39
|
+
'test_unit'
|
40
40
|
end
|
41
41
|
require File.join(File.dirname(__FILE__), 'blueprints', 'extensions', extension)
|
42
42
|
end
|
@@ -45,12 +45,12 @@ module Blueprints
|
|
45
45
|
def self.load
|
46
46
|
return unless Namespace.root.empty?
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
if_orm do
|
49
|
+
DatabaseCleaner.clean_with :truncation
|
50
|
+
DatabaseCleaner.strategy = (config.transactions ? :transaction : :truncation)
|
51
|
+
end
|
51
52
|
load_scenarios_files(config.filename)
|
52
53
|
|
53
|
-
DatabaseCleaner.strategy = (config.transactions ? :transaction : :truncation) if config.orm
|
54
54
|
Namespace.root.prebuild(config.prebuild) if config.transactions
|
55
55
|
end
|
56
56
|
|
@@ -59,10 +59,10 @@ module Blueprints
|
|
59
59
|
root_sub = /^#{config.root}[\\\/]/
|
60
60
|
blueprints_path = File.dirname(__FILE__).sub(root_sub, '')
|
61
61
|
|
62
|
-
bc.add_filter {|line| line.sub(root_sub, '') }
|
62
|
+
bc.add_filter { |line| line.sub(root_sub, '') }
|
63
63
|
|
64
|
-
bc.add_silencer {|line| File.dirname(line).starts_with?(blueprints_path) }
|
65
|
-
bc.add_silencer {|line| Gem.path.any? {|path| File.dirname(line).starts_with?(path) } }
|
64
|
+
bc.add_silencer { |line| File.dirname(line).starts_with?(blueprints_path) }
|
65
|
+
bc.add_silencer { |line| Gem.path.any? { |path| File.dirname(line).starts_with?(path) } }
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -77,10 +77,18 @@ module Blueprints
|
|
77
77
|
def self.load_scenarios_files(patterns)
|
78
78
|
patterns.each do |pattern|
|
79
79
|
pattern = config.root.join(pattern)
|
80
|
-
Dir[pattern]
|
81
|
-
|
80
|
+
files = Dir[pattern.to_s]
|
81
|
+
files.each { |f| FileContext.new f }
|
82
|
+
return if files.size > 0
|
82
83
|
end
|
83
84
|
|
84
85
|
raise "Blueprints file not found! Put blueprints in #{patterns.join(' or ')} or pass custom filename pattern with :filename option"
|
85
86
|
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def self.if_orm
|
91
|
+
yield
|
92
|
+
rescue DatabaseCleaner::NoORMDetected, DatabaseCleaner::NoStrategySetError
|
93
|
+
end
|
86
94
|
end
|
@@ -44,6 +44,7 @@ Tree.blueprint(:oak_without_attributes)
|
|
44
44
|
|
45
45
|
blueprint :pine do
|
46
46
|
@the_pine = Tree.blueprint :name => 'Pine', :size => 'medium'
|
47
|
+
@pine = Tree.blueprint :name => 'Pine', :size => 'small'
|
47
48
|
end
|
48
49
|
|
49
50
|
Fruit.blueprint(:acorn, :species => 'Acorn', :tree => d(:oak))
|
@@ -74,7 +75,7 @@ namespace :attributes do
|
|
74
75
|
|
75
76
|
Fruit.blueprint :shortened_cherry, :species => 'cherry'
|
76
77
|
|
77
|
-
Fruit.blueprint :dependent_cherry1, :tree => d(:pine)
|
78
|
+
Fruit.blueprint :dependent_cherry1, :tree => d(:pine, :the_pine)
|
78
79
|
Fruit.blueprint(:dependent_cherry2, :tree => :@the_pine).depends_on(:pine)
|
79
80
|
end.attributes(:average_diameter => 10, :species => 'fruit with attributes')
|
80
81
|
|