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
@@ -0,0 +1,14 @@
1
+ require 'values'
2
+
3
+ module Babl
4
+ module Schema
5
+ class Static < Value.new(:value)
6
+ NULL = new(nil)
7
+
8
+ def json
9
+ return { type: 'null' } if value.nil?
10
+ { enum: [value] }
11
+ end
12
+ end
13
+ end
14
+ end
File without changes
data/lib/babl/template.rb CHANGED
@@ -1,7 +1,7 @@
1
- require 'babl/utils/hash'
2
-
3
1
  require 'babl/operators/array'
4
2
  require 'babl/operators/call'
3
+ require 'babl/operators/continue'
4
+ require 'babl/operators/default'
5
5
  require 'babl/operators/dep'
6
6
  require 'babl/operators/each'
7
7
  require 'babl/operators/enter'
@@ -20,18 +20,13 @@ require 'babl/operators/switch'
20
20
  require 'babl/operators/with'
21
21
 
22
22
  require 'babl/builder/template_base'
23
- require 'babl/builder/chain_builder'
24
-
25
- require 'babl/rendering/compiled_template'
26
- require 'babl/rendering/context'
27
- require 'babl/rendering/internal_value_node'
28
- require 'babl/rendering/terminal_value_node'
29
- require 'babl/rendering/noop_preloader'
30
23
 
31
24
  module Babl
32
25
  class Template < Babl::Builder::TemplateBase
33
26
  include Operators::Array::DSL
34
27
  include Operators::Call::DSL
28
+ include Operators::Continue::DSL
29
+ include Operators::Default::DSL
35
30
  include Operators::Dep::DSL
36
31
  include Operators::Each::DSL
37
32
  include Operators::Enter::DSL
@@ -0,0 +1,6 @@
1
+ module Babl
2
+ module Utils
3
+ class Ref
4
+ end
5
+ end
6
+ end
data/lib/babl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Babl
2
- VERSION = '0.1.4'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -1,13 +1,37 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Array do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Array do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#array' do
7
- let(:template) { dsl.source { array('coucou', 45, a: 1, b: [_]) } }
8
- let(:object) { { b: 12 } }
9
- it { expect(json).to eq ['coucou', 45, { 'a' => 1, 'b' => [12] }] }
10
- it { expect(dependencies).to eq(b: {}) }
11
- it { expect(documentation).to eq ['coucou', 45, a: 1, b: [:__value__]] }
7
+ context 'statically defined array' do
8
+ template { array('coucou', 45, a: 1, b: [_]) }
9
+
10
+ let(:object) { { b: 12 } }
11
+
12
+ it { expect(json).to eq ['coucou', 45, { 'a' => 1, 'b' => [12] }] }
13
+ it { expect(dependencies).to eq(b: {}) }
14
+ it {
15
+ expect(schema).to eq(
16
+ s_fixed_array(
17
+ s_static('coucou'),
18
+ s_static(45),
19
+ s_object(
20
+ s_property(:a, s_static(1)),
21
+ s_property(:b, s_fixed_array(s_anything))
22
+ )
23
+ )
24
+ )
25
+ }
26
+ end
27
+
28
+ context 'nullable array' do
29
+ template { nullable.array(itself) }
30
+
31
+ let(:object) { 1 }
32
+
33
+ it { expect(json).to eq([1]) }
34
+ it { expect(schema).to eq s_fixed_array(s_anything, nullable: true) }
35
+ end
12
36
  end
13
37
  end
@@ -1,62 +1,64 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Call do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Call do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#call' do
7
- let(:object) { nil }
8
-
9
7
  context 'primitive' do
10
- let(:template) { dsl.call(false) }
8
+ template { call(false) }
11
9
 
12
10
  it { expect(json).to eq false }
13
11
  it { expect(dependencies).to eq({}) }
14
- it { expect(documentation).to eq false }
12
+ it { expect(schema).to eq s_static(false) }
15
13
 
16
14
  context 'call primitive after a conditional' do
17
- let(:template) { dsl.nullable.call(34) }
15
+ template { nullable.call(34) }
16
+
18
17
  it { expect(json).to eq nil }
19
18
  end
20
19
  end
21
20
 
22
21
  context 'block' do
22
+ template { call { self * 2 } }
23
+
23
24
  let(:object) { 2 }
24
- let(:template) { dsl.call { self * 2 } }
25
25
 
26
26
  it { expect(json).to eq 4 }
27
27
  end
28
28
 
29
29
  context 'hash' do
30
- let(:object) { nil }
31
- let(:template) { dsl.call('a' => 1, b: 2) }
30
+ template { call('a' => 1, b: 2) }
32
31
 
33
32
  it { expect(json).to eq('a' => 1, 'b' => 2) }
34
33
  it { expect(dependencies).to eq({}) }
35
34
  end
36
35
 
37
36
  context 'array' do
37
+ template { call(['a', 2, :b]) }
38
+
38
39
  let(:object) { { b: 42 } }
39
- let(:template) { dsl.call(['a', 2, :b]) }
40
40
 
41
41
  it { expect(json).to eq(['a', 2, 42]) }
42
42
  it { expect(dependencies).to eq(b: {}) }
43
43
  end
44
44
 
45
45
  context 'block' do
46
+ template { call(:lol) }
47
+
46
48
  let(:object) { OpenStruct.new(lol: 'tam') }
47
- let(:template) { dsl.call(:lol) }
48
49
 
49
50
  it { expect(json).to eq 'tam' }
50
51
  it { expect(dependencies).to eq(lol: {}) }
51
52
  end
52
53
 
53
54
  context 'template' do
55
+ template { object(coucou: nav(:a).call(nav(:b))) }
56
+
54
57
  let(:object) { OpenStruct.new(a: OpenStruct.new(b: 1)) }
55
- let(:template) { dsl.source { object(coucou: nav(:a).call(nav(:b))) } }
56
58
 
57
59
  it { expect(dependencies).to eq(a: { b: {} }) }
58
60
  it { expect(json).to eq('coucou' => 1) }
59
- it { expect(documentation).to eq(coucou: :__value__) }
61
+ it { expect(schema).to eq(s_object(s_property(:coucou, s_anything))) }
60
62
  end
61
63
  end
62
64
  end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Babl::Operators::Continue do
4
+ extend SpecHelper::OperatorTesting
5
+
6
+ describe '#switch' do
7
+ context 'navigation before continue' do
8
+ template { nav(:abc).switch(false => 1, default => nav(:lol).continue).object(val: nav(:ok)) }
9
+
10
+ it { expect { compiled }.to raise_error Babl::Errors::InvalidTemplateError }
11
+ end
12
+
13
+ context 'continue without switch' do
14
+ template { continue }
15
+
16
+ it { expect { compiled }.to raise_error Babl::Errors::InvalidTemplateError }
17
+ end
18
+
19
+ context 'continue in sub-object' do
20
+ template { object(a: switch(default => object(x: continue))) }
21
+
22
+ it { expect { compiled }.to raise_error Babl::Errors::InvalidTemplateError }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Babl::Operators::Default do
6
+ extend SpecHelper::OperatorTesting
7
+
8
+ describe '#default' do
9
+ template { default }
10
+
11
+ it { expect(json).to eq true }
12
+ it { expect(schema).to eq s_static(true) }
13
+ it { expect(dependencies).to eq({}) }
14
+ end
15
+ end
@@ -1,18 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Dep do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Dep do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#dep' do
7
- let(:template) {
8
- dsl.source {
9
- dep(a: [:b, :c]).nav(:b).dep(x: :y).nav(:z)
10
- }
11
- }
7
+ template { dep(a: [:b, :c]).nav(:b).dep(x: :y).nav(:z) }
12
8
 
13
9
  let(:object) { { b: { z: 42 } } }
14
10
 
15
- it { expect(documentation).to eq :__value__ }
11
+ it { expect(schema).to eq s_anything }
16
12
  it { expect(dependencies).to eq(a: { b: {}, c: {} }, b: { x: { y: {} }, z: {} }) }
17
13
  it { expect(json).to eq(42) }
18
14
  end
@@ -1,23 +1,42 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Each do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Each do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#each' do
7
7
  context 'when everything is fine' do
8
- let(:template) { dsl.source { each.nav(:a) } }
8
+ template { each.nav(:a) }
9
+
9
10
  let(:object) { [{ a: 3 }, { a: 2 }, { a: 1 }] }
10
11
 
11
12
  it { expect(json).to eq [3, 2, 1] }
12
13
  it { expect(dependencies).to eq(__each__: { a: {} }) }
13
- it { expect(documentation).to eq [:__value__] }
14
+ it { expect(schema).to eq s_dyn_array(s_anything) }
14
15
  end
15
16
 
16
17
  context 'error while navigating' do
18
+ template { nav(:box).each.nav(:trololol) }
19
+
17
20
  let(:object) { { box: [{ trololol: 2 }, 42] } }
18
- let(:template) { dsl.source { nav(:box).each.nav(:trololol) } }
19
21
 
20
22
  it { expect { json }.to raise_error(/\__root__\.box\.1\.trololol/) }
21
23
  end
24
+
25
+ context 'not enumerable' do
26
+ template { nav(:lol).each }
27
+
28
+ let(:object) { { lol: 'not enumerable' } }
29
+
30
+ it { expect { json }.to raise_error(Babl::Errors::RenderingError, /\__root__\.lol/) }
31
+ end
32
+
33
+ context 'nullable array' do
34
+ template { nullable.each.nullable.object }
35
+
36
+ let(:object) { [1, nil] }
37
+
38
+ it { expect(json).to eq [{}, nil] }
39
+ it { expect(schema).to eq s_dyn_array(s_object(nullable: true), nullable: true) }
40
+ end
22
41
  end
23
42
  end
@@ -1,24 +1,26 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Enter do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Enter do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#enter' do
7
7
  context 'invalid usage' do
8
- let(:template) { dsl.source { enter } }
9
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
8
+ template { enter }
9
+
10
+ it { expect { compiled }.to raise_error Babl::Errors::InvalidTemplateError }
10
11
  end
11
12
 
12
13
  context 'valid usage' do
13
- let(:template) { dsl.source { object(a: enter) } }
14
+ template { object(a: enter) }
15
+
14
16
  let(:object) { { a: 42 } }
15
17
 
16
- it { expect(documentation).to eq(a: :__value__) }
18
+ it { expect(schema).to eq(s_object(s_property(:a, s_anything))) }
17
19
  it { expect(dependencies).to eq(a: {}) }
18
20
  it { expect(json).to eq('a' => 42) }
19
21
 
20
22
  context 'using alias' do
21
- let(:template) { dsl.source { object(a: _) } }
23
+ template { object(a: _) }
22
24
  it { expect(json).to eq('a' => 42) }
23
25
  end
24
26
  end
@@ -1,16 +1,30 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Extends do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Extends do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  let(:custom_lookup_context) {
7
- TestLookupContext.new(base_partial: TestLookupContext.new('object(a: 1, b: 3)'))
7
+ TestLookupContext.new(
8
+ object_partial: TestLookupContext.new('object(a: 1, b: 3)'),
9
+ string_partial: TestLookupContext.new('"lol"')
10
+ )
8
11
  }
9
- let(:ctx_dsl) { dsl.with_lookup_context(custom_lookup_context) }
12
+ let(:dsl) { Babl::Template.new.with_lookup_context(custom_lookup_context) }
10
13
  let(:object) { [nil] }
11
14
 
12
15
  context 'simple use case' do
13
- let(:template) { ctx_dsl.source { each.extends('base_partial', object(x: 1), b: 34) } }
16
+ template { each.extends('object_partial', object(x: 1), b: 34) }
14
17
  it { expect(json).to eq(['a' => 1, 'x' => 1, 'b' => 34]) }
15
18
  end
19
+
20
+ context 'extend a non-object' do
21
+ template { extends('string_partial') }
22
+ it { expect(json).to eq('lol') }
23
+ it { expect(schema).to eq s_static('lol') }
24
+ end
25
+
26
+ context 'extend a non-object and try to add properties' do
27
+ template { each.extends('string_partial', test: 1) }
28
+ it { expect { schema }.to raise_error Babl::Errors::InvalidTemplateError }
29
+ end
16
30
  end
@@ -1,31 +1,124 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ::Babl::Operators::Merge do
4
- include SpecHelper::Operators
3
+ describe Babl::Operators::Merge do
4
+ extend SpecHelper::OperatorTesting
5
5
 
6
6
  describe '#merge' do
7
- context do
8
- let(:template) {
9
- dsl.source {
10
- merge(
11
- object(a: static('A')),
12
- b: _
13
- )
14
- }
7
+ context 'merge two objects' do
8
+ template {
9
+ merge(
10
+ object(a: static('A')),
11
+ b: _
12
+ )
15
13
  }
16
14
 
17
15
  let(:object) { { b: 42 } }
18
16
 
19
17
  it { expect(json).to eq('a' => 'A', 'b' => 42) }
20
18
  it { expect(dependencies).to eq(b: {}) }
21
- it { expect(documentation).to eq('Merge 1': { a: 'A' }, 'Merge 2': { b: :__value__ }) }
19
+ it {
20
+ expect(schema).to eq(
21
+ s_object(
22
+ s_property(:a, s_static('A')),
23
+ s_property(:b, s_anything)
24
+ )
25
+ )
26
+ }
22
27
  end
23
28
 
24
29
  context 'merge inside object' do
25
- let(:template) { dsl.source { object(toto: merge(_, lol: 42)) } }
30
+ template { object(toto: merge(_, lol: 42)) }
31
+
26
32
  let(:object) { { toto: { cool: 'ouai' } } }
27
33
 
28
34
  it { expect(json).to eq('toto' => { 'lol' => 42, 'cool' => 'ouai' }) }
35
+ it {
36
+ expect(schema).to eq(
37
+ s_object(
38
+ s_property(:toto,
39
+ s_object(
40
+ s_property(:lol, s_static(42)),
41
+ additional: true
42
+ ))
43
+ )
44
+ )
45
+ }
46
+ end
47
+
48
+ context 'merge nothing' do
49
+ template { merge }
50
+
51
+ it { expect(json).to eq({}) }
52
+ it { expect(schema).to eq s_object }
53
+ end
54
+
55
+ context 'merge that could fail in some case' do
56
+ template {
57
+ merge(
58
+ switch(
59
+ false => switch(
60
+ true => {},
61
+ default => 'not an object'
62
+ ),
63
+ default => {}
64
+ ),
65
+ object(test: 1)
66
+ )
67
+ }
68
+
69
+ it { expect { schema }.to raise_error Babl::Errors::InvalidTemplateError }
70
+ end
71
+
72
+ context 'merge only one static value' do
73
+ template { merge(42) }
74
+
75
+ it { expect { schema }.to raise_error Babl::Errors::InvalidTemplateError }
76
+ end
77
+
78
+ context 'merge only one dynamic value' do
79
+ template { merge(itself) }
80
+
81
+ let(:object) { 43 }
82
+
83
+ it { expect { json }.to raise_error Babl::Errors::RenderingError }
84
+ it { expect(schema).to eq s_object(additional: true) }
85
+ end
86
+
87
+ context 'merge object with static' do
88
+ template { merge(object(a: 1), static(b: 2)) }
89
+
90
+ it { expect(json).to eq('a' => 1, 'b' => 2) }
91
+ it { expect(schema).to eq s_object(s_property(:a, s_static(1)), s_property(:b, s_static(2))) }
92
+ end
93
+
94
+ context 'merge object with conditionally present properties' do
95
+ template {
96
+ merge(
97
+ switch(
98
+ itself => object(a: 1, b: 2),
99
+ default => object(b: 3, c: 4)
100
+ ),
101
+ itself,
102
+ switch(
103
+ itself => object(c: 7),
104
+ default => object(c: 5)
105
+ )
106
+ )
107
+ }
108
+
109
+ let(:object) { { b: 1 } }
110
+
111
+ it { expect(json).to eq('a' => 1, 'b' => 1, 'c' => 7) }
112
+ it {
113
+ expect(schema).to eq(
114
+ s_object(
115
+ s_property(:a, s_any_of(s_anything, s_static(1)), required: false),
116
+ s_property(:b, s_any_of(s_anything, s_static(2), s_static(3))),
117
+ s_property(:c, s_any_of(s_static(7), s_static(5))),
118
+ additional: true
119
+ )
120
+ )
121
+ }
29
122
  end
30
123
  end
31
124
  end