props_template 0.14.0 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -1
- data/lib/props_template.rb +2 -8
- data/lib/props_template/base.rb +40 -23
- data/lib/props_template/base_with_extensions.rb +12 -12
- data/lib/props_template/debug_writer.rb +55 -0
- data/lib/props_template/extension_manager.rb +31 -22
- data/lib/props_template/railtie.rb +0 -8
- data/spec/props_template_spec.rb +4 -0
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f324de590ac7fad6c1152e6e45a80b407044461fb33fc6b265955afd536d2aca
|
4
|
+
data.tar.gz: 945bd9ffa5457a422d65e49fdc16d5f73c1718fad4e38a78923afee24f7fa067
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c4b2f13494e4ec00f5c2a9510f536d3bff51133b36726dc4ed4aaef2f03940a314fbdd5163406e0826535df45268c7e3b4300e4f3fda8536da5b64a3c3346b8
|
7
|
+
data.tar.gz: 0ce796eb28ce86a5d4fb00301c72ac2b97fd5a500fba43cb32c6d3ab3df2c5c36a628973d6fd9975dca24fdbdb8ea0f2754eaea23f28e4664d65a3d22c4b5097
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# PropsTemplate
|
2
2
|
|
3
|
-
PropsTemplate is a queryable JSON templating library inspired by JBuilder. It has support for layouts, partials, russian-doll caching, multi-fetch and can selectively render nodes in your tree without executing others.
|
3
|
+
PropsTemplate is a fast queryable JSON templating library inspired by JBuilder. It has support for layouts, partials, russian-doll caching, multi-fetch and can selectively render nodes in your tree without executing others.
|
4
4
|
|
5
5
|
Example:
|
6
6
|
|
@@ -45,6 +45,29 @@ json.footer partial: 'shared/footer' do
|
|
45
45
|
end
|
46
46
|
```
|
47
47
|
|
48
|
+
## Installation
|
49
|
+
If you plan to use PropsTemplate alone just add it to your Gemfile.
|
50
|
+
|
51
|
+
```
|
52
|
+
gem 'props_template'
|
53
|
+
```
|
54
|
+
|
55
|
+
and run `bundle`
|
56
|
+
|
57
|
+
Then add the following to a initializer:
|
58
|
+
|
59
|
+
```
|
60
|
+
Props.reset_encoder!
|
61
|
+
```
|
62
|
+
|
63
|
+
PropsTemplate uses a single instance of `Oj::StringWriter` for a process. If you're using a forking server like puma, be sure to add this to your `config/puma.rb`.
|
64
|
+
|
65
|
+
```
|
66
|
+
on_worker_boot do
|
67
|
+
Props.reset_encoder!
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
48
71
|
## API
|
49
72
|
|
50
73
|
### json.set! or json.<your key here>
|
data/lib/props_template.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require 'props_template/base_with_extensions'
|
4
2
|
require 'props_template/searcher'
|
5
3
|
require 'props_template/handler'
|
@@ -15,7 +13,6 @@ module Props
|
|
15
13
|
self.template_lookup_options = { handlers: [:props] }
|
16
14
|
|
17
15
|
delegate :result!, :array!,
|
18
|
-
:commands_to_json!,
|
19
16
|
:deferred!,
|
20
17
|
:fragments!,
|
21
18
|
:set_block_content!,
|
@@ -49,11 +46,8 @@ module Props
|
|
49
46
|
@builder
|
50
47
|
end
|
51
48
|
|
52
|
-
|
53
|
-
|
54
|
-
def method_missing(*args, &block)
|
55
|
-
set!(*args, &block)
|
56
|
-
end
|
49
|
+
alias_method :method_missing, :set!
|
50
|
+
private :method_missing
|
57
51
|
end
|
58
52
|
end
|
59
53
|
|
data/lib/props_template/base.rb
CHANGED
@@ -1,45 +1,62 @@
|
|
1
1
|
require 'oj'
|
2
2
|
require 'active_support'
|
3
|
-
|
4
3
|
#todo: active_support/core_ext/string/output_safety.rb
|
5
4
|
|
6
5
|
module Props
|
7
6
|
class InvalidScopeForArrayError < StandardError; end
|
8
7
|
class InvalidScopeForObjError < StandardError; end
|
9
8
|
|
9
|
+
def self.reset_encoder!
|
10
|
+
@@encoder = Oj::StringWriter.new(mode: :rails)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.encoder
|
14
|
+
@@encoder
|
15
|
+
end
|
16
|
+
|
10
17
|
class Base
|
11
|
-
def initialize
|
12
|
-
@
|
13
|
-
@stream
|
18
|
+
def initialize(encoder = nil)
|
19
|
+
@stream = encoder || Props.encoder
|
20
|
+
@stream.reset
|
14
21
|
@scope = nil
|
22
|
+
@key_cache = {}
|
15
23
|
end
|
16
24
|
|
17
25
|
def set_block_content!(options = {})
|
18
|
-
@commands.push([:push_object])
|
19
26
|
@scope = nil
|
20
27
|
yield
|
21
|
-
@
|
28
|
+
if @scope.nil?
|
29
|
+
@stream.push_object
|
30
|
+
end
|
31
|
+
@stream.pop
|
22
32
|
end
|
23
33
|
|
24
34
|
def handle_set_block(key, options)
|
25
|
-
@
|
35
|
+
@stream.push_key(key)
|
26
36
|
set_block_content!(options) do
|
27
37
|
yield
|
28
38
|
end
|
29
39
|
end
|
30
40
|
|
31
41
|
def set!(key, value = nil)
|
32
|
-
@
|
42
|
+
@key_cache[key] ||= key.to_s.freeze
|
43
|
+
key = @key_cache[key]
|
44
|
+
|
33
45
|
if @scope == :array
|
34
46
|
raise InvalidScopeForObjError.new('Attempted to set! on an array! scope')
|
35
47
|
end
|
48
|
+
|
49
|
+
if @scope.nil?
|
50
|
+
@scope = :object
|
51
|
+
@stream.push_object
|
52
|
+
end
|
53
|
+
|
36
54
|
if block_given?
|
37
55
|
handle_set_block(key, value) do
|
38
56
|
yield
|
39
57
|
end
|
40
58
|
else
|
41
|
-
@
|
42
|
-
@commands.push([:push_value, value])
|
59
|
+
@stream.push_value(value, key)
|
43
60
|
end
|
44
61
|
|
45
62
|
@scope = :object
|
@@ -76,19 +93,18 @@ module Props
|
|
76
93
|
end
|
77
94
|
end
|
78
95
|
end
|
96
|
+
|
79
97
|
#todo, add ability to define contents of array
|
80
98
|
def array!(collection, options = {})
|
81
99
|
if @scope.nil?
|
82
100
|
@scope = :array
|
101
|
+
@stream.push_array
|
83
102
|
else
|
84
103
|
raise InvalidScopeForArrayError.new('array! expects exclusive use of this block')
|
85
104
|
end
|
86
|
-
@commands[-1] = [:push_array]
|
87
105
|
|
88
|
-
|
89
|
-
|
90
|
-
yield item, index
|
91
|
-
end
|
106
|
+
handle_collection(collection, options) do |item, index|
|
107
|
+
yield item, index
|
92
108
|
end
|
93
109
|
|
94
110
|
@scope = :array
|
@@ -96,18 +112,19 @@ module Props
|
|
96
112
|
nil
|
97
113
|
end
|
98
114
|
|
99
|
-
def
|
100
|
-
|
101
|
-
@stream.
|
115
|
+
def result!
|
116
|
+
if @scope.nil?
|
117
|
+
@stream.push_object
|
118
|
+
@stream.pop
|
119
|
+
else
|
120
|
+
@stream.pop
|
102
121
|
end
|
122
|
+
|
103
123
|
json = @stream.to_s
|
124
|
+
@scope = nil
|
125
|
+
@key_cache = {}
|
104
126
|
@stream.reset
|
105
127
|
json
|
106
128
|
end
|
107
|
-
|
108
|
-
def result!
|
109
|
-
@commands.push([:pop])
|
110
|
-
commands_to_json!(@commands)
|
111
|
-
end
|
112
129
|
end
|
113
130
|
end
|
@@ -4,12 +4,11 @@ require 'props_template/extensions/cache'
|
|
4
4
|
require 'props_template/extensions/deferment'
|
5
5
|
require 'props_template/extension_manager'
|
6
6
|
require 'props_template/key_formatter'
|
7
|
-
|
8
7
|
require 'active_support/core_ext/string/output_safety'
|
9
8
|
|
10
9
|
module Props
|
11
10
|
class BaseWithExtensions < Base
|
12
|
-
attr_reader :builder, :context, :fragments, :traveled_path, :deferred, :
|
11
|
+
attr_reader :builder, :context, :fragments, :traveled_path, :deferred, :stream
|
13
12
|
|
14
13
|
def initialize(builder, context = nil, options = {})
|
15
14
|
@context = context
|
@@ -36,21 +35,21 @@ module Props
|
|
36
35
|
def set_block_content!(options = {})
|
37
36
|
return super if !@em.has_extensions(options)
|
38
37
|
|
39
|
-
@em.handle(
|
38
|
+
@em.handle(options) do
|
40
39
|
yield
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
44
43
|
def scoped_state
|
45
|
-
prev_state = [@
|
46
|
-
@
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
@
|
51
|
-
@em = ExtensionManager.new(self, prev_state[1], prev_state[2])
|
44
|
+
prev_state = [@stream, @em.deferred, @em.fragments]
|
45
|
+
@em = ExtensionManager.new(self)
|
46
|
+
prev_scope = @scope
|
47
|
+
@scope = nil
|
48
|
+
|
49
|
+
yield @stream, @em.deferred, @em.fragments
|
52
50
|
|
53
|
-
|
51
|
+
@scope = prev_scope
|
52
|
+
@em = ExtensionManager.new(self, prev_state[1], prev_state[2])
|
54
53
|
end
|
55
54
|
|
56
55
|
def set!(key, options = {}, &block)
|
@@ -100,8 +99,9 @@ module Props
|
|
100
99
|
@em.refine_all_item_options(all_options)
|
101
100
|
end
|
102
101
|
|
103
|
-
|
104
102
|
def refine_item_options(item, options)
|
103
|
+
return options if options.empty?
|
104
|
+
|
105
105
|
if key = options[:key]
|
106
106
|
val = if item.respond_to? key
|
107
107
|
item.send(key)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'oj'
|
2
|
+
require 'active_support'
|
3
|
+
require 'byebug'
|
4
|
+
|
5
|
+
module Props
|
6
|
+
class DebugWriter
|
7
|
+
attr_accessor :commands
|
8
|
+
|
9
|
+
def initialize(opts)
|
10
|
+
@stream = Oj::StringWriter.new(opts)
|
11
|
+
@commands = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def push_object
|
15
|
+
@commands.push([:push_object])
|
16
|
+
end
|
17
|
+
|
18
|
+
def push_key(key)
|
19
|
+
@commands.push([:push_key, key])
|
20
|
+
end
|
21
|
+
|
22
|
+
def push_value(value, key = nil)
|
23
|
+
if key
|
24
|
+
@commands.push([:push_value, value, key])
|
25
|
+
else
|
26
|
+
@commands.push([:push_value, value])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def push_array
|
31
|
+
@commands.push([:push_array])
|
32
|
+
end
|
33
|
+
|
34
|
+
def pop
|
35
|
+
@commands.push([:pop])
|
36
|
+
end
|
37
|
+
|
38
|
+
def reset
|
39
|
+
@commands = []
|
40
|
+
@stream.reset
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
@commands.each do |command|
|
45
|
+
begin
|
46
|
+
@stream.send(*command)
|
47
|
+
rescue => e
|
48
|
+
byebug
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
@stream.to_s
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -25,6 +25,8 @@ module Props
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def refine_all_item_options(all_options)
|
28
|
+
return all_options if all_options.empty?
|
29
|
+
|
28
30
|
all_options = @partialer.find_and_add_template(all_options)
|
29
31
|
all_options = @cache.multi_fetch_and_add_results(all_options)
|
30
32
|
all_options
|
@@ -46,12 +48,12 @@ module Props
|
|
46
48
|
options[:defer] || options[:cache] || options[:partial] || options[:key]
|
47
49
|
end
|
48
50
|
|
49
|
-
def handle(
|
51
|
+
def handle(options)
|
50
52
|
return yield if !has_extensions(options)
|
51
53
|
|
52
54
|
if options[:defer]
|
53
55
|
placeholder = @deferment.handle(options)
|
54
|
-
|
56
|
+
base.stream.push_value(placeholder)
|
55
57
|
@fragment.handle(options)
|
56
58
|
else
|
57
59
|
handle_cache(options) do
|
@@ -76,32 +78,39 @@ module Props
|
|
76
78
|
|
77
79
|
private
|
78
80
|
|
79
|
-
def content_for_cache(commands, deferred_paths, fragment_paths)
|
80
|
-
suffix = [
|
81
|
-
[:push_value, deferred_paths],
|
82
|
-
[:push_value, fragment_paths],
|
83
|
-
[:pop]
|
84
|
-
]
|
85
|
-
|
86
|
-
[[:push_array]] + commands + suffix
|
87
|
-
end
|
88
|
-
|
89
81
|
def handle_cache(options)
|
90
82
|
if options[:cache]
|
83
|
+
recently_cached = false
|
84
|
+
|
91
85
|
state = @cache.cache(*options[:cache]) do
|
92
|
-
|
93
|
-
|
86
|
+
recently_cached = true
|
87
|
+
result = nil
|
88
|
+
start = base.stream.to_s.length
|
89
|
+
base.scoped_state { |stream, deferred_paths, fragment_paths|
|
90
|
+
yield
|
91
|
+
meta = Oj.dump([deferred_paths, fragment_paths]).strip
|
92
|
+
json_in_progress = base.stream.to_s
|
93
|
+
if json_in_progress[start] == ','
|
94
|
+
start += 1
|
95
|
+
end
|
96
|
+
raw = base.stream.to_s[start..-1].strip
|
97
|
+
result = "#{meta}\n#{raw}"
|
98
|
+
}
|
99
|
+
result
|
94
100
|
end
|
95
101
|
|
96
|
-
|
97
|
-
|
98
|
-
|
102
|
+
if !recently_cached
|
103
|
+
meta, raw_json = state.split("\n")
|
104
|
+
next_deferred, next_fragments = Oj.load(meta)
|
105
|
+
base.stream.push_json(raw_json)
|
106
|
+
deferred.push(*next_deferred)
|
99
107
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
108
|
+
next_fragments.each do |k, v|
|
109
|
+
if fragments[k]
|
110
|
+
fragments[k].push(*v)
|
111
|
+
else
|
112
|
+
fragments[k] = v
|
113
|
+
end
|
105
114
|
end
|
106
115
|
end
|
107
116
|
else
|
@@ -10,13 +10,5 @@ module Props
|
|
10
10
|
require 'props_template/layout_patch'
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
14
|
-
# if Rails::VERSION::MAJOR >= 4
|
15
|
-
# generators do |app|
|
16
|
-
# Rails::Generators.configure! app.config.generators
|
17
|
-
# Rails::Generators.hidden_namespaces.uniq!
|
18
|
-
# require 'generators/rails/scaffold_controller_generator'
|
19
|
-
# end
|
20
|
-
# end
|
21
13
|
end
|
22
14
|
end
|
data/spec/props_template_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: props_template
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johny Ho
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -77,6 +77,7 @@ files:
|
|
77
77
|
- lib/props_template/base.rb
|
78
78
|
- lib/props_template/base_with_extensions.rb
|
79
79
|
- lib/props_template/core_ext.rb
|
80
|
+
- lib/props_template/debug_writer.rb
|
80
81
|
- lib/props_template/dependency_tracker.rb
|
81
82
|
- lib/props_template/extension_manager.rb
|
82
83
|
- lib/props_template/extensions/cache.rb
|
@@ -95,7 +96,7 @@ homepage: https://github.com/jho406/breezy/
|
|
95
96
|
licenses:
|
96
97
|
- MIT
|
97
98
|
metadata: {}
|
98
|
-
post_install_message:
|
99
|
+
post_install_message:
|
99
100
|
rdoc_options: []
|
100
101
|
require_paths:
|
101
102
|
- lib
|
@@ -111,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
112
|
version: '0'
|
112
113
|
requirements: []
|
113
114
|
rubygems_version: 3.0.3
|
114
|
-
signing_key:
|
115
|
+
signing_key:
|
115
116
|
specification_version: 4
|
116
117
|
summary: A JSON builder for your React props
|
117
118
|
test_files:
|