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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +6 -0
  4. data/README.md +1 -3
  5. data/babl.gemspec +3 -1
  6. data/lib/babl.rb +4 -6
  7. data/lib/babl/builder/chain_builder.rb +6 -2
  8. data/lib/babl/builder/template_base.rb +16 -3
  9. data/lib/babl/errors.rb +7 -0
  10. data/lib/babl/nodes/create_pin.rb +24 -0
  11. data/lib/babl/nodes/dep.rb +38 -0
  12. data/lib/babl/nodes/each.rb +29 -0
  13. data/lib/babl/nodes/fixed_array.rb +25 -0
  14. data/lib/babl/nodes/goto_pin.rb +24 -0
  15. data/lib/babl/{rendering/internal_value_node.rb → nodes/internal_value.rb} +6 -5
  16. data/lib/babl/nodes/merge.rb +102 -0
  17. data/lib/babl/nodes/nav.rb +33 -0
  18. data/lib/babl/nodes/object.rb +26 -0
  19. data/lib/babl/nodes/parent.rb +64 -0
  20. data/lib/babl/nodes/static.rb +34 -0
  21. data/lib/babl/nodes/switch.rb +29 -0
  22. data/lib/babl/nodes/terminal_value.rb +76 -0
  23. data/lib/babl/nodes/with.rb +28 -0
  24. data/lib/babl/operators/array.rb +5 -28
  25. data/lib/babl/operators/call.rb +4 -2
  26. data/lib/babl/operators/continue.rb +19 -0
  27. data/lib/babl/operators/default.rb +13 -0
  28. data/lib/babl/operators/dep.rb +3 -36
  29. data/lib/babl/operators/each.rb +3 -33
  30. data/lib/babl/operators/enter.rb +4 -2
  31. data/lib/babl/operators/extends.rb +4 -1
  32. data/lib/babl/operators/merge.rb +7 -30
  33. data/lib/babl/operators/nav.rb +4 -36
  34. data/lib/babl/operators/object.rb +7 -29
  35. data/lib/babl/operators/parent.rb +4 -73
  36. data/lib/babl/operators/partial.rb +4 -2
  37. data/lib/babl/operators/pin.rb +14 -58
  38. data/lib/babl/operators/static.rb +11 -30
  39. data/lib/babl/operators/switch.rb +8 -51
  40. data/lib/babl/operators/with.rb +5 -34
  41. data/lib/babl/railtie.rb +2 -2
  42. data/lib/babl/rendering/compiled_template.rb +5 -13
  43. data/lib/babl/rendering/context.rb +13 -7
  44. data/lib/babl/schema/any_of.rb +137 -0
  45. data/lib/babl/schema/anything.rb +13 -0
  46. data/lib/babl/schema/dyn_array.rb +11 -0
  47. data/lib/babl/schema/fixed_array.rb +13 -0
  48. data/lib/babl/schema/object.rb +35 -0
  49. data/lib/babl/schema/static.rb +14 -0
  50. data/lib/babl/schema/typed.rb +0 -0
  51. data/lib/babl/template.rb +4 -9
  52. data/lib/babl/utils/ref.rb +6 -0
  53. data/lib/babl/version.rb +1 -1
  54. data/spec/operators/array_spec.rb +31 -7
  55. data/spec/operators/call_spec.rb +16 -14
  56. data/spec/operators/continue_spec.rb +25 -0
  57. data/spec/operators/default_spec.rb +15 -0
  58. data/spec/operators/dep_spec.rb +4 -8
  59. data/spec/operators/each_spec.rb +24 -5
  60. data/spec/operators/enter_spec.rb +9 -7
  61. data/spec/operators/extends_spec.rb +19 -5
  62. data/spec/operators/merge_spec.rb +105 -12
  63. data/spec/operators/nav_spec.rb +22 -10
  64. data/spec/operators/null_spec.rb +5 -4
  65. data/spec/operators/nullable_spec.rb +13 -13
  66. data/spec/operators/object_spec.rb +17 -6
  67. data/spec/operators/parent_spec.rb +18 -22
  68. data/spec/operators/partial_spec.rb +8 -6
  69. data/spec/operators/pin_spec.rb +100 -61
  70. data/spec/operators/source_spec.rb +10 -6
  71. data/spec/operators/static_spec.rb +17 -9
  72. data/spec/operators/switch_spec.rb +85 -45
  73. data/spec/operators/with_spec.rb +13 -15
  74. data/spec/spec_helper.rb +2 -31
  75. data/spec/spec_helper/operator_testing.rb +46 -0
  76. data/spec/spec_helper/schema_utils.rb +33 -0
  77. metadata +63 -4
  78. data/lib/babl/rendering/terminal_value_node.rb +0 -54
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Nav do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Nav do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#nav' do
7
- let(:template) { dsl.source { nav(:a) } }
7
+ template { nav(:a) }
8
8
 
9
9
  context 'hash navigation' do
10
10
  let(:object) { { a: 42 } }
@@ -12,15 +12,27 @@ describe ::Babl::Operators::Nav do
12
12
  it { expect(dependencies).to eq(a: {}) }
13
13
 
14
14
  context 'block navigation propagate dependency chain' do
15
- let(:template) { dsl.source { nav(:a).nav(:to_i) } }
15
+ template { nav(:a).nav(:to_i) }
16
16
  it { expect(dependencies).to eq(a: { to_i: {} }) }
17
17
  end
18
18
  end
19
19
 
20
20
  context 'navigate to non serializable' do
21
- let(:template) { dsl.source { nav(:a) } }
21
+ template { nav(:a) }
22
22
  let(:object) { { a: :test } }
23
- it { expect { json }.to raise_error Babl::RenderingError }
23
+ it { expect { json }.to raise_error Babl::Errors::RenderingError }
24
+ end
25
+
26
+ context 'navigate to non serializable in nested object' do
27
+ template { nav(:a) }
28
+ let(:object) { { a: { b: [1, 2, { c: 1, d: Object.new }] } } }
29
+ it { expect { json }.to raise_error Babl::Errors::RenderingError, /\__root__\.a\.b\.2\.d/ }
30
+ end
31
+
32
+ context 'navigate to non serializable in nested object with invalid key' do
33
+ template { nav(:a) }
34
+ let(:object) { { a: { b: [1, 2, { c: 1, Object.new => 1 }] } } }
35
+ it { expect { json }.to raise_error Babl::Errors::RenderingError, /\__root__\.a\.b\.2/ }
24
36
  end
25
37
 
26
38
  context 'object navigation' do
@@ -31,20 +43,20 @@ describe ::Babl::Operators::Nav do
31
43
 
32
44
  context 'block navigation' do
33
45
  let(:object) { 42 }
34
- let(:template) { dsl.source { nav { |x| x * 2 } } }
46
+ template { nav { |x| x * 2 } }
35
47
 
36
48
  it { expect(json).to eq(84) }
37
49
  it { expect(dependencies).to eq({}) }
38
50
 
39
51
  context 'block navigation breaks dependency chain' do
40
- let(:template) { dsl.source { nav { |x| x * 2 }.nav(:to_i) } }
52
+ template { nav { |x| x * 2 }.nav(:to_i) }
41
53
  it { expect(dependencies).to eq({}) }
42
54
  end
43
55
  end
44
56
 
45
57
  context '#nav should stop key propagation for #enter' do
46
- let(:template) { dsl.source { object(a: nav._) } }
47
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
58
+ template { object(a: nav._) }
59
+ it { expect { compiled }.to raise_error Babl::Errors::InvalidTemplateError }
48
60
  end
49
61
  end
50
62
  end
@@ -1,13 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Null do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Null do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#null' do
7
- let(:template) { dsl.source { { val: null } } }
7
+ template { { val: null } }
8
+
8
9
  let(:object) { {} }
9
10
 
10
- it { expect(documentation).to eq(val: nil) }
11
+ it { expect(schema).to eq s_object(s_property(:val, s_static(nil))) }
11
12
  it { expect(dependencies).to eq({}) }
12
13
  it { expect(json).to eq('val' => nil) }
13
14
  end
@@ -1,26 +1,26 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Nullable do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Nullable do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#nullable' do
7
7
  let(:object) { { nullprop: nil, notnullprop: { abc: 12 } } }
8
8
 
9
- let(:template) {
10
- dsl.source {
11
- object(
12
- nullprop: nav(:nullprop).nullable.nav(:abc),
13
- notnullprop: nav(:notnullprop).nullable.nav(:abc)
14
- )
15
- }
9
+ template {
10
+ object(
11
+ nullprop: nav(:nullprop).nullable.nav(:abc),
12
+ notnullprop: nav(:notnullprop).nullable.object(:abc)
13
+ )
16
14
  }
17
15
 
18
- it { expect(json).to eq('nullprop' => nil, 'notnullprop' => 12) }
16
+ it { expect(json).to eq('nullprop' => nil, 'notnullprop' => { 'abc' => 12 }) }
19
17
 
20
18
  it {
21
- expect(documentation).to eq(
22
- notnullprop: { "Case 1": nil, "Case 2": :__value__ },
23
- nullprop: { "Case 1": nil, "Case 2": :__value__ }
19
+ expect(schema).to eq(
20
+ s_object(
21
+ s_property(:nullprop, s_anything),
22
+ s_property(:notnullprop, s_object(s_property(:abc, s_anything), nullable: true))
23
+ )
24
24
  )
25
25
  }
26
26
 
@@ -1,19 +1,30 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Object do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Object do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#object' do
7
- let(:template) { dsl.source { object(:a, :b, c: _, d: nav(:d)) } }
7
+ template { object(:a, :b, c: _, d: nav(:d)) }
8
+
8
9
  let(:object) { { a: 1, b: 2, c: 3, d: 4 } }
9
10
 
10
11
  it { expect(json).to eq('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4) }
11
- it { expect(documentation).to eq(a: :__value__, b: :__value__, c: :__value__, d: :__value__) }
12
+ it {
13
+ expect(schema).to eq(
14
+ s_object(
15
+ s_property(:a, s_anything),
16
+ s_property(:b, s_anything),
17
+ s_property(:c, s_anything),
18
+ s_property(:d, s_anything)
19
+ )
20
+ )
21
+ }
12
22
  it { expect(dependencies).to eq(a: {}, b: {}, c: {}, d: {}) }
13
23
 
14
24
  context 'misused (chaining after object)' do
15
- let(:template) { dsl.source { object(:a).object(:b) } }
16
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
25
+ template { object(:a).object(:b) }
26
+
27
+ it { expect { compiled }.to raise_error Babl::Errors::InvalidTemplateError }
17
28
  end
18
29
  end
19
30
  end
@@ -1,53 +1,49 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Parent do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Parent do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#parent' do
7
7
  context 'valid usage' do
8
- let(:template) {
9
- dsl.source {
10
- nav(:box).dep(:box_dep).parent.dep(:root_dep)
11
- }
12
- }
8
+ template { nav(:box).dep(:box_dep).parent.dep(:root_dep) }
13
9
 
14
10
  let(:object) { { box: 42 } }
15
11
 
16
- it { expect(documentation).to eq :__value__ }
12
+ it { expect(schema).to eq s_anything }
17
13
  it { expect(dependencies).to eq(box: { box_dep: {} }, root_dep: {}) }
18
14
  it { expect(json).to eq('box' => 42) }
19
15
  end
20
16
 
21
17
  context 'error while navigating' do
18
+ template { nav(:a).parent.nav(:a).nav(:b, :x) }
19
+
22
20
  let(:object) { { a: { b: { c: 56 } } } }
23
- let(:template) { dsl.source { nav(:a).parent.nav(:a).nav(:b, :x) } }
24
21
 
25
22
  it { expect { json }.to raise_error(/\__root__\.a\.b\.x/) }
26
23
  end
27
24
 
28
25
  context 'invalid usage' do
29
- let(:template) { dsl.source { parent } }
30
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
26
+ template { parent }
27
+
28
+ it { expect { compiled }.to raise_error Babl::Errors::InvalidTemplateError }
31
29
  end
32
30
 
33
31
  context 'deeply nested parent chain' do
34
- let(:template) {
35
- dsl.source {
36
- nav(:a, :b, :c, :d, :e).parent.parent.parent.nav(:f, :g, :h).parent.parent.parent.parent.nav(:i)
37
- }
32
+ template {
33
+ nav(:a, :b, :c, :d, :e).parent.parent.parent.nav(:f, :g, :h).parent.parent.parent.parent.nav(:i)
38
34
  }
35
+
39
36
  it { expect(dependencies).to eq(a: { b: { f: { g: { h: {} } }, c: { d: { e: {} } } }, i: {} }) }
40
37
  end
41
38
 
42
39
  context 'same-level key + nested parent chain' do
43
- let(:template) {
44
- dsl.source {
45
- object(
46
- a: _.nav(:b, :c).parent.parent.nav(:h),
47
- b: _.nav(:a).parent.nav(:a)
48
- )
49
- }
40
+ template {
41
+ object(
42
+ a: _.nav(:b, :c).parent.parent.nav(:h),
43
+ b: _.nav(:a).parent.nav(:a)
44
+ )
50
45
  }
46
+
51
47
  it { expect(dependencies).to eq(a: { b: { c: {} }, h: {} }, b: { a: {} }) }
52
48
  end
53
49
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Partial do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Partial do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  let(:custom_lookup_context) {
7
7
  TestLookupContext.new(
@@ -19,16 +19,18 @@ describe ::Babl::Operators::Partial do
19
19
  )
20
20
  )
21
21
  }
22
- let(:ctx_dsl) { dsl.with_lookup_context(custom_lookup_context) }
22
+ let(:dsl) { Babl::Template.new.with_lookup_context(custom_lookup_context) }
23
23
  let(:object) { { some_property: 12 } }
24
24
 
25
25
  context 'missing partial' do
26
- let(:template) { ctx_dsl.partial('i_do_not_exist') }
27
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
26
+ template { partial('i_do_not_exist') }
27
+
28
+ it { expect { compiled }.to raise_error Babl::Errors::InvalidTemplateError }
28
29
  end
29
30
 
30
31
  context 'found partial' do
31
- let(:template) { ctx_dsl.partial('blabla') }
32
+ template { partial('blabla') }
33
+
32
34
  it { expect(json).to eq [13, 23] }
33
35
  end
34
36
  end
@@ -1,18 +1,16 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Pin do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Pin do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#pin' do
7
7
  context 'simple pinning' do
8
- let(:template) {
9
- dsl.source {
10
- nav(:a).pin { |a|
11
- nav(:b).object(
12
- x: _,
13
- y: a.nav(:y)
14
- )
15
- }
8
+ template {
9
+ nav(:a).pin { |a|
10
+ nav(:b).object(
11
+ x: _,
12
+ y: a.nav(:y)
13
+ )
16
14
  }
17
15
  }
18
16
 
@@ -22,15 +20,20 @@ describe ::Babl::Operators::Pin do
22
20
 
23
21
  it { expect(json).to eq('x' => 42, 'y' => 13) }
24
22
  it { expect(dependencies).to eq(a: { y: {}, b: { x: {} } }) }
25
- it { expect(documentation).to eq(x: :__value__, y: :__value__) }
23
+ it {
24
+ expect(schema).to eq(
25
+ s_object(
26
+ s_property(:x, s_anything),
27
+ s_property(:y, s_anything)
28
+ )
29
+ )
30
+ }
26
31
  end
27
32
 
28
33
  context 'when visiting parent from pin' do
29
- let(:template) {
30
- dsl.source {
31
- nav(:a).pin { |p1|
32
- object(x: _, y: p1.parent.pin { |p2| p2.nav(:a, :b) })
33
- }
34
+ template {
35
+ nav(:a).pin { |p1|
36
+ object(x: _, y: p1.parent.pin { |p2| p2.nav(:a, :b) })
34
37
  }
35
38
  }
36
39
 
@@ -38,32 +41,35 @@ describe ::Babl::Operators::Pin do
38
41
 
39
42
  it { expect(json).to eq('x' => 12, 'y' => 42) }
40
43
  it { expect(dependencies).to eq(a: { x: {}, b: {} }) }
41
- it { expect(documentation).to eq(x: :__value__, y: :__value__) }
44
+ it {
45
+ expect(schema).to eq(
46
+ s_object(
47
+ s_property(:x, s_anything),
48
+ s_property(:y, s_anything)
49
+ )
50
+ )
51
+ }
42
52
  end
43
53
 
44
54
  context 'when pinning is misused (out of context)' do
45
- let(:template) {
46
- dsl.source {
47
- pinref = nil
48
- object(
49
- a: pin { |p| pinref = p },
50
- b: pinref.nav(:lol)
51
- )
52
- }
55
+ template {
56
+ pinref = nil
57
+ object(
58
+ a: pin { |p| pinref = p },
59
+ b: pinref.nav(:lol)
60
+ )
53
61
  }
54
62
 
55
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
63
+ it { expect { compiled }.to raise_error Babl::Errors::InvalidTemplateError }
56
64
  end
57
65
 
58
66
  context 'when pinning is mixed with a "with" context' do
59
- let(:template) {
60
- dsl.source {
61
- pin { |root|
62
- with(:a) { |a| a }.object(
63
- x: _,
64
- y: root.nav(:lol)
65
- )
66
- }
67
+ template {
68
+ pin { |root|
69
+ with(:a) { |a| a }.object(
70
+ x: _,
71
+ y: root.nav(:lol)
72
+ )
67
73
  }
68
74
  }
69
75
 
@@ -71,35 +77,48 @@ describe ::Babl::Operators::Pin do
71
77
 
72
78
  it { expect(json).to eq('x' => 34, 'y' => 1) }
73
79
  it { expect(dependencies).to eq(a: {}, lol: {}) }
74
- it { expect(documentation).to eq(x: :__value__, y: :__value__) }
80
+ it {
81
+ expect(schema).to eq(
82
+ s_object(
83
+ s_property(:x, s_anything),
84
+ s_property(:y, s_anything)
85
+ )
86
+ )
87
+ }
75
88
  end
76
89
 
77
90
  context 'navigating pinning' do
78
- let(:template) {
79
- dsl.source {
80
- pin(:timezone) { |timezone| object(applicant: _.object(:id, tz: timezone)) }
81
- }
91
+ template {
92
+ pin(:timezone) { |timezone| object(applicant: _.object(:id, tz: timezone)) }
82
93
  }
83
94
 
84
95
  let(:object) { { applicant: { id: 1 }, timezone: 'LA' } }
85
96
 
86
97
  it { expect(json).to eq('applicant' => { 'id' => 1, 'tz' => 'LA' }) }
87
98
  it { expect(dependencies).to eq(timezone: {}, applicant: { id: {} }) }
88
- it { expect(documentation).to eq(applicant: { id: :__value__, tz: :__value__ }) }
99
+ it {
100
+ expect(schema).to eq(
101
+ s_object(
102
+ s_property(:applicant,
103
+ s_object(
104
+ s_property(:id, s_anything),
105
+ s_property(:tz, s_anything)
106
+ ))
107
+ )
108
+ )
109
+ }
89
110
  end
90
111
 
91
112
  context 'pin used twice in same chain' do
92
- let(:template) {
93
- dsl.source {
94
- nav(:a).pin { |a|
95
- object(
96
- h: nav(:h),
97
- a: a.object(
98
- x: _,
99
- y: a.nav(:lol).parent.nav(:mdr)
100
- )
113
+ template {
114
+ nav(:a).pin { |a|
115
+ object(
116
+ h: nav(:h),
117
+ a: a.object(
118
+ x: _,
119
+ y: a.nav(:lol).parent.nav(:mdr)
101
120
  )
102
- }
121
+ )
103
122
  }
104
123
  }
105
124
 
@@ -107,19 +126,31 @@ describe ::Babl::Operators::Pin do
107
126
 
108
127
  it { expect(json).to eq('h' => 42, 'a' => { 'x' => 13, 'y' => 34 }) }
109
128
  it { expect(dependencies).to eq(a: { h: {}, x: {}, lol: {}, mdr: {} }) }
110
- it { expect(documentation).to eq(h: :__value__, a: { x: :__value__, y: :__value__ }) }
129
+
130
+ it {
131
+ expect(schema).to eq(
132
+ s_object(
133
+ s_property(
134
+ :a,
135
+ s_object(
136
+ s_property(:x, s_anything),
137
+ s_property(:y, s_anything)
138
+ )
139
+ ),
140
+ s_property(:h, s_anything)
141
+ )
142
+ )
143
+ }
111
144
  end
112
145
 
113
146
  context 'nested pinning' do
114
- let(:template) {
115
- dsl.source {
116
- pin { |root|
117
- nav(:a).pin { |a|
118
- object(
119
- a: a.nav(:x),
120
- root: root.nav(:y)
121
- )
122
- }
147
+ template {
148
+ pin { |root|
149
+ nav(:a).pin { |a|
150
+ object(
151
+ a: a.nav(:x),
152
+ root: root.nav(:y)
153
+ )
123
154
  }
124
155
  }
125
156
  }
@@ -127,7 +158,15 @@ describe ::Babl::Operators::Pin do
127
158
  let(:object) { { a: { x: 42 }, y: 13 } }
128
159
 
129
160
  it { expect(json).to eq('a' => 42, 'root' => 13) }
130
- it { expect(documentation).to eq(a: :__value__, root: :__value__) }
161
+
162
+ it {
163
+ expect(schema).to eq(
164
+ s_object(
165
+ s_property(:a, s_anything),
166
+ s_property(:root, s_anything)
167
+ )
168
+ )
169
+ }
131
170
  end
132
171
  end
133
172
  end