breezy 0.1.1 → 0.1.3
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 +17 -5
- data/lib/breezy/version.rb +1 -1
- data/lib/breezy_template/deferment_extension.rb +48 -0
- data/lib/breezy_template/dependency_tracker.rb +47 -0
- data/lib/breezy_template/digestor.rb +30 -0
- data/lib/breezy_template/handler.rb +43 -0
- data/lib/breezy_template/partial_extension.rb +87 -0
- data/lib/breezy_template/search_extension.rb +83 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ce62034c621228792d356fbfaa25033f2636132
|
4
|
+
data.tar.gz: 6f29e954b0b7402138e5e2c0f63736f1880c3638
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1d54e6480b866bdd8d6bd36d1b31106a78c25c892e6101f7e1aff6a9ec8c703ef40b36555fae584806e1728302e1c01df9dba518a6b39e9eaca988763af0428
|
7
|
+
data.tar.gz: 9bb3e30225f2df6796e35e3e221ddf0509ea334ae98452a79115a27326e2d72d0b7ca7aa8ab72b50389c27e91343e9df2c7735faee27976ecf538d769dfd91c1
|
data/README.md
CHANGED
@@ -45,12 +45,12 @@ Use the included BreezyTemplates to create your content.
|
|
45
45
|
|
46
46
|
json.heading @greeting
|
47
47
|
|
48
|
-
# `defer:
|
48
|
+
# `defer: :auto` will no-op the following block on a direct
|
49
49
|
# visit, use null as a standin value, and append additional
|
50
50
|
# javascript in the response to fetch only this content node
|
51
51
|
# (no-oping other sibiling blocks) and graft it in the right
|
52
52
|
# place on the client side.
|
53
|
-
json.dashboard(defer:
|
53
|
+
json.dashboard(defer: :auto) do
|
54
54
|
sleep 10
|
55
55
|
json.num_of_views 100
|
56
56
|
end
|
@@ -274,16 +274,28 @@ would become
|
|
274
274
|
```
|
275
275
|
|
276
276
|
### Deferment
|
277
|
-
You can defer rendering of expensive content using the `defer:
|
277
|
+
You can defer rendering of expensive content using the `defer: :auto` option available in blocks. Behind the scenes BreezyTemplates will no-op the block entirely, replace the value with a `null` as a standin, and append a `Breezy.visit(/somepath?_breezy_filter=keypath.to.node)` to the response. When the client recieves the payload, `breezy:load` will be fired, then the appended `Breezy.visit` will be called to fetch and graft the missing node before firing `breezy:load` a second time.
|
278
278
|
|
279
279
|
Usage:
|
280
280
|
```ruby
|
281
|
-
json.dashboard(defer:
|
281
|
+
json.dashboard(defer: :auto) do
|
282
282
|
sleep 10
|
283
283
|
json.some_fancy_metric 42
|
284
284
|
end
|
285
285
|
```
|
286
286
|
|
287
|
+
A manual option is also available:
|
288
|
+
|
289
|
+
```ruby
|
290
|
+
json.dashboard(defer: :manual) do
|
291
|
+
sleep 10
|
292
|
+
json.some_fancy_metric 42
|
293
|
+
end
|
294
|
+
```
|
295
|
+
If `:manual` is used, Breezy will no-op the block and not append `Breezy.visit` to the payload. Its up to you to use [node filtering](#filtering_nodes) to fetch the node seperately. A common usecase would be tab content that does not load until you click the tab.
|
296
|
+
|
297
|
+
|
298
|
+
|
287
299
|
#### Working with arrays
|
288
300
|
If you want to defer elements in an array, you should add a key as an option on `array!` to help breezy generate a more specific keypath, otherwise it'll just use the index.
|
289
301
|
|
@@ -291,7 +303,7 @@ If you want to defer elements in an array, you should add a key as an option on
|
|
291
303
|
data = [{id: 1, name: 'foo'}, {id: 2, name: 'bar'}]
|
292
304
|
|
293
305
|
json.array! data, key: :id do
|
294
|
-
json.greeting defer:
|
306
|
+
json.greeting defer: :auto do
|
295
307
|
json.greet 'hi'
|
296
308
|
end
|
297
309
|
end
|
data/lib/breezy/version.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
module BreezyTemplate
|
2
|
+
module DefermentExtension
|
3
|
+
ACTIVE_MODES = [:auto, :manual].freeze
|
4
|
+
|
5
|
+
def set!(key, value = BLANK, *args)
|
6
|
+
options = args.first || {}
|
7
|
+
options = _normalize_options(options)
|
8
|
+
if ::Kernel.block_given? && _deferment_enabled?(options)
|
9
|
+
if _deferment_auto?(options)
|
10
|
+
@js.push(_breezy_visit_current(@path))
|
11
|
+
end
|
12
|
+
return _set_value key, nil
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def _deferment_auto?(options)
|
19
|
+
options[:defer] == :auto
|
20
|
+
end
|
21
|
+
|
22
|
+
def _deferment_enabled?(options)
|
23
|
+
ACTIVE_MODES.include?(options[:defer]) && (@search_path.nil? || @search_path.size == 0)
|
24
|
+
end
|
25
|
+
|
26
|
+
def _set_request_url(request_path)
|
27
|
+
@request_path = request_path
|
28
|
+
end
|
29
|
+
|
30
|
+
def _deferment_options?(options)
|
31
|
+
::Hash === options && options.key?(:defer)
|
32
|
+
end
|
33
|
+
|
34
|
+
def _mapping_element(element, options)
|
35
|
+
if _deferment_enabled? options
|
36
|
+
if options.has_key? :key
|
37
|
+
id_name = options[:key]
|
38
|
+
id_val = element[id_name]
|
39
|
+
::Hash[id_name, id_val]
|
40
|
+
else
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# This was taken from jbuilder
|
2
|
+
|
3
|
+
dependency_tracker = false
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'action_view'
|
7
|
+
require 'action_view/dependency_tracker'
|
8
|
+
dependency_tracker = ::ActionView::DependencyTracker
|
9
|
+
rescue LoadError
|
10
|
+
begin
|
11
|
+
require 'cache_digests'
|
12
|
+
dependency_tracker = ::CacheDigests::DependencyTracker
|
13
|
+
rescue LoadError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if dependency_tracker
|
18
|
+
class BreezyTemplate::Template
|
19
|
+
module DependencyTrackerMethods
|
20
|
+
# Matches:
|
21
|
+
# json.partial! partial: "comments/comment"
|
22
|
+
# json.comments @post.comments, partial: "comments/comment", as: :comment
|
23
|
+
# json.array! @posts, partial: "posts/post", as: :post
|
24
|
+
# = render partial: "account"
|
25
|
+
#
|
26
|
+
INDIRECT_RENDERS = /
|
27
|
+
(?::partial\s*=>|partial:) # partial: or :partial =>
|
28
|
+
\s* # optional whitespace
|
29
|
+
(['"])([^'"]+)\1 # quoted value
|
30
|
+
/x
|
31
|
+
|
32
|
+
def dependencies
|
33
|
+
indirect_dependencies + explicit_dependencies
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def indirect_dependencies
|
39
|
+
source.scan(INDIRECT_RENDERS).map(&:second)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
::BreezyTemplate::DependencyTracker = Class.new(dependency_tracker::ERBTracker)
|
45
|
+
::BreezyTemplate::DependencyTracker.send :include, ::BreezyTemplate::Template::DependencyTrackerMethods
|
46
|
+
dependency_tracker.register_tracker :breezy, ::BreezyTemplate::DependencyTracker
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
require 'action_view/digestor'
|
3
|
+
|
4
|
+
module BreezyTemplate
|
5
|
+
module PartialDigestor
|
6
|
+
if ::Rails.version >= '5.0'
|
7
|
+
def _partial_digestor(options)
|
8
|
+
name = options[:name]
|
9
|
+
finder = options[:finder]
|
10
|
+
::ActionView::Digestor.digest(name: name, finder: finder)
|
11
|
+
end
|
12
|
+
elsif ::Rails.version >= '4.1'
|
13
|
+
def _partial_digestor(options)
|
14
|
+
name = options[:name]
|
15
|
+
finder = options[:finder]
|
16
|
+
::ActionView::PartialDigestor.new(name: name, finder: finder).digest
|
17
|
+
end
|
18
|
+
elsif ::Rails.version >= '4.0'
|
19
|
+
def _partial_digestor(options={})
|
20
|
+
name = options[:name]
|
21
|
+
finder = options[:finder]
|
22
|
+
::ActionView::PartialDigestor.new(name, finder.formats.last, finder).digest
|
23
|
+
end
|
24
|
+
else
|
25
|
+
def _partial_digestor(options)
|
26
|
+
options[:name]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module BreezyTemplate
|
2
|
+
class Handler
|
3
|
+
cattr_accessor :default_format
|
4
|
+
self.default_format = Mime[:js]
|
5
|
+
|
6
|
+
def self.call(template)
|
7
|
+
# this juggling is required to keep line numbers right in the error
|
8
|
+
%{__already_defined = defined?(json); json||=::BreezyTemplate::Template.new(self);json._filter_by_path(breezy_filter) if defined?(breezy_filter); json._set_request_url(request.path);#{template.source}
|
9
|
+
if !(__already_defined && __already_defined != "method")
|
10
|
+
json.merge!({data: json.found! || json.empty! })
|
11
|
+
if defined?(breezy) && breezy
|
12
|
+
breezy.each do |k, v|
|
13
|
+
json.set! k, v
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if protect_against_forgery?
|
18
|
+
json.csrf_token form_authenticity_token
|
19
|
+
end
|
20
|
+
|
21
|
+
if ::Breezy.configuration.track_assets.any?
|
22
|
+
json.assets do
|
23
|
+
json.array! (::Breezy.configuration.track_assets || []).map{|assets|
|
24
|
+
asset_path(assets)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
if defined?(breezy_filter) && !!breezy_filter
|
30
|
+
json.action 'graft'
|
31
|
+
json.path breezy_filter
|
32
|
+
end
|
33
|
+
|
34
|
+
if defined?(session) && session
|
35
|
+
session.delete(:breezy_filter)
|
36
|
+
end
|
37
|
+
|
38
|
+
json.target!
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module BreezyTemplate
|
2
|
+
module PartialExtension
|
3
|
+
def set!(key, value = BLANK, *args)
|
4
|
+
options = args.first || {}
|
5
|
+
options = _normalize_options(options)
|
6
|
+
if args.one? && _partial_options?(options)
|
7
|
+
_set_inline_partial key, value, options
|
8
|
+
else
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def _fragment_name_with_digest(key, options)
|
14
|
+
if options[:partial] && !options[:skip_digest]
|
15
|
+
[key, _partial_digest(options[:partial])]
|
16
|
+
else
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def array!(collection = [], *attributes)
|
22
|
+
options = attributes.first || {}
|
23
|
+
options = _normalize_options(options)
|
24
|
+
|
25
|
+
if attributes.one? && _partial_options?(options)
|
26
|
+
_render_partial_with_options(options.merge(collection: collection))
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def _partial_options?(options)
|
33
|
+
::Hash === options && options.key?(:partial)
|
34
|
+
end
|
35
|
+
|
36
|
+
def _partial_digest(partial)
|
37
|
+
lookup_context = @context.lookup_context
|
38
|
+
name = lookup_context.find(partial, lookup_context.prefixes, true).virtual_path
|
39
|
+
_partial_digestor({name: name, finder: lookup_context})
|
40
|
+
end
|
41
|
+
|
42
|
+
def _set_inline_partial(name, object, options)
|
43
|
+
value = if object.nil?
|
44
|
+
[]
|
45
|
+
elsif _is_collection?(object)
|
46
|
+
_scope{ _render_partial_with_options options.merge(collection: object) }
|
47
|
+
else
|
48
|
+
locals = {}
|
49
|
+
locals[options[:as]] = object if !_blank?(object) && options.key?(:as)
|
50
|
+
locals.merge!(options[:locals]) if options.key? :locals
|
51
|
+
|
52
|
+
_cache(*options[:cache]) {
|
53
|
+
_scope{ _render_partial options.merge(locals: locals) }
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
set! name, value
|
58
|
+
end
|
59
|
+
|
60
|
+
def _render_partial(options)
|
61
|
+
options[:locals].merge! json: self
|
62
|
+
@context.render options
|
63
|
+
end
|
64
|
+
|
65
|
+
def _render_partial_with_options(options)
|
66
|
+
ary_opts = options.dup
|
67
|
+
options.reverse_merge! locals: {}
|
68
|
+
options.reverse_merge! ::BreezyTemplate::Template.template_lookup_options
|
69
|
+
as = options[:as]
|
70
|
+
|
71
|
+
if options.key?(:collection)
|
72
|
+
collection = options.delete(:collection)
|
73
|
+
locals = options.delete(:locals)
|
74
|
+
|
75
|
+
ary_opts.delete(:partial)
|
76
|
+
array! collection, ary_opts do |member|
|
77
|
+
member_locals = locals.clone
|
78
|
+
member_locals.merge! collection: collection
|
79
|
+
member_locals.merge! as.to_sym => member if as
|
80
|
+
_render_partial options.merge(locals: member_locals)
|
81
|
+
end
|
82
|
+
else
|
83
|
+
_render_partial options
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module BreezyTemplate
|
2
|
+
module SearchExtension
|
3
|
+
def found!
|
4
|
+
found = @found
|
5
|
+
@found = nil
|
6
|
+
@search_path = []
|
7
|
+
found
|
8
|
+
end
|
9
|
+
|
10
|
+
def array!(collection = [], *attributes)
|
11
|
+
original_search_path = @search_path
|
12
|
+
super
|
13
|
+
ensure
|
14
|
+
@search_path = original_search_path
|
15
|
+
end
|
16
|
+
|
17
|
+
def _filter_by_path(search_path)
|
18
|
+
if search_path.is_a? ::String
|
19
|
+
return _filter_by_path(search_path.split('.'))
|
20
|
+
end
|
21
|
+
@search_path = search_path
|
22
|
+
end
|
23
|
+
|
24
|
+
def _prepare_collection_for_map(collection)
|
25
|
+
if @search_path && !@search_path.empty?
|
26
|
+
id_name, id_val = @search_path.first.split('=')
|
27
|
+
|
28
|
+
@search_path = @search_path[1..-1]
|
29
|
+
|
30
|
+
if (defined? ::ActiveRecord) && collection.is_a?(::ActiveRecord::Relation)
|
31
|
+
if id_val
|
32
|
+
id_val = id_val.to_i
|
33
|
+
collection = collection.where(::Hash[id_name, id_val])
|
34
|
+
else
|
35
|
+
index = id_name.to_i
|
36
|
+
collection = collection.offset(index).limit(1)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
if id_val
|
40
|
+
id_val = id_val.to_i
|
41
|
+
found = collection.find do |ele|
|
42
|
+
ele[id_name] == id_val || ele[id_name.to_sym] == id_val
|
43
|
+
end
|
44
|
+
else
|
45
|
+
index = id_name.to_i
|
46
|
+
found = collection[index]
|
47
|
+
end
|
48
|
+
|
49
|
+
collection = [found]
|
50
|
+
end
|
51
|
+
else
|
52
|
+
super
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def set!(key, value = BLANK, *args)
|
57
|
+
options = args.first || {}
|
58
|
+
options = _normalize_options(options)
|
59
|
+
|
60
|
+
if ::Kernel.block_given? && @search_path && !@search_path.empty?
|
61
|
+
if key.to_s == @search_path.first
|
62
|
+
original_search_path = @search_path
|
63
|
+
@search_path = original_search_path[1..-1]
|
64
|
+
if @search_path.size == 0
|
65
|
+
@found = if _cache_options?(options)
|
66
|
+
_cache(*options[:cache]) { _scope { yield self } }
|
67
|
+
else
|
68
|
+
_scope { yield self }
|
69
|
+
end
|
70
|
+
else
|
71
|
+
yield self
|
72
|
+
end
|
73
|
+
|
74
|
+
@search_path = original_search_path
|
75
|
+
end
|
76
|
+
|
77
|
+
return _blank
|
78
|
+
else
|
79
|
+
super
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
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.3
|
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-04-
|
11
|
+
date: 2017-04-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coffee-rails
|
@@ -126,6 +126,12 @@ files:
|
|
126
126
|
- lib/breezy/xhr_redirect.rb
|
127
127
|
- lib/breezy/xhr_url_for.rb
|
128
128
|
- lib/breezy_template.rb
|
129
|
+
- lib/breezy_template/deferment_extension.rb
|
130
|
+
- lib/breezy_template/dependency_tracker.rb
|
131
|
+
- lib/breezy_template/digestor.rb
|
132
|
+
- lib/breezy_template/handler.rb
|
133
|
+
- lib/breezy_template/partial_extension.rb
|
134
|
+
- lib/breezy_template/search_extension.rb
|
129
135
|
- test/blade_helper.rb
|
130
136
|
- test/breezy_template_test.rb
|
131
137
|
- test/breezy_test.rb
|