Class: Rabl::Engine

Inherits:
Object
  • Object
show all
Includes:
Helpers, Helpers::Escaper, Partials
Defined in:
lib/rabl/engine.rb

Constant Summary collapse

FORMATS =

List of supported rendering formats

[:json, :xml, :plist, :bson, :msgpack]
SAFE_FORMATS =
FORMATS + [:mpac, :dumpable, :hash]

Instance Method Summary collapse

Methods included from Helpers::Escaper

#escape_output, #escape_value

Methods included from Partials

#partial_as_engine

Methods included from Sources

#fetch_source

Methods included from Helpers

#collection_root_name, #context_scope, #data_name, #data_object, #data_object_attribute, #determine_object_root, #fetch_result_from_cache, #is_collection?, #is_name_value?, #is_object?, #object_root_name, #object_to_engine, #template_cache_configured?, #view_path, #write_result_to_cache

Constructor Details

#initialize(source, options = {}) ⇒ Engine

Constructs a new ejs engine based on given vars, handler and declarations Rabl::Engine.new(“…source…”, { :format => “xml”, :root => true, :view_path => “/path/to/views” })



13
14
15
16
17
18
19
20
21
22
# File 'lib/rabl/engine.rb', line 13

def initialize(source, options = {})
  @_source        = source
  @_settings      = {}
  @_options       = options

  @_view_path     = options[:view_path]
  @_context_scope = options[:scope]

  @_cache_read_on_render = true
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, **kwargs, &block) ⇒ Object (protected)

Supports calling helpers defined for the template context_scope using method_missing hook



359
360
361
362
363
364
365
366
367
# File 'lib/rabl/engine.rb', line 359

def method_missing(name, *args, **kwargs, &block)
  return super unless context_scope.respond_to?(name, true)

  if kwargs.empty?
    context_scope.__send__(name, *args, &block)
  else
    context_scope.__send__(name, *args, **kwargs, &block)
  end
end

Instance Method Details

#apply(context_scope, locals, &block) ⇒ Object

Renders the representation based on source, object, context_scope and locals Rabl::Engine.new(“…source…”, { :format => “xml” }).apply(context_scope, { :foo => “bar”, :object => @user })



30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/rabl/engine.rb', line 30

def apply(context_scope, locals, &block)
  locals = locals.dup unless locals.nil?

  set_instance_variables!(context_scope, locals)

  reset_settings!
  reset_options!

  eval_source(locals, &block)

  instance_exec(root_object, &block) if block_given?

  self
end

#attribute(*args) ⇒ Object Also known as: attributes

Indicates an attribute or method should be included in the json output attribute :foo, :as => “bar” attribute :foo => :bar, :bar => :baz attribute :foo => :bar, :bar => :baz, :if => lambda { |r| r.foo }



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/rabl/engine.rb', line 230

def attribute(*args)
  if args.first.is_a?(Hash) # :foo => :bar, :bar => :baz
    attr_aliases  = args.first.except(:if, :unless)
    conditions    = args.first.slice(:if, :unless)

    attr_aliases.each do |key, as|
      attribute(key, conditions.merge(:as => as))
    end
  else # array of attributes i.e :foo, :bar, :baz
    options = args.extract_options!
    args.each do |name|
      @_settings[:attributes] << { :name => name, :options => options }
    end
  end
end

#cache(key = nil, options = {}) ⇒ Object

Sets the cache key to be used by ActiveSupport::Cache.expand_cache_key cache @user # calls @user.cache_key cache [‘rabl’, @user] # calls @user.cache_key and prefixes with rabl/ cache ‘user’ # explicit key of ‘user’ cache # uses the current item within a collection cache ‘user’, expires_in: 1.hour options is passed through to the cache store



220
221
222
223
224
# File 'lib/rabl/engine.rb', line 220

def cache(key = nil, options = {})
  key ||= root_object # if called but missing, use object
  @_cache_key     = key
  @_cache_options = options
end

#cache_keyObject



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rabl/engine.rb', line 55

def cache_key
  return unless defined?(@_cache_key)

  @_full_cache_key ||= begin
    cache_key = Array(@_cache_key) + [@_options[:root_name], @_options[:format]]

    if digestor_available? && respond_to?(:lookup_context) && lookup_context
      template = @_options[:template] || @virtual_path

      digest =
        if Rails.version.to_s =~ /^[678]/
          Digestor.digest(name: template, finder: lookup_context, format: :rabl)
        elsif Gem::Version.new(Rails.version) >= Gem::Version.new('4.1')
          Digestor.digest(:name => template, :finder => lookup_context)
        else
          Digestor.digest(template, :rabl, lookup_context)
        end

      cache_key << digest
    end

    cache_key
  end
end

#cache_read_on_render=(read) ⇒ Object

Disables reading (but not writing) from the cache when rendering.



293
294
295
# File 'lib/rabl/engine.rb', line 293

def cache_read_on_render=(read)
  @_cache_read_on_render = read
end

#cache_read_on_render?Boolean

Returns:

  • (Boolean)


297
298
299
# File 'lib/rabl/engine.rb', line 297

def cache_read_on_render?
  @_cache_read_on_render
end

#child(data, options = {}, &block) ⇒ Object

Creates a child node that is included in json output child(@user) { attribute :full_name }



257
258
259
# File 'lib/rabl/engine.rb', line 257

def child(data, options = {}, &block)
  @_settings[:child] << { :data => data, :options => options, :block => block }
end

#collection(data, options = {}) ⇒ Object

Sets the object as a collection casted to a simple array collection @users collection @users => :people collection @users, :root => :person collection @users, :object_root => :person



204
205
206
207
208
209
210
211
# File 'lib/rabl/engine.rb', line 204

def collection(data, options = {})
  @_collection_name = options[:root] if options[:root]
  @_collection_name ||= data.values.first if data.is_a?(Hash)

  @_object_root_name = options[:object_root] if options.has_key?(:object_root)

  object(data_object(data) || [])
end

#extends(file, options = {}, &block) ⇒ Object

Extends an existing rabl template with additional attributes in the block extends(“users/show”, :object => @user) { attribute :full_name }



269
270
271
272
273
# File 'lib/rabl/engine.rb', line 269

def extends(file, options = {}, &block)
  options.reverse_merge!({ :view_path => options[:view_path] || view_path })

  @_settings[:extends] << { :file => file, :options => options, :block => block }
end

#glue(data, options = {}, &block) ⇒ Object

Glues data from a child node to the json_output glue(@user) { attribute :full_name => :user_full_name }



263
264
265
# File 'lib/rabl/engine.rb', line 263

def glue(data, options = {}, &block)
  @_settings[:glue] << { :data => data, :options => options, :block => block }
end

#helper(*klasses) ⇒ Object Also known as: helpers

Includes a helper module with a RABL template helper ExampleHelper



277
278
279
# File 'lib/rabl/engine.rb', line 277

def helper(*klasses)
  klasses.each { |klass| self.class.__send__(:include, klass) }
end

#node(name = nil, options = {}, &block) ⇒ Object Also known as: code

Creates an arbitrary node that is included in the json output. node(:foo) { “bar” } node(:foo, :if => lambda { … }) { “bar” }



250
251
252
# File 'lib/rabl/engine.rb', line 250

def node(name = nil, options = {}, &block)
  @_settings[:node] << { :name => name, :options => options, :block => block }
end

#object(template_data) ⇒ Object

Sets the object to be used as the data source for this template object(@user) object @user => :person object @users



166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/rabl/engine.rb', line 166

def object(template_data)
  current_data  = (@_locals[:object].nil? || template_data == false) ? template_data : @_locals[:object]
  @_data_object = data_object(current_data)
  @_root_name_data = template_data.is_a?(Hash) && !current_data.is_a?(Hash) ? template_data : current_data
  @_root_name_data = @_root_name_data.values.first if @_root_name_data.is_a?(Hash)

  # If we turn this around, `@_root_name_date ==` may trigger data to be loaded unnecessarily.
  # TODO: is nil a different semantic? otherwise don't use `false ==`, use !
  if false == @_root_name_data
    @_object_root_name = false
    @_collection_name = false
  end
end

#partial(file, options = {}, &block) ⇒ Object

Returns a hash representing the partial partial(“users/show”, :object => @user) options must have :object options can have :view_path, :child_root, :root



286
287
288
289
290
# File 'lib/rabl/engine.rb', line 286

def partial(file, options = {}, &block)
  engine = partial_as_engine(file, options, &block)
  engine = engine.render if engine.is_a?(Engine)
  engine
end

#render(context_scope = nil, locals = nil, &block) ⇒ Object

Renders the representation based on a previous apply Rabl::Engine.new(“…source…”, { :format => “xml” }).apply(context_scope, { :foo => “bar”, :object => @user }).render



47
48
49
50
51
52
53
# File 'lib/rabl/engine.rb', line 47

def render(context_scope = nil, locals = nil, &block)
  apply(context_scope, locals, &block) if context_scope || locals || block

  cache_results do
    send("to_#{@_options[:format]}")
  end
end

#root_nameObject



190
191
192
193
194
195
196
197
# File 'lib/rabl/engine.rb', line 190

def root_name
  return @_data_name if defined?(@_data_name)

  @_data_name = @_options[:object_root_name] || begin
    data = defined?(@_root_name_data) ? @_root_name_data : (@_locals[:object].nil? ? root_object : @_locals[:object])
    data_name(data)
  end
end

#root_objectObject

Returns the current object that is the topic of this template Can be the collection or the object depending on topic assigned root_object => @user



183
184
185
186
187
188
# File 'lib/rabl/engine.rb', line 183

def root_object
  return @_data_object if defined?(@_data_object)

  data = @_locals[:object].nil? ? default_object : @_locals[:object]
  @_data_object = data_object(data)
end

#source=(source) ⇒ Object



24
25
26
# File 'lib/rabl/engine.rb', line 24

def source=(source)
  @_source = source
end

#to_bson(options = {}) ⇒ Object

Returns a bson representation of the data object to_bson(:root => true)



151
152
153
154
155
156
157
158
159
160
# File 'lib/rabl/engine.rb', line 151

def to_bson(options = {})
  options = { :root => Rabl.configuration.include_bson_root }.merge(options)
  result = to_dumpable(options)

  if !collection_root_name && is_collection?(root_object) && root_object.is_a?(Array)
    result = { root_name => result }
  end

  Rabl.configuration.bson_engine.serialize(result).to_s
end

#to_dumpable(options = {}) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/rabl/engine.rb', line 101

def to_dumpable(options = {})
  options.reverse_merge!({ :child_root => Rabl.configuration.include_child_root })

  result = to_hash(options)
  result = { collection_root_name => result } if collection_root_name
  result
end

#to_hash(options = {}) ⇒ Object

Returns a hash representation of the data object to_hash(:root => true, :child_root => true)



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/rabl/engine.rb', line 82

def to_hash(options = {})
  options.reverse_merge!(@_options)

  data = root_object

  options[:root_name] = determine_object_root(data, root_name, options[:root])

  result =
    if is_object?(data) || !data # object @user
      Builder.new(data, @_settings, options).to_hash
    elsif is_collection?(data) # collection @users
      MultiBuilder.new(data, @_settings, options).to_a
    end

  result = escape_output(result) if Rabl.configuration.escape_all_output

  result
end

#to_json(options = {}) ⇒ Object

Returns a json representation of the data object to_json(:root => true)



111
112
113
114
115
# File 'lib/rabl/engine.rb', line 111

def to_json(options = {})
  options.reverse_merge!({ :root => Rabl.configuration.include_json_root })
  result = to_dumpable(options)
  format_json(result)
end

#to_msgpack(options = {}) ⇒ Object Also known as: to_mpac

Returns a msgpack representation of the data object to_msgpack(:root => true)



119
120
121
122
123
# File 'lib/rabl/engine.rb', line 119

def to_msgpack(options = {})
  options = { :root => Rabl.configuration.include_msgpack_root }.merge(options)
  result = to_dumpable(options)
  Rabl.configuration.msgpack_engine.pack(result)
end

#to_plist(options = {}) ⇒ Object

Returns a plist representation of the data object to_plist(:root => true)



128
129
130
131
132
# File 'lib/rabl/engine.rb', line 128

def to_plist(options = {})
  options = { :root => Rabl.configuration.include_plist_root }.merge(options)
  result = to_dumpable(options)
  Rabl.configuration.plist_engine.dump(result)
end

#to_xml(options = {}) ⇒ Object

Returns an xml representation of the data object to_xml(:root => true)



136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/rabl/engine.rb', line 136

def to_xml(options = {})
  options = {
    :root       => (include_root = Rabl.configuration.include_xml_root),
    :child_root => include_root && Rabl.configuration.include_child_root
  }.merge(options)

  xml_options = Rabl.configuration.default_xml_options.merge(:root => collection_root_name || root_name)

  result = to_hash(options)

  result.to_xml(xml_options)
end