breezy 0.1.1 → 0.1.3

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: bdb89b96ab7b57f15c03452a4b837750946635ac
4
- data.tar.gz: c87b2f313de0c13f1ba6373850e9b07fe5e1a82d
3
+ metadata.gz: 8ce62034c621228792d356fbfaa25033f2636132
4
+ data.tar.gz: 6f29e954b0b7402138e5e2c0f63736f1880c3638
5
5
  SHA512:
6
- metadata.gz: d1eb1c5bf8d46964e6b79819f8d67e94616f8810b782c69cdccd0508359b43b00ff1ed03ba0e5f301e4a02b91b8a02431821375dc73afb54a913e0b954e99e6d
7
- data.tar.gz: a3d62b3e1c163bbe520ad74d7082a0681481a57146b0d6d72baf2da245eb3ed50f4ebab69a4e3f65481710ba38501b9de820d6172ed33df497d2ac6cf08ac24f
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: true` will no-op the following block on a direct
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: true) do
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: true` 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.
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: true) do
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: true do
306
+ json.greeting defer: :auto do
295
307
  json.greet 'hi'
296
308
  end
297
309
  end
@@ -1,3 +1,3 @@
1
1
  module Breezy
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.3'
3
3
  end
@@ -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.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-15 00:00:00.000000000 Z
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