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
@@ -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