babl-json 0.1.1 → 0.1.2

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