breezy 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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