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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28b02ed9694b5b85d6646507c147c938500ecd7c
4
- data.tar.gz: 3d0e115680c7b088dd4ed03376d18bbdfdca392f
3
+ metadata.gz: bdb89b96ab7b57f15c03452a4b837750946635ac
4
+ data.tar.gz: c87b2f313de0c13f1ba6373850e9b07fe5e1a82d
5
5
  SHA512:
6
- metadata.gz: 252ac9b68b92cdfa5ee57e7a49521f6338f54042e3d17d8a34a73de377d4b69f8f680897209e619b6b65a8e6a4b2a9ce715bd67190d12445d4f33bb3accf867c
7
- data.tar.gz: 93e38dea643db06c33a8542d116a4baa861c0b2a85f54e12130b6945346f51bc75c76cff45d2bad2588aa813aaef81bd09e4463bc4e45b0b3850ae3dbf8a3ed3
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', git: 'https://github.com/jho406/Breezy.git'
93
+ gem 'breezy'
94
94
  ```
95
95
 
96
96
  Then use the provided installation generator:
@@ -1,3 +1,3 @@
1
1
  module Breezy
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
@@ -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: true do
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: true do
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: true)
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: true do
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: true do
1010
- json.content defer: true do
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.0
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-03-05 00:00:00.000000000 Z
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