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.
- data/.gitignore +4 -1
- data/Gemfile +2 -0
- data/Gemfile.lock +82 -18
- data/LICENSE +1 -1
- data/README.rdoc +38 -8
- data/Rakefile +11 -35
- data/blueprints.gemspec +29 -123
- data/features/support/env.rb +7 -10
- data/lib/blueprints.rb +68 -12
- data/lib/blueprints/blueprint.rb +39 -19
- data/lib/blueprints/buildable.rb +92 -74
- data/lib/blueprints/configuration.rb +18 -4
- data/lib/blueprints/context.rb +148 -5
- data/lib/blueprints/database_cleaner_fix.rb +9 -0
- data/lib/blueprints/dependency.rb +32 -21
- data/lib/blueprints/eval_context.rb +51 -0
- data/lib/blueprints/extensions.rb +115 -0
- data/lib/blueprints/extensions/rspec.rb +3 -1
- data/lib/blueprints/helper.rb +52 -20
- data/lib/blueprints/namespace.rb +31 -12
- data/lib/blueprints/root_namespace.rb +24 -25
- data/lib/blueprints/version.rb +3 -0
- data/spec/{active_record/blueprint.rb → blueprint.rb} +14 -17
- data/spec/{active_record/blueprints_spec.rb → blueprints_spec.rb} +40 -59
- data/spec/spec_helper.rb +34 -0
- data/spec/support/active_record/database.yml.example +7 -0
- data/spec/support/active_record/initializer.rb +15 -0
- data/spec/{active_record/fixtures → support/active_record}/schema.rb +0 -0
- data/spec/support/dm-core/initializer.rb +31 -0
- data/spec/support/mongo_mapper/database.yml.example +2 -0
- data/spec/support/mongo_mapper/initializer.rb +20 -0
- data/spec/support/mongoid/database.yml.example +2 -0
- data/spec/support/mongoid/initializer.rb +23 -0
- data/spec/support/none/initializer.rb +63 -0
- data/spec/unit/active_record_spec.rb +1 -6
- data/spec/unit/blueprint_spec.rb +91 -20
- data/spec/unit/blueprints_spec.rb +44 -0
- data/spec/unit/buildable_spec.rb +37 -6
- data/spec/unit/configuration_spec.rb +11 -0
- data/spec/unit/context_spec.rb +100 -0
- data/spec/unit/dependency_spec.rb +24 -19
- data/spec/unit/eval_context_spec.rb +56 -0
- data/spec/unit/fixtures.rb +61 -0
- data/spec/unit/namespace_spec.rb +59 -11
- data/spec/unit/spec_helper.rb +8 -16
- data/test/blueprints_test.rb +40 -59
- data/test/test_helper.rb +6 -16
- data/test_all.sh +45 -0
- metadata +178 -61
- data/VERSION +0 -1
- data/lib/blueprints/core_ext.rb +0 -69
- data/lib/blueprints/file_context.rb +0 -37
- data/spec/active_record/fixtures/database.yml.example +0 -8
- data/spec/active_record/fixtures/fruit.rb +0 -3
- data/spec/active_record/fixtures/tree.rb +0 -4
- data/spec/active_record/spec_helper.rb +0 -37
- data/spec/no_db/blueprint.rb +0 -9
- data/spec/no_db/blueprints_spec.rb +0 -45
- data/spec/no_db/fixtures/fruit.rb +0 -15
- data/spec/no_db/spec_helper.rb +0 -14
- data/spec/test_all.sh +0 -39
data/features/support/env.rb
CHANGED
@@ -1,19 +1,16 @@
|
|
1
1
|
require 'cucumber'
|
2
2
|
require 'active_record'
|
3
|
-
|
4
|
-
|
3
|
+
require 'pathname'
|
4
|
+
Root = Pathname.new(__FILE__).dirname.join('..', '..')
|
5
|
+
$: << Root.join('lib').to_s
|
6
|
+
|
7
|
+
require 'blueprints'
|
8
|
+
require File.dirname(__FILE__) + "/../../spec/support/active_record/initializer"
|
5
9
|
|
6
|
-
ActiveRecord::Base.logger = Logger.new("debug.log")
|
7
|
-
databases = YAML::load_file(Root + "/spec/active_record/fixtures/database.yml")
|
8
|
-
db_info = databases[ENV["DB"] || "test"]
|
9
|
-
ActiveRecord::Base.establish_connection(db_info)
|
10
10
|
# Comment out the next two lines if you're not using RSpec's matchers (should / should_not) in your steps.
|
11
11
|
#require 'cucumber/rspec'
|
12
12
|
|
13
|
-
require Root + '/spec/active_record/fixtures/fruit'
|
14
|
-
require Root + '/spec/active_record/fixtures/tree'
|
15
|
-
|
16
13
|
Blueprints.enable do |config|
|
17
|
-
config.root = Root
|
14
|
+
config.root = Root.join('spec')
|
18
15
|
config.prebuild = :big_cherry
|
19
16
|
end
|
data/lib/blueprints.rb
CHANGED
@@ -1,23 +1,33 @@
|
|
1
1
|
require 'active_support'
|
2
|
-
require 'active_support/core_ext'
|
2
|
+
require 'active_support/core_ext/kernel/singleton_class'
|
3
|
+
require 'active_support/core_ext/object/blank'
|
4
|
+
require 'active_support/core_ext/module/delegation'
|
5
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
6
|
+
require 'active_support/core_ext/hash/reverse_merge'
|
7
|
+
require 'active_support/core_ext/hash/keys'
|
8
|
+
require 'active_support/core_ext/string/inflections'
|
9
|
+
require 'active_support/core_ext/enumerable'
|
3
10
|
require 'database_cleaner'
|
4
11
|
require 'set'
|
5
12
|
|
6
13
|
files = %w{
|
7
|
-
configuration context buildable namespace root_namespace blueprint
|
14
|
+
configuration context eval_context buildable namespace root_namespace blueprint helper errors dependency extensions database_cleaner_fix
|
8
15
|
}
|
9
|
-
files.each { |f| require
|
16
|
+
files.each { |f| require "blueprints/#{f}" }
|
10
17
|
|
18
|
+
# Main namespace of blueprints. Contains methods for Blueprints setup.
|
11
19
|
module Blueprints
|
12
20
|
# Contains current configuration of blueprints
|
21
|
+
# @return [Blueprints::Configuration] Current configuration.
|
13
22
|
def self.config
|
14
23
|
@@config ||= Blueprints::Configuration.new
|
15
24
|
end
|
16
25
|
|
17
26
|
# Setups variables from global context and starts transaction. Should be called before every test case.
|
27
|
+
# @param current_context Object to copy instance variables for prebuilt blueprints/namespaces.
|
18
28
|
def self.setup(current_context)
|
19
29
|
Namespace.root.setup
|
20
|
-
Namespace.root.
|
30
|
+
Namespace.root.eval_context.copy_instance_variables(current_context)
|
21
31
|
if_orm { DatabaseCleaner.start }
|
22
32
|
end
|
23
33
|
|
@@ -28,6 +38,8 @@ module Blueprints
|
|
28
38
|
|
29
39
|
# Enables blueprints support for RSpec or Test::Unit depending on whether (R)Spec is defined or not. Yields
|
30
40
|
# Blueprints::Configuration object that you can use to configure blueprints.
|
41
|
+
# @yield [config] Used to configure blueprints.
|
42
|
+
# @yieldparam [Blueprints::Configuration] config Current blueprints configuration.
|
31
43
|
def self.enable
|
32
44
|
yield config if block_given?
|
33
45
|
load
|
@@ -54,18 +66,39 @@ module Blueprints
|
|
54
66
|
Namespace.root.prebuild(config.prebuild) if config.transactions
|
55
67
|
end
|
56
68
|
|
69
|
+
# Returns backtrace cleaner that is used to extract lines from user application.
|
70
|
+
# @return [ActiveSupport::BacktraceCleaner] Backtrace cleaner
|
57
71
|
def self.backtrace_cleaner
|
58
72
|
@backtrace_cleaner ||= ActiveSupport::BacktraceCleaner.new.tap do |bc|
|
59
|
-
root_sub
|
60
|
-
blueprints_path = File.dirname(__FILE__)
|
73
|
+
root_sub = /^#{config.root}[\\\/]/
|
74
|
+
blueprints_path = File.expand_path(File.dirname(__FILE__))
|
61
75
|
|
62
76
|
bc.add_filter { |line| line.sub(root_sub, '') }
|
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) } }
|
77
|
+
bc.add_silencer { |line| [blueprints_path, *Gem.path].any? { |path| File.expand_path(File.dirname(line)).starts_with?(path) } }
|
66
78
|
end
|
67
79
|
end
|
68
80
|
|
81
|
+
# Returns array of blueprints that have not been used until now.
|
82
|
+
# @return [Array<String>] List of unused blueprints.
|
83
|
+
def self.unused
|
84
|
+
each_blueprint.select { |blueprint| blueprint.uses.zero? }.collect(&:full_name)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns array of most used blueprints.
|
88
|
+
# @param [Hash] options Options on what blueprints to return.
|
89
|
+
# @option options [Integer] :count Max amount of most used blueprints to return.
|
90
|
+
# @option options [Integer] :at_least Only blueprints that have at least specified number of uses will be returned.
|
91
|
+
# @return [Array<Array<String, Integer>>] List of most used blueprints together with their use counts.
|
92
|
+
def self.most_used(options = {})
|
93
|
+
blueprints = each_blueprint.collect { |blueprint| [blueprint.full_name, blueprint.uses] }.sort { |a, b| b[1] <=> a[1] }
|
94
|
+
blueprints = blueprints.take(options[:count]) if options[:count]
|
95
|
+
blueprints.reject! { |blueprint| blueprint[1] < options[:at_least] } if options[:at_least]
|
96
|
+
blueprints
|
97
|
+
end
|
98
|
+
|
99
|
+
# Warns a user (often about deprecated feature).
|
100
|
+
# @param [String] message Message to output.
|
101
|
+
# @param [Blueprints::Blueprint] blueprint Name of blueprint that this occurred in.
|
69
102
|
def self.warn(message, blueprint)
|
70
103
|
$stderr.puts("**WARNING** #{message}: '#{blueprint.name}'")
|
71
104
|
$stderr.puts(backtrace_cleaner.clean(blueprint.backtrace(caller)).first)
|
@@ -73,12 +106,14 @@ module Blueprints
|
|
73
106
|
|
74
107
|
protected
|
75
108
|
|
76
|
-
# Loads blueprints file and creates blueprints from data it contains. Is run by setup method
|
109
|
+
# Loads blueprints file and creates blueprints from data it contains. Is run by setup method.
|
110
|
+
# @param [Array<String>] patterns List of filesystem patterns to search blueprint files in.
|
111
|
+
# @raise [RuntimeError] If no blueprints file can be found.
|
77
112
|
def self.load_scenarios_files(patterns)
|
78
113
|
patterns.each do |pattern|
|
79
114
|
pattern = config.root.join(pattern)
|
80
|
-
files
|
81
|
-
files.each { |
|
115
|
+
files = Dir[pattern.to_s]
|
116
|
+
files.each { |file| Context.eval_within_context(:file => file, :namespace => Namespace.root) }
|
82
117
|
return if files.size > 0
|
83
118
|
end
|
84
119
|
|
@@ -87,6 +122,27 @@ module Blueprints
|
|
87
122
|
|
88
123
|
private
|
89
124
|
|
125
|
+
def self.each_blueprint(from = Namespace.root)
|
126
|
+
enumerator_class.new do |enum|
|
127
|
+
from.children.values.collect do |child|
|
128
|
+
if child.is_a?(Blueprints::Blueprint)
|
129
|
+
enum.yield child
|
130
|
+
else
|
131
|
+
each_blueprint(child).each { |blueprint| enum.yield blueprint }
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.enumerator_class
|
138
|
+
@enumerator_class ||= if defined?(Enumerator)
|
139
|
+
Enumerator
|
140
|
+
else
|
141
|
+
require 'generator'
|
142
|
+
Generator
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
90
146
|
def self.if_orm
|
91
147
|
yield
|
92
148
|
rescue DatabaseCleaner::NoORMDetected, DatabaseCleaner::NoStrategySetError
|
data/lib/blueprints/blueprint.rb
CHANGED
@@ -1,48 +1,68 @@
|
|
1
1
|
module Blueprints
|
2
2
|
# Class for actual blueprints. Allows building itself by executing block passed against current context.
|
3
3
|
class Blueprint < Buildable
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
# Holds how many times this particular blueprint was built
|
5
|
+
attr_reader :uses
|
6
|
+
|
7
|
+
# Initializes blueprint by name, context and block. Also sets default demolish and update blocks.
|
8
|
+
# @param name (see Buildable#initialize)
|
9
|
+
# @param context (see Buildable#initialize)
|
10
|
+
def initialize(name, context, &block)
|
11
|
+
super(name, context)
|
9
12
|
|
10
13
|
ivname = variable_name
|
11
14
|
@block = block
|
12
|
-
@demolish_block =
|
13
|
-
@update_block =
|
15
|
+
@demolish_block = Proc.new { instance_variable_get(ivname).destroy }
|
16
|
+
@update_block = Proc.new { instance_variable_get(ivname).blueprint(options) }
|
17
|
+
@uses = 0
|
14
18
|
end
|
15
19
|
|
16
|
-
# Builds blueprint and adds it to executed blueprint
|
17
|
-
|
20
|
+
# Builds blueprint and adds it to executed blueprint array. Setups instance variable with same name as blueprint if it is not defined yet.
|
21
|
+
# Marks blueprint as used.
|
22
|
+
# @param eval_context (see Buildable#build)
|
23
|
+
# @param build_once (see Buildable#build)
|
24
|
+
# @param options (see Buildable#build)
|
25
|
+
def build_self(eval_context, build_once, options)
|
26
|
+
@uses += 1 unless built?
|
18
27
|
surface_errors do
|
19
28
|
if built? and build_once
|
20
|
-
|
29
|
+
eval_context.instance_eval(@context, options, &@update_block) if options.present?
|
21
30
|
elsif @block
|
22
|
-
|
31
|
+
result(eval_context) { eval_context.instance_eval(@context, options, &@block) }
|
23
32
|
end
|
24
33
|
end
|
25
34
|
end
|
26
35
|
|
27
36
|
# Changes blueprint block to build another blueprint by passing additional options to it. Usually used to dry up
|
28
37
|
# blueprints that are often built with some options.
|
38
|
+
# @example Extending blueprints
|
39
|
+
# Post.blueprint :post, :title => 'hello blueprints'
|
40
|
+
# blueprint(:published_post).extends(:post, :published_at => Time.now)
|
41
|
+
# @param [Symbol, String] parent Name of parent blueprint.
|
42
|
+
# @param [Hash] options Options to be passed when building parent.
|
29
43
|
def extends(parent, options)
|
30
44
|
attributes(options)
|
31
45
|
@block = Proc.new { build parent => attributes }
|
32
46
|
end
|
33
47
|
|
48
|
+
# Changes backtrace to include what blueprint was being built.
|
49
|
+
# @param [Array<String>] trace Current trace
|
50
|
+
# @return [Array<String>] Changed trace with included currently built blueprint name.
|
34
51
|
def backtrace(trace)
|
35
|
-
trace.collect { |line| line.sub(
|
52
|
+
trace.collect! { |line| line.sub(/^#{@context.file}:(\d+).*/, "#{@context.file}:\\1:in blueprint '#{@name}'") }
|
36
53
|
end
|
37
54
|
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
|
55
|
+
# @overload demolish(&block)
|
56
|
+
# Sets custom block for demolishing this blueprint.
|
57
|
+
# @overload demolish(eval_context)
|
58
|
+
# Demolishes blueprint by calling demolish block.
|
59
|
+
# @param [Blueprints::EvalContext] eval_context Context where blueprint was built in.
|
60
|
+
# @raise [Blueprints::DemolishError] If blueprint has not been built yet.
|
61
|
+
def demolish(eval_context = nil, &block)
|
42
62
|
if block
|
43
63
|
@demolish_block = block
|
44
|
-
elsif built?
|
45
|
-
|
64
|
+
elsif eval_context and built?
|
65
|
+
eval_context.instance_eval(@context, {}, &@demolish_block)
|
46
66
|
undo!
|
47
67
|
else
|
48
68
|
raise DemolishError, @name
|
@@ -59,7 +79,7 @@ module Blueprints
|
|
59
79
|
def surface_errors
|
60
80
|
yield
|
61
81
|
rescue StandardError => error
|
62
|
-
|
82
|
+
backtrace(error.backtrace)
|
63
83
|
raise error
|
64
84
|
end
|
65
85
|
end
|
data/lib/blueprints/buildable.rb
CHANGED
@@ -1,60 +1,72 @@
|
|
1
1
|
module Blueprints
|
2
2
|
class Buildable
|
3
|
+
delegate :namespace, :dependencies, :to => :@context
|
3
4
|
attr_reader :name
|
4
|
-
attr_accessor :namespace
|
5
5
|
|
6
|
-
# Initializes new Buildable object by name.
|
7
|
-
#
|
8
|
-
# are assumed as dependencies.
|
9
|
-
#
|
10
|
-
|
6
|
+
# Initializes new Buildable object by name and context which it belongs to.
|
7
|
+
# @param [#to_sym, Hash] name Name of buildable. If hash is passed then first key is assumed name, and
|
8
|
+
# value(s) of that key are assumed as dependencies.
|
9
|
+
# @param [Blueprints::Context] context Context of buildable that later might get updated.
|
10
|
+
# @raise [TypeError] If name is invalid.
|
11
|
+
def initialize(name, context)
|
12
|
+
@context = context
|
13
|
+
|
14
|
+
if name.nil?
|
15
|
+
default_attribute = Blueprints.config.default_attributes.detect { |attribute| attributes.has_key?(attribute) }
|
16
|
+
name = attributes[default_attribute].parameterize('_') if default_attribute
|
17
|
+
end
|
11
18
|
@name, parents = parse_name(name)
|
12
19
|
depends_on(*parents)
|
13
20
|
|
14
|
-
|
15
|
-
Namespace.root.add_child(self) if Namespace.root
|
21
|
+
namespace.add_child(self) if namespace
|
16
22
|
end
|
17
23
|
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
self
|
24
|
+
# Returns class, name, attributes and dependencies of buildable in nice formatted string.
|
25
|
+
# @return [String] Inspected properties of buildable.
|
26
|
+
def inspect
|
27
|
+
"<##{self.class} name: #{full_name.inspect}, attributes: #{attributes.inspect}, dependencies: #{dependencies.inspect}>"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Defines dependencies of buildable by updating it's context.
|
31
|
+
# @param [Array<String, Symbol>] dependencies List of dependencies.
|
32
|
+
def depends_on(*dependencies)
|
33
|
+
update_context(:dependencies => dependencies)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @overload attributes
|
37
|
+
# Returns attributes of buildable
|
38
|
+
# @return [Hash] Attributes of buildable
|
39
|
+
# @overload attributes(value)
|
40
|
+
# Merges attributes of buildable with new attributes by updating context
|
41
|
+
# @param [Hash] Updated attributes
|
42
|
+
def attributes(value = nil)
|
43
|
+
if value
|
44
|
+
update_context(:attributes => value)
|
45
|
+
else
|
46
|
+
@context.attributes
|
47
|
+
end
|
22
48
|
end
|
23
49
|
|
24
50
|
# Builds dependencies of blueprint and then blueprint itself.
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
return result if @building or (built? and build_once and options.blank?)
|
51
|
+
# @param [Blueprints::EvalContext] eval_context Context to build buildable object in.
|
52
|
+
# @param [true, false] build_once Used if buildable is already built. If true then old one is updated else buildable is built again.
|
53
|
+
# @param [Hash] options List of options to be accessible in the body of a blueprint.
|
54
|
+
def build(eval_context, build_once = true, options = {})
|
55
|
+
return result(eval_context) if @building or (built? and build_once and options.blank?)
|
31
56
|
@building = true
|
32
57
|
|
33
|
-
each_namespace {|namespace| namespace.build_parents }
|
34
|
-
build_parents
|
58
|
+
each_namespace { |namespace| namespace.build_parents(eval_context) }
|
59
|
+
build_parents(eval_context)
|
35
60
|
|
36
|
-
|
37
|
-
Namespace.root.context.options, Namespace.root.context.attributes = options, normalized_attributes.merge(options)
|
38
|
-
each_namespace {|namespace| Namespace.root.context.attributes.reverse_merge! namespace.normalized_attributes }
|
39
|
-
|
40
|
-
build_self(build_once)
|
41
|
-
Namespace.root.context.options, Namespace.root.context.attributes = old_options, old_attributes
|
61
|
+
result = build_self(eval_context, build_once, options)
|
42
62
|
Namespace.root.executed_blueprints << self
|
63
|
+
|
43
64
|
@building = false
|
44
65
|
result
|
45
66
|
end
|
46
67
|
|
47
|
-
# Returns the result of blueprint
|
48
|
-
def result
|
49
|
-
Namespace.root.context.instance_variable_get(variable_name)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Sets the result of blueprint
|
53
|
-
def result=(value)
|
54
|
-
Namespace.root.add_variable(variable_name, value)
|
55
|
-
end
|
56
|
-
|
57
68
|
# Returns if blueprint has been built
|
69
|
+
# @return [true, false] true if was built, false otherwise
|
58
70
|
def built?
|
59
71
|
Namespace.root.executed_blueprints.include?(self)
|
60
72
|
end
|
@@ -64,40 +76,31 @@ module Blueprints
|
|
64
76
|
Namespace.root.executed_blueprints.delete self
|
65
77
|
end
|
66
78
|
|
67
|
-
#
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
# Returns normalized attributes for that particular blueprint.
|
75
|
-
def normalized_attributes
|
76
|
-
Buildable.normalize_attributes(@attributes ||= {})
|
79
|
+
# Returns full path to this buildable
|
80
|
+
# @param [String] join_with Separator used to join names of parent namespaces and buildable itself.
|
81
|
+
# @return [String] full path to this buildable joined with separator
|
82
|
+
def path(join_with = '_')
|
83
|
+
(namespace.path(join_with) + join_with unless namespace.nil? or namespace.path.empty?).to_s + @name.to_s
|
77
84
|
end
|
78
85
|
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
attributes[attr] = value.blueprint_value if value.respond_to?(:blueprint_value)
|
84
|
-
if value.is_a? Symbol and value.to_s =~ /^@.+$/
|
85
|
-
STDERR.puts "DEPRECATION WARNING: :@variables are deprecated in favor of `d` method"
|
86
|
-
attributes[attr] = Blueprints::Namespace.root.context.instance_variable_get(value)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
attributes
|
86
|
+
# Returns full name for this buildable
|
87
|
+
# @return [String] full buildable name
|
88
|
+
def full_name
|
89
|
+
path('.')
|
90
90
|
end
|
91
91
|
|
92
|
-
|
93
|
-
|
92
|
+
# Builds all dependencies. Should be called before building itself. Searches dependencies first in parent then in root namespace.
|
93
|
+
# @param [Blueprints::EvalContext] eval_context Context to build parents against.
|
94
|
+
# @raise [Blueprints::BlueprintNotFoundError] If one of dependencies can't be found.
|
95
|
+
def build_parents(eval_context)
|
96
|
+
@context.dependencies.each do |name|
|
94
97
|
parent = begin
|
95
|
-
namespace[
|
98
|
+
namespace[name]
|
96
99
|
rescue BlueprintNotFoundError
|
97
|
-
Namespace.root[
|
100
|
+
Namespace.root[name]
|
98
101
|
end
|
99
102
|
|
100
|
-
parent.build
|
103
|
+
parent.build(eval_context)
|
101
104
|
end
|
102
105
|
end
|
103
106
|
|
@@ -108,23 +111,38 @@ module Blueprints
|
|
108
111
|
yield(namespace) while namespace = namespace.namespace
|
109
112
|
end
|
110
113
|
|
111
|
-
def path
|
112
|
-
@path = (namespace.path + "_" unless namespace.nil? or namespace.path.empty?).to_s + @name.to_s
|
113
|
-
end
|
114
|
-
|
115
114
|
def variable_name
|
116
115
|
:"@#{path}"
|
117
116
|
end
|
118
117
|
|
119
118
|
def parse_name(name)
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
119
|
+
if name.is_a?(Hash)
|
120
|
+
return name.keys.first.to_sym, [name.values.first].flatten.map { |sc| parse_name(sc).first }
|
121
|
+
elsif name.respond_to?(:to_sym)
|
122
|
+
name = name.to_sym unless name == ''
|
123
|
+
return name, []
|
124
|
+
else
|
125
|
+
raise TypeError, "Pass blueprint names as strings or symbols only, cannot define blueprint #{name.inspect}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def update_context(options)
|
130
|
+
@context = @context.with_context(options)
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def result(eval_context)
|
137
|
+
if block_given?
|
138
|
+
yield.tap do |result|
|
139
|
+
if @auto_variable or not eval_context.instance_variable_defined?(variable_name)
|
140
|
+
eval_context.instance_variable_set(variable_name, result)
|
141
|
+
@auto_variable = true
|
142
|
+
end
|
143
|
+
end
|
144
|
+
else
|
145
|
+
eval_context.instance_variable_get(variable_name)
|
128
146
|
end
|
129
147
|
end
|
130
148
|
end
|