props_template 1.1.1 → 1.2.0

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
  SHA256:
3
- metadata.gz: 9a54115d5cb581b3b4a3c487ca6bdad66a2f533a56f1171d65c9f1759ca9f2ec
4
- data.tar.gz: d7672f8b3324ec7ae2b63e790b2c0f38e73f3b5534ad18a5e8a1704bd14c98b2
3
+ metadata.gz: 4b2f7cf3a4eca0bead0971f22d1f75de65d3e365c2684d9055b80c6310b07df3
4
+ data.tar.gz: bd190fb9a3581b9f056eef6512f2ad6c7331b03f033553a4c236dc10effcac76
5
5
  SHA512:
6
- metadata.gz: d07608d99ad469d3dfe6c4f264b7addb844b7a35f6a5ce2c13469bd1bd1dfa14d41c6800f62933a122d86d3ecf65a08aba95a4746d3fc329b5daf1305ec288af
7
- data.tar.gz: b76b141b1938ebc83b40c2208c0d77274472c02615a17a0a6771147b38ac7639923b092b066333708087f2074b920e06d99e824b4b36fc9a8e4d517afb7d3f3a
6
+ metadata.gz: 421bcf7b29a5f7ce4a21ce99a39db7b243f86eac63ae3cdb6d513745cd91f2bd830a72c360826048a7fafd03dff293bcc4024311e053f9a330a5880212c0439e
7
+ data.tar.gz: 4efdc30e4b36fdc382b75936625b7ae233ea065bf7c1f632e2e943730c28ea8f9b4e3b8d58a28a788d67102995948b7fffac61042b9ce4479e068435e952d935
@@ -1,5 +1,6 @@
1
1
  require "oj"
2
2
  require "active_support"
3
+ require "props_template/raw_json"
3
4
 
4
5
  module Props
5
6
  class InvalidScopeForArrayError < StandardError; end
@@ -11,8 +12,10 @@ module Props
11
12
  class Base
12
13
  attr_accessor :item_context
13
14
 
15
+ WRITER_OPTIONS = {mode: :rails, use_raw_json: true}.freeze
16
+
14
17
  def initialize(encoder = nil)
15
- @stream = Oj::StringWriter.new(mode: :rails)
18
+ @stream = Oj::StringWriter.new(WRITER_OPTIONS)
16
19
  @scope = nil
17
20
  @item_context = nil
18
21
  end
@@ -170,13 +173,18 @@ module Props
170
173
 
171
174
  def capture_json
172
175
  parent_stream = @stream
173
- @stream = Oj::StringWriter.new(mode: :rails)
176
+ @stream = Oj::StringWriter.new(WRITER_OPTIONS)
174
177
  yield
175
178
  @stream.raw_json.strip
176
179
  ensure
177
180
  @stream = parent_stream
178
181
  end
179
182
 
183
+ # Adds already-encoded JSON, such as a cached fragment, as the next value.
184
+ def push_cached_json(json)
185
+ @stream.push_value(RawJSON.new(json))
186
+ end
187
+
180
188
  def result!
181
189
  if @scope.nil?
182
190
  @stream.push_object
@@ -1,5 +1,9 @@
1
1
  module Props
2
2
  class ExtensionManager
3
+ # A cached fragment is stored after a line of the deferred and fragment
4
+ # paths inside it, which is this when there are none.
5
+ EMPTY_META_LINE = "[[],[]]\n".freeze
6
+
3
7
  attr_reader :base, :builder, :context, :cache, :partialer
4
8
 
5
9
  delegate :load_cache, to: :cache
@@ -69,7 +73,7 @@ module Props
69
73
  private
70
74
 
71
75
  def handle_cache(options, item)
72
- if options[:cache]
76
+ if options[:cache] && @cache.enabled?
73
77
  key, rest = Cache
74
78
  .normalize_options(options[:cache], item)
75
79
 
@@ -85,12 +89,19 @@ module Props
85
89
  result
86
90
  end
87
91
 
88
- meta, raw_json = state.split("\n", 2)
89
- next_deferred, next_fragments = Oj.load(meta)
90
- deferred.push(*next_deferred)
91
- fragments.push(*next_fragments)
92
+ # Nearly every fragment has no deferred or fragment paths, so the
93
+ # empty line is skipped without being split off or parsed.
94
+ if state.start_with?(EMPTY_META_LINE)
95
+ raw_json = state.byteslice(EMPTY_META_LINE.bytesize..)
96
+ else
97
+ separator = state.byteindex("\n")
98
+ next_deferred, next_fragments = Oj.load(state.byteslice(0, separator))
99
+ deferred.push(*next_deferred)
100
+ fragments.push(*next_fragments)
101
+ raw_json = state.byteslice((separator + 1)..)
102
+ end
92
103
 
93
- base.stream.push_json(raw_json)
104
+ base.stream.push_value(RawJSON.new(raw_json))
94
105
  else
95
106
  yield
96
107
  end
@@ -56,15 +56,21 @@ module Props
56
56
  result
57
57
  end
58
58
 
59
+ def enabled?
60
+ controller.perform_caching
61
+ end
62
+
59
63
  def load_cache(keys, options = {})
60
- @results = results.merge multi_fetch(keys, options)
64
+ if enabled?
65
+ @results = results.merge multi_fetch(keys, options)
66
+ end
61
67
  end
62
68
 
63
69
  # The below was copied from the wonderful jbuilder library Its also MIT
64
70
  # licensed, so no issues there. Thanks to the jbuilder authors!
65
71
 
66
72
  def cache(key = nil, options = {})
67
- if controller.perform_caching
73
+ if enabled?
68
74
  cache_fragment_for(key, options) do
69
75
  yield
70
76
  end
@@ -0,0 +1,15 @@
1
+ module Props
2
+ # Already-encoded JSON, such as a cached fragment, for Oj to insert as is.
3
+ # Oj calls raw_json on values when its use_raw_json option is on, and
4
+ # takes the length from the String rather than scanning for it as
5
+ # push_json does.
6
+ class RawJSON
7
+ def initialize(json)
8
+ @json = json
9
+ end
10
+
11
+ def raw_json(depth, indent)
12
+ @json
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module Props
2
- VERSION = "1.1.1".freeze
2
+ VERSION = "1.2.0".freeze
3
3
  end
@@ -17,6 +17,12 @@ require "active_support"
17
17
 
18
18
  module Props
19
19
  class Template
20
+ GENERATED_KEY_METHODS = Module.new
21
+ include GENERATED_KEY_METHODS
22
+
23
+ GENERATABLE_KEY_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
24
+ GENERATED_KEY_METHODS_LOCK = Mutex.new
25
+
20
26
  class << self
21
27
  attr_accessor :template_lookup_options
22
28
  end
@@ -93,8 +99,30 @@ module Props
93
99
  @builder
94
100
  end
95
101
 
96
- alias_method :method_missing, :set!
97
- private :method_missing
102
+ def self.generate_key_method(key)
103
+ GENERATED_KEY_METHODS_LOCK.synchronize do
104
+ name = key.name
105
+ already_implemented = method_defined?(key) || private_method_defined?(key)
106
+
107
+ if !already_implemented && GENERATABLE_KEY_REGEXP.match?(name)
108
+ GENERATED_KEY_METHODS.module_eval <<~RUBY, __FILE__, __LINE__ + 1
109
+ def #{name}(options = {}, &block)
110
+ set!(#{key.inspect}, options, &block)
111
+ end
112
+ RUBY
113
+ end
114
+ end
115
+ end
116
+
117
+ private
118
+
119
+ # No respond_to_missing?: a builder accepts any key, but claiming to
120
+ # respond to everything would answer yes to probes like to_ary or to_hash.
121
+ # Generated methods are real methods, so respond_to? sees those already.
122
+ def method_missing(key, ...) # standard:disable Style/MissingRespondToMissing
123
+ self.class.generate_key_method(key)
124
+ set!(key, ...)
125
+ end
98
126
  end
99
127
  end
100
128
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: props_template
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johny Ho
@@ -92,6 +92,7 @@ files:
92
92
  - lib/props_template/options.rb
93
93
  - lib/props_template/partial_patch.rb
94
94
  - lib/props_template/railtie.rb
95
+ - lib/props_template/raw_json.rb
95
96
  - lib/props_template/searcher.rb
96
97
  - lib/props_template/version.rb
97
98
  homepage: https://github.com/thoughtbot/props_template/