rabl 0.11.1 → 0.11.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -21,7 +21,7 @@ module Rabl
21
21
  end
22
22
  end
23
23
 
24
- def write(key, value, options={})
24
+ def write(key, value, options = {})
25
25
  if defined?(Rails)
26
26
  Rails.cache.write(key, value, options)
27
27
  end
@@ -80,7 +80,7 @@ module Rabl
80
80
  @replace_nil_values_with_empty_strings = false
81
81
  @replace_empty_string_values_with_nil_values = false
82
82
  @exclude_nil_values = false
83
- @exclude_empty_values_in_collections = false
83
+ @exclude_empty_values_in_collections = false
84
84
  end
85
85
 
86
86
  # @return The JSON engine used to encode Rabl templates into JSON
data/lib/rabl/engine.rb CHANGED
@@ -1,124 +1,158 @@
1
1
  module Rabl
2
2
  class Engine
3
- include Rabl::Partials
4
- include Rabl::Helpers::Escaper
3
+ include Helpers
4
+ include Partials
5
+ include Helpers::Escaper
5
6
 
6
7
  # List of supported rendering formats
7
8
  FORMATS = [:json, :xml, :plist, :bson, :msgpack]
8
9
 
9
10
  # Constructs a new ejs engine based on given vars, handler and declarations
10
11
  # Rabl::Engine.new("...source...", { :format => "xml", :root => true, :view_path => "/path/to/views" })
11
- def initialize(source, options={})
12
- @_source = source
13
- @_options = options
14
- @_view_path = options[:view_path]
12
+ def initialize(source, options = {})
13
+ @_source = source
14
+ @_settings = {}
15
+ @_options = options
16
+
17
+ @_view_path = options[:view_path]
18
+ @_context_scope = options[:scope]
19
+
20
+ @_cache_read_on_render = true
15
21
  end
16
22
 
17
- def source=(string)
18
- @_source = string
23
+ def source=(source)
24
+ @_source = source
19
25
  end
20
26
 
21
- # Renders the representation based on source, object, scope and locals
22
- # Rabl::Engine.new("...source...", { :format => "xml" }).apply(scope, { :foo => "bar", :object => @user })
23
- def apply(scope, locals, &block)
24
- reset_options!(scope)
25
- set_instance_variables!(scope, locals, &block)
27
+ # Renders the representation based on source, object, context_scope and locals
28
+ # Rabl::Engine.new("...source...", { :format => "xml" }).apply(context_scope, { :foo => "bar", :object => @user })
29
+ def apply(context_scope, locals, &block)
30
+ set_instance_variables!(context_scope, locals)
31
+
32
+ reset_settings!
33
+ reset_options!
34
+
35
+ eval_source(locals, &block)
36
+
26
37
  instance_exec(root_object, &block) if block_given?
27
38
 
28
39
  self
29
40
  end
30
41
 
31
42
  # Renders the representation based on a previous apply
32
- # Rabl::Engine.new("...source...", { :format => "xml" }).apply(scope, { :foo => "bar", :object => @user }).render
33
- def render(scope = nil, locals = nil, &block)
34
- apply(scope, locals) if scope || locals
35
- cache_results { self.send("to_#{@_options[:format]}", @_options) }
43
+ # Rabl::Engine.new("...source...", { :format => "xml" }).apply(context_scope, { :foo => "bar", :object => @user }).render
44
+ def render(context_scope = nil, locals = nil, &block)
45
+ apply(context_scope, locals, &block) if context_scope || locals || block
46
+
47
+ cache_results do
48
+ send("to_#{@_options[:format]}")
49
+ end
36
50
  end
37
51
 
38
- # Returns the cache key of the engine
39
52
  def cache_key
40
- _cache = @_cache if defined?(@_cache)
41
- cache_key, _ = *_cache || nil
42
- return nil if cache_key.nil?
43
- Array(cache_key) + [@_options[:root_name], @_options[:format]]
53
+ return unless defined?(@_cache_key)
54
+
55
+ @_full_cache_key ||= begin
56
+ cache_key = Array(@_cache_key) + [@_options[:root_name], @_options[:format]]
57
+
58
+ if digestor_available? && defined?(lookup_context)
59
+ template = @_options[:template] || @virtual_path
60
+
61
+ digest = \
62
+ if Gem::Version.new(Rails.version) >= Gem::Version.new('4.1')
63
+ Digestor.digest(:name => template, :finder => lookup_context)
64
+ else
65
+ Digestor.digest(template, :rabl, lookup_context)
66
+ end
67
+
68
+ cache_key << digest
69
+ end
70
+
71
+ cache_key
72
+ end
44
73
  end
45
74
 
46
75
  # Returns a hash representation of the data object
47
76
  # to_hash(:root => true, :child_root => true)
48
- def to_hash(options={})
49
- options = options.merge(@_options)
77
+ def to_hash(options = {})
78
+ options = @_options.merge(options)
79
+
50
80
  data = root_object
51
- builder = Rabl::Builder.new(options)
81
+
52
82
  options[:root_name] = determine_object_root(data, root_name, options[:root])
53
83
 
54
- if is_object?(data) || !data # object @user
55
- result = builder.build(data, options)
56
- elsif is_collection?(data) # collection @users
57
- result = if template_cache_configured? && Rabl.configuration.use_read_multi
58
- read_multi(*data, options)
59
- else
60
- data.map { |object| builder.build(object, options) }
84
+ result = \
85
+ if is_object?(data) || !data # object @user
86
+ Builder.new(data, @_settings, options).to_hash
87
+ elsif is_collection?(data) # collection @users
88
+ MultiBuilder.new(data, @_settings, options).to_a
61
89
  end
62
- result = result.map(&:presence).compact if Rabl.configuration.exclude_empty_values_in_collections
63
- end
64
- Rabl.configuration.escape_all_output ? escape_output(result) : result
90
+
91
+ result = escape_output(result) if Rabl.configuration.escape_all_output
92
+
93
+ result
94
+ end
95
+
96
+ def to_dumpable(options = {})
97
+ options = {
98
+ :child_root => Rabl.configuration.include_child_root
99
+ }.merge(options)
100
+
101
+ result = to_hash(options)
102
+ result = { collection_root_name => result } if collection_root_name
103
+ result
65
104
  end
66
105
 
67
106
  # Returns a json representation of the data object
68
107
  # to_json(:root => true)
69
- def to_json(options={})
70
- include_root = Rabl.configuration.include_json_root
71
- include_child_root = Rabl.configuration.include_child_root
72
- options = options.reverse_merge(:root => include_root, :child_root => include_child_root)
73
- result = collection_root_name ? { collection_root_name => to_hash(options) } : to_hash(options)
108
+ def to_json(options = {})
109
+ options = { :root => Rabl.configuration.include_json_root }.merge(options)
110
+ result = to_dumpable(options)
74
111
  format_json(result)
75
112
  end
76
113
 
77
114
  # Returns a msgpack representation of the data object
78
115
  # to_msgpack(:root => true)
79
- def to_msgpack(options={})
80
- include_root = Rabl.configuration.include_msgpack_root
81
- include_child_root = Rabl.configuration.include_child_root
82
- options = options.reverse_merge(:root => include_root, :child_root => include_child_root)
83
- result = collection_root_name ? { collection_root_name => to_hash(options) } : to_hash(options)
84
- Rabl.configuration.msgpack_engine.pack result
116
+ def to_msgpack(options = {})
117
+ options = { :root => Rabl.configuration.include_msgpack_root }.merge(options)
118
+ result = to_dumpable(options)
119
+ Rabl.configuration.msgpack_engine.pack(result)
85
120
  end
86
121
  alias_method :to_mpac, :to_msgpack
87
122
 
88
123
  # Returns a plist representation of the data object
89
124
  # to_plist(:root => true)
90
- def to_plist(options={})
91
- include_root = Rabl.configuration.include_plist_root
92
- include_child_root = Rabl.configuration.include_child_root
93
- options = options.reverse_merge(:root => include_root, :child_root => include_child_root)
94
- result = defined?(@_collection_name) ? { @_collection_name => to_hash(options) } : to_hash(options)
125
+ def to_plist(options = {})
126
+ options = { :root => Rabl.configuration.include_plist_root }.merge(options)
127
+ result = to_dumpable(options)
95
128
  Rabl.configuration.plist_engine.dump(result)
96
129
  end
97
130
 
98
131
  # Returns an xml representation of the data object
99
132
  # to_xml(:root => true)
100
- def to_xml(options={})
101
- include_root = Rabl.configuration.include_xml_root
102
- include_child_root = include_root && Rabl.configuration.include_child_root
103
- options = options.reverse_merge(:root => include_root, :child_root => include_child_root)
133
+ def to_xml(options = {})
134
+ options = {
135
+ :root => (include_root = Rabl.configuration.include_xml_root),
136
+ :child_root => include_root && Rabl.configuration.include_child_root
137
+ }.merge(options)
138
+
104
139
  xml_options = Rabl.configuration.default_xml_options.merge(:root => collection_root_name || root_name)
140
+
105
141
  result = to_hash(options)
142
+
106
143
  result.to_xml(xml_options)
107
144
  end
108
145
 
109
146
  # Returns a bson representation of the data object
110
147
  # to_bson(:root => true)
111
- def to_bson(options={})
112
- include_root = Rabl.configuration.include_bson_root
113
- include_child_root = Rabl.configuration.include_child_root
114
- options = options.reverse_merge(:root => include_root, :child_root => include_child_root)
115
- result = if collection_root_name
116
- { collection_root_name => to_hash(options) }
117
- elsif is_collection?(root_object) && root_object.is_a?(Array)
118
- { root_name => to_hash(options) }
119
- else
120
- to_hash(options)
121
- end
148
+ def to_bson(options = {})
149
+ options = { :root => Rabl.configuration.include_bson_root }.merge(options)
150
+ result = to_dumpable(options)
151
+
152
+ if !collection_root_name && is_collection?(root_object) && root_object.is_a?(Array)
153
+ result = { root_name => result }
154
+ end
155
+
122
156
  Rabl.configuration.bson_engine.serialize(result).to_s
123
157
  end
124
158
 
@@ -130,6 +164,7 @@ module Rabl
130
164
  current_data = (@_locals[:object].nil? || template_data == false) ? template_data : @_locals[:object]
131
165
  @_data_object = data_object(current_data)
132
166
  @_data_name = data_name(template_data.is_a?(Hash) && !current_data.is_a?(Hash) ? template_data : current_data)
167
+
133
168
  if @_data_name == false
134
169
  @_object_root_name = false
135
170
  @_collection_name = false
@@ -142,7 +177,7 @@ module Rabl
142
177
  def root_object
143
178
  return @_data_object if defined?(@_data_object)
144
179
 
145
- data = @_locals[:object].nil? ? self.default_object : @_locals[:object]
180
+ data = @_locals[:object].nil? ? default_object : @_locals[:object]
146
181
  @_data_object = data_object(data)
147
182
  end
148
183
 
@@ -160,11 +195,13 @@ module Rabl
160
195
  # collection @users => :people
161
196
  # collection @users, :root => :person
162
197
  # collection @users, :object_root => :person
163
- def collection(data, options={})
198
+ def collection(data, options = {})
164
199
  @_collection_name = options[:root] if options[:root]
165
- @_collection_name ||= data.values.first if data.respond_to?(:each_pair)
200
+ @_collection_name ||= data.values.first if data.is_a?(Hash)
201
+
166
202
  @_object_root_name = options[:object_root] if options.has_key?(:object_root)
167
- self.object(Array(data_object(data)))
203
+
204
+ object(Array(data_object(data)))
168
205
  end
169
206
 
170
207
  # Sets the cache key to be used by ActiveSupport::Cache.expand_cache_key
@@ -176,7 +213,8 @@ module Rabl
176
213
  # options is passed through to the cache store
177
214
  def cache(key = nil, options = nil)
178
215
  key ||= root_object # if called but missing, use object
179
- @_cache = [key, options]
216
+ @_cache_key = key
217
+ @_cache_options = options
180
218
  end
181
219
 
182
220
  # Indicates an attribute or method should be included in the json output
@@ -185,11 +223,17 @@ module Rabl
185
223
  # attribute :foo => :bar, :bar => :baz, :if => lambda { |r| r.foo }
186
224
  def attribute(*args)
187
225
  if args.first.is_a?(Hash) # :foo => :bar, :bar => :baz
188
- attr_aliases, conds = args.first.except(:if, :unless), args.first.slice(:if, :unless)
189
- attr_aliases.each_pair { |k,v| self.attribute(k, conds.merge(:as => v)) }
226
+ attr_aliases = args.first.except(:if, :unless)
227
+ conditions = args.first.slice(:if, :unless)
228
+
229
+ attr_aliases.each do |key, as|
230
+ attribute(key, conditions.merge(:as => as))
231
+ end
190
232
  else # array of attributes i.e :foo, :bar, :baz
191
- attr_options = args.extract_options!
192
- args.each { |name| @_options[:attributes][name] = attr_options }
233
+ options = args.extract_options!
234
+ args.each do |name|
235
+ @_settings[:attributes] << { :name => name, :options => options }
236
+ end
193
237
  end
194
238
  end
195
239
  alias_method :attributes, :attribute
@@ -197,193 +241,181 @@ module Rabl
197
241
  # Creates an arbitrary node that is included in the json output.
198
242
  # node(:foo) { "bar" }
199
243
  # node(:foo, :if => lambda { ... }) { "bar" }
200
- def node(name = nil, options={}, &block)
201
- @_options[:node].push({ :name => name, :options => options, :block => block })
244
+ def node(name = nil, options = {}, &block)
245
+ @_settings[:node] << { :name => name, :options => options, :block => block }
202
246
  end
203
247
  alias_method :code, :node
204
248
 
205
249
  # Creates a child node that is included in json output
206
250
  # child(@user) { attribute :full_name }
207
- def child(data, options={}, &block)
208
- @_options[:child].push({ :data => data, :options => options, :block => block })
251
+ def child(data, options = {}, &block)
252
+ @_settings[:child] << { :data => data, :options => options, :block => block }
209
253
  end
210
254
 
211
255
  # Glues data from a child node to the json_output
212
256
  # glue(@user) { attribute :full_name => :user_full_name }
213
- def glue(data, options={}, &block)
214
- @_options[:glue].push({ :data => data, :options => options, :block => block })
257
+ def glue(data, options = {}, &block)
258
+ @_settings[:glue] << { :data => data, :options => options, :block => block }
215
259
  end
216
260
 
217
261
  # Extends an existing rabl template with additional attributes in the block
218
262
  # extends("users/show", :object => @user) { attribute :full_name }
219
- def extends(file, options={}, &block)
220
- extend_ops = options.merge(:view_path => options.fetch(:view_path, @_options[:view_path]))
221
- @_options[:extends].push({ :file => file, :options => extend_ops, :block => block })
263
+ def extends(file, options = {}, &block)
264
+ options = { :view_path => options[:view_path] || view_path }.merge(options)
265
+
266
+ @_settings[:extends] << { :file => file, :options => options, :block => block }
222
267
  end
223
268
 
224
269
  # Includes a helper module with a RABL template
225
270
  # helper ExampleHelper
226
- def helper(*klazzes)
227
- klazzes.each { |klazz| self.class.__send__(:include, klazz) }
271
+ def helper(*klasses)
272
+ klasses.each { |klass| self.class.__send__(:include, klass) }
228
273
  end
229
274
  alias_method :helpers, :helper
230
275
 
276
+ # Returns a hash representing the partial
277
+ # partial("users/show", :object => @user)
278
+ # options must have :object
279
+ # options can have :view_path, :child_root, :root
280
+ def partial(file, options = {}, &block)
281
+ engine = partial_as_engine(file, options, &block)
282
+ engine = engine.render if engine.is_a?(Engine)
283
+ engine
284
+ end
285
+
231
286
  # Disables reading (but not writing) from the cache when rendering.
232
- def cache_read_on_render=(c)
233
- @_cache_read_on_render = c
287
+ def cache_read_on_render=(read)
288
+ @_cache_read_on_render = read
289
+ end
290
+
291
+ def cache_read_on_render?
292
+ @_cache_read_on_render
234
293
  end
235
294
 
236
295
  protected
296
+ # Returns a guess at the default object for this template
297
+ # default_object => @user
298
+ def default_object
299
+ return unless context_scope.respond_to?(:controller)
237
300
 
238
- # Returns a guess at the default object for this template
239
- # default_object => @user
240
- def default_object
241
- if context_scope.respond_to?(:controller)
242
301
  controller_name = context_scope.controller.controller_name
243
302
  stripped_name = controller_name.split(%r{::|\/}).last
244
303
  ivar_object = instance_variable_get("@#{stripped_name}")
245
304
  ivar_object if is_object?(ivar_object)
246
305
  end
247
- end
248
306
 
249
- # Returns a guess at the format in this scope
250
- # request_format => "xml"
251
- def request_format
252
- format = self.request_params.has_key?(:format) ? context_scope.params[:format] : nil
253
- if request = context_scope.respond_to?(:request) && context_scope.request
254
- format ||= request.format.to_sym.to_s if request.respond_to?(:format)
307
+ # Returns a guess at the format in this context_scope
308
+ # request_format => "xml"
309
+ def request_format
310
+ format = request_params[:format]
311
+
312
+ if format.nil? && context_scope.respond_to?(:request)
313
+ request = context_scope.request
314
+ format = request.format.to_sym.to_s if request.respond_to?(:format)
315
+ end
316
+
317
+ format = "json" unless format && respond_to?("to_#{format}")
318
+
319
+ format
255
320
  end
256
- format && self.respond_to?("to_#{format}") ? format : "json"
257
- end
258
321
 
259
- # Returns the request parameters if available in the scope
260
- # request_params => { :foo => "bar" }
261
- def request_params
262
- (context_scope.params if context_scope.respond_to?(:params)) || {}
263
- end
322
+ # Returns the request parameters if available in the context_scope
323
+ # request_params => { :foo => "bar" }
324
+ def request_params
325
+ (context_scope.params if context_scope.respond_to?(:params)) || {}
326
+ end
264
327
 
265
- # Returns data as json embraced with callback when detected
266
- # format_json({ :foo => "bar" }) => "test({ foo : 'bar' })"
267
- # format_json("{ foo : "bar" }") => "test({ foo : 'bar' })"
268
- def format_json(json_output)
269
- json_engine = Rabl.configuration.json_engine
270
- json_method = json_engine.respond_to?(:dump) ? 'dump' : 'encode'
271
- json_output = json_engine.send(json_method, json_output) unless json_output.is_a?(String)
272
- use_callback = Rabl.configuration.enable_json_callbacks && request_params[:callback].present?
273
- use_callback ? "#{request_params[:callback]}(#{json_output})" : json_output
274
- end
328
+ # Returns data as json embraced with callback when detected
329
+ # format_json({ :foo => "bar" }) => "test({ foo : 'bar' })"
330
+ # format_json("{ foo : "bar" }") => "test({ foo : 'bar' })"
331
+ def format_json(json_output)
332
+ unless json_output.is_a?(String)
333
+ json_engine = Rabl.configuration.json_engine
334
+ json_output = if json_engine.respond_to?(:dump)
335
+ json_engine.dump(json_output)
336
+ else
337
+ json_engine.encode(json_output)
338
+ end
339
+ end
275
340
 
276
- # Augments respond to supporting scope methods
277
- def respond_to?(name, include_private=false)
278
- context_scope.respond_to?(name, include_private) ? true : super
279
- end
341
+ use_callback = Rabl.configuration.enable_json_callbacks && request_params[:callback].present?
342
+ json_output = "#{request_params[:callback]}(#{json_output})" if use_callback
280
343
 
281
- # Supports calling helpers defined for the template scope using method_missing hook
282
- def method_missing(name, *args, &block)
283
- context_scope.respond_to?(name, true) ? context_scope.__send__(name, *args, &block) : super
284
- end
344
+ json_output
345
+ end
285
346
 
286
- def copy_instance_variables_from(object, exclude = []) #:nodoc:
287
- vars = object.instance_variables.map(&:to_s) - exclude.map(&:to_s)
288
- vars.each { |name| instance_variable_set(name, object.instance_variable_get(name)) }
289
- end
347
+ # Augments respond to supporting context_scope methods
348
+ def respond_to?(name, include_private = false)
349
+ context_scope.respond_to?(name, include_private) || super
350
+ end
290
351
 
291
- def cache_read_on_render
292
- @_cache_read_on_render = @_cache_read_on_render.nil? ? true : @_cache_read_on_render
293
- end
352
+ # Supports calling helpers defined for the template context_scope using method_missing hook
353
+ def method_missing(name, *args, &block)
354
+ context_scope.respond_to?(name, true) ? context_scope.__send__(name, *args, &block) : super
355
+ end
294
356
 
295
- private
296
-
297
- # Resets the options parsed from a rabl template.
298
- def reset_options!(scope)
299
- @_options[:attributes] = {}
300
- @_options[:node] = []
301
- @_options[:child] = []
302
- @_options[:glue] = []
303
- @_options[:extends] = []
304
- @_options[:root_name] = nil
305
- @_options[:read_multi] = false
306
- @_options[:scope] = scope
307
- end
357
+ def copy_instance_variables_from(object, exclude = []) #:nodoc:
358
+ vars = object.instance_variables.map(&:to_s) - exclude.map(&:to_s)
359
+ vars.each { |name| instance_variable_set(name, object.instance_variable_get(name)) }
360
+ end
308
361
 
309
- # Caches the results of the block based on object cache_key
310
- # cache_results { compile_hash(options) }
311
- def cache_results(&block)
312
- _cache = @_cache if defined?(@_cache)
313
- cache_key, cache_options = *_cache || nil
314
- if template_cache_configured? && cache_key
315
- result_cache_key = if digestor_available?
316
- cache_key_with_digest(cache_key)
317
- else # fallback for Rails 3, and Non-Rails app
318
- cache_key_simple(cache_key)
319
- end
362
+ def reset_settings!
363
+ @_settings[:attributes] = []
364
+ @_settings[:node] = []
365
+ @_settings[:child] = []
366
+ @_settings[:glue] = []
367
+ @_settings[:extends] = []
368
+ end
369
+
370
+ # Resets the options parsed from a rabl template.
371
+ def reset_options!
372
+ @_options[:root_name] = nil
373
+ @_options[:read_multi] = false
374
+ @_options[:scope] = context_scope
375
+ end
320
376
 
321
- if self.cache_read_on_render
322
- fetch_result_from_cache(result_cache_key, cache_options, &block)
377
+ # Caches the results of the block based on object cache_key
378
+ # cache_results { compile_hash(options) }
379
+ def cache_results(&block)
380
+ return yield unless template_cache_configured? && defined?(@_cache_key)
381
+
382
+ if cache_read_on_render?
383
+ fetch_result_from_cache(cache_key, @_cache_options, &block)
323
384
  else
324
- write_result_to_cache(result_cache_key, cache_options, &block)
385
+ write_result_to_cache(cache_key, @_cache_options, &block)
325
386
  end
326
- else # skip caching
327
- yield
328
387
  end
329
- end
330
388
 
331
- # Uses read_multi to render a collection of cache keys,
332
- # falling back to a normal render in the event of a miss.
333
- def read_multi(*data)
334
- options = data.extract_options!
335
- builder = Rabl::MultiBuilder.new(data, options)
336
- builder.to_a
337
- end
338
-
339
- def digestor_available?
340
- defined?(Rails) && Rails.version =~ /^[4]/
341
- end
389
+ def digestor_available?
390
+ defined?(Rails) && Rails.version =~ /^[4]/
391
+ end
342
392
 
343
- def cache_key_with_digest(cache_key)
344
- template = @_options[:template] || @virtual_path
393
+ def set_instance_variables!(context_scope, locals)
394
+ @_context_scope = context_scope
395
+ @_locals = locals
345
396
 
346
- if Gem::Version.new(Rails.version) >= Gem::Version.new('4.1')
347
- digested = Digestor.digest(:name => template, :finder => lookup_context)
348
- else
349
- digested = Digestor.digest(template, :rabl, lookup_context)
350
- end
397
+ copy_instance_variables_from(context_scope, [:@assigns, :@helpers])
351
398
 
352
- Array(cache_key) + [
353
- @_options[:root_name],
354
- @_options[:format],
355
- digested
356
- ]
357
- rescue NameError => e # Handle case where lookup_context doesn't exist
358
- raise e unless e.message =~ /lookup_context/
359
- cache_key_simple(cache_key)
360
- end # cache_key_with_digest
361
-
362
- def cache_key_simple(key)
363
- Array(key) + [@_options[:root_name], @_options[:format]]
364
- end
399
+ @_options[:format] ||= request_format
365
400
 
366
- def set_instance_variables!(scope, locals, &block)
367
- @_locals, @_scope = locals, scope
368
- self.copy_instance_variables_from(@_scope, [:@assigns, :@helpers])
369
- @_options[:format] ||= self.request_format
370
- set_locals(locals)
371
- set_source(locals, &block)
372
- end
401
+ set_locals(locals)
402
+ end
373
403
 
374
- def set_locals(locals)
375
- locals.merge!(locals.delete(:locals) || {})
376
- locals.each { |k,v| instance_variable_set(:"@#{k}", v) }
377
- end
404
+ def set_locals(locals)
405
+ locals.merge!(locals.delete(:locals) || {})
406
+ locals.each { |key, value| instance_variable_set(:"@#{key}", value) }
407
+ end
378
408
 
379
- def set_source(locals, &block)
380
- return unless @_source.present?
409
+ def eval_source(locals, &block)
410
+ # Note: locals and block may be used by the eval'ed source
411
+
412
+ return unless @_source.present?
381
413
 
382
- if @_options[:source_location]
383
- instance_eval(@_source, @_options[:source_location])
384
- else # without source location
385
- instance_eval(@_source)
414
+ if @_options[:source_location]
415
+ instance_eval(@_source, @_options[:source_location])
416
+ else
417
+ instance_eval(@_source)
418
+ end
386
419
  end
387
420
  end
388
- end
389
421
  end