babl-json 0.1.4 → 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/.travis.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/README.md +1 -3
- data/babl.gemspec +3 -1
- data/lib/babl.rb +4 -6
- data/lib/babl/builder/chain_builder.rb +6 -2
- data/lib/babl/builder/template_base.rb +16 -3
- data/lib/babl/errors.rb +7 -0
- data/lib/babl/nodes/create_pin.rb +24 -0
- data/lib/babl/nodes/dep.rb +38 -0
- data/lib/babl/nodes/each.rb +29 -0
- data/lib/babl/nodes/fixed_array.rb +25 -0
- data/lib/babl/nodes/goto_pin.rb +24 -0
- data/lib/babl/{rendering/internal_value_node.rb → nodes/internal_value.rb} +6 -5
- data/lib/babl/nodes/merge.rb +102 -0
- data/lib/babl/nodes/nav.rb +33 -0
- data/lib/babl/nodes/object.rb +26 -0
- data/lib/babl/nodes/parent.rb +64 -0
- data/lib/babl/nodes/static.rb +34 -0
- data/lib/babl/nodes/switch.rb +29 -0
- data/lib/babl/nodes/terminal_value.rb +76 -0
- data/lib/babl/nodes/with.rb +28 -0
- data/lib/babl/operators/array.rb +5 -28
- data/lib/babl/operators/call.rb +4 -2
- data/lib/babl/operators/continue.rb +19 -0
- data/lib/babl/operators/default.rb +13 -0
- data/lib/babl/operators/dep.rb +3 -36
- data/lib/babl/operators/each.rb +3 -33
- data/lib/babl/operators/enter.rb +4 -2
- data/lib/babl/operators/extends.rb +4 -1
- data/lib/babl/operators/merge.rb +7 -30
- data/lib/babl/operators/nav.rb +4 -36
- data/lib/babl/operators/object.rb +7 -29
- data/lib/babl/operators/parent.rb +4 -73
- data/lib/babl/operators/partial.rb +4 -2
- data/lib/babl/operators/pin.rb +14 -58
- data/lib/babl/operators/static.rb +11 -30
- data/lib/babl/operators/switch.rb +8 -51
- data/lib/babl/operators/with.rb +5 -34
- data/lib/babl/railtie.rb +2 -2
- data/lib/babl/rendering/compiled_template.rb +5 -13
- data/lib/babl/rendering/context.rb +13 -7
- data/lib/babl/schema/any_of.rb +137 -0
- data/lib/babl/schema/anything.rb +13 -0
- data/lib/babl/schema/dyn_array.rb +11 -0
- data/lib/babl/schema/fixed_array.rb +13 -0
- data/lib/babl/schema/object.rb +35 -0
- data/lib/babl/schema/static.rb +14 -0
- data/lib/babl/schema/typed.rb +0 -0
- data/lib/babl/template.rb +4 -9
- data/lib/babl/utils/ref.rb +6 -0
- data/lib/babl/version.rb +1 -1
- data/spec/operators/array_spec.rb +31 -7
- data/spec/operators/call_spec.rb +16 -14
- data/spec/operators/continue_spec.rb +25 -0
- data/spec/operators/default_spec.rb +15 -0
- data/spec/operators/dep_spec.rb +4 -8
- data/spec/operators/each_spec.rb +24 -5
- data/spec/operators/enter_spec.rb +9 -7
- data/spec/operators/extends_spec.rb +19 -5
- data/spec/operators/merge_spec.rb +105 -12
- data/spec/operators/nav_spec.rb +22 -10
- data/spec/operators/null_spec.rb +5 -4
- data/spec/operators/nullable_spec.rb +13 -13
- data/spec/operators/object_spec.rb +17 -6
- data/spec/operators/parent_spec.rb +18 -22
- data/spec/operators/partial_spec.rb +8 -6
- data/spec/operators/pin_spec.rb +100 -61
- data/spec/operators/source_spec.rb +10 -6
- data/spec/operators/static_spec.rb +17 -9
- data/spec/operators/switch_spec.rb +85 -45
- data/spec/operators/with_spec.rb +13 -15
- data/spec/spec_helper.rb +2 -31
- data/spec/spec_helper/operator_testing.rb +46 -0
- data/spec/spec_helper/schema_utils.rb +33 -0
- metadata +63 -4
- data/lib/babl/rendering/terminal_value_node.rb +0 -54
data/lib/babl/operators/enter.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'babl/errors'
|
2
|
+
|
1
3
|
module Babl
|
2
4
|
module Operators
|
3
5
|
module Enter
|
@@ -7,8 +9,8 @@ module Babl
|
|
7
9
|
def enter
|
8
10
|
construct_node(key: nil, continue: nil) { |node, context|
|
9
11
|
key = context[:key]
|
10
|
-
raise InvalidTemplateError, "No key to enter into" unless key
|
11
|
-
Nav
|
12
|
+
raise Errors::InvalidTemplateError, "No key to enter into" unless key
|
13
|
+
Nodes::Nav.new(key, node)
|
12
14
|
}
|
13
15
|
end
|
14
16
|
|
@@ -3,7 +3,10 @@ module Babl
|
|
3
3
|
module Extends
|
4
4
|
module DSL
|
5
5
|
def extends(partial_path, *args)
|
6
|
-
source {
|
6
|
+
source {
|
7
|
+
partial_template = partial(partial_path)
|
8
|
+
args.empty? ? partial_template : merge(partial_template, *args)
|
9
|
+
}
|
7
10
|
end
|
8
11
|
end
|
9
12
|
end
|
data/lib/babl/operators/merge.rb
CHANGED
@@ -1,14 +1,19 @@
|
|
1
|
+
require 'babl/nodes/merge'
|
2
|
+
require 'babl/nodes/terminal_value'
|
3
|
+
|
1
4
|
module Babl
|
2
5
|
module Operators
|
3
6
|
module Merge
|
4
7
|
module DSL
|
5
8
|
# Merge multiple JSON objects (non-deep)
|
6
9
|
def merge(*templates)
|
10
|
+
return call({}) if templates.empty?
|
11
|
+
|
7
12
|
construct_terminal { |context|
|
8
|
-
|
13
|
+
Nodes::Merge.new(
|
9
14
|
templates.map { |t|
|
10
15
|
unscoped.call(t).builder.precompile(
|
11
|
-
|
16
|
+
Nodes::TerminalValue.instance,
|
12
17
|
context.merge(continue: nil)
|
13
18
|
)
|
14
19
|
}
|
@@ -16,34 +21,6 @@ module Babl
|
|
16
21
|
}
|
17
22
|
end
|
18
23
|
end
|
19
|
-
|
20
|
-
class MergeNode
|
21
|
-
def initialize(nodes)
|
22
|
-
@nodes = nodes
|
23
|
-
end
|
24
|
-
|
25
|
-
def dependencies
|
26
|
-
nodes.map(&:dependencies).reduce({}) { |a, b| Babl::Utils::Hash.deep_merge(a, b) }
|
27
|
-
end
|
28
|
-
|
29
|
-
def pinned_dependencies
|
30
|
-
nodes.map(&:pinned_dependencies).reduce({}) { |a, b| Babl::Utils::Hash.deep_merge(a, b) }
|
31
|
-
end
|
32
|
-
|
33
|
-
def documentation
|
34
|
-
nodes.map(&:documentation).each_with_index.map { |doc, idx|
|
35
|
-
[:"Merge #{idx + 1}", doc]
|
36
|
-
}.to_h
|
37
|
-
end
|
38
|
-
|
39
|
-
def render(ctx)
|
40
|
-
nodes.map { |node| node.render(ctx) }.compact.reduce({}, :merge)
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
attr_reader :nodes
|
46
|
-
end
|
47
24
|
end
|
48
25
|
end
|
49
26
|
end
|
data/lib/babl/operators/nav.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'babl/nodes/nav'
|
2
|
+
|
1
3
|
module Babl
|
2
4
|
module Operators
|
3
5
|
module Nav
|
@@ -12,42 +14,8 @@ module Babl
|
|
12
14
|
return (block ? with(unscoped, &block) : construct_node(key: nil, continue: nil) { |node| node })
|
13
15
|
end
|
14
16
|
|
15
|
-
construct_node(key: nil, continue: nil) { |node|
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
class NavNode
|
20
|
-
def initialize(through, node)
|
21
|
-
@through = through
|
22
|
-
@node = node
|
23
|
-
end
|
24
|
-
|
25
|
-
def dependencies
|
26
|
-
{ through => node.dependencies }
|
27
|
-
end
|
28
|
-
|
29
|
-
def documentation
|
30
|
-
node.documentation
|
31
|
-
end
|
32
|
-
|
33
|
-
def pinned_dependencies
|
34
|
-
node.pinned_dependencies
|
35
|
-
end
|
36
|
-
|
37
|
-
def render(ctx)
|
38
|
-
node.render(ctx.move_forward_block(through) { navigate(ctx.object) })
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
attr_reader :through, :node
|
44
|
-
|
45
|
-
def navigate(object)
|
46
|
-
if object.is_a?(Hash)
|
47
|
-
object.fetch(through)
|
48
|
-
else
|
49
|
-
object.send(through)
|
50
|
-
end
|
17
|
+
construct_node(key: nil, continue: nil) { |node| Nodes::Nav.new(path.first, node) }
|
18
|
+
.nav(*path[1..-1], &block)
|
51
19
|
end
|
52
20
|
end
|
53
21
|
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'babl/nodes/object'
|
2
|
+
require 'babl/nodes/terminal_value'
|
3
|
+
require 'babl/errors'
|
4
|
+
|
1
5
|
module Babl
|
2
6
|
module Operators
|
3
7
|
module Object
|
@@ -5,7 +9,7 @@ module Babl
|
|
5
9
|
# Create a JSON object node with static structure
|
6
10
|
def object(*attrs, **nested)
|
7
11
|
(attrs.map(&:to_sym) + nested.keys).group_by(&:itself).values.each do |keys|
|
8
|
-
raise ::
|
12
|
+
raise Errors::InvalidTemplateError, "Duplicate key in object(): #{keys.first}" if keys.size > 1
|
9
13
|
end
|
10
14
|
|
11
15
|
construct_terminal { |ctx|
|
@@ -14,42 +18,16 @@ module Babl
|
|
14
18
|
.merge(nested)
|
15
19
|
.map { |k, v|
|
16
20
|
[k, unscoped.call(v).builder.precompile(
|
17
|
-
|
21
|
+
Nodes::TerminalValue.instance,
|
18
22
|
ctx.merge(key: k, continue: nil)
|
19
23
|
)]
|
20
24
|
}
|
21
25
|
.to_h
|
22
26
|
|
23
|
-
|
27
|
+
Nodes::Object.new(nodes)
|
24
28
|
}
|
25
29
|
end
|
26
30
|
end
|
27
|
-
|
28
|
-
class ObjectNode
|
29
|
-
def initialize(nodes)
|
30
|
-
@nodes = nodes
|
31
|
-
end
|
32
|
-
|
33
|
-
def dependencies
|
34
|
-
nodes.values.map(&:dependencies).reduce({}) { |a, b| Babl::Utils::Hash.deep_merge(a, b) }
|
35
|
-
end
|
36
|
-
|
37
|
-
def pinned_dependencies
|
38
|
-
nodes.values.map(&:pinned_dependencies).reduce({}) { |a, b| Babl::Utils::Hash.deep_merge(a, b) }
|
39
|
-
end
|
40
|
-
|
41
|
-
def documentation
|
42
|
-
nodes.map { |k, v| [k, v.documentation] }.to_h
|
43
|
-
end
|
44
|
-
|
45
|
-
def render(ctx)
|
46
|
-
nodes.map { |k, v| [k, v.render(ctx)] }.to_h
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
attr_reader :nodes
|
52
|
-
end
|
53
31
|
end
|
54
32
|
end
|
55
33
|
end
|
@@ -1,89 +1,20 @@
|
|
1
|
+
require 'babl/nodes/parent'
|
2
|
+
|
1
3
|
module Babl
|
2
4
|
module Operators
|
3
5
|
module Parent
|
4
|
-
PARENT = ::Object.new
|
5
|
-
|
6
6
|
module DSL
|
7
7
|
# Navigate to the parent of the current object.
|
8
8
|
def parent
|
9
|
-
construct_node(key: nil, continue: nil) { |node|
|
9
|
+
construct_node(key: nil, continue: nil) { |node| Nodes::Parent.new(node) }
|
10
10
|
end
|
11
11
|
|
12
12
|
protected
|
13
13
|
|
14
14
|
# Override TemplateBase#precompile to add parent dependencies verification
|
15
15
|
def precompile
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class ParentResolverNode
|
21
|
-
def initialize(node)
|
22
|
-
@node = node
|
23
|
-
end
|
24
|
-
|
25
|
-
def dependencies
|
26
|
-
backpropagate_dependencies(node.dependencies)
|
27
|
-
end
|
28
|
-
|
29
|
-
def documentation
|
30
|
-
node.documentation
|
31
|
-
end
|
32
|
-
|
33
|
-
def pinned_dependencies
|
34
|
-
node.pinned_dependencies
|
35
|
-
end
|
36
|
-
|
37
|
-
def render(ctx)
|
38
|
-
node.render(ctx)
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
attr_reader :node
|
44
|
-
|
45
|
-
def backpropagate_dependencies(deps)
|
46
|
-
raise InvalidTemplateError, 'Out of context parent dependency' if deps.key? PARENT
|
47
|
-
new_deps = backpropagate_dependencies_one_level(deps)
|
48
|
-
deps == new_deps ? new_deps : backpropagate_dependencies(new_deps)
|
16
|
+
Nodes::Parent::Resolver.new(super)
|
49
17
|
end
|
50
|
-
|
51
|
-
def backpropagate_dependencies_one_level(deps)
|
52
|
-
deps.reduce({}) do |out, (k, v)|
|
53
|
-
next out if k == PARENT
|
54
|
-
|
55
|
-
Babl::Utils::Hash.deep_merge(
|
56
|
-
Babl::Utils::Hash.deep_merge(out, k => backpropagate_dependencies_one_level(v)),
|
57
|
-
v[PARENT] || {}
|
58
|
-
)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
class ParentNode
|
64
|
-
def initialize(node)
|
65
|
-
@node = node
|
66
|
-
end
|
67
|
-
|
68
|
-
def documentation
|
69
|
-
node.documentation
|
70
|
-
end
|
71
|
-
|
72
|
-
def pinned_dependencies
|
73
|
-
node.pinned_dependencies
|
74
|
-
end
|
75
|
-
|
76
|
-
def dependencies
|
77
|
-
{ PARENT => node.dependencies }
|
78
|
-
end
|
79
|
-
|
80
|
-
def render(ctx)
|
81
|
-
node.render(ctx.move_backward)
|
82
|
-
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
attr_reader :node
|
87
18
|
end
|
88
19
|
end
|
89
20
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'babl/errors'
|
2
|
+
|
1
3
|
module Babl
|
2
4
|
module Operators
|
3
5
|
module Partial
|
@@ -5,10 +7,10 @@ module Babl
|
|
5
7
|
# Load a partial template given its name
|
6
8
|
# A 'lookup_context' must be defined
|
7
9
|
def partial(partial_name)
|
8
|
-
raise InvalidTemplateError, "Cannot use partial without lookup context" unless lookup_context
|
10
|
+
raise Errors::InvalidTemplateError, "Cannot use partial without lookup context" unless lookup_context
|
9
11
|
|
10
12
|
path, source, partial_lookup_context = lookup_context.find(partial_name)
|
11
|
-
raise InvalidTemplateError, "Cannot find partial '#{partial_name}'" unless path
|
13
|
+
raise Errors::InvalidTemplateError, "Cannot find partial '#{partial_name}'" unless path
|
12
14
|
|
13
15
|
with_lookup_context(partial_lookup_context)
|
14
16
|
.source(source, path, 0)
|
data/lib/babl/operators/pin.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
require 'babl/nodes/create_pin'
|
2
|
+
require 'babl/nodes/goto_pin'
|
3
|
+
require 'babl/utils/ref'
|
4
|
+
require 'babl/errors'
|
5
|
+
|
1
6
|
module Babl
|
2
7
|
module Operators
|
3
8
|
module Pin
|
@@ -5,9 +10,14 @@ module Babl
|
|
5
10
|
# Create a pin
|
6
11
|
def pin(navigation = nil, &block)
|
7
12
|
return pin { |p| block[p.call(navigation)] } if navigation
|
8
|
-
ref = ::
|
9
|
-
|
10
|
-
construct_node(continue: nil) { |node|
|
13
|
+
ref = Utils::Ref.new
|
14
|
+
|
15
|
+
referenced_scope = unscoped.construct_node(key: nil, continue: nil) { |node|
|
16
|
+
Nodes::GotoPin.new(node, ref)
|
17
|
+
}
|
18
|
+
|
19
|
+
construct_node(continue: nil) { |node| Nodes::CreatePin.new(node, ref) }
|
20
|
+
.call(block[referenced_scope])
|
11
21
|
end
|
12
22
|
|
13
23
|
protected
|
@@ -15,64 +25,10 @@ module Babl
|
|
15
25
|
# Override TemplateBase#precompile to ensure that all pin dependencies are satisfied.
|
16
26
|
def precompile
|
17
27
|
super.tap do |node|
|
18
|
-
raise
|
28
|
+
raise Errors::InvalidTemplateError, 'Unresolved pin' unless node.pinned_dependencies.empty?
|
19
29
|
end
|
20
30
|
end
|
21
31
|
end
|
22
|
-
|
23
|
-
class CreatePinNode
|
24
|
-
def initialize(node, ref)
|
25
|
-
@node = node
|
26
|
-
@ref = ref
|
27
|
-
end
|
28
|
-
|
29
|
-
def render(ctx)
|
30
|
-
node.render(ctx.create_pin(ref))
|
31
|
-
end
|
32
|
-
|
33
|
-
def documentation
|
34
|
-
node.documentation
|
35
|
-
end
|
36
|
-
|
37
|
-
def dependencies
|
38
|
-
Babl::Utils::Hash.deep_merge(node.dependencies, node.pinned_dependencies[ref] || {})
|
39
|
-
end
|
40
|
-
|
41
|
-
def pinned_dependencies
|
42
|
-
node.pinned_dependencies.reject { |k, _v| k == ref }
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
attr_reader :node, :ref
|
48
|
-
end
|
49
|
-
|
50
|
-
class GotoPinNode
|
51
|
-
def initialize(node, ref)
|
52
|
-
@node = node
|
53
|
-
@ref = ref
|
54
|
-
end
|
55
|
-
|
56
|
-
def dependencies
|
57
|
-
{}
|
58
|
-
end
|
59
|
-
|
60
|
-
def pinned_dependencies
|
61
|
-
Babl::Utils::Hash.deep_merge(node.pinned_dependencies, ref => node.dependencies)
|
62
|
-
end
|
63
|
-
|
64
|
-
def documentation
|
65
|
-
node.documentation
|
66
|
-
end
|
67
|
-
|
68
|
-
def render(ctx)
|
69
|
-
node.render(ctx.goto_pin(ref))
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
attr_reader :node, :ref
|
75
|
-
end
|
76
32
|
end
|
77
33
|
end
|
78
34
|
end
|
@@ -1,39 +1,20 @@
|
|
1
|
+
require 'babl/nodes/static'
|
2
|
+
require 'babl/nodes/terminal_value'
|
3
|
+
require 'babl/errors'
|
4
|
+
|
1
5
|
module Babl
|
2
6
|
module Operators
|
3
7
|
module Static
|
4
8
|
module DSL
|
5
9
|
# Create a static JSON value
|
6
|
-
def static(
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@serialized_value = Rendering::TerminalValueNode.instance.render_object(value)
|
14
|
-
rescue Babl::RenderingError => exception
|
15
|
-
raise Babl::InvalidTemplateError, exception.message
|
16
|
-
end
|
17
|
-
|
18
|
-
def documentation
|
19
|
-
serialized_value
|
20
|
-
end
|
21
|
-
|
22
|
-
def render(_ctx)
|
23
|
-
serialized_value
|
24
|
-
end
|
25
|
-
|
26
|
-
def dependencies
|
27
|
-
{}
|
10
|
+
def static(val)
|
11
|
+
case val
|
12
|
+
when String, Numeric, NilClass, TrueClass, FalseClass then construct_terminal { Nodes::Static.new(val) }
|
13
|
+
else call(Nodes::TerminalValue.instance.render_object(val))
|
14
|
+
end
|
15
|
+
rescue Errors::RenderingError => exception
|
16
|
+
raise Errors::InvalidTemplateError, exception.message
|
28
17
|
end
|
29
|
-
|
30
|
-
def pinned_dependencies
|
31
|
-
{}
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
attr_reader :serialized_value
|
37
18
|
end
|
38
19
|
end
|
39
20
|
end
|