breezy_template 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/breezy_template.rb +285 -211
- data/lib/breezy_template/active_support.rb +3 -3
- data/lib/breezy_template/blank.rb +11 -0
- data/lib/breezy_template/breezy_template.rb +7 -0
- data/lib/breezy_template/cache_extension.rb +75 -27
- data/lib/breezy_template/configuration.rb +3 -1
- data/lib/breezy_template/deferment_extension.rb +14 -12
- data/lib/breezy_template/dependency_tracker.rb +5 -2
- data/lib/breezy_template/digestor.rb +2 -1
- data/lib/breezy_template/errors.rb +24 -0
- data/lib/breezy_template/handler.rb +4 -2
- data/lib/breezy_template/key_formatter.rb +34 -0
- data/lib/breezy_template/partial_extension.rb +57 -19
- data/lib/breezy_template/search_extension.rb +3 -3
- data/test/dependency_tracker_test.rb +80 -64
- data/test/{breezy_template_test.rb → extensions_test.rb} +130 -77
- data/test/template_test.rb +714 -0
- data/test/test_helper.rb +0 -1
- metadata +31 -25
- data/lib/breezy_template/version.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5615a0d5186cccdec50df4bc728c6d472f877254
|
4
|
+
data.tar.gz: ae3d4643bfa89ebbf2d38fd285b74ee909a73b06
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e639ce8e936ebb85324b90830425f005b3f17d7e1366ddb2f9d1d0a096cf4275e56b64ccc0c64aa32c66c365f94c6ca1c7e933a7ea71c50ef35101940f1d7d8
|
7
|
+
data.tar.gz: 30b7c0e630b346d037447f26ca3a5265c8d0839c42c3218060fcbd37e2b5dd431819e7ab27136789b202dd8295794fb49d74d4f17c0c5178b74648867ce7805c
|
data/lib/breezy_template.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
require '
|
4
|
-
require '
|
1
|
+
require 'breezy_template/breezy_template'
|
2
|
+
|
3
|
+
require 'breezy_template/blank'
|
4
|
+
require 'breezy_template/key_formatter'
|
5
|
+
require 'breezy_template/errors'
|
6
|
+
|
5
7
|
require 'breezy_template/active_support'
|
6
8
|
require 'breezy_template/digestor'
|
7
9
|
require 'breezy_template/configuration'
|
@@ -11,258 +13,330 @@ require 'breezy_template/cache_extension'
|
|
11
13
|
require 'breezy_template/deferment_extension'
|
12
14
|
require 'breezy_template/search_extension'
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
ActionView::Template.register_template_handler :props, BreezyTemplate::Handler
|
20
|
-
require 'breezy_template/dependency_tracker'
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
16
|
+
require 'digest/md5'
|
17
|
+
require 'action_view'
|
18
|
+
require 'active_support'
|
19
|
+
require 'multi_json'
|
20
|
+
require 'ostruct'
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
prepend PartialExtension
|
22
|
+
class BreezyTemplate
|
23
|
+
include PartialDigestor
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
prepend PartialExtension
|
26
|
+
prepend CacheExtension
|
27
|
+
prepend SearchExtension
|
28
|
+
prepend DefermentExtension
|
32
29
|
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
class << self
|
31
|
+
attr_accessor :template_lookup_options
|
32
|
+
end
|
36
33
|
|
37
|
-
|
34
|
+
self.template_lookup_options = { handlers: [:breezy, :props] }
|
38
35
|
|
39
|
-
|
40
|
-
|
41
|
-
@js = []
|
42
|
-
@path = []
|
43
|
-
@joints = {}
|
44
|
-
@extensions = {}
|
45
|
-
super(*args)
|
46
|
-
end
|
36
|
+
@@key_formatter = nil
|
37
|
+
@@ignore_nil = false
|
47
38
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
39
|
+
def initialize(context, options = {})
|
40
|
+
@context = context
|
41
|
+
@js = []
|
42
|
+
@path = []
|
43
|
+
@joints = {}
|
53
44
|
|
54
|
-
|
55
|
-
|
56
|
-
|
45
|
+
@attributes = {}
|
46
|
+
@key_formatter = options.fetch(:key_formatter){ @@key_formatter ? @@key_formatter.clone : nil}
|
47
|
+
@ignore_nil = options.fetch(:ignore_nil, @@ignore_nil)
|
57
48
|
|
58
|
-
|
59
|
-
|
60
|
-
end
|
49
|
+
yield self if ::Kernel.block_given?
|
50
|
+
end
|
61
51
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
52
|
+
# Yields a builder and automatically turns the result into a JSON string
|
53
|
+
def self.encode(*args, &block)
|
54
|
+
new(*args, &block).target!
|
55
|
+
end
|
56
|
+
|
57
|
+
BLANK = Blank.new
|
58
|
+
NON_ENUMERABLES = [ ::Struct, ::OpenStruct ].to_set
|
59
|
+
|
60
|
+
def set!(key, value = BLANK, *args)
|
61
|
+
result = if ::Kernel.block_given?
|
62
|
+
_result(value, *args, &::Proc.new)
|
63
|
+
else
|
64
|
+
if _is_collection?(value) && !args.last.is_a?(::Hash)
|
65
|
+
_scope{ array! value, *args }
|
66
|
+
# elsif args.empty?
|
67
|
+
# _result(value, *args)
|
68
|
+
# elsif !args.last.is_a? ::Hash
|
69
|
+
# _merge_block(key){ extract! value, *args }
|
68
70
|
else
|
69
|
-
|
70
|
-
|
71
|
+
_result(value, *args)
|
72
|
+
# value
|
71
73
|
end
|
72
|
-
ensure
|
73
|
-
# ::Byebug.byebug
|
74
|
-
@extensions = {}
|
75
|
-
@path.pop
|
76
74
|
end
|
77
75
|
|
78
|
-
|
79
|
-
|
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
|
76
|
+
_set_value key, result
|
77
|
+
end
|
98
78
|
|
99
|
-
|
79
|
+
def _result(value, *args)
|
80
|
+
if ::Kernel.block_given?
|
81
|
+
_scope { yield self }
|
82
|
+
elsif ::BreezyTemplate === value
|
83
|
+
# json.age 32
|
84
|
+
# json.person another_jbuilder
|
85
|
+
# { "age": 32, "person": { ... }
|
86
|
+
value.attributes!
|
87
|
+
else
|
88
|
+
# json.age 32
|
89
|
+
# { "age": 32 }
|
90
|
+
value
|
100
91
|
end
|
92
|
+
end
|
101
93
|
|
102
|
-
|
103
|
-
|
104
|
-
|
94
|
+
def method_missing(*args)
|
95
|
+
key = args[0]
|
96
|
+
@path.push(key)
|
97
|
+
if ::Kernel.block_given?
|
98
|
+
args = _args_for_set_with_block(*args)
|
99
|
+
set!(*args, &::Proc.new)
|
100
|
+
else
|
101
|
+
args = _args_for_set(*args)
|
102
|
+
set!(*args)
|
105
103
|
end
|
104
|
+
ensure
|
105
|
+
@path.pop
|
106
|
+
end
|
106
107
|
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
108
|
+
def key_format!(*args)
|
109
|
+
@key_formatter = KeyFormatter.new(*args)
|
110
|
+
end
|
121
111
|
|
122
|
-
|
123
|
-
|
124
|
-
|
112
|
+
# Same as the instance method key_format! except sets the default.
|
113
|
+
def self.key_format(*args)
|
114
|
+
@@key_formatter = KeyFormatter.new(*args)
|
115
|
+
end
|
116
|
+
|
117
|
+
def empty!
|
118
|
+
attributes = @attributes
|
119
|
+
@attributes = {}
|
120
|
+
attributes
|
121
|
+
end
|
125
122
|
|
126
|
-
|
127
|
-
|
128
|
-
|
123
|
+
def ignore_nil!(value = true)
|
124
|
+
@ignore_nil = value
|
125
|
+
end
|
129
126
|
|
130
|
-
|
131
|
-
|
127
|
+
# Same as instance method ignore_nil! except sets the default.
|
128
|
+
def self.ignore_nil(value = true)
|
129
|
+
@@ignore_nil = value
|
130
|
+
end
|
131
|
+
|
132
|
+
def child!
|
133
|
+
@attributes = [] unless ::Array === @attributes
|
134
|
+
@attributes << _scope{ yield self }
|
135
|
+
end
|
132
136
|
|
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
137
|
|
141
|
-
|
142
|
-
|
138
|
+
def array!(collection = [], *attributes)
|
139
|
+
options = attributes.first || {}
|
140
|
+
|
141
|
+
collection = [] if collection.nil?
|
142
|
+
collection = _prepare_collection_for_map(collection)
|
143
|
+
array = if ::Kernel.block_given?
|
144
|
+
_map_collection(collection, options, &::Proc.new)
|
145
|
+
# elsif attributes.any?
|
146
|
+
# if (!attributes.last.is_a? ::Hash)
|
147
|
+
# _map_collection(collection) { |element|
|
148
|
+
# extract! element, *attributes
|
149
|
+
# }
|
150
|
+
# else
|
151
|
+
# _map_collection(collection, options) { |element|
|
152
|
+
# extract! element, *attributes
|
153
|
+
# }
|
154
|
+
# end
|
155
|
+
else
|
156
|
+
collection.to_a
|
143
157
|
end
|
144
158
|
|
145
|
-
|
146
|
-
|
159
|
+
merge! array #remove this depednacy
|
160
|
+
end
|
147
161
|
|
148
|
-
|
149
|
-
|
162
|
+
def extract!(object, *attributes)
|
163
|
+
if ::Hash === object
|
164
|
+
_extract_hash_values(object, attributes)
|
165
|
+
else
|
166
|
+
_extract_method_values(object, attributes)
|
150
167
|
end
|
168
|
+
end
|
151
169
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
170
|
+
# def call(object, *attributes)
|
171
|
+
# if ::Kernel.block_given?
|
172
|
+
# array! object, &::Proc.new
|
173
|
+
# else
|
174
|
+
# extract! object, *attributes
|
175
|
+
# end
|
176
|
+
# end
|
177
|
+
|
178
|
+
# Returns the nil JSON.
|
179
|
+
def nil!
|
180
|
+
@attributes = nil
|
181
|
+
end
|
157
182
|
|
158
|
-
|
159
|
-
end
|
183
|
+
alias_method :null!, :nil!
|
160
184
|
|
161
|
-
|
162
|
-
|
163
|
-
|
185
|
+
def attributes!
|
186
|
+
@attributes
|
187
|
+
end
|
164
188
|
|
165
|
-
|
166
|
-
|
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
|
189
|
+
def target!
|
190
|
+
js = _breezy_return(@attributes)
|
175
191
|
|
176
|
-
|
177
|
-
|
178
|
-
|
192
|
+
@js.push(js)
|
193
|
+
"(function(){var joints={};var cache={};var defers=[];#{@js.join}})()"
|
194
|
+
end
|
179
195
|
|
180
|
-
|
181
|
-
|
182
|
-
|
196
|
+
# Merges hash or array into current builder.
|
197
|
+
# No longer works on Breezy
|
198
|
+
def merge!(hash_or_array)
|
199
|
+
@attributes = _merge_values(@attributes, hash_or_array)
|
200
|
+
end
|
183
201
|
|
184
|
-
|
185
|
-
end
|
186
|
-
end
|
202
|
+
private
|
187
203
|
|
188
|
-
|
189
|
-
|
190
|
-
|
204
|
+
def _extract_hash_values(object, attributes)
|
205
|
+
attributes.each{ |key| _set_value key, object.fetch(key) }
|
206
|
+
end
|
191
207
|
|
192
|
-
|
193
|
-
|
194
|
-
|
208
|
+
def _extract_method_values(object, attributes)
|
209
|
+
attributes.each{ |key| _set_value key, object.public_send(key) }
|
210
|
+
end
|
195
211
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
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
|
212
|
+
def _merge_block(key)
|
213
|
+
current_value = _blank? ? BLANK : @attributes.fetch(_key(key), BLANK)
|
214
|
+
raise NullError.build(key) if current_value.nil?
|
215
|
+
new_value = _scope{ yield self }
|
216
|
+
_merge_values(current_value, new_value)
|
217
|
+
end
|
213
218
|
|
219
|
+
def _merge_values(current_value, updates)
|
220
|
+
# Always use the new values. This is because cached values
|
221
|
+
# are no longer a Ruby object. They are JS values and can't
|
222
|
+
# be merged.
|
214
223
|
|
215
|
-
|
216
|
-
|
217
|
-
end
|
224
|
+
updates
|
225
|
+
end
|
218
226
|
|
219
|
-
|
220
|
-
|
221
|
-
|
227
|
+
def _key(key)
|
228
|
+
@key_formatter ? @key_formatter.format(key) : key.to_s
|
229
|
+
end
|
222
230
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
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
|
231
|
+
def _set_value(key, value)
|
232
|
+
raise NullError.build(key) if @attributes.nil?
|
233
|
+
raise ArrayError.build(key) if ::Array === @attributes
|
234
|
+
return if @ignore_nil && value.nil? or _blank?(value)
|
235
|
+
@attributes = {} if _blank?
|
236
|
+
@attributes[_key(key)] = value
|
237
|
+
end
|
238
|
+
|
239
|
+
def _prepare_collection_for_map(collection)
|
240
|
+
collection
|
241
|
+
end
|
249
242
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
key
|
260
|
-
end
|
243
|
+
def _map_collection(collection, options = {})
|
244
|
+
@path.push(nil)
|
245
|
+
collection.map.with_index do |element, i|
|
246
|
+
if options.has_key? :key
|
247
|
+
id_name = options[:key]
|
248
|
+
id_val = element[id_name]
|
249
|
+
@path[-1] = "#{id_name}=#{id_val}"
|
250
|
+
else
|
251
|
+
@path[-1] = i
|
261
252
|
end
|
262
253
|
|
254
|
+
_mapping_element(element, options, &::Proc.new)
|
255
|
+
|
256
|
+
end - [BLANK]
|
257
|
+
ensure
|
258
|
+
@path.pop
|
259
|
+
end
|
260
|
+
|
261
|
+
def _mapping_element(element, options)
|
262
|
+
_scope { yield element }
|
263
|
+
end
|
264
|
+
|
265
|
+
def _scope
|
266
|
+
parent_attributes, parent_formatter = @attributes, @key_formatter
|
267
|
+
@attributes = BLANK
|
268
|
+
yield
|
269
|
+
@attributes
|
270
|
+
ensure
|
271
|
+
@attributes, @key_formatter = parent_attributes, parent_formatter
|
272
|
+
end
|
273
|
+
|
274
|
+
def _is_collection?(object)
|
275
|
+
_object_respond_to?(object, :map, :count) && NON_ENUMERABLES.none?{ |klass| klass === object }
|
276
|
+
end
|
263
277
|
|
264
|
-
|
265
|
-
|
278
|
+
def _blank?(value=@attributes)
|
279
|
+
BLANK == value
|
280
|
+
end
|
281
|
+
|
282
|
+
def _blank
|
283
|
+
BLANK
|
284
|
+
end
|
285
|
+
|
286
|
+
def _object_respond_to?(object, *methods)
|
287
|
+
methods.all?{ |m| object.respond_to?(m) }
|
288
|
+
end
|
289
|
+
|
290
|
+
def _args_for_set_with_block(*args)
|
291
|
+
# return args
|
292
|
+
key = args[0]
|
293
|
+
# #todo: check this
|
294
|
+
# #
|
295
|
+
if ::Hash === args[1] && _extended_options?(args[1])
|
296
|
+
options = args[1]
|
297
|
+
[key, BLANK, options]
|
298
|
+
else
|
299
|
+
[key, BLANK]
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def _args_for_set(*args)
|
304
|
+
return args
|
305
|
+
# if args.length >= 3
|
306
|
+
# return args
|
307
|
+
# # key, value, options = args
|
308
|
+
# #
|
309
|
+
# # [key, value, options]
|
310
|
+
# else
|
311
|
+
# key, value = args
|
312
|
+
#
|
313
|
+
# [key, value]
|
314
|
+
# end
|
315
|
+
end
|
316
|
+
|
317
|
+
def _extended_options?(value)
|
318
|
+
false
|
319
|
+
end
|
320
|
+
|
321
|
+
def _breezy_return(results)
|
322
|
+
"return (#{_dump(results)});"
|
323
|
+
end
|
324
|
+
|
325
|
+
def _dump(value)
|
326
|
+
::MultiJson.dump(value)
|
327
|
+
end
|
328
|
+
|
329
|
+
def _logger
|
330
|
+
::ActionView::Base.logger
|
331
|
+
end
|
332
|
+
|
333
|
+
class Engine < ::Rails::Engine
|
334
|
+
initializer :breezy_template do |app|
|
335
|
+
ActiveSupport.on_load(:action_view) do
|
336
|
+
ActionView::Template.register_template_handler :breezy, BreezyTemplate::Handler
|
337
|
+
ActionView::Template.register_template_handler :props, BreezyTemplate::Handler
|
338
|
+
require 'breezy_template/dependency_tracker'
|
266
339
|
end
|
340
|
+
end
|
267
341
|
end
|
268
342
|
end
|