babl-json 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/babl.rb +64 -12
- data/lib/babl/builder/chain_builder.rb +1 -5
- data/lib/babl/builder/template_base.rb +11 -8
- data/lib/babl/operators.rb +1 -0
- data/lib/babl/operators/parent.rb +1 -1
- data/lib/babl/operators/partial.rb +8 -34
- data/lib/babl/operators/pin.rb +1 -1
- data/lib/babl/operators/using.rb +19 -0
- data/lib/babl/rendering/context.rb +1 -1
- data/lib/babl/schema/fixed_array.rb +2 -2
- data/lib/babl/schema/object.rb +2 -2
- data/lib/babl/template.rb +1 -0
- data/lib/babl/utils/dsl_proxy.rb +1 -1
- data/lib/babl/utils/value.rb +32 -23
- data/lib/babl/version.rb +1 -1
- metadata +26 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bad3eaac421de5e967efa6a17096a9a95529174
|
4
|
+
data.tar.gz: e722e283eb9a3004a935a28bac8b09f8f94a10e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa8c6c330b936f4c1b4a3a455bba8491a43911c7c644d161b233215e8a436e2091722e6d85c0005d2b6aa89f5641d69dddb8d50ebd1cc49010368caa434633fb
|
7
|
+
data.tar.gz: 9a6a76cc67edcf4f7f2b952b645d5fa974f492294dde354925c9eb3aa794dd3c210689c55b082923ee4682eaaa960cc6db540dd78776cc10ac7fc6cb83758bc6
|
data/lib/babl.rb
CHANGED
@@ -6,32 +6,84 @@ require 'babl/rendering'
|
|
6
6
|
require 'babl/operators'
|
7
7
|
|
8
8
|
module Babl
|
9
|
+
# There is basically two ways to use BABL: the Rails way, and the clean way.
|
10
|
+
#
|
11
|
+
# Rails way
|
12
|
+
# - BABL detects Rails and integrates with it automatically (only if BABL is required AFTER Rails).
|
13
|
+
# - BABL configuration is global (defined via Babl.configure).
|
14
|
+
# - Global configuration is also used by:
|
15
|
+
# Babl.template
|
16
|
+
# Babl.compile
|
17
|
+
# Babl.source
|
18
|
+
#
|
19
|
+
# Clean way
|
20
|
+
# - You can decide not to use global configuration. It will result in more verbosity
|
21
|
+
# but it protects you from global settings.
|
22
|
+
# - Equivalences:
|
23
|
+
# Babl.template ==> Babl::Template.new
|
24
|
+
# Babl.compile ==> Babl::Template#compile
|
25
|
+
# Babl.source ==> Babl::Template#source
|
26
|
+
#
|
9
27
|
class Config
|
10
|
-
attr_accessor :
|
28
|
+
attr_accessor :preloader, # No practical use outside Bannerman today.
|
29
|
+
:pretty, # Pretty format JSON output (boolean).
|
30
|
+
:cache_templates, # Enable or disable caching of compiled templates (Rails only, boolean).
|
31
|
+
:lookup_context, # Specify how to find templates.
|
32
|
+
:using # List of user-defined modules containing custom operators.
|
11
33
|
|
12
34
|
def initialize
|
13
|
-
@search_path = nil
|
14
35
|
@preloader = Rendering::NoopPreloader
|
15
36
|
@pretty = true
|
16
37
|
@cache_templates = false
|
38
|
+
@lookup_context = nil
|
39
|
+
@using = []
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class AbsoluteLookupContext
|
44
|
+
attr_reader :search_path
|
45
|
+
|
46
|
+
def initialize(search_path)
|
47
|
+
@search_path = search_path
|
48
|
+
raise Errors::InvalidTemplate, 'Missing search path' unless search_path
|
49
|
+
end
|
50
|
+
|
51
|
+
def find(current_template, partial_name)
|
52
|
+
query = File.join(search_path, "{#{partial_name}}{.babl,}")
|
53
|
+
path = Dir[query].first
|
54
|
+
return unless path
|
55
|
+
source = File.read(path)
|
56
|
+
[current_template.source(source, path, 0), self]
|
17
57
|
end
|
18
58
|
end
|
19
59
|
|
20
60
|
class << self
|
21
|
-
def compile(&block)
|
22
|
-
|
61
|
+
def compile(*args, &block)
|
62
|
+
raise ArgumentError, 'Wrong number of arguments' if args.size > 1
|
63
|
+
raise ArgumentError, 'Template or block expected' unless args.empty? ^ block.nil?
|
64
|
+
|
65
|
+
(args.empty? ? source(&block) : template.call(args.first)).compile(
|
23
66
|
pretty: config.pretty,
|
24
|
-
preloader: config.preloader
|
67
|
+
preloader: config.preloader,
|
68
|
+
lookup_context: config.lookup_context
|
25
69
|
)
|
26
70
|
end
|
27
71
|
|
28
|
-
def source(&block)
|
29
|
-
template
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
72
|
+
def source(*args, &block)
|
73
|
+
template.source(*args, &block)
|
74
|
+
end
|
75
|
+
|
76
|
+
def template
|
77
|
+
cached = @cached_template
|
78
|
+
return cached.last if cached && config.using == cached.first
|
79
|
+
# Calling 'using' is a very inefficient operation, because
|
80
|
+
# it creates a new class. We can avoid that cost most of the
|
81
|
+
# time, assuming 'config.using' does not change often (typically
|
82
|
+
# it should only change once at startup)
|
83
|
+
modules = config.using.dup
|
84
|
+
template = Template.new.using(*modules)
|
85
|
+
@cached_template = [modules, template]
|
86
|
+
template
|
35
87
|
end
|
36
88
|
|
37
89
|
def configure
|
@@ -8,17 +8,20 @@ module Babl
|
|
8
8
|
module Builder
|
9
9
|
# TemplateBase is a thin wrapper around Builder.
|
10
10
|
#
|
11
|
-
# Since the BABL code is run via #
|
11
|
+
# Since the BABL code is run via #instance_exec within an instance of this class, we want to
|
12
12
|
# define as few methods as possible here.
|
13
|
-
class TemplateBase
|
13
|
+
class TemplateBase
|
14
|
+
attr_reader :builder
|
15
|
+
|
14
16
|
def initialize(builder = ChainBuilder.new(&:itself))
|
15
|
-
|
17
|
+
@builder = builder
|
18
|
+
freeze
|
16
19
|
end
|
17
20
|
|
18
|
-
def compile(preloader: Rendering::NoopPreloader, pretty: true, optimize: true)
|
21
|
+
def compile(preloader: Rendering::NoopPreloader, pretty: true, optimize: true, lookup_context: nil)
|
19
22
|
# Compute dependencies & schema on the non-simplified node tree in order
|
20
23
|
# to catch all errors.
|
21
|
-
tree = precompile
|
24
|
+
tree = precompile(lookup_context: lookup_context)
|
22
25
|
dependencies = tree.dependencies
|
23
26
|
schema = tree.schema
|
24
27
|
|
@@ -40,13 +43,13 @@ module Babl
|
|
40
43
|
end
|
41
44
|
|
42
45
|
def unscoped
|
43
|
-
self.class.new
|
46
|
+
self.class.new
|
44
47
|
end
|
45
48
|
|
46
49
|
protected
|
47
50
|
|
48
|
-
def precompile
|
49
|
-
builder.precompile(
|
51
|
+
def precompile(node = Nodes::TerminalValue.instance, **context)
|
52
|
+
builder.precompile(node, **context)
|
50
53
|
end
|
51
54
|
|
52
55
|
def construct_node(**new_context, &block)
|
data/lib/babl/operators.rb
CHANGED
@@ -8,40 +8,14 @@ module Babl
|
|
8
8
|
# Load a partial template given its name
|
9
9
|
# A 'lookup_context' must be defined
|
10
10
|
def partial(partial_name)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
.
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
def with_lookup_context(lookup_context)
|
22
|
-
self.class.new(builder.dup.tap { |inst| inst.instance_variable_set(:@lookup_context, lookup_context) })
|
23
|
-
end
|
24
|
-
|
25
|
-
def lookup_context
|
26
|
-
builder.instance_variable_get(:@lookup_context)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class AbsoluteLookupContext
|
31
|
-
attr_reader :search_path
|
32
|
-
|
33
|
-
def initialize(search_path)
|
34
|
-
@search_path = search_path
|
35
|
-
raise Errors::InvalidTemplate, 'Invalid search path' unless search_path
|
36
|
-
end
|
37
|
-
|
38
|
-
def find(partial_name)
|
39
|
-
query = File.join(search_path, "{#{partial_name}}{.babl,}")
|
40
|
-
path = Dir[query].first
|
41
|
-
return unless path
|
42
|
-
|
43
|
-
source = File.read(path)
|
44
|
-
[path, source, self]
|
11
|
+
current_template = unscoped
|
12
|
+
construct_terminal { |ctx|
|
13
|
+
lookup_context = ctx[:lookup_context]
|
14
|
+
raise Errors::InvalidTemplate, 'Cannot use partial without lookup context' unless lookup_context
|
15
|
+
template, new_lookup_context = lookup_context.find(current_template, partial_name)
|
16
|
+
raise Errors::InvalidTemplate, "Cannot find partial '#{partial_name}'" unless template
|
17
|
+
template.precompile(Nodes::TerminalValue.instance, lookup_context: new_lookup_context)
|
18
|
+
}
|
45
19
|
end
|
46
20
|
end
|
47
21
|
end
|
data/lib/babl/operators/pin.rb
CHANGED
@@ -23,7 +23,7 @@ module Babl
|
|
23
23
|
protected
|
24
24
|
|
25
25
|
# Override TemplateBase#precompile to ensure that all pin dependencies are satisfied.
|
26
|
-
def precompile
|
26
|
+
def precompile(*)
|
27
27
|
super.tap do |node|
|
28
28
|
raise Errors::InvalidTemplate, 'Unresolved pin' unless node.pinned_dependencies.empty?
|
29
29
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Babl
|
3
|
+
module Operators
|
4
|
+
module Using
|
5
|
+
module DSL
|
6
|
+
def using(*mods, &block)
|
7
|
+
extended_self =
|
8
|
+
if mods.empty?
|
9
|
+
self
|
10
|
+
else
|
11
|
+
::Class.new(self.class) { mods.each { |mod| include mod } }.new(builder)
|
12
|
+
end
|
13
|
+
|
14
|
+
extended_self.source(&(block || -> { self }))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -4,11 +4,11 @@ require 'babl/utils'
|
|
4
4
|
module Babl
|
5
5
|
module Schema
|
6
6
|
class FixedArray < Utils::Value.new(:items)
|
7
|
-
EMPTY = new(
|
7
|
+
EMPTY = new(Utils::Array::EMPTY)
|
8
8
|
|
9
9
|
def json
|
10
10
|
if items.empty?
|
11
|
-
{ enum: [
|
11
|
+
{ enum: [Utils::Array::EMPTY] }
|
12
12
|
else
|
13
13
|
{ type: 'array', items: items.map(&:json), additionalItems: false }
|
14
14
|
end
|
data/lib/babl/schema/object.rb
CHANGED
@@ -9,8 +9,8 @@ module Babl
|
|
9
9
|
super(properties.to_set.freeze, additional)
|
10
10
|
end
|
11
11
|
|
12
|
-
EMPTY = new(
|
13
|
-
EMPTY_WITH_ADDITIONAL = new(
|
12
|
+
EMPTY = new(Utils::Array::EMPTY, false)
|
13
|
+
EMPTY_WITH_ADDITIONAL = new(Utils::Array::EMPTY, true)
|
14
14
|
|
15
15
|
class Property < Utils::Value.new(:name, :value, :required)
|
16
16
|
def initialize(name, value, required)
|
data/lib/babl/template.rb
CHANGED
data/lib/babl/utils/dsl_proxy.rb
CHANGED
data/lib/babl/utils/value.rb
CHANGED
@@ -5,35 +5,44 @@ module Babl
|
|
5
5
|
module Utils
|
6
6
|
# Construct deeply immutable value objects
|
7
7
|
# Similar to Struct, but:
|
8
|
-
# - Properties are assumed deeply immutable (#hash is assumed constant)
|
8
|
+
# - Properties are assumed deeply immutable (#hash is assumed constant & store permanently)
|
9
9
|
# - Constructor requires all arguments
|
10
10
|
# - #== has the same meaning as #eql?
|
11
|
-
|
11
|
+
# - The object is frozen
|
12
|
+
#
|
13
|
+
# Goals :
|
14
|
+
# - Create completely immutable value objects
|
15
|
+
# - Fast comparison between instances (using precomputed hash values)
|
16
|
+
# - Low overhead (relies on native Ruby Struct)
|
17
|
+
class Value < Struct
|
12
18
|
def self.new(*fields)
|
13
|
-
|
14
|
-
|
15
|
-
const_set(:FIELDS, fields.map(&:to_sym))
|
16
|
-
class_eval <<-RUBY
|
17
|
-
def initialize(#{field_aliases.join(',')})
|
18
|
-
super(#{['nil', field_aliases].join(',')})
|
19
|
-
hash
|
20
|
-
freeze
|
21
|
-
end
|
19
|
+
fields = fields.map(&:to_sym)
|
20
|
+
field_aliases = ::Array.new(fields.size) { |i| "v#{i}" }
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
clazz = super(:_cached_hash, *fields)
|
23
|
+
clazz.const_set(:FIELDS, fields)
|
24
|
+
clazz.class_eval <<-RUBY
|
25
|
+
def initialize(#{field_aliases.join(',')})
|
26
|
+
super(#{['nil', field_aliases].join(',')})
|
27
|
+
hash
|
28
|
+
freeze
|
29
|
+
end
|
30
|
+
RUBY
|
26
31
|
|
27
|
-
|
28
|
-
|
29
|
-
|
32
|
+
clazz
|
33
|
+
end
|
34
|
+
|
35
|
+
def hash
|
36
|
+
self._cached_hash ||= super
|
37
|
+
end
|
38
|
+
|
39
|
+
def ==(other)
|
40
|
+
eql?(other)
|
41
|
+
end
|
30
42
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
35
|
-
RUBY
|
36
|
-
end
|
43
|
+
def self.with(hash = Utils::Hash::EMPTY)
|
44
|
+
raise ::ArgumentError unless ::Hash === hash && (hash.keys - self::FIELDS).empty?
|
45
|
+
new(*self::FIELDS.map { |f| hash.fetch(f) })
|
37
46
|
end
|
38
47
|
end
|
39
48
|
end
|
data/lib/babl/version.rb
CHANGED
metadata
CHANGED
@@ -1,113 +1,113 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: babl-json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
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-10-
|
11
|
+
date: 2017-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: coveralls
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '0.8'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '0.8'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: jbuilder
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '2'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: json-schema
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '2.8'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '2.8'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: pry
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: rabl
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0.
|
75
|
+
version: '0.13'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0.
|
82
|
+
version: '0.13'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '3'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '3'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: rubocop
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - '='
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0.
|
103
|
+
version: '0.51'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - '='
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0.
|
110
|
+
version: '0.51'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: multi_json
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -175,6 +175,7 @@ files:
|
|
175
175
|
- lib/babl/operators/static.rb
|
176
176
|
- lib/babl/operators/switch.rb
|
177
177
|
- lib/babl/operators/typed.rb
|
178
|
+
- lib/babl/operators/using.rb
|
178
179
|
- lib/babl/operators/with.rb
|
179
180
|
- lib/babl/railtie.rb
|
180
181
|
- lib/babl/rendering.rb
|