calificador 0.1.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +97 -0
- data/lib/calificador.rb +44 -0
- data/lib/calificador/assertor.rb +134 -0
- data/lib/calificador/build/attribute.rb +20 -0
- data/lib/calificador/build/attribute_container.rb +103 -0
- data/lib/calificador/build/attribute_evaluator.rb +85 -0
- data/lib/calificador/build/factory.rb +132 -0
- data/lib/calificador/build/trait.rb +20 -0
- data/lib/calificador/key.rb +59 -0
- data/lib/calificador/minitest/minitest_patches.rb +27 -0
- data/lib/calificador/spec/basic_context.rb +353 -0
- data/lib/calificador/spec/class_method_context.rb +42 -0
- data/lib/calificador/spec/condition_context.rb +10 -0
- data/lib/calificador/spec/examine_context.rb +29 -0
- data/lib/calificador/spec/instance_method_context.rb +38 -0
- data/lib/calificador/spec/test_environment.rb +141 -0
- data/lib/calificador/spec/test_method.rb +64 -0
- data/lib/calificador/spec/test_root.rb +44 -0
- data/lib/calificador/spec/type_context.rb +29 -0
- data/lib/calificador/spec/value_override.rb +37 -0
- data/lib/calificador/test.rb +12 -0
- data/lib/calificador/test_mixin.rb +264 -0
- data/lib/calificador/util/call_formatter.rb +41 -0
- data/lib/calificador/util/class_mixin.rb +14 -0
- data/lib/calificador/util/core_extensions.rb +135 -0
- data/lib/calificador/util/missing.rb +26 -0
- data/lib/calificador/util/nil.rb +59 -0
- data/lib/calificador/version.rb +5 -0
- metadata +257 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
using Calificador::Util::CoreExtensions
|
4
|
+
|
5
|
+
module Calificador
|
6
|
+
module Build
|
7
|
+
# Factory calss
|
8
|
+
class Factory < AttributeContainer
|
9
|
+
# Configuration derived factories
|
10
|
+
class Dsl < AttributeContainer::Dsl
|
11
|
+
def trait(name, description = nil, &block)
|
12
|
+
factory = Build::Factory.new(
|
13
|
+
context: @delegate.context,
|
14
|
+
parent: @delegate,
|
15
|
+
key: @delegate.key.with(name),
|
16
|
+
name: [@delegate.name, name].compact.join("_"),
|
17
|
+
source_location: block.source_location,
|
18
|
+
description: description || __default_trait_description(trait: name)
|
19
|
+
)
|
20
|
+
|
21
|
+
factory.dsl_config(&block)
|
22
|
+
@delegate.context.add_factory(factory)
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def __default_trait_description(trait:)
|
28
|
+
trait.to_s.gsub("_", " ").chomp
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :key, :context, :name, :source_location
|
33
|
+
attr_accessor :init_with
|
34
|
+
|
35
|
+
def initialize(context:, parent: nil, key:, name:, description: nil, source_location:, values: nil)
|
36
|
+
super(parent: parent, description: description)
|
37
|
+
|
38
|
+
raise "Parent factory must have same type" unless parent.nil? || parent.key.type == key.type
|
39
|
+
|
40
|
+
@context = context
|
41
|
+
@key = key
|
42
|
+
@name = name.to_sym
|
43
|
+
@source_location = source_location
|
44
|
+
@values = values&.dup || {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def create(context:)
|
48
|
+
evaluator = AttributeEvaluator.new(context: context)
|
49
|
+
|
50
|
+
collect_attributes_and_values(evaluator: evaluator)
|
51
|
+
|
52
|
+
before_create(evaluator: evaluator)
|
53
|
+
|
54
|
+
object = create_object(evaluator: evaluator)
|
55
|
+
|
56
|
+
set_properties(object: object, evaluator: evaluator)
|
57
|
+
|
58
|
+
after_create(evaluator: evaluator, object: object)
|
59
|
+
|
60
|
+
object
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_values(values)
|
64
|
+
@values.merge!(values)
|
65
|
+
end
|
66
|
+
|
67
|
+
def setup(test_class:); end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
def collect_attributes_and_values(evaluator:)
|
72
|
+
@parent&.collect_attributes_and_values(evaluator: evaluator)
|
73
|
+
evaluator.add_attributes(@attributes.values)
|
74
|
+
evaluator.add_values(@values)
|
75
|
+
end
|
76
|
+
|
77
|
+
def before_create(evaluator:)
|
78
|
+
@parent&.before_create(evaluator: evaluator)
|
79
|
+
evaluator.evaluate(&@before_create) unless @before_create.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
def after_create(evaluator:, object:)
|
83
|
+
@parent&.after_create(evaluator: evaluator, object: object)
|
84
|
+
evaluator.evaluate(object, &@after_create) unless @after_create.nil?
|
85
|
+
end
|
86
|
+
|
87
|
+
def nearest_init_with
|
88
|
+
@init_with || @parent&.nearest_init_with
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_object(evaluator:)
|
92
|
+
init_with = nearest_init_with
|
93
|
+
|
94
|
+
if init_with.nil?
|
95
|
+
call_initializer(evaluator: evaluator)
|
96
|
+
else
|
97
|
+
evaluator.evaluate(&init_with)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def set_properties(object:, evaluator:)
|
102
|
+
evaluator.attributes.each_value do |attribute|
|
103
|
+
object.send(:"#{attribute.name}=", evaluator.value(name: attribute.name)) if attribute.type == :property
|
104
|
+
end
|
105
|
+
|
106
|
+
evaluator.values.each do |name, value| # rubocop:disable Style/HashEachMethods
|
107
|
+
object.send(:"#{name}=", value) unless evaluator.attribute?(name: name)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def call_initializer(evaluator:)
|
112
|
+
parameters = []
|
113
|
+
options = {}
|
114
|
+
|
115
|
+
@key.type.instance_method(:initialize).parameters.each do |type, name|
|
116
|
+
case type
|
117
|
+
when :req
|
118
|
+
parameters << evaluator.value(name: name)
|
119
|
+
when :opt
|
120
|
+
parameters << evaluator.value(name: name) if evaluator.attribute?(name: name)
|
121
|
+
when :keyreq
|
122
|
+
options[name] = evaluator.value(name: name)
|
123
|
+
when :key
|
124
|
+
options[name] = evaluator.value(name: name) if evaluator.attribute?(name: name)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
@key.type.new(*parameters, **options)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Calificador
|
4
|
+
module Build
|
5
|
+
# Trait description
|
6
|
+
class Trait < AttributeContainer
|
7
|
+
# Configuration proxy for traits
|
8
|
+
class Dsl < AttributeContainer::Dsl
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :name
|
12
|
+
|
13
|
+
def initialize(parent:, name:, description: nil)
|
14
|
+
super(parent: parent, description: description)
|
15
|
+
|
16
|
+
@name = name.to_sym
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest"
|
4
|
+
|
5
|
+
using Calificador::Util::CoreExtensions
|
6
|
+
|
7
|
+
module Calificador
|
8
|
+
# Test subject key
|
9
|
+
class Key
|
10
|
+
DEFAULT_TRAIT = :"<default>"
|
11
|
+
INHERITED_TRAIT = :"<inherited>"
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def [](type, trait = DEFAULT_TRAIT)
|
15
|
+
new(type: type, trait: trait)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :type, :trait
|
20
|
+
|
21
|
+
def initialize(type:, trait: DEFAULT_TRAIT)
|
22
|
+
raise ArgumentError, "Illegal trait value #{trait}" if trait == INHERITED_TRAIT
|
23
|
+
|
24
|
+
@type = type
|
25
|
+
@trait = trait || DEFAULT_TRAIT
|
26
|
+
end
|
27
|
+
|
28
|
+
def hash
|
29
|
+
(@type.hash * 31) + @trait.hash
|
30
|
+
end
|
31
|
+
|
32
|
+
def ==(other)
|
33
|
+
(@type == other.type) && (@trait == other.trait)
|
34
|
+
end
|
35
|
+
|
36
|
+
alias_method :eql?, :==
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
trait == DEFAULT_TRAIT ? type.to_s : "#{type} (#{trait})"
|
40
|
+
end
|
41
|
+
|
42
|
+
alias_method :inspect, :to_s
|
43
|
+
|
44
|
+
def with(trait)
|
45
|
+
case trait
|
46
|
+
when INHERITED_TRAIT
|
47
|
+
self
|
48
|
+
when nil, DEFAULT_TRAIT
|
49
|
+
@trait == DEFAULT_TRAIT ? self : Key.new(type: @type, trait: DEFAULT_TRAIT)
|
50
|
+
else
|
51
|
+
trait == @trait ? self : Key.new(type: @type, trait: trait)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def trait?
|
56
|
+
@trait != DEFAULT_TRAIT
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest/test"
|
4
|
+
|
5
|
+
using Calificador::Util::CoreExtensions
|
6
|
+
|
7
|
+
module Calificador
|
8
|
+
module Minitest
|
9
|
+
# Patches to minitest classes
|
10
|
+
module MinitestPatches
|
11
|
+
# Patches to Minitest::Assertion
|
12
|
+
module AssertionMethods
|
13
|
+
def location
|
14
|
+
last_before_assertion = ""
|
15
|
+
|
16
|
+
backtrace.reverse_each do |s|
|
17
|
+
break if s =~ %r{assertor|in .(assert|refute|flunk|pass|fail|raise|must|wont)}
|
18
|
+
|
19
|
+
last_before_assertion = s
|
20
|
+
end
|
21
|
+
|
22
|
+
last_before_assertion.sub(%r{:in .*$}, "")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,353 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
using Calificador::Util::CoreExtensions
|
4
|
+
|
5
|
+
module Calificador
|
6
|
+
module Spec
|
7
|
+
class BasicContext
|
8
|
+
class Dsl
|
9
|
+
def initialize(delegate:)
|
10
|
+
@delegate = delegate
|
11
|
+
end
|
12
|
+
|
13
|
+
def factory(type, description = nil, name: nil, &block)
|
14
|
+
key = Key[type]
|
15
|
+
name ||= BasicContext.default_factory_name(test_class: @delegate.test_class, key: key)
|
16
|
+
|
17
|
+
factory = Build::Factory.new(
|
18
|
+
context: @delegate,
|
19
|
+
key: key,
|
20
|
+
name: name,
|
21
|
+
description: description,
|
22
|
+
source_location: block.source_location
|
23
|
+
)
|
24
|
+
|
25
|
+
factory.dsl_config(&block)
|
26
|
+
@delegate.add_factory(factory)
|
27
|
+
end
|
28
|
+
|
29
|
+
def examine(subject_type, description = nil, trait: Key::DEFAULT_TRAIT, **values, &block)
|
30
|
+
subject_key = Key[subject_type, trait == Key::INHERITED_TRAIT ? Key::DEFAULT_TRAIT : trait]
|
31
|
+
overrides = BasicContext.collect_overrides(values: values, default_key: subject_key)
|
32
|
+
|
33
|
+
description ||= BasicContext.default_examine_description(
|
34
|
+
test_class: @delegate.test_class,
|
35
|
+
subject_key: subject_key,
|
36
|
+
values: values
|
37
|
+
)
|
38
|
+
|
39
|
+
context = Spec::ExamineContext.new(
|
40
|
+
parent: @delegate,
|
41
|
+
subject_key: subject_key,
|
42
|
+
description: description,
|
43
|
+
overrides: overrides
|
44
|
+
)
|
45
|
+
|
46
|
+
context.dsl_config(&block)
|
47
|
+
|
48
|
+
@delegate.add_context(context, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def method(method, description = nil, &block)
|
52
|
+
context = Spec::InstanceMethodContext.new(
|
53
|
+
parent: @delegate,
|
54
|
+
method: method,
|
55
|
+
description: description || "\##{method}"
|
56
|
+
)
|
57
|
+
|
58
|
+
context.dsl_config(&block)
|
59
|
+
|
60
|
+
@delegate.add_context(context, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def class_method(method, description = nil, &block)
|
64
|
+
context = Spec::ClassMethodContext.new(
|
65
|
+
parent: @delegate,
|
66
|
+
method: method,
|
67
|
+
description: description || ".#{method}"
|
68
|
+
)
|
69
|
+
|
70
|
+
context.dsl_config(&block)
|
71
|
+
|
72
|
+
@delegate.add_context(context, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
def must(description, trait: Key::INHERITED_TRAIT, **values, &block)
|
76
|
+
subject_key = @delegate.subject_key.with(trait)
|
77
|
+
overrides = BasicContext.collect_overrides(values: values, default_key: subject_key)
|
78
|
+
|
79
|
+
context = Spec::TestMethod.new(
|
80
|
+
parent: @delegate,
|
81
|
+
subject_key: subject_key,
|
82
|
+
description: "must #{description}",
|
83
|
+
overrides: overrides,
|
84
|
+
expected_to_fail: false,
|
85
|
+
body: block
|
86
|
+
)
|
87
|
+
|
88
|
+
@delegate.add_context(context)
|
89
|
+
end
|
90
|
+
|
91
|
+
def must_fail(description, trait:, **values, &block)
|
92
|
+
subject_key = @delegate.subject_key.with(trait)
|
93
|
+
overrides = BasicContext.collect_overrides(values: values, default_key: subject_key)
|
94
|
+
|
95
|
+
context = Spec::TestMethod.new(
|
96
|
+
parent: @delegate,
|
97
|
+
subject_key: subject_key,
|
98
|
+
description: "must fail #{description}",
|
99
|
+
overrides: overrides,
|
100
|
+
expected_to_fail: true,
|
101
|
+
body: block
|
102
|
+
)
|
103
|
+
|
104
|
+
@delegate.add_context(context)
|
105
|
+
end
|
106
|
+
|
107
|
+
def with(description, trait: Key::INHERITED_TRAIT, **values, &block)
|
108
|
+
__condition(conjunction: "with", description: description, trait: trait, values: values, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
def without(description, trait: Key::INHERITED_TRAIT, **values, &block)
|
112
|
+
__condition(conjunction: "without", description: description, trait: trait, values: values, &block)
|
113
|
+
end
|
114
|
+
|
115
|
+
def where(description, trait: Key::INHERITED_TRAIT, **values, &block)
|
116
|
+
__condition(conjunction: "where", description: "description", trait: trait, values: values, &block)
|
117
|
+
end
|
118
|
+
|
119
|
+
protected
|
120
|
+
|
121
|
+
def __condition(conjunction:, description:, trait: Key::INHERITED_TRAIT, values: {}, &block)
|
122
|
+
if description.is_a?(Symbol) && trait == Key::INHERITED_TRAIT
|
123
|
+
trait = description
|
124
|
+
description = nil
|
125
|
+
end
|
126
|
+
|
127
|
+
subject_key = @delegate.subject_key.with(trait)
|
128
|
+
overrides = BasicContext.collect_overrides(values: values, default_key: subject_key)
|
129
|
+
|
130
|
+
description ||= __default_description(key: subject_key)
|
131
|
+
|
132
|
+
context = Spec::ConditionContext.new(
|
133
|
+
parent: @delegate,
|
134
|
+
subject_key: subject_key,
|
135
|
+
description: description,
|
136
|
+
overrides: overrides
|
137
|
+
)
|
138
|
+
|
139
|
+
context.dsl_config(&block)
|
140
|
+
|
141
|
+
@delegate.add_context(context, &block)
|
142
|
+
end
|
143
|
+
|
144
|
+
def __default_description(key:)
|
145
|
+
raise "Please provide a description or a trait" if key.trait == Key::INHERITED_TRAIT
|
146
|
+
|
147
|
+
factory = @delegate.lookup_factory(key: key)
|
148
|
+
|
149
|
+
raise "No factory defined for #{key}" if factory.nil?
|
150
|
+
|
151
|
+
factory.description
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class << self
|
156
|
+
def default_factory_name(test_class:, key:)
|
157
|
+
name = key.type.name.delete_prefix(test_class.parent_prefix).gsub("::", "").snake_case
|
158
|
+
|
159
|
+
name = "#{name}_#{key.trait}" if key.trait?
|
160
|
+
|
161
|
+
name.to_sym
|
162
|
+
end
|
163
|
+
|
164
|
+
def default_examine_description(test_class:, subject_key:, values:)
|
165
|
+
description = StringIO.new
|
166
|
+
description << subject_key.type.name.delete_prefix(test_class.parent_prefix)
|
167
|
+
|
168
|
+
description << " (" << subject_key.trait.to_s.gsub("_", " ") << ")" if subject_key.trait?
|
169
|
+
|
170
|
+
append_values_description(description: description, values: values)
|
171
|
+
|
172
|
+
description.string
|
173
|
+
end
|
174
|
+
|
175
|
+
def collect_overrides(values:, default_key:)
|
176
|
+
result = Hash.new { |hash, key| hash[key] = ValueOverride.new(key: key) }
|
177
|
+
default_values = {}
|
178
|
+
|
179
|
+
values.each do |key, value|
|
180
|
+
case key
|
181
|
+
when Symbol
|
182
|
+
default_values[key] = value
|
183
|
+
when Class
|
184
|
+
key = Key[key]
|
185
|
+
result[key] = result[key].merge_values(value)
|
186
|
+
when Key
|
187
|
+
result[key] = result[key].merge_values(value)
|
188
|
+
else
|
189
|
+
raise ArgumentError, "Illegal override key '#{key}'"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
result[default_key] = result[default_key].merge_values(default_values) unless default_values.empty?
|
194
|
+
result.default_proc = nil
|
195
|
+
|
196
|
+
result
|
197
|
+
end
|
198
|
+
|
199
|
+
protected
|
200
|
+
|
201
|
+
def append_values_description(description:, values:)
|
202
|
+
unless values.empty?
|
203
|
+
values.each_with_index do |(name, value), index|
|
204
|
+
description << case index
|
205
|
+
when 0
|
206
|
+
" where "
|
207
|
+
when values.size - 1
|
208
|
+
" and "
|
209
|
+
else
|
210
|
+
", "
|
211
|
+
end
|
212
|
+
|
213
|
+
description << name
|
214
|
+
|
215
|
+
description << case value
|
216
|
+
when NilClass
|
217
|
+
"is not set"
|
218
|
+
when TrueClass
|
219
|
+
"is true"
|
220
|
+
when FalseClass
|
221
|
+
"is false"
|
222
|
+
else
|
223
|
+
"is set"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
description
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
attr_reader :description, :parent, :overrides
|
233
|
+
|
234
|
+
def initialize(parent:, subject_key:, description:, overrides:)
|
235
|
+
@parent = parent
|
236
|
+
@subject_key = subject_key
|
237
|
+
@description = description
|
238
|
+
|
239
|
+
@children = []
|
240
|
+
|
241
|
+
factories = overrides.map do |key, override|
|
242
|
+
parent_factory = parent.lookup_factory(key: key)
|
243
|
+
|
244
|
+
factory = Build::Factory.new(
|
245
|
+
parent: parent_factory,
|
246
|
+
context: self,
|
247
|
+
key: key,
|
248
|
+
name: parent_factory&.name || BasicContext.default_factory_name(test_class: test_class, key: key),
|
249
|
+
source_location: Kernel.caller_locations(0, 1).first
|
250
|
+
)
|
251
|
+
|
252
|
+
factory.add_values(override.values)
|
253
|
+
|
254
|
+
factory
|
255
|
+
end
|
256
|
+
|
257
|
+
@factories = factories.map { |f| [f.key, f] }.to_h
|
258
|
+
@named_factories = factories.map { |f| [f.name, f] }.to_h
|
259
|
+
end
|
260
|
+
|
261
|
+
def setup; end
|
262
|
+
|
263
|
+
def subtree_root?
|
264
|
+
false
|
265
|
+
end
|
266
|
+
|
267
|
+
def add_context(context, &block)
|
268
|
+
@children << context
|
269
|
+
|
270
|
+
context.setup
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_class
|
274
|
+
parent&.test_class || raise(StandardError, "No parent context defines a test class")
|
275
|
+
end
|
276
|
+
|
277
|
+
def subject_key
|
278
|
+
@subject_key || (parent.subject_key unless subtree_root? || parent.nil?)
|
279
|
+
end
|
280
|
+
|
281
|
+
def context_path(subtree: true)
|
282
|
+
add_context_to_path([], subtree: subtree).freeze
|
283
|
+
end
|
284
|
+
|
285
|
+
def full_description
|
286
|
+
context_path.reduce(StringIO.new) do |description, context|
|
287
|
+
description << " " if description.length.positive? && context.separate_description_by_space?
|
288
|
+
description << context.description
|
289
|
+
end.string
|
290
|
+
end
|
291
|
+
|
292
|
+
def root
|
293
|
+
result = self
|
294
|
+
result = result.parent until result.parent.nil?
|
295
|
+
result
|
296
|
+
end
|
297
|
+
|
298
|
+
def add_factory(factory)
|
299
|
+
raise KeyError, "Factory for type #{factory.key.type} already defined" if @factories.key?(factory.key.type)
|
300
|
+
raise KeyError, "Factory with name #{factory.name} already defined" if @named_factories.key?(factory.name)
|
301
|
+
|
302
|
+
@factories[factory.key] = factory
|
303
|
+
@named_factories[factory.name] = factory
|
304
|
+
|
305
|
+
test_class.__define_factory_method(factory: factory)
|
306
|
+
end
|
307
|
+
|
308
|
+
def factories
|
309
|
+
@factories.dup.freeze
|
310
|
+
end
|
311
|
+
|
312
|
+
def named_factories
|
313
|
+
@named_factories.dup.freeze
|
314
|
+
end
|
315
|
+
|
316
|
+
def lookup_factory(key:)
|
317
|
+
@factories[key] || @parent&.lookup_factory(key: key)
|
318
|
+
end
|
319
|
+
|
320
|
+
def lookup_named_factory(name:)
|
321
|
+
@named_factories[name] || @parent&.lookup_named_factory(name: name)
|
322
|
+
end
|
323
|
+
|
324
|
+
def create_subject(environment:, subject_key:)
|
325
|
+
@parent.create_subject(environment: environment, subject_key: subject_key)
|
326
|
+
end
|
327
|
+
|
328
|
+
def create_result(subject:, arguments:, options:, block:)
|
329
|
+
@parent.create_result(subject: subject, arguments: arguments, options: options, block: block)
|
330
|
+
end
|
331
|
+
|
332
|
+
protected
|
333
|
+
|
334
|
+
def effective_overrides
|
335
|
+
context_path.each_with_object({}) do |context, overrides|
|
336
|
+
overrides.merge!(context.overrides) do |_key, existing_override, additional_override|
|
337
|
+
existing_override.merge(additional_override)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
def add_context_to_path(path, subtree: true)
|
343
|
+
@parent.add_context_to_path(path, subtree: subtree) unless @parent.nil? || (subtree && subtree_root?)
|
344
|
+
|
345
|
+
path << self
|
346
|
+
end
|
347
|
+
|
348
|
+
def separate_description_by_space?
|
349
|
+
true
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|