babl-json 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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