breezy_template 0.2.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1034948b51df6045cd4ebed1fec5278d578b6232
4
+ data.tar.gz: 37f2073cb2c299d22fa2d12b0b022d34d531ed7e
5
+ SHA512:
6
+ metadata.gz: ceab85197a0d71c53c3b4ac25263bc392fcf700b1a23e88f5dcb8a79f6634b7bc6d6e93e10d3ff0f2222a3c5d8b3345e02b66978d44e452463ae53aa05c567a4
7
+ data.tar.gz: 7fc963e83b28dfdbb7a2216815e7e3319089c7bb6745ffe92f3e37d583490d492adc8607cc097b21c905052d5077ba5a6994474f60c28773315be42c0659fc64
@@ -0,0 +1,268 @@
1
+ require 'jbuilder'
2
+ require 'digest/md5'
3
+ require 'action_view'
4
+ require 'active_support'
5
+ require 'breezy_template/active_support'
6
+ require 'breezy_template/digestor'
7
+ require 'breezy_template/configuration'
8
+ require 'breezy_template/handler'
9
+ require 'breezy_template/partial_extension'
10
+ require 'breezy_template/cache_extension'
11
+ require 'breezy_template/deferment_extension'
12
+ require 'breezy_template/search_extension'
13
+
14
+ module BreezyTemplate
15
+ class Engine < ::Rails::Engine
16
+ initializer :breezy_template do |app|
17
+ ActiveSupport.on_load(:action_view) do
18
+ ActionView::Template.register_template_handler :breezy, BreezyTemplate::Handler
19
+ ActionView::Template.register_template_handler :props, BreezyTemplate::Handler
20
+ require 'breezy_template/dependency_tracker'
21
+ end
22
+ end
23
+ end
24
+
25
+ class Template < ::Jbuilder
26
+ include PartialDigestor
27
+ prepend PartialExtension
28
+
29
+ prepend CacheExtension
30
+ prepend SearchExtension
31
+ prepend DefermentExtension
32
+
33
+ class << self
34
+ attr_accessor :template_lookup_options
35
+ end
36
+
37
+ self.template_lookup_options = { handlers: [:breezy] }
38
+
39
+ def initialize(context, *args)
40
+ @context = context
41
+ @js = []
42
+ @path = []
43
+ @joints = {}
44
+ @extensions = {}
45
+ super(*args)
46
+ end
47
+
48
+ def empty!
49
+ attributes = @attributes
50
+ @attributes = {}
51
+ attributes
52
+ end
53
+
54
+ def wrap!(name, *args)
55
+ @extensions[name.to_sym] = args
56
+ end
57
+
58
+ def _blank
59
+ BLANK
60
+ end
61
+
62
+ def method_missing(*args)
63
+ key = args[0]
64
+ @path.push(key)
65
+ if ::Kernel.block_given?
66
+ args = _args_for_set_with_block(*args)
67
+ set!(*args, &::Proc.new)
68
+ else
69
+ args = _args_for_set(*args)
70
+ set!(*args)
71
+ end
72
+ ensure
73
+ # ::Byebug.byebug
74
+ @extensions = {}
75
+ @path.pop
76
+ end
77
+
78
+ def _scope
79
+ parent_extensions = @extensions
80
+ @extensions = {}
81
+ parent_attributes, parent_formatter = @attributes, @key_formatter
82
+ @attributes = BLANK
83
+ yield
84
+ @attributes
85
+ ensure
86
+ # ::Byebug.byebug
87
+ @extensions = parent_extensions
88
+ @attributes, @key_formatter = parent_attributes, parent_formatter
89
+ end
90
+
91
+ def set!(key, value = BLANK, *args)
92
+ _ensure_valid_key(key)
93
+ result = if ::Kernel.block_given?
94
+ _result(value, &::Proc.new)
95
+ else
96
+ _result(value)
97
+ end
98
+
99
+ _set_value key, result
100
+ end
101
+
102
+ def _ensure_valid_key(key)
103
+ current_value = _blank? ? _blank : @attributes.fetch(_key(key), _blank)
104
+ raise NullError.build(key) if current_value.nil?
105
+ end
106
+
107
+ def _result(value)
108
+ if ::Kernel.block_given?
109
+ _scope { yield self }
110
+ elsif ::Jbuilder === value
111
+ # json.age 32
112
+ # json.person another_jbuilder
113
+ # { "age": 32, "person": { ... }
114
+ value.attributes!
115
+ else
116
+ # json.age 32
117
+ # { "age": 32 }
118
+ value
119
+ end
120
+ end
121
+
122
+ def _set_value(key, result)
123
+ super
124
+ end
125
+
126
+ def array!(collection = [], *attributes)
127
+ options = attributes.first || {}
128
+ options = _normalize_options(options)
129
+
130
+ collection = [] if collection.nil?
131
+ collection = _prepare_collection_for_map(collection)
132
+
133
+ array = if ::Kernel.block_given?
134
+ _map_collection(collection, options, &::Proc.new)
135
+ elsif attributes.any?
136
+ _map_collection(collection, options) { |element| extract! element, *attributes }
137
+ else
138
+ collection.to_a
139
+ end
140
+
141
+ @extensions = {}
142
+ merge! array #remove this depednacy
143
+ end
144
+
145
+ def target!
146
+ js = _breezy_return(@attributes)
147
+
148
+ @js.push(js)
149
+ "(function(){var joints={};var cache={};var defers=[];#{@js.join}})()"
150
+ end
151
+
152
+ private
153
+ def _merge_values(current_value, updates)
154
+ # Always use the new values. This is because cached values
155
+ # are no longer a Ruby object. They are JS values and can't
156
+ # be merged.
157
+
158
+ updates
159
+ end
160
+
161
+ def _prepare_collection_for_map(collection)
162
+ collection
163
+ end
164
+
165
+ def _args_for_set_with_block(*args)
166
+ key = args[0]
167
+ #todo: check this
168
+ if ::Hash === args[1] && _extended_options?(args[1])
169
+ options = args[1]
170
+ [key, BLANK, options]
171
+ else
172
+ [key, BLANK]
173
+ end
174
+ end
175
+
176
+ def _args_for_set(*args)
177
+ if args.length == 3
178
+ key, value, options = args
179
+
180
+ [key, value, options]
181
+ else
182
+ key, value = args
183
+
184
+ [key, value]
185
+ end
186
+ end
187
+
188
+ def _extended_options?(value)
189
+ false
190
+ end
191
+
192
+ def _mapping_element(element, options)
193
+ _scope { yield element }
194
+ end
195
+
196
+ def _map_collection(collection, options)
197
+ @path.push(nil)
198
+ collection.map.with_index do |element, i|
199
+ if options.has_key? :key
200
+ id_name = options[:key]
201
+ id_val = element[id_name]
202
+ @path[-1] = "#{id_name}=#{id_val}"
203
+ else
204
+ @path[-1] = i
205
+ end
206
+
207
+ _mapping_element(element, options, &::Proc.new)
208
+
209
+ end - [BLANK]
210
+ ensure
211
+ @path.pop
212
+ end
213
+
214
+
215
+ def _breezy_return(results)
216
+ "return (#{_dump(results)});"
217
+ end
218
+
219
+ def _dump(value)
220
+ ::MultiJson.dump(value)
221
+ end
222
+
223
+ def _normalize_options(options)
224
+ options = options.dup
225
+ key = options[:cache]
226
+ opts = {}
227
+ return options if !key
228
+
229
+ if ::Array === key && key.length == 2 && ::Hash === key.last
230
+ return options
231
+ end
232
+
233
+ if options[:partial]
234
+ opts[:partial] = options[:partial]
235
+ end
236
+
237
+ key = case key
238
+ when ::Array
239
+ key
240
+ when ::Proc
241
+ key
242
+ else
243
+ [key]
244
+ end
245
+
246
+ options[:cache] = [key, opts]
247
+ options
248
+ end
249
+
250
+ def _fragment_name_with_digest(key, options)
251
+ if @context.respond_to?(:cache_fragment_name)
252
+ # Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
253
+ # should be used instead.
254
+ @context.cache_fragment_name(key, options)
255
+ elsif @context.respond_to?(:fragment_name_with_digest)
256
+ # Backwards compatibility for period of time when fragment_name_with_digest was made public.
257
+ @context.fragment_name_with_digest(key)
258
+ else
259
+ key
260
+ end
261
+ end
262
+
263
+
264
+ def _logger
265
+ ::ActionView::Base.logger
266
+ end
267
+ end
268
+ end
@@ -0,0 +1,24 @@
1
+ # https://github.com/rails/jbuilder/issues/204
2
+ if Rails.version >= '4.1'
3
+ module ActiveSupport
4
+ module JSON
5
+ module Encoding
6
+ class JSONGemEncoder
7
+ alias_method :original_jsonify, :jsonify
8
+
9
+ def jsonify(value)
10
+ if ::BreezyTemplate::Template::Digest === value
11
+ value
12
+ elsif ::BreezyTemplate::Template::JointVar === value
13
+ value
14
+ elsif ::BreezyTemplate::Template::DeferVar === value
15
+ value
16
+ else
17
+ original_jsonify(value)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,131 @@
1
+ module BreezyTemplate
2
+ module CacheExtension
3
+ class Digest
4
+ def initialize(digest)
5
+ @digest = "cache[\"#{digest}\"]"
6
+ end
7
+
8
+ def to_json(*)
9
+ @digest
10
+ end
11
+
12
+ def as_json(*)
13
+ self
14
+ end
15
+
16
+ def encode_json(*)
17
+ @digest
18
+ end
19
+ end
20
+
21
+ def _result(value)
22
+ if _cache_options?
23
+ _cache(*_cache_options) { super }
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ def set!(key, value = BLANK, *args)
30
+ options = args.first || {}
31
+ options = _normalize_options(options)
32
+ if options[:partial] && _cache_options?
33
+ _cache_options[1] ||= {}
34
+ _cache_options[1][:_partial] = options[:partial]
35
+ end
36
+ super
37
+ end
38
+
39
+ def array!(collection=[], *attributes)
40
+ options = attributes.first || {}
41
+ options = _normalize_options(options)
42
+
43
+ if options[:partial] && _cache_options?
44
+ _cache_options[1] ||= {}
45
+ _cache_options[1][:_partial] = options[:partial]
46
+ end
47
+
48
+ super
49
+ end
50
+
51
+ def _mapping_element(element, opts={})
52
+ if _cache_options
53
+ key = _cache_options.first
54
+ if ::Proc === key
55
+ key = key.call(element)
56
+ end
57
+
58
+ _cache(key, opts) {
59
+ _scope { yield element }
60
+ }
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ def _cache_options?
67
+ !!@extensions[:cache]
68
+ end
69
+
70
+ def _cache_options
71
+ @extensions[:cache]
72
+ end
73
+
74
+ def _extended_options?(value)
75
+ _cache_options? || super
76
+ end
77
+
78
+ def _breezy_set_cache(key, value)
79
+ "cache[\"#{key}\"]=#{_dump(value)};"
80
+ end
81
+
82
+ def _cache_key(key, options={})
83
+ key = _fragment_name_with_digest(key, options)
84
+ key = url_for(key).split('://', 2).last if ::Hash === key
85
+ key = ::ActiveSupport::Cache.expand_cache_key(key, :jbuilder)
86
+
87
+ ::Digest::MD5.hexdigest(key.to_s).tap do |digest|
88
+ _logger.try :debug, "Cache key :#{key} was digested to #{digest}"
89
+ end
90
+ end
91
+
92
+ def _cache(key=nil, options={})
93
+ return yield self if !@context.controller.perform_caching || key.nil?
94
+
95
+ parent_js = @js
96
+ key = _cache_key(key, options)
97
+ @js = []
98
+
99
+ blank_or_value = begin
100
+ ::Rails.cache.fetch(key, options) do
101
+ result = yield self
102
+ if result != _blank
103
+ @js << _breezy_set_cache(key, result)
104
+ @js.join
105
+ else
106
+ _blank
107
+ end
108
+ end
109
+ ensure
110
+ @js = parent_js
111
+ end
112
+
113
+ if blank_or_value == _blank
114
+ _blank
115
+ else
116
+ v = blank_or_value
117
+ @js.push(v)
118
+ Digest.new(key)
119
+ end
120
+ end
121
+
122
+ def _fragment_name_with_digest(key, options)
123
+ if _cache_options? && _cache_options[1] && _cache_options[1][:_partial] && !options[:skip_digest]
124
+ partial = _cache_options[1][:_partial]
125
+ [key, _partial_digest(partial)]
126
+ else
127
+ super
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,21 @@
1
+ module BreezyTemplate
2
+ class Configuration
3
+ attr_accessor :track_assets
4
+
5
+ def initialize
6
+ @track_assets = ['application.js', 'application.css']
7
+ end
8
+ end
9
+
10
+ def self.configuration
11
+ @configuration ||= Configuration.new
12
+ end
13
+
14
+ def self.configuration=(config)
15
+ @configuration = config
16
+ end
17
+
18
+ def self.configure
19
+ yield configuration
20
+ end
21
+ end