breezy 0.1.0 → 0.1.1
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 +4 -4
- data/README.md +1 -1
- data/lib/breezy/version.rb +1 -1
- data/lib/breezy_template.rb +320 -0
- data/test/breezy_template_test.rb +32 -6
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdb89b96ab7b57f15c03452a4b837750946635ac
|
4
|
+
data.tar.gz: c87b2f313de0c13f1ba6373850e9b07fe5e1a82d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1eb1c5bf8d46964e6b79819f8d67e94616f8810b782c69cdccd0508359b43b00ff1ed03ba0e5f301e4a02b91b8a02431821375dc73afb54a913e0b954e99e6d
|
7
|
+
data.tar.gz: a3d62b3e1c163bbe520ad74d7082a0681481a57146b0d6d72baf2da245eb3ed50f4ebab69a4e3f65481710ba38501b9de820d6172ed33df497d2ac6cf08ac24f
|
data/README.md
CHANGED
@@ -90,7 +90,7 @@ App.Views.PostsIndex = function(json) {
|
|
90
90
|
Breezy does not include ReactJS, you'll have to download it seperately and include it in your path. Or just include [react-rails](https://github.com/reactjs/react-rails).
|
91
91
|
|
92
92
|
```
|
93
|
-
gem 'breezy'
|
93
|
+
gem 'breezy'
|
94
94
|
```
|
95
95
|
|
96
96
|
Then use the provided installation generator:
|
data/lib/breezy/version.rb
CHANGED
@@ -0,0 +1,320 @@
|
|
1
|
+
require 'jbuilder'
|
2
|
+
require 'digest/md5'
|
3
|
+
require 'action_view'
|
4
|
+
require 'breezy_template/digestor'
|
5
|
+
require 'breezy_template/handler'
|
6
|
+
require 'breezy_template/partial_extension'
|
7
|
+
require 'breezy_template/deferment_extension'
|
8
|
+
require 'breezy_template/search_extension'
|
9
|
+
|
10
|
+
module BreezyTemplate
|
11
|
+
class Template < ::Jbuilder
|
12
|
+
include PartialDigestor
|
13
|
+
|
14
|
+
prepend PartialExtension
|
15
|
+
prepend SearchExtension
|
16
|
+
prepend DefermentExtension
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_accessor :template_lookup_options
|
20
|
+
end
|
21
|
+
|
22
|
+
self.template_lookup_options = { handlers: [:breezy] }
|
23
|
+
|
24
|
+
|
25
|
+
class Digest
|
26
|
+
def initialize(digest)
|
27
|
+
@digest = "Breezy.cache(\"#{digest}\")"
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_json(*)
|
31
|
+
@digest
|
32
|
+
end
|
33
|
+
|
34
|
+
def as_json(*)
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def encode_json(*)
|
39
|
+
@digest
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(context, *args)
|
44
|
+
@context = context
|
45
|
+
@js = []
|
46
|
+
@path = []
|
47
|
+
super(*args)
|
48
|
+
end
|
49
|
+
|
50
|
+
def empty!
|
51
|
+
attributes = @attributes
|
52
|
+
@attributes = {}
|
53
|
+
attributes
|
54
|
+
end
|
55
|
+
|
56
|
+
def _breezy_visit_current(path)
|
57
|
+
uri = ::URI.parse(@request_path)
|
58
|
+
qry = ::URI.decode_www_form(uri.query || '') << ["_breezy_filter", path.join('.')]
|
59
|
+
uri.query = ::URI.encode_www_form(qry)
|
60
|
+
"Breezy.visit('#{uri}', {async: true, pushState: false});"
|
61
|
+
end
|
62
|
+
|
63
|
+
def _blank
|
64
|
+
BLANK
|
65
|
+
end
|
66
|
+
|
67
|
+
def method_missing(*args)
|
68
|
+
key = args[0]
|
69
|
+
@path.push(key)
|
70
|
+
if ::Kernel.block_given?
|
71
|
+
args = _args_for_set_with_block(*args)
|
72
|
+
set!(*args, &::Proc.new)
|
73
|
+
else
|
74
|
+
args = _args_for_set(*args)
|
75
|
+
set!(*args)
|
76
|
+
end
|
77
|
+
ensure
|
78
|
+
@path.pop
|
79
|
+
end
|
80
|
+
|
81
|
+
def set!(key, value = BLANK, *args)
|
82
|
+
options = args.first || {}
|
83
|
+
options = _normalize_options(options)
|
84
|
+
return super if !_cache_options?(options) && !_deferment_options?(options)
|
85
|
+
|
86
|
+
result = if ::Kernel.block_given?
|
87
|
+
_ensure_valid_key(key)
|
88
|
+
_cache(*options[:cache]) { _scope { yield self } }
|
89
|
+
elsif ::Jbuilder === value
|
90
|
+
# json.age 32
|
91
|
+
# json.person another_jbuilder
|
92
|
+
# { "age": 32, "person": { ... }
|
93
|
+
_ensure_valid_key(key)
|
94
|
+
_cache(*options[:cache]) { value.attributes! }
|
95
|
+
else
|
96
|
+
# json.age 32
|
97
|
+
# { "age": 32 }
|
98
|
+
_ensure_valid_key(key)
|
99
|
+
_cache(*options[:cache]) { value }
|
100
|
+
end
|
101
|
+
|
102
|
+
_set_value key, result
|
103
|
+
end
|
104
|
+
|
105
|
+
def child!(options = {})
|
106
|
+
return super(&::Proc.new) if !_cache_options?(options)
|
107
|
+
options = _normalize_options(options)
|
108
|
+
|
109
|
+
@attributes = [] unless ::Array === @attributes
|
110
|
+
@attributes << _cache(*options[:cache]) {
|
111
|
+
_scope { yield self }
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
def array!(collection = [], *attributes)
|
116
|
+
options = attributes.first || {}
|
117
|
+
options = _normalize_options(options)
|
118
|
+
|
119
|
+
collection = [] if collection.nil?
|
120
|
+
collection = _prepare_collection_for_map(collection)
|
121
|
+
array = if ::Kernel.block_given?
|
122
|
+
_map_collection(collection, options, &::Proc.new)
|
123
|
+
elsif attributes.any?
|
124
|
+
_map_collection(collection, options) { |element| extract! element, *attributes }
|
125
|
+
else
|
126
|
+
collection.to_a
|
127
|
+
end
|
128
|
+
|
129
|
+
merge! array #remove this depednacy
|
130
|
+
end
|
131
|
+
|
132
|
+
def target!
|
133
|
+
js = _breezy_return(@attributes)
|
134
|
+
@js.push(js)
|
135
|
+
"(function(){#{@js.join}})()"
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
def _merge_values(current_value, updates)
|
140
|
+
# Always use the new values. This is because cached values
|
141
|
+
# are no longer a Ruby object. They are JS values and can't
|
142
|
+
# be merged.
|
143
|
+
|
144
|
+
updates
|
145
|
+
end
|
146
|
+
|
147
|
+
def _prepare_collection_for_map(collection)
|
148
|
+
collection
|
149
|
+
end
|
150
|
+
|
151
|
+
def _args_for_set_with_block(*args)
|
152
|
+
key = args[0]
|
153
|
+
if ::Hash === args[1] && _extended_options?(args[1])
|
154
|
+
options = args[1]
|
155
|
+
[key, BLANK, options]
|
156
|
+
else
|
157
|
+
[key, BLANK]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def _args_for_set(*args)
|
162
|
+
if args.length == 3
|
163
|
+
key, value, options = args
|
164
|
+
|
165
|
+
[key, value, options]
|
166
|
+
elsif args.length == 2 && _extended_options?(args[1])
|
167
|
+
options = args[1]
|
168
|
+
key = args[0]
|
169
|
+
|
170
|
+
[key, BLANK, options]
|
171
|
+
else
|
172
|
+
key, value = args
|
173
|
+
|
174
|
+
[key, value]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def _extended_options?(value)
|
179
|
+
_partial_options?(value) || _cache_options?(value) || _deferment_options?(value)
|
180
|
+
end
|
181
|
+
|
182
|
+
def _mapping_element(element, options)
|
183
|
+
opts = options.dup
|
184
|
+
if opts[:cache]
|
185
|
+
opts[:cache] = opts[:cache].dup
|
186
|
+
|
187
|
+
if ::Array === opts[:cache] && ::Proc === opts[:cache].first
|
188
|
+
key_proc = opts[:cache][0]
|
189
|
+
opts[:cache][0] = key_proc.call(element)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
_cache(*opts[:cache]) {
|
193
|
+
_scope { yield element }
|
194
|
+
}
|
195
|
+
end
|
196
|
+
|
197
|
+
def _map_collection(collection, options)
|
198
|
+
@path.push(nil)
|
199
|
+
collection.map.with_index do |element, i|
|
200
|
+
if options.has_key? :key
|
201
|
+
id_name = options[:key]
|
202
|
+
id_val = element[id_name]
|
203
|
+
@path[-1] = "#{id_name}=#{id_val}"
|
204
|
+
else
|
205
|
+
@path[-1] = i
|
206
|
+
end
|
207
|
+
|
208
|
+
_mapping_element(element, options, &::Proc.new)
|
209
|
+
|
210
|
+
end - [BLANK]
|
211
|
+
ensure
|
212
|
+
@path.pop
|
213
|
+
end
|
214
|
+
|
215
|
+
def _cache_key(key, options={})
|
216
|
+
key = _fragment_name_with_digest(key, options)
|
217
|
+
key = url_for(key).split('://', 2).last if ::Hash === key
|
218
|
+
key = ::ActiveSupport::Cache.expand_cache_key(key, :jbuilder)
|
219
|
+
|
220
|
+
::Digest::MD5.hexdigest(key.to_s).tap do |digest|
|
221
|
+
_logger.try :debug, "Cache key :#{key} was digested to #{digest}"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def _cache(key=nil, options={})
|
226
|
+
return yield self if !@context.controller.perform_caching || key.nil?
|
227
|
+
|
228
|
+
parent_js = @js
|
229
|
+
key = _cache_key(key, options)
|
230
|
+
@js = []
|
231
|
+
|
232
|
+
blank_or_value = begin
|
233
|
+
::Rails.cache.fetch(key, options) do
|
234
|
+
result = yield self
|
235
|
+
if result !=BLANK
|
236
|
+
@js << _breezy_set_cache(key, result)
|
237
|
+
@js.join
|
238
|
+
else
|
239
|
+
BLANK
|
240
|
+
end
|
241
|
+
end
|
242
|
+
ensure
|
243
|
+
@js = parent_js
|
244
|
+
end
|
245
|
+
|
246
|
+
if blank_or_value == BLANK
|
247
|
+
BLANK
|
248
|
+
else
|
249
|
+
v = blank_or_value
|
250
|
+
@js.push(v)
|
251
|
+
Digest.new(key)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def _breezy_set_cache(key, value)
|
256
|
+
"Breezy.cache(\"#{key}\", #{_dump(value)});"
|
257
|
+
end
|
258
|
+
|
259
|
+
def _breezy_return(results)
|
260
|
+
"return (#{_dump(results)});"
|
261
|
+
end
|
262
|
+
|
263
|
+
def _dump(value)
|
264
|
+
::MultiJson.dump(value)
|
265
|
+
end
|
266
|
+
|
267
|
+
def _ensure_valid_key(key)
|
268
|
+
current_value = _blank? ? BLANK : @attributes.fetch(_key(key), BLANK)
|
269
|
+
raise NullError.build(key) if current_value.nil?
|
270
|
+
end
|
271
|
+
|
272
|
+
def _normalize_options(options)
|
273
|
+
options = options.dup
|
274
|
+
key = options[:cache]
|
275
|
+
opts = {}
|
276
|
+
return options if !key
|
277
|
+
|
278
|
+
if ::Array === key && key.length == 2 && ::Hash === key.last
|
279
|
+
return options
|
280
|
+
end
|
281
|
+
|
282
|
+
if options[:partial]
|
283
|
+
opts[:partial] = options[:partial]
|
284
|
+
end
|
285
|
+
|
286
|
+
key = case key
|
287
|
+
when ::Array
|
288
|
+
key
|
289
|
+
when ::Proc
|
290
|
+
key
|
291
|
+
else
|
292
|
+
[key]
|
293
|
+
end
|
294
|
+
|
295
|
+
options[:cache] = [key, opts]
|
296
|
+
options
|
297
|
+
end
|
298
|
+
|
299
|
+
def _fragment_name_with_digest(key, options)
|
300
|
+
if @context.respond_to?(:cache_fragment_name)
|
301
|
+
# Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
|
302
|
+
# should be used instead.
|
303
|
+
@context.cache_fragment_name(key, options)
|
304
|
+
elsif @context.respond_to?(:fragment_name_with_digest)
|
305
|
+
# Backwards compatibility for period of time when fragment_name_with_digest was made public.
|
306
|
+
@context.fragment_name_with_digest(key)
|
307
|
+
else
|
308
|
+
key
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def _cache_options?(options)
|
313
|
+
::Hash === options && options.key?(:cache)
|
314
|
+
end
|
315
|
+
|
316
|
+
def _logger
|
317
|
+
::ActionView::Base.logger
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
@@ -917,7 +917,7 @@ class BreezyTemplateTest < ActionView::TestCase
|
|
917
917
|
|
918
918
|
result = jbuild(<<-JBUILDER, request: req)
|
919
919
|
json.hit do
|
920
|
-
json.hit2 defer:
|
920
|
+
json.hit2 defer: :auto do
|
921
921
|
json.hit3 do
|
922
922
|
json.greeting 'hello world'
|
923
923
|
end
|
@@ -938,6 +938,32 @@ class BreezyTemplateTest < ActionView::TestCase
|
|
938
938
|
assert_equal expected, result
|
939
939
|
end
|
940
940
|
|
941
|
+
test "rendering with manual node deferement" do
|
942
|
+
req = action_controller_test_request
|
943
|
+
req.path = '/some_url'
|
944
|
+
|
945
|
+
result = jbuild(<<-JBUILDER, request: req)
|
946
|
+
json.hit do
|
947
|
+
json.hit2 defer: :manual do
|
948
|
+
json.hit3 do
|
949
|
+
json.greeting 'hello world'
|
950
|
+
end
|
951
|
+
end
|
952
|
+
end
|
953
|
+
JBUILDER
|
954
|
+
Rails.cache.clear
|
955
|
+
|
956
|
+
expected = strip_format(<<-JS)
|
957
|
+
(function(){
|
958
|
+
return (
|
959
|
+
{"data":{"hit":{"hit2":null}}}
|
960
|
+
);
|
961
|
+
})()
|
962
|
+
JS
|
963
|
+
|
964
|
+
assert_equal expected, result
|
965
|
+
end
|
966
|
+
|
941
967
|
test "rendering with node array deferment" do
|
942
968
|
req = action_controller_test_request
|
943
969
|
req.path = '/some_url'
|
@@ -947,7 +973,7 @@ class BreezyTemplateTest < ActionView::TestCase
|
|
947
973
|
json.hit2 do
|
948
974
|
data = [{id: 1, name: 'foo'}, {id: 2, name: 'bar'}]
|
949
975
|
json.array! data, key: :id do
|
950
|
-
json.greeting defer:
|
976
|
+
json.greeting defer: :auto do
|
951
977
|
json.gree 'hi'
|
952
978
|
end
|
953
979
|
end
|
@@ -973,7 +999,7 @@ class BreezyTemplateTest < ActionView::TestCase
|
|
973
999
|
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
|
974
1000
|
|
975
1001
|
result = jbuild(<<-JBUILDER)
|
976
|
-
json.hello(32, defer:
|
1002
|
+
json.hello(32, defer: :auto)
|
977
1003
|
JBUILDER
|
978
1004
|
|
979
1005
|
expected = strip_format(<<-JS)
|
@@ -988,7 +1014,7 @@ class BreezyTemplateTest < ActionView::TestCase
|
|
988
1014
|
test 'deferment is disabled when filtering by keypath' do
|
989
1015
|
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
|
990
1016
|
result = jbuild(<<-JBUILDER, breezy_filter: 'hello.world')
|
991
|
-
json.hello defer:
|
1017
|
+
json.hello defer: :auto do
|
992
1018
|
json.world 32
|
993
1019
|
end
|
994
1020
|
JBUILDER
|
@@ -1006,8 +1032,8 @@ class BreezyTemplateTest < ActionView::TestCase
|
|
1006
1032
|
test 'deferment is enabled at the end of a keypath when filtering' do
|
1007
1033
|
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
|
1008
1034
|
result = jbuild(<<-JBUILDER, breezy_filter: 'hello')
|
1009
|
-
json.hello defer:
|
1010
|
-
json.content defer:
|
1035
|
+
json.hello defer: :auto do
|
1036
|
+
json.content defer: :auto do
|
1011
1037
|
json.world 32
|
1012
1038
|
end
|
1013
1039
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: breezy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johny Ho
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coffee-rails
|
@@ -125,6 +125,7 @@ files:
|
|
125
125
|
- lib/breezy/xhr_headers.rb
|
126
126
|
- lib/breezy/xhr_redirect.rb
|
127
127
|
- lib/breezy/xhr_url_for.rb
|
128
|
+
- lib/breezy_template.rb
|
128
129
|
- test/blade_helper.rb
|
129
130
|
- test/breezy_template_test.rb
|
130
131
|
- test/breezy_test.rb
|