factrey 0.1.0 → 0.2.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 +4 -4
- data/lib/factrey/blueprint/instantiator.rb +40 -27
- data/lib/factrey/blueprint/node.rb +3 -0
- data/lib/factrey/blueprint.rb +16 -10
- data/lib/factrey/dsl.rb +8 -4
- data/lib/factrey/version.rb +1 -1
- data/lib/factrey.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c99d12d76f3bb5c00381aa92c12fa7590256312a4bc44af811b6ebfcc379ac2a
|
4
|
+
data.tar.gz: 62cfdf298cfa82d3341d26e140e57d28660376ed810142b54486650deb37ecd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68317b56351965174b8ae361c2a68e9d125359f8d9f2ec3203b6892391cacb8c9a2db6e4056c2e13531c8ffbb4a47d141bed74662327b170da55de6852fcc806
|
7
|
+
data.tar.gz: 3705848394bf3870e84505241ecfbd7075813c558d9b377848c60b6bb939a8cda789edd3bc5d0cf24087bd7847daf4f1fb5fe62ba9f7e2da9dd240f470b9e9d9
|
@@ -18,50 +18,63 @@ module Factrey
|
|
18
18
|
@blueprint = blueprint
|
19
19
|
end
|
20
20
|
|
21
|
+
def instantiate_objects
|
22
|
+
@blueprint.nodes.each_value { ensure_object_instantiated(_1) }
|
23
|
+
@objects
|
24
|
+
end
|
25
|
+
|
26
|
+
def instantiate_result
|
27
|
+
instantiate_objects # To keep consistency in the order of instantiation
|
28
|
+
resolver.resolve(@blueprint.result)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
21
33
|
# @param node [Node]
|
22
34
|
# @return [Object]
|
23
|
-
def
|
35
|
+
def ensure_object_instantiated(node)
|
24
36
|
@objects.fetch(node.name) do
|
25
37
|
unless @visited.add?(node.name)
|
26
38
|
raise ArgumentError, "Circular references detected around #{node.type_annotated_name}"
|
27
39
|
end
|
28
40
|
|
29
|
-
|
41
|
+
args = resolver.resolve(node.args)
|
42
|
+
kwargs = resolver.resolve(node.kwargs)
|
43
|
+
resolve_auto_references(node.type.auto_references, node.ancestors, kwargs)
|
44
|
+
@objects[node.name] = node.type.factory.call(node.type, @context, *args, **kwargs)
|
30
45
|
end
|
31
46
|
end
|
32
47
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
resolver = Ref::Resolver.new(recursion_limit: 5) do |name|
|
39
|
-
visit(
|
40
|
-
@blueprint.nodes.fetch(name) do
|
41
|
-
raise ArgumentError, "Missing definition #{name} around #{node.type_annotated_name}"
|
42
|
-
end,
|
43
|
-
)
|
48
|
+
# @return [Ref::Resolver]
|
49
|
+
def resolver
|
50
|
+
@resolver ||= Ref::Resolver.new(recursion_limit: 5) do |name|
|
51
|
+
node = @blueprint.nodes.fetch(name) { raise ArgumentError, "Missing definition: #{name}" }
|
52
|
+
ensure_object_instantiated(node)
|
44
53
|
end
|
54
|
+
end
|
45
55
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
next if
|
56
|
+
# @param auto_references [Hash{Symbol => Symbol}]
|
57
|
+
# @param referenceable_nodes [Array<Node>]
|
58
|
+
# @param dest [Hash{Symbol => Object}]
|
59
|
+
def resolve_auto_references(auto_references, referenceable_nodes, dest)
|
60
|
+
candidates = {}
|
61
|
+
auto_references.each do |type_name, attribute|
|
62
|
+
next if dest.member? attribute # this attribute is explicitly specified
|
53
63
|
|
54
|
-
|
55
|
-
|
64
|
+
compatible_node, index = referenceable_nodes.reverse_each.with_index.find do |node, _|
|
65
|
+
node.type.compatible_types.include?(type_name)
|
56
66
|
end
|
57
|
-
next unless
|
58
|
-
|
67
|
+
next unless compatible_node
|
68
|
+
|
69
|
+
# the node closest to the end of the array has priority
|
70
|
+
next if candidates.member?(attribute) && candidates[attribute][1] <= index
|
59
71
|
|
60
|
-
|
72
|
+
candidates[attribute] = [compatible_node, index]
|
61
73
|
end
|
62
|
-
auto_references.each { |attribute, (ancestor, _)| kwargs[attribute] = visit(ancestor) }
|
63
74
|
|
64
|
-
|
75
|
+
candidates.each do |attribute, (node, _)|
|
76
|
+
dest[attribute] = ensure_object_instantiated(node)
|
77
|
+
end
|
65
78
|
end
|
66
79
|
end
|
67
80
|
end
|
data/lib/factrey/blueprint.rb
CHANGED
@@ -10,6 +10,8 @@ module Factrey
|
|
10
10
|
class Blueprint
|
11
11
|
# @return [Hash{Symbol => Node}] a set of nodes
|
12
12
|
attr_reader :nodes
|
13
|
+
# @return [Object] the result of the DSL code is defined here
|
14
|
+
attr_reader :result
|
13
15
|
|
14
16
|
# Creates an empty blueprint.
|
15
17
|
def initialize
|
@@ -34,10 +36,6 @@ module Factrey
|
|
34
36
|
result
|
35
37
|
end
|
36
38
|
|
37
|
-
# Get the last root node.
|
38
|
-
# @return [Node, nil]
|
39
|
-
def representative_node = nodes.each_value.reverse_each.find(&:root?)
|
40
|
-
|
41
39
|
# Add a node. This method is used by {DSL} and usually does not need to be called directly.
|
42
40
|
# @return [Node]
|
43
41
|
def add_node(...)
|
@@ -48,15 +46,23 @@ module Factrey
|
|
48
46
|
node
|
49
47
|
end
|
50
48
|
|
51
|
-
#
|
49
|
+
# Define the result. This method is used by {DSL} and usually does not need to be called directly.
|
50
|
+
# @param result [Object]
|
51
|
+
# @param overwrite [Boolean] whether to overwrite the existing result
|
52
|
+
def define_result(result, overwrite: false)
|
53
|
+
return if defined?(@result) && !overwrite
|
54
|
+
|
55
|
+
@result = result
|
56
|
+
end
|
57
|
+
|
58
|
+
# Create a set of objects and compute the result based on this blueprint.
|
52
59
|
# @param context [Object] context object to be passed to the factories
|
53
|
-
# @return [
|
60
|
+
# @return [(Object, {Symbol => Object})] the result and the created objects
|
54
61
|
def instantiate(context = nil)
|
55
62
|
instantiator = Instantiator.new(context, self)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
instantiator.objects
|
63
|
+
objects = instantiator.instantiate_objects
|
64
|
+
result = instantiator.instantiate_result
|
65
|
+
[result, objects]
|
60
66
|
end
|
61
67
|
end
|
62
68
|
end
|
data/lib/factrey/dsl.rb
CHANGED
@@ -89,6 +89,8 @@ module Factrey
|
|
89
89
|
#
|
90
90
|
# This method is usually not called directly. Use the shorthand method defined by {.add_type} instead.
|
91
91
|
# @param type [Blueprint::Type]
|
92
|
+
# @yieldparam ref [Ref]
|
93
|
+
# @return [Ref]
|
92
94
|
def node(type, ...)
|
93
95
|
name = @let_scope ? (@let_scope.name || type.name) : nil
|
94
96
|
@let_scope = nil # consumed
|
@@ -98,6 +100,8 @@ module Factrey
|
|
98
100
|
end
|
99
101
|
|
100
102
|
# Enter the node to configure arguments and child nodes.
|
103
|
+
# @yieldparam ref [Ref]
|
104
|
+
# @return [Ref]
|
101
105
|
# @example
|
102
106
|
# Factrey.blueprint do
|
103
107
|
# let.blog do
|
@@ -110,7 +114,7 @@ module Factrey
|
|
110
114
|
# # Add title to `article2`
|
111
115
|
# on.article2(title: "This is an article 2")
|
112
116
|
# end
|
113
|
-
def on(name = nil,
|
117
|
+
def on(name = nil, *args, **kwargs)
|
114
118
|
return On.new(self) if name.nil? && !block_given?
|
115
119
|
|
116
120
|
node = @blueprint.nodes[name]
|
@@ -118,9 +122,10 @@ module Factrey
|
|
118
122
|
|
119
123
|
stashed_ancestors = @ancestors
|
120
124
|
@ancestors = node.ancestors + [node]
|
121
|
-
args(
|
125
|
+
args(*args, **kwargs)
|
126
|
+
yield node.to_ref if block_given?
|
122
127
|
@ancestors = stashed_ancestors
|
123
|
-
node
|
128
|
+
node.to_ref
|
124
129
|
end
|
125
130
|
|
126
131
|
# Add arguments to the current node.
|
@@ -137,7 +142,6 @@ module Factrey
|
|
137
142
|
|
138
143
|
@ancestors.last.args.concat(args)
|
139
144
|
@ancestors.last.kwargs.update(kwargs)
|
140
|
-
yield if block_given?
|
141
145
|
end
|
142
146
|
|
143
147
|
class << self
|
data/lib/factrey/version.rb
CHANGED
data/lib/factrey.rb
CHANGED
@@ -37,7 +37,7 @@ module Factrey
|
|
37
37
|
raise TypeError, "dsl must be a subclass of DSL" unless dsl <= DSL
|
38
38
|
|
39
39
|
blueprint ||= Blueprint.new
|
40
|
-
dsl.new(blueprint:, ext:).instance_exec(&) if block_given?
|
40
|
+
blueprint.define_result dsl.new(blueprint:, ext:).instance_exec(&) if block_given?
|
41
41
|
blueprint
|
42
42
|
end
|
43
43
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factrey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yubrot
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
Factrey provides a declarative DSL to represent the creation plan of objects, for FactoryBot::Blueprint.
|