babl-json 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 656d75b72add7bd391267cf72e6e45959a5aaf7d
4
- data.tar.gz: 34c2a76f614a357da5ac05a18c37f7bd585c8e5c
3
+ metadata.gz: 9465c242a044d65452c010e57c73b913e02191e9
4
+ data.tar.gz: 9de5d1761abe484d99ab4dbcd63a02e3a48c4004
5
5
  SHA512:
6
- metadata.gz: 8c651ce6396f0c2ea87fe1d1be350074c3425ff6c2718940e0ff404a889e805c483fa88e4442d7dc5d9e1b4457af62bec0650d301f7aa1882d5034895e84c383
7
- data.tar.gz: '08b57f384167c02bf9268bab025261394726d285051e8a583f76bf0f8a47264c12af1dcc7427ff8bd1e560fc081a11abe7bb9289cf8e4bcb9855adfb410695ed'
6
+ metadata.gz: f6cfe7ee5e5a957f12b33791b34e6db6bc2980ec533e4975bac8a7de380a551d9d5a1923e65c60bf2406928275a118ae79eb85c987c958b710fdfe19eb5c1500
7
+ data.tar.gz: df646dfc2fe0dd1e64cd8f6da9ca71f1d478fa93267f8141869c5bef7f4af17c2af3edc282a346b6b527cd4203fbefea7049d349e61d336520121264ff2c3767
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # BABL Changelog
2
2
 
3
- ## 0.1 (May 16, 2017)
3
+ ## 0.1.2 (May 22, 2017)
4
+
5
+ - Fixed a bug in #call(primitive)
6
+ - Improved test suite
7
+
8
+ ## 0.1.1 (May 16, 2017)
4
9
 
5
10
  - First released version
data/README.md CHANGED
@@ -17,7 +17,7 @@ BABL is also able to infer the "input schema". It can loosely be seen as the lis
17
17
 
18
18
  ### Simple syntax
19
19
 
20
- JSON is simple, and generating JSON should be as simple as possible.
20
+ JSON is simple, and generating JSON should be as simple as possible. We do not rely on `#method_missing`.
21
21
 
22
22
  BABL template:
23
23
 
@@ -64,7 +64,7 @@ As of today, the only compatible preloader implementation *has not been released
64
64
 
65
65
  ### Automatic documentation
66
66
 
67
- Support for automatic documentation is very limited, and the output is indecently ugly. It is more a proof-of-concept that a useful feature.
67
+ Support for automatic documentation is very limited, and the output is indecently ugly. It is more a proof-of-concept than a useful feature.
68
68
 
69
69
  The mid-term goal is to generate a [JSON schema](http://json-schema.org/) documentation.
70
70
 
@@ -13,9 +13,9 @@ module Babl
13
13
  when self.class then self.class.new(builder.wrap { |bound| arg.builder.bind(bound) })
14
14
  when ::Symbol then nav(arg)
15
15
  when ::Proc then call(&arg)
16
- when ::Hash then object(**arg.map { |k, v| [k.to_s.to_sym, v] }.to_h)
16
+ when ::Hash then object(**arg.map { |k, v| [:"#{k}", v] }.to_h)
17
17
  when ::Array then array(*arg)
18
- when ::String, ::Numeric, ::NilClass, ::TrueClass, ::FalseClass then unscoped.static(arg)
18
+ when ::String, ::Numeric, ::NilClass, ::TrueClass, ::FalseClass then static(arg)
19
19
  else raise ::Babl::InvalidTemplateError, "call() received invalid argument: #{arg}"
20
20
  end
21
21
  end
@@ -5,10 +5,12 @@ module Babl
5
5
  # Nullify the current construction if
6
6
  # the current element is Nil.
7
7
  def nullable
8
- switch(
9
- unscoped.nav(&:nil?) => nil,
10
- unscoped.default => unscoped.continue
11
- )
8
+ source {
9
+ switch(
10
+ nav(&:nil?) => nil,
11
+ default => continue
12
+ )
13
+ }
12
14
  end
13
15
  end
14
16
  end
data/lib/babl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Babl
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Array do
4
+ include SpecHelper::Operators
5
+
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__]] }
12
+ end
13
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Call do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#call' do
7
+ let(:object) { nil }
8
+
9
+ context 'primitive' do
10
+ let(:template) { dsl.call(false) }
11
+
12
+ it { expect(json).to eq false }
13
+ it { expect(dependencies).to eq({}) }
14
+ it { expect(documentation).to eq false }
15
+
16
+ context 'call primitive after a conditional' do
17
+ let(:template) { dsl.nullable.call(34) }
18
+ it { expect(json).to eq nil }
19
+ end
20
+ end
21
+
22
+ context 'block' do
23
+ let(:object) { 2 }
24
+ let(:template) { dsl.call { self * 2 } }
25
+
26
+ it { expect(json).to eq 4 }
27
+ end
28
+
29
+ context 'hash' do
30
+ let(:object) { nil }
31
+ let(:template) { dsl.call('a' => 1, b: 2) }
32
+
33
+ it { expect(json).to eq('a' => 1, 'b' => 2) }
34
+ it { expect(dependencies).to eq({}) }
35
+ end
36
+
37
+ context 'array' do
38
+ let(:object) { { b: 42 } }
39
+ let(:template) { dsl.call(['a', 2, :b]) }
40
+
41
+ it { expect(json).to eq(['a', 2, 42]) }
42
+ it { expect(dependencies).to eq(b: {}) }
43
+ end
44
+
45
+ context 'block' do
46
+ let(:object) { OpenStruct.new(lol: 'tam') }
47
+ let(:template) { dsl.call(:lol) }
48
+
49
+ it { expect(json).to eq 'tam' }
50
+ it { expect(dependencies).to eq(lol: {}) }
51
+ end
52
+
53
+ context 'template' do
54
+ let(:object) { OpenStruct.new(a: OpenStruct.new(b: 1)) }
55
+ let(:template) { dsl.source { object(coucou: nav(:a).call(nav(:b))) } }
56
+
57
+ it { expect(dependencies).to eq(a: { b: {} }) }
58
+ it { expect(json).to eq('coucou' => 1) }
59
+ it { expect(documentation).to eq(coucou: :__value__) }
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Dep do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#dep' do
7
+ let(:template) {
8
+ dsl.source {
9
+ dep(a: [:b, :c]).nav(:b).dep(x: :y).nav(:z)
10
+ }
11
+ }
12
+
13
+ let(:object) { { b: { z: 42 } } }
14
+
15
+ it { expect(documentation).to eq :__value__ }
16
+ it { expect(dependencies).to eq(a: { b: {}, c: {} }, b: { x: { y: {} }, z: {} }) }
17
+ it { expect(json).to eq(42) }
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Each do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#each' do
7
+ context 'when everything is fine' do
8
+ let(:template) { dsl.source { each.nav(:a) } }
9
+ let(:object) { [{ a: 3 }, { a: 2 }, { a: 1 }] }
10
+
11
+ it { expect(json).to eq [3, 2, 1] }
12
+ it { expect(dependencies).to eq(__each__: { a: {} }) }
13
+ it { expect(documentation).to eq [:__value__] }
14
+ end
15
+
16
+ context 'error while navigating' do
17
+ let(:object) { { box: [{ trololol: 2 }, 42] } }
18
+ let(:template) { dsl.source { nav(:box).each.nav(:trololol) } }
19
+
20
+ it { expect { json }.to raise_error(/\__root__\.box\.1\.trololol/) }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Enter do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#enter' do
7
+ context 'invalid usage' do
8
+ let(:template) { dsl.source { enter } }
9
+ it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
10
+ end
11
+
12
+ context 'valid usage' do
13
+ let(:template) { dsl.source { object(a: enter) } }
14
+ let(:object) { { a: 42 } }
15
+
16
+ it { expect(documentation).to eq(a: :__value__) }
17
+ it { expect(dependencies).to eq(a: {}) }
18
+ it { expect(json).to eq('a' => 42) }
19
+
20
+ context 'using alias' do
21
+ let(:template) { dsl.source { object(a: _) } }
22
+ it { expect(json).to eq('a' => 42) }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Merge do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#merge' do
7
+ context do
8
+ let(:template) {
9
+ dsl.source {
10
+ merge(
11
+ object(a: static('A')),
12
+ b: _
13
+ )
14
+ }
15
+ }
16
+
17
+ let(:object) { { b: 42 } }
18
+
19
+ it { expect(json).to eq('a' => 'A', 'b' => 42) }
20
+ it { expect(dependencies).to eq(b: {}) }
21
+ it { expect(documentation).to eq('Merge 1': { a: 'A' }, 'Merge 2': { b: :__value__ }) }
22
+ end
23
+
24
+ context 'merge inside object' do
25
+ let(:template) { dsl.source { object(toto: merge(_, lol: 42)) } }
26
+ let(:object) { { toto: { cool: 'ouai' } } }
27
+
28
+ it { expect(json).to eq('toto' => { 'lol' => 42, 'cool' => 'ouai' }) }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Nav do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#nav' do
7
+ let(:template) { dsl.source { nav(:a) } }
8
+
9
+ context 'hash navigation' do
10
+ let(:object) { { a: 42 } }
11
+ it { expect(json).to eq(42) }
12
+ it { expect(dependencies).to eq(a: {}) }
13
+
14
+ context 'block navigation propagate dependency chain' do
15
+ let(:template) { dsl.source { nav(:a).nav(:to_i) } }
16
+ it { expect(dependencies).to eq(a: { to_i: {} }) }
17
+ end
18
+ end
19
+
20
+ context 'navigate to non serializable' do
21
+ let(:template) { dsl.source { nav(:a) } }
22
+ let(:object) { { a: :test } }
23
+ it { expect { json }.to raise_error Babl::RenderingError }
24
+ end
25
+
26
+ context 'object navigation' do
27
+ let(:object) { Struct.new(:a).new(42) }
28
+ it { expect(json).to eq(42) }
29
+ it { expect(dependencies).to eq(a: {}) }
30
+ end
31
+
32
+ context 'block navigation' do
33
+ let(:object) { 42 }
34
+ let(:template) { dsl.source { nav { |x| x * 2 } } }
35
+
36
+ it { expect(json).to eq(84) }
37
+ it { expect(dependencies).to eq({}) }
38
+
39
+ context 'block navigation breaks dependency chain' do
40
+ let(:template) { dsl.source { nav { |x| x * 2 }.nav(:to_i) } }
41
+ it { expect(dependencies).to eq({}) }
42
+ end
43
+ end
44
+
45
+ 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 }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Nullable do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#nullable' do
7
+ let(:object) { { nullprop: nil, notnullprop: { abc: 12 } } }
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
+ }
16
+ }
17
+
18
+ it { expect(json).to eq('nullprop' => nil, 'notnullprop' => 12) }
19
+
20
+ it {
21
+ expect(documentation).to eq(
22
+ notnullprop: { "Case 1": nil, "Case 2": :__value__ },
23
+ nullprop: { "Case 1": nil, "Case 2": :__value__ }
24
+ )
25
+ }
26
+
27
+ it { expect(dependencies).to eq(nullprop: { abc: {} }, notnullprop: { abc: {} }) }
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Object do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#object' do
7
+ let(:template) { dsl.source { object(:a, :b, c: _, d: nav(:d)) } }
8
+ let(:object) { { a: 1, b: 2, c: 3, d: 4 } }
9
+
10
+ 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 { expect(dependencies).to eq(a: {}, b: {}, c: {}, d: {}) }
13
+
14
+ context 'misused (chaining after object)' do
15
+ let(:template) { dsl.source { object(:a).object(:b) } }
16
+ it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Parent do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#parent' do
7
+ context 'valid usage' do
8
+ let(:template) {
9
+ dsl.source {
10
+ nav(:box).dep(:box_dep).parent.dep(:root_dep)
11
+ }
12
+ }
13
+
14
+ let(:object) { { box: 42 } }
15
+
16
+ it { expect(documentation).to eq :__value__ }
17
+ it { expect(dependencies).to eq(box: { box_dep: {} }, root_dep: {}) }
18
+ it { expect(json).to eq('box' => 42) }
19
+ end
20
+
21
+ context 'error while navigating' do
22
+ let(:object) { { a: { b: { c: 56 } } } }
23
+ let(:template) { dsl.source { nav(:a).parent.nav(:a).nav(:b, :x) } }
24
+
25
+ it { expect { json }.to raise_error(/\__root__\.a\.b\.x/) }
26
+ end
27
+
28
+ context 'invalid usage' do
29
+ let(:template) { dsl.source { parent } }
30
+ it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
31
+ end
32
+
33
+ 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
+ }
38
+ }
39
+ it { expect(dependencies).to eq(a: { b: { f: { g: { h: {} } }, c: { d: { e: {} } } }, i: {} }) }
40
+ end
41
+
42
+ 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
+ }
50
+ }
51
+ it { expect(dependencies).to eq(a: { b: { c: {} }, h: {} }, b: { a: {} }) }
52
+ end
53
+ end
54
+ end
@@ -1,6 +1,8 @@
1
- require 'babl'
1
+ require 'spec_helper'
2
2
 
3
3
  describe ::Babl::Operators::Partial do
4
+ include SpecHelper::Operators
5
+
4
6
  before {
5
7
  stub_const('TestLookupContext', Class.new {
6
8
  attr_reader :code, :childs
@@ -18,11 +20,6 @@ describe ::Babl::Operators::Partial do
18
20
  })
19
21
  }
20
22
 
21
- let(:dsl) { ::Babl::Template.new }
22
- let(:compiled) { template.compile }
23
- let(:json) { Oj.load(compiled.json(object)) }
24
- let(:object) { { some_property: 12 } }
25
-
26
23
  let(:custom_lookup_context) {
27
24
  TestLookupContext.new(
28
25
  blabla: TestLookupContext.new(
@@ -40,6 +37,7 @@ describe ::Babl::Operators::Partial do
40
37
  )
41
38
  }
42
39
  let(:ctx_dsl) { dsl.with_lookup_context(custom_lookup_context) }
40
+ let(:object) { { some_property: 12 } }
43
41
 
44
42
  context 'missing partial' do
45
43
  let(:template) { ctx_dsl.partial('i_do_not_exist') }
@@ -1,11 +1,7 @@
1
- require 'babl'
2
-
3
- describe ::Babl::Template do
4
- let(:dsl) { ::Babl::Template.new }
5
- let(:compiled) { template.compile }
6
- let(:json) { Oj.load(compiled.json(object)) }
7
- let(:dependencies) { compiled.dependencies }
8
- let(:documentation) { compiled.documentation }
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Pin do
4
+ include SpecHelper::Operators
9
5
 
10
6
  describe '#pin' do
11
7
  context 'simple pinning' do
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Source do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#source' do
7
+ let(:object) { { abc: { def: 12 } } }
8
+
9
+ context 'block returning primitive' do
10
+ let(:template) { dsl.source { true } }
11
+ it { expect(json).to eq(true) }
12
+ end
13
+
14
+ context 'block using operators' do
15
+ let(:template) { dsl.source { static(3) } }
16
+ it { expect(json).to eq(3) }
17
+ end
18
+
19
+ context 'two level sourcing' do
20
+ let(:template) { dsl.source { nav(:abc).source { nav(:def) } } }
21
+ it { expect(json).to eq(12) }
22
+ end
23
+
24
+ context 'string template' do
25
+ let(:template) { dsl.source('object(a: static(true))') }
26
+ it { expect(json).to eq('a' => true) }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Static do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#static' do
7
+ let(:template) { dsl.source { static('1': 'cava') } }
8
+ let(:object) { nil }
9
+
10
+ it { expect(json).to eq('1' => 'cava') }
11
+ it { expect(dependencies).to eq({}) }
12
+ it { expect(documentation).to eq('1': 'cava') }
13
+
14
+ context 'invalid' do
15
+ let(:template) { dsl.source { static(test: Object.new) } }
16
+ it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::Switch do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#switch' do
7
+ context do
8
+ let(:template) {
9
+ dsl.source {
10
+ even = nullable.nav(:even?)
11
+ odd = nullable.nav(:odd?)
12
+
13
+ each.switch(
14
+ even => nav { |x| "#{x} is even" },
15
+ odd => nav { |x| "#{x} is odd" },
16
+ default => continue
17
+ ).static('WTF')
18
+ }
19
+ }
20
+
21
+ let(:object) { [1, 2, nil, 5] }
22
+
23
+ it { expect(json).to eq ['1 is odd', '2 is even', 'WTF', '5 is odd'] }
24
+ it { expect(dependencies).to eq(__each__: { even?: {}, odd?: {} }) }
25
+ it {
26
+ expect(documentation).to eq [
27
+ 'Case 1': :__value__,
28
+ 'Case 2': :__value__,
29
+ 'Case 3': 'WTF'
30
+ ]
31
+ }
32
+ end
33
+
34
+ context 'static condition' do
35
+ let(:template) { dsl.source { switch(true => 42) } }
36
+ let(:object) { {} }
37
+ it { expect(json).to eq 42 }
38
+ end
39
+
40
+ context 'navigation before continue' do
41
+ let(:template) { dsl.source { nav(:abc).switch(false => 1, default => nav(:lol).continue).object(val: nav(:ok)) } }
42
+
43
+ it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
44
+ end
45
+
46
+ context 'continue in sub-object' do
47
+ let(:template) { dsl.source { object(a: switch(default => object(x: continue))) } }
48
+
49
+ it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
50
+ end
51
+
52
+ context 'unhandled default' do
53
+ let(:object) { { abc: { lol: { ok: 42 } } } }
54
+ let(:template) { dsl.source { switch(false => 1) } }
55
+
56
+ it { expect(dependencies).to eq({}) }
57
+ it { expect { json }.to raise_error Babl::RenderingError }
58
+ end
59
+
60
+ context 'continue without switch' do
61
+ let(:template) { dsl.source { continue } }
62
+
63
+ it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
64
+ end
65
+
66
+ context 'non serializable objects are allowed internally' do
67
+ let(:template) { dsl.source { switch(test: 42) } }
68
+ let(:object) { { test: Object.new } }
69
+
70
+ it { expect(json).to eq 42 }
71
+ end
72
+
73
+ context do
74
+ let(:template) {
75
+ dsl.source {
76
+ nav(:test).switch(nav(:keke) => parent.nav(:lol))
77
+ }
78
+ }
79
+ it { expect(dependencies).to eq(test: { keke: {} }, lol: {}) }
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Babl::Operators::With do
4
+ include SpecHelper::Operators
5
+
6
+ describe '#with' do
7
+ context 'everything is fine' do
8
+ let(:template) {
9
+ dsl.source {
10
+ object(
11
+ result: with(
12
+ unscoped,
13
+ :msg,
14
+ _.parent.nav(:msg).dep(:lol)
15
+ ) { |obj, a, b| "#{a} #{b} #{obj[:msg]}" }
16
+ )
17
+ }
18
+ }
19
+
20
+ let(:object) { { result: 42, msg: 'Hello C' } }
21
+
22
+ it { expect(json).to eq('result' => 'Hello C Hello C Hello C') }
23
+ it { expect(dependencies).to eq(result: {}, msg: { lol: {} }) }
24
+ it { expect(documentation).to eq(result: :__value__) }
25
+ end
26
+
27
+ context 'when the block raise an exception' do
28
+ let(:object) { nil }
29
+ let(:template) { dsl.source { with { raise 'lol' } } }
30
+ it { expect { json }.to raise_error(/\__root__\.__block__/) }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,14 @@
1
+ require 'babl'
2
+ require 'oj'
3
+
4
+ module SpecHelper
5
+ module Operators
6
+ def self.included(base)
7
+ base.let(:dsl) { ::Babl::Template.new }
8
+ base.let(:compiled) { template.compile }
9
+ base.let(:json) { ::Oj.load(compiled.json(object)) }
10
+ base.let(:dependencies) { compiled.dependencies }
11
+ base.let(:documentation) { compiled.documentation }
12
+ end
13
+ end
14
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: babl-json
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frederic Terrazzoni
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-15 00:00:00.000000000 Z
11
+ date: 2017-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -110,10 +110,23 @@ files:
110
110
  - lib/babl/template.rb
111
111
  - lib/babl/utils/hash.rb
112
112
  - lib/babl/version.rb
113
- - spec/construction_spec.rb
114
- - spec/navigation_spec.rb
115
- - spec/partial_spec.rb
116
- - spec/pinning_spec.rb
113
+ - spec/operators/array_spec.rb
114
+ - spec/operators/call_spec.rb
115
+ - spec/operators/dep_spec.rb
116
+ - spec/operators/each_spec.rb
117
+ - spec/operators/enter_spec.rb
118
+ - spec/operators/merge_spec.rb
119
+ - spec/operators/nav_spec.rb
120
+ - spec/operators/nullable_spec.rb
121
+ - spec/operators/object_spec.rb
122
+ - spec/operators/parent_spec.rb
123
+ - spec/operators/partial_spec.rb
124
+ - spec/operators/pin_spec.rb
125
+ - spec/operators/source_spec.rb
126
+ - spec/operators/static_spec.rb
127
+ - spec/operators/switch_spec.rb
128
+ - spec/operators/with_spec.rb
129
+ - spec/spec_helper.rb
117
130
  homepage: https://github.com/getbannerman/babl
118
131
  licenses:
119
132
  - MIT
@@ -139,7 +152,20 @@ signing_key:
139
152
  specification_version: 4
140
153
  summary: JSON templating on steroids
141
154
  test_files:
142
- - spec/construction_spec.rb
143
- - spec/navigation_spec.rb
144
- - spec/partial_spec.rb
145
- - spec/pinning_spec.rb
155
+ - spec/operators/array_spec.rb
156
+ - spec/operators/call_spec.rb
157
+ - spec/operators/dep_spec.rb
158
+ - spec/operators/each_spec.rb
159
+ - spec/operators/enter_spec.rb
160
+ - spec/operators/merge_spec.rb
161
+ - spec/operators/nav_spec.rb
162
+ - spec/operators/nullable_spec.rb
163
+ - spec/operators/object_spec.rb
164
+ - spec/operators/parent_spec.rb
165
+ - spec/operators/partial_spec.rb
166
+ - spec/operators/pin_spec.rb
167
+ - spec/operators/source_spec.rb
168
+ - spec/operators/static_spec.rb
169
+ - spec/operators/switch_spec.rb
170
+ - spec/operators/with_spec.rb
171
+ - spec/spec_helper.rb
@@ -1,246 +0,0 @@
1
- require 'babl'
2
-
3
- describe ::Babl::Template do
4
- let(:dsl) { ::Babl::Template.new }
5
- let(:compiled) { template.compile }
6
- let(:json) { Oj.load(compiled.json(object)) }
7
- let(:dependencies) { compiled.dependencies }
8
- let(:documentation) { compiled.documentation }
9
-
10
- describe '#object' do
11
- let(:template) { dsl.source { object(:a, :b, c: _, d: nav(:d)) } }
12
- let(:object) { { a: 1, b: 2, c: 3, d: 4 } }
13
-
14
- it { expect(json).to eq('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4) }
15
- it { expect(documentation).to eq(a: :__value__, b: :__value__, c: :__value__, d: :__value__) }
16
- it { expect(dependencies).to eq(a: {}, b: {}, c: {}, d: {}) }
17
-
18
- context 'misused (chaining after object)' do
19
- let(:template) { dsl.source { object(:a).object(:b) } }
20
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
21
- end
22
- end
23
-
24
- describe '#each' do
25
- context 'when everything is fine' do
26
- let(:template) { dsl.source { each.nav(:a) } }
27
- let(:object) { [{ a: 3 }, { a: 2 }, { a: 1 }] }
28
-
29
- it { expect(json).to eq [3, 2, 1] }
30
- it { expect(dependencies).to eq(__each__: { a: {} }) }
31
- it { expect(documentation).to eq [:__value__] }
32
- end
33
-
34
- context 'error while navigating' do
35
- let(:object) { { box: [{ trololol: 2 }, 42] } }
36
- let(:template) { dsl.source { nav(:box).each.nav(:trololol) } }
37
-
38
- it { expect { json }.to raise_error(/\__root__\.box\.1\.trololol/) }
39
- end
40
- end
41
-
42
- describe '#static' do
43
- let(:template) { dsl.source { static('1': 'cava') } }
44
- let(:object) { nil }
45
-
46
- it { expect(json).to eq('1' => 'cava') }
47
- it { expect(dependencies).to eq({}) }
48
- it { expect(documentation).to eq('1': 'cava') }
49
-
50
- context 'invalid' do
51
- let(:template) { dsl.source { static(test: Object.new) } }
52
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
53
- end
54
- end
55
-
56
- describe '#array' do
57
- let(:template) { dsl.source { array('coucou', 45, a: 1, b: [_]) } }
58
- let(:object) { { b: 12 } }
59
- it { expect(json).to eq ['coucou', 45, { 'a' => 1, 'b' => [12] }] }
60
- it { expect(dependencies).to eq(b: {}) }
61
- it { expect(documentation).to eq ['coucou', 45, a: 1, b: [:__value__]] }
62
- end
63
-
64
- describe '#call' do
65
- let(:object) { nil }
66
-
67
- context 'false' do
68
- let(:template) { dsl.call(false) }
69
-
70
- it { expect(json).to eq false }
71
- it { expect(dependencies).to eq({}) }
72
- it { expect(documentation).to eq false }
73
- end
74
-
75
- context 'block' do
76
- let(:object) { 2 }
77
- let(:template) { dsl.call { self * 2 } }
78
-
79
- it { expect(json).to eq 4 }
80
- end
81
-
82
- context 'hash' do
83
- let(:object) { nil }
84
- let(:template) { dsl.call('a' => 1, b: 2) }
85
-
86
- it { expect(json).to eq('a' => 1, 'b' => 2) }
87
- it { expect(dependencies).to eq({}) }
88
- end
89
-
90
- context 'array' do
91
- let(:object) { { b: 42 } }
92
- let(:template) { dsl.call(['a', 2, :b]) }
93
-
94
- it { expect(json).to eq(['a', 2, 42]) }
95
- it { expect(dependencies).to eq(b: {}) }
96
- end
97
-
98
- context 'block' do
99
- let(:object) { OpenStruct.new(lol: 'tam') }
100
- let(:template) { dsl.call(:lol) }
101
-
102
- it { expect(json).to eq 'tam' }
103
- it { expect(dependencies).to eq(lol: {}) }
104
- end
105
-
106
- context 'template' do
107
- let(:object) { OpenStruct.new(a: OpenStruct.new(b: 1)) }
108
- let(:template) { dsl.source { object(coucou: nav(:a).call(nav(:b))) } }
109
-
110
- it { expect(dependencies).to eq(a: { b: {} }) }
111
- it { expect(json).to eq('coucou' => 1) }
112
- it { expect(documentation).to eq(coucou: :__value__) }
113
- end
114
- end
115
-
116
- describe '#switch' do
117
- context do
118
- let(:template) {
119
- dsl.source {
120
- even = nullable.nav(:even?)
121
- odd = nullable.nav(:odd?)
122
-
123
- each.switch(
124
- even => nav { |x| "#{x} is even" },
125
- odd => nav { |x| "#{x} is odd" },
126
- default => continue
127
- ).static('WTF')
128
- }
129
- }
130
-
131
- let(:object) { [1, 2, nil, 5] }
132
-
133
- it { expect(json).to eq ['1 is odd', '2 is even', 'WTF', '5 is odd'] }
134
- it { expect(dependencies).to eq(__each__: { even?: {}, odd?: {} }) }
135
- it {
136
- expect(documentation).to eq [
137
- 'Case 1': :__value__,
138
- 'Case 2': :__value__,
139
- 'Case 3': 'WTF'
140
- ]
141
- }
142
- end
143
-
144
- context 'static condition' do
145
- let(:template) { dsl.source { switch(true => 42) } }
146
- let(:object) { {} }
147
- it { expect(json).to eq 42 }
148
- end
149
-
150
- context 'navigation before continue' do
151
- let(:template) { dsl.source { nav(:abc).switch(false => 1, default => nav(:lol).continue).object(val: nav(:ok)) } }
152
-
153
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
154
- end
155
-
156
- context 'continue in sub-object' do
157
- let(:template) { dsl.source { object(a: switch(default => object(x: continue))) } }
158
-
159
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
160
- end
161
-
162
- context 'unhandled default' do
163
- let(:object) { { abc: { lol: { ok: 42 } } } }
164
- let(:template) { dsl.source { switch(false => 1) } }
165
-
166
- it { expect(dependencies).to eq({}) }
167
- it { expect { json }.to raise_error Babl::RenderingError }
168
- end
169
-
170
- context 'continue without switch' do
171
- let(:template) { dsl.source { continue } }
172
-
173
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
174
- end
175
-
176
- context 'non serializable objects are allowed internally' do
177
- let(:template) { dsl.source { switch(test: 42) } }
178
- let(:object) { { test: Object.new } }
179
-
180
- it { expect(json).to eq 42 }
181
- end
182
-
183
- context do
184
- let(:template) {
185
- dsl.source {
186
- nav(:test).switch(nav(:keke) => parent.nav(:lol))
187
- }
188
- }
189
- it { expect(dependencies).to eq(test: { keke: {} }, lol: {}) }
190
- end
191
- end
192
-
193
- describe '#with' do
194
- context 'everything is fine' do
195
- let(:template) {
196
- dsl.source {
197
- object(
198
- result: with(
199
- unscoped,
200
- :msg,
201
- _.parent.nav(:msg).dep(:lol)
202
- ) { |obj, a, b| "#{a} #{b} #{obj[:msg]}" }
203
- )
204
- }
205
- }
206
-
207
- let(:object) { { result: 42, msg: 'Hello C' } }
208
-
209
- it { expect(json).to eq('result' => 'Hello C Hello C Hello C') }
210
- it { expect(dependencies).to eq(result: {}, msg: { lol: {} }) }
211
- it { expect(documentation).to eq(result: :__value__) }
212
- end
213
-
214
- context 'when the block raise an exception' do
215
- let(:object) { nil }
216
- let(:template) { dsl.source { with { raise 'lol' } } }
217
- it { expect { json }.to raise_error(/\__root__\.__block__/) }
218
- end
219
- end
220
-
221
- describe '#merge' do
222
- context do
223
- let(:template) {
224
- dsl.source {
225
- merge(
226
- object(a: static('A')),
227
- b: _
228
- )
229
- }
230
- }
231
-
232
- let(:object) { { b: 42 } }
233
-
234
- it { expect(json).to eq('a' => 'A', 'b' => 42) }
235
- it { expect(dependencies).to eq(b: {}) }
236
- it { expect(documentation).to eq('Merge 1': { a: 'A' }, 'Merge 2': { b: :__value__ }) }
237
- end
238
-
239
- context 'merge inside object' do
240
- let(:template) { dsl.source { object(toto: merge(_, lol: 42)) } }
241
- let(:object) { { toto: { cool: 'ouai' } } }
242
-
243
- it { expect(json).to eq('toto' => { 'lol' => 42, 'cool' => 'ouai' }) }
244
- end
245
- end
246
- end
@@ -1,133 +0,0 @@
1
- require 'babl'
2
-
3
- describe ::Babl::Template do
4
- let(:dsl) { ::Babl::Template.new }
5
- let(:compiled) { template.compile }
6
- let(:json) { Oj.load(compiled.json(object)) }
7
- let(:dependencies) { compiled.dependencies }
8
- let(:documentation) { compiled.documentation }
9
-
10
- describe '#parent' do
11
- context 'valid usage' do
12
- let(:template) {
13
- dsl.source {
14
- nav(:box).dep(:box_dep).parent.dep(:root_dep)
15
- }
16
- }
17
-
18
- let(:object) { { box: 42 } }
19
-
20
- it { expect(documentation).to eq :__value__ }
21
- it { expect(dependencies).to eq(box: { box_dep: {} }, root_dep: {}) }
22
- it { expect(json).to eq('box' => 42) }
23
- end
24
-
25
- context 'error while navigating' do
26
- let(:object) { { a: { b: { c: 56 } } } }
27
- let(:template) { dsl.source { nav(:a).parent.nav(:a).nav(:b, :x) } }
28
-
29
- it { expect { json }.to raise_error(/\__root__\.a\.b\.x/) }
30
- end
31
-
32
- context 'invalid usage' do
33
- let(:template) { dsl.source { parent } }
34
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
35
- end
36
-
37
- context 'deeply nested parent chain' do
38
- let(:template) {
39
- dsl.source {
40
- nav(:a, :b, :c, :d, :e).parent.parent.parent.nav(:f, :g, :h).parent.parent.parent.parent.nav(:i)
41
- }
42
- }
43
- it { expect(dependencies).to eq(a: { b: { f: { g: { h: {} } }, c: { d: { e: {} } } }, i: {} }) }
44
- end
45
-
46
- context 'same-level key + nested parent chain' do
47
- let(:template) {
48
- dsl.source {
49
- object(
50
- a: _.nav(:b, :c).parent.parent.nav(:h),
51
- b: _.nav(:a).parent.nav(:a)
52
- )
53
- }
54
- }
55
- it { expect(dependencies).to eq(a: { b: { c: {} }, h: {} }, b: { a: {} }) }
56
- end
57
- end
58
-
59
- describe '#dep' do
60
- let(:template) {
61
- dsl.source {
62
- dep(a: [:b, :c]).nav(:b).dep(x: :y).nav(:z)
63
- }
64
- }
65
-
66
- let(:object) { { b: { z: 42 } } }
67
-
68
- it { expect(documentation).to eq :__value__ }
69
- it { expect(dependencies).to eq(a: { b: {}, c: {} }, b: { x: { y: {} }, z: {} }) }
70
- it { expect(json).to eq(42) }
71
- end
72
-
73
- describe '#enter' do
74
- context 'invalid usage' do
75
- let(:template) { dsl.source { enter } }
76
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
77
- end
78
-
79
- context 'valid usage' do
80
- let(:template) { dsl.source { object(a: enter) } }
81
- let(:object) { { a: 42 } }
82
-
83
- it { expect(documentation).to eq(a: :__value__) }
84
- it { expect(dependencies).to eq(a: {}) }
85
- it { expect(json).to eq('a' => 42) }
86
- end
87
- end
88
-
89
- describe '#nav' do
90
- let(:template) { dsl.source { nav(:a) } }
91
-
92
- context 'hash navigation' do
93
- let(:object) { { a: 42 } }
94
- it { expect(json).to eq(42) }
95
- it { expect(dependencies).to eq(a: {}) }
96
-
97
- context 'block navigation propagate dependency chain' do
98
- let(:template) { dsl.source { nav(:a).nav(:to_i) } }
99
- it { expect(dependencies).to eq(a: { to_i: {} }) }
100
- end
101
- end
102
-
103
- context 'navigate to non serializable' do
104
- let(:template) { dsl.source { nav(:a) } }
105
- let(:object) { { a: :test } }
106
- it { expect { json }.to raise_error Babl::RenderingError }
107
- end
108
-
109
- context 'object navigation' do
110
- let(:object) { Struct.new(:a).new(42) }
111
- it { expect(json).to eq(42) }
112
- it { expect(dependencies).to eq(a: {}) }
113
- end
114
-
115
- context 'block navigation' do
116
- let(:object) { 42 }
117
- let(:template) { dsl.source { nav { |x| x * 2 } } }
118
-
119
- it { expect(json).to eq(84) }
120
- it { expect(dependencies).to eq({}) }
121
-
122
- context 'block navigation breaks dependency chain' do
123
- let(:template) { dsl.source { nav { |x| x * 2 }.nav(:to_i) } }
124
- it { expect(dependencies).to eq({}) }
125
- end
126
- end
127
-
128
- context '#nav should stop key propagation for #enter' do
129
- let(:template) { dsl.source { object(a: nav._) } }
130
- it { expect { compiled }.to raise_error Babl::InvalidTemplateError }
131
- end
132
- end
133
- end