rabl 0.5.5.e → 0.5.5.f

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.
@@ -1,11 +1,14 @@
1
1
  # CHANGELOG
2
2
 
3
- ## 0.5.5.a-e
3
+ ## 0.5.5.a-f
4
4
 
5
5
  * Change engine to only instantiate one builder when rendering a collection
6
6
  * Alias to\_msgpack to to\_mpac
7
7
  * Cache template sources for faster partial lookups (thanks cj)
8
8
  * Adds BSON format support (thanks Antiarchitect)
9
+ * Use template lookup mechanism to find templates in Rails 3 (thanks blakewatters)
10
+ * Adds a 'object_root' option to collection (thanks blakewatters)
11
+ * Adds a 'root_name' option to collection
9
12
 
10
13
  ## 0.5.4
11
14
 
data/README.md CHANGED
@@ -165,7 +165,9 @@ To enable, include the bson gem in your project's Gemfile. Then use Rabl as norm
165
165
  # Gemfile
166
166
  gem 'bson', '~> 1.5.2'
167
167
  ```
168
- To use it with Rails just register bson mime type format.
168
+
169
+ To use it with Rails, also register the bson mime type format:
170
+
169
171
  ```ruby
170
172
  # config/initializers/mime_types.rb
171
173
  Mime::Type.register "application/bson", :bson
@@ -214,13 +216,20 @@ collection @users
214
216
  # => [ { "user" : { ... } } ]
215
217
  ```
216
218
 
217
- or even specify a root node label for the collection:
219
+ or specify a root node label for the collection:
218
220
 
219
221
  ```ruby
220
222
  collection @users => :people
221
223
  # => { "people" : [ { "person" : { ... } } ] }
222
224
  ```
223
225
 
226
+ or even specify both the child and root labels for a collection:
227
+
228
+ ```ruby
229
+ collection @users, :root_name => "people", :object_root => "user"
230
+ # => { "people" : [ { "user" : { ... } } ] }
231
+ ```
232
+
224
233
  and this will be used as the default data for the rendering.
225
234
 
226
235
  There can also be odd cases where the root-level of the response doesn't map directly to any object:
@@ -3,25 +3,26 @@ module Rabl
3
3
  include Rabl::Partials
4
4
 
5
5
  # Constructs a new rabl hash based on given object and options
6
- # options = { :format => "json", :attributes, :root => true,
7
- # :child_root => true, :node, :child, :glue, :extends }
6
+ # options = { :format => "json", :root => true, :child_root => true,
7
+ # :attributes, :node, :child, :glue, :extends }
8
+ #
8
9
  def initialize(options={}, &block)
9
10
  @options = options
10
11
  @_scope = options[:scope]
11
12
  end
12
13
 
13
14
  # Given an object and options, returns the hash representation
14
- # build(@user, :format => "json", :attributes => { ... })
15
- def build(data, options={})
16
- @_data = data
17
- @_object = data_object(data)
15
+ # build(@user, :format => "json", :attributes => { ... }, :root_name => "user")
16
+ def build(object, options={})
17
+ @_object = object
18
18
  compile_hash(options)
19
19
  end
20
20
 
21
21
  protected
22
22
 
23
23
  # Returns a hash representation of the data object
24
- # compile_hash(:root => true)
24
+ # compile_hash(:root_name => false)
25
+ # compile_hash(:root_name => "user")
25
26
  def compile_hash(options={})
26
27
  @_result = {}
27
28
  # Extends
@@ -46,8 +47,8 @@ module Rabl
46
47
  end if @options.has_key?(:glue)
47
48
 
48
49
  # Wrap result in root
49
- if @options[:root] || options[:root]
50
- @_root_name ||= data_name(@_data)
50
+ if options[:root_name].present?
51
+ @_root_name = options[:root_name]
51
52
  else # no root
52
53
  @_root_name = nil
53
54
  end
@@ -31,17 +31,15 @@ module Rabl
31
31
  # to_hash(:root => true, :child_root => true)
32
32
  def to_hash(options={})
33
33
  options = @_options.merge(options)
34
- data = data_object(@_data)
34
+ data, root_name = data_object(@_data), data_name(@_data)
35
35
  builder = Rabl::Builder.new(options)
36
36
  if is_object?(data) || !data # object @user
37
- builder.build(@_data, options)
37
+ options[:root_name] = root_name if options[:root]
38
+ builder.build(data, options)
38
39
  elsif is_collection?(data) # collection @users
39
- if options[:root] # only calculate root name if needed
40
- object_name = data_name(@_data).to_s.singularize # @users => :users
41
- data.map { |object| builder.build({ object => object_name }, options) }
42
- else # skip root name
43
- data.map { |object| builder.build(object, options) }
44
- end
40
+ options[:root_name] = object_root_name if object_root_name
41
+ options[:root_name] ||= root_name.to_s.singularize if options[:root]
42
+ data.map { |object| builder.build(object, options) }
45
43
  end
46
44
  end
47
45
 
@@ -50,7 +48,7 @@ module Rabl
50
48
  def to_json(options={})
51
49
  include_root = Rabl.configuration.include_json_root
52
50
  options = options.reverse_merge(:root => include_root, :child_root => include_root)
53
- result = defined?(@_collection_name) ? { @_collection_name => to_hash(options) } : to_hash(options)
51
+ result = collection_root_name ? { collection_root_name => to_hash(options) } : to_hash(options)
54
52
  format_json(result)
55
53
  end
56
54
 
@@ -59,7 +57,7 @@ module Rabl
59
57
  def to_msgpack(options={})
60
58
  include_root = Rabl.configuration.include_msgpack_root
61
59
  options = options.reverse_merge(:root => include_root, :child_root => include_root)
62
- result = defined?(@_collection_name) ? { @_collection_name => to_hash(options) } : to_hash(options)
60
+ result = collection_root_name ? { collection_root_name => to_hash(options) } : to_hash(options)
63
61
  Rabl.configuration.msgpack_engine.pack result
64
62
  end
65
63
  alias_method :to_mpac, :to_msgpack
@@ -78,8 +76,8 @@ module Rabl
78
76
  def to_bson(options={})
79
77
  include_root = Rabl.configuration.include_bson_root
80
78
  options = options.reverse_merge(:root => include_root, :child_root => include_root)
81
- result = if defined?(@_collection_name)
82
- { @_collection_name => to_hash(options) }
79
+ result = if collection_root_name
80
+ { collection_root_name => to_hash(options) }
83
81
  elsif is_collection?(@_data) && @_data.is_a?(Array)
84
82
  { data_name(@_data) => to_hash(options) }
85
83
  else
@@ -99,8 +97,12 @@ module Rabl
99
97
  # Sets the object as a collection casted to a simple array
100
98
  # collection @users
101
99
  # collection @users => :people
102
- def collection(data)
103
- @_collection_name = data.values.first if data.respond_to?(:each_pair)
100
+ # collection @users, :root => :person
101
+ # collection @users, :object_root => :person
102
+ def collection(data, options={})
103
+ @_collection_name = options[:root] if options[:root]
104
+ @_collection_name ||= data.values.first if data.respond_to?(:each_pair)
105
+ @_object_root_name = options[:object_root] if options[:object_root]
104
106
  self.object(data_object(data).to_a) if data
105
107
  end
106
108
 
@@ -155,8 +157,8 @@ module Rabl
155
157
  # Returns a guess at the default object for this template
156
158
  # default_object => @user
157
159
  def default_object
158
- if @_scope.respond_to?(:controller)
159
- full_name = @_scope.controller.controller_name
160
+ if context_scope.respond_to?(:controller)
161
+ full_name = context_scope.controller.controller_name
160
162
  instance_variable_get("@#{ full_name.split("::").last }")
161
163
  end
162
164
  end
@@ -164,8 +166,8 @@ module Rabl
164
166
  # Returns a guess at the format in this scope
165
167
  # request_format => "xml"
166
168
  def request_format
167
- format = self.request_params.has_key?(:format) ? @_scope.params[:format] : nil
168
- if request = @_scope.respond_to?(:request) && @_scope.request
169
+ format = self.request_params.has_key?(:format) ? context_scope.params[:format] : nil
170
+ if request = context_scope.respond_to?(:request) && context_scope.request
169
171
  format ||= request.format.to_sym.to_s if request.respond_to?(:format)
170
172
  end
171
173
  format && self.respond_to?("to_#{format}") ? format : "json"
@@ -174,7 +176,7 @@ module Rabl
174
176
  # Returns the request parameters if available in the scope
175
177
  # request_params => { :foo => "bar" }
176
178
  def request_params
177
- @_scope.respond_to?(:params) ? @_scope.params : {}
179
+ context_scope.respond_to?(:params) ? context_scope.params : {}
178
180
  end
179
181
 
180
182
  # Returns data as json embraced with callback when detected
@@ -188,12 +190,12 @@ module Rabl
188
190
 
189
191
  # Augments respond to supporting scope methods
190
192
  def respond_to?(name, include_private=false)
191
- @_scope.respond_to?(name, include_private) ? true : super
193
+ context_scope.respond_to?(name, include_private) ? true : super
192
194
  end
193
195
 
194
196
  # Supports calling helpers defined for the template scope using method_missing hook
195
197
  def method_missing(name, *args, &block)
196
- @_scope.respond_to?(name) ? @_scope.send(name, *args, &block) : super
198
+ context_scope.respond_to?(name) ? context_scope.send(name, *args, &block) : super
197
199
  end
198
200
 
199
201
  def copy_instance_variables_from(object, exclude = []) #:nodoc:
@@ -210,6 +212,7 @@ module Rabl
210
212
  @_options[:child] = []
211
213
  @_options[:glue] = []
212
214
  @_options[:extends] = []
215
+ @_options[:root_name] = nil
213
216
  end
214
217
  end
215
218
  end
@@ -23,7 +23,8 @@ module Rabl
23
23
  if data.respond_to?(:first)
24
24
  data_name(data.first).to_s.pluralize if data.first.present?
25
25
  else # actual data object
26
- object_name = @_collection_name.to_s.singularize if defined? @_collection_name
26
+ object_name = object_root_name if object_root_name
27
+ object_name ||= collection_root_name.to_s.singularize if collection_root_name
27
28
  object_name ||= data.class.respond_to?(:model_name) ? data.class.model_name.element : data.class.to_s.downcase
28
29
  object_name
29
30
  end
@@ -42,5 +43,25 @@ module Rabl
42
43
  obj && data_object(obj).respond_to?(:each)
43
44
  end
44
45
 
46
+ # Returns the scope wrapping this engine, used for retrieving data, invoking methods, etc
47
+ # In Rails, this is the controller and in Padrino this is the request context
48
+ def context_scope
49
+ defined?(@_scope) ? @_scope : nil
50
+ end
51
+
52
+ # Returns the root (if any) name for an object within a collection
53
+ # Sets the name of the object i.e "person"
54
+ # => { "users" : [{ "person" : {} }] }
55
+ def object_root_name
56
+ defined?(@_object_root_name) ? @_object_root_name : nil
57
+ end
58
+
59
+ # Returns the root for the collection
60
+ # Sets the name of the collection i.e "people"
61
+ # => { "people" : [] }
62
+ def collection_root_name
63
+ defined?(@_collection_name) ? @_collection_name : nil
64
+ end
65
+
45
66
  end
46
67
  end
@@ -7,6 +7,7 @@ module Rabl
7
7
  # options must have :object
8
8
  # options can have :view_path, :child_root, :root
9
9
  def partial(file, options={}, &block)
10
+ raise ArgumentError, "Must provide an :object option to render a partial" unless options[:object]
10
11
  object, view_path = options.delete(:object), options.delete(:view_path)
11
12
  source, location = self.fetch_source(file, :view_path => view_path)
12
13
  engine_options = options.merge(:source => source, :source_location => location)
@@ -35,9 +36,16 @@ module Rabl
35
36
  # Padrino chops the extension, stitch it back on
36
37
  file_path = File.join(@_scope.settings.views, (file_path.to_s + ".rabl"))
37
38
  elsif defined? Rails
38
- root_path = Rails.root
39
- view_path = options[:view_path] || File.join(root_path, "app/views/")
40
- file_path = Dir[File.join(view_path, file + ".{*.,}rabl")].first
39
+ if defined?(@_scope) && @_scope.respond_to?(:find_template)
40
+ # use Rails's own template resolution mechanism (partials and no partial)
41
+ lookup_proc = lambda { |partial| @_scope.find_template(file, [], partial) }
42
+ template = lookup_proc.call(false) rescue lookup_proc.call(true)
43
+ file_path = File.join(Rails.root.to_s, template.inspect) if template
44
+ else # fallback to manual
45
+ root_path = Rails.root
46
+ view_path = options[:view_path] || File.join(root_path, "app/views/")
47
+ file_path = Dir[File.join(view_path, file + ".{*.,}rabl")].first
48
+ end
41
49
  elsif defined? Sinatra
42
50
  view_path = options[:view_path] || @_scope.settings.views
43
51
  file_path = Dir[File.join(view_path, file + ".{*.,}rabl")].first
@@ -1,3 +1,3 @@
1
1
  module Rabl
2
- VERSION = "0.5.5.e"
2
+ VERSION = "0.5.5.f"
3
3
  end
@@ -28,7 +28,7 @@ context "Rabl::Builder" do
28
28
 
29
29
  setup { builder({ :attributes => { :name => :name } }) }
30
30
  asserts "that the object is set properly" do
31
- topic.build(User.new, :root => true)
31
+ topic.build(User.new, :root_name => "user")
32
32
  end.equivalent_to({ "user" => { :name => "rabl" } })
33
33
 
34
34
  end
@@ -37,7 +37,7 @@ context "Rabl::Builder" do
37
37
 
38
38
  setup { builder({ :attributes => { :name => :name } }) }
39
39
  asserts "that the object is set properly" do
40
- topic.build({ User.new => "person" }, :root => true)
40
+ topic.build(User.new, :root_name => "person")
41
41
  end.equivalent_to({ "person" => { :name => "rabl" } })
42
42
 
43
43
  end
@@ -263,15 +263,32 @@ context "Rabl::Engine" do
263
263
  template.render(scope)
264
264
  end.equals "[{},{}]"
265
265
 
266
- asserts "that it sets root node for objects" do
266
+ asserts "that it sets root node for objects using hash" do
267
267
  template = rabl %{
268
- collection @users => :person
268
+ collection @users => :people
269
269
  }
270
270
  scope = Object.new
271
271
  scope.instance_variable_set :@users, [User.new, User.new]
272
272
  template.render(scope)
273
- end.equals "{\"person\":[{},{}]}"
273
+ end.equals "{\"people\":[{},{}]}"
274
274
 
275
+ asserts "that it sets root node for objects using root option" do
276
+ template = rabl %{
277
+ collection @users, :root => :people
278
+ }
279
+ scope = Object.new
280
+ scope.instance_variable_set :@users, [User.new, User.new]
281
+ template.render(scope)
282
+ end.equals "{\"people\":[{},{}]}"
283
+
284
+ asserts "that it sets root node for objects using object_root option" do
285
+ template = rabl %{
286
+ collection @users, :root => :humans, :object_root => :person
287
+ }
288
+ scope = Object.new
289
+ scope.instance_variable_set :@users, [User.new, User.new]
290
+ template.render(scope)
291
+ end.equals %Q^{"humans":[{"person":{}},{"person":{}}]}^
275
292
  end
276
293
 
277
294
  context "#attribute" do
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rabl
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 6
5
- version: 0.5.5.e
5
+ version: 0.5.5.f
6
6
  platform: ruby
7
7
  authors:
8
8
  - Nathan Esquenazi