rabl 0.7.6 → 0.7.7
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.
- data/CHANGELOG.md +7 -1
- data/CONTRIBUTING.md +37 -0
- data/README.md +16 -1
- data/fixtures/rails3_2/Gemfile +1 -1
- data/lib/rabl.rb +1 -0
- data/lib/rabl/builder.rb +6 -4
- data/lib/rabl/engine.rb +7 -5
- data/lib/rabl/helpers.rb +8 -2
- data/lib/rabl/version.rb +1 -1
- data/test/builder_test.rb +5 -5
- data/test/engine_test.rb +56 -1
- data/test/helpers_test.rb +18 -8
- metadata +3 -2
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
-
## 0.7.
|
3
|
+
## 0.7.8 (unreleased)
|
4
|
+
|
5
|
+
## 0.7.7
|
6
|
+
|
7
|
+
* Fix #344 to avoid: "warning: default `to_a' will be obsolete"
|
8
|
+
* Fix #356 by adding 'known object classes' like struct to be recognized as objects.
|
9
|
+
* Fix #354 by adding 'if' and 'unless' to `attribute` (Thanks @andrewhubbs)
|
4
10
|
|
5
11
|
## 0.7.6
|
6
12
|
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
We love pull requests. Here's a quick guide:
|
2
|
+
|
3
|
+
1. Fork the repo.
|
4
|
+
|
5
|
+
2. Run the tests. We only take pull requests with passing tests, and it's great
|
6
|
+
to know that you have a clean slate: `bundle && rake test`
|
7
|
+
|
8
|
+
3. Add a test for your change. Only refactoring and documentation changes
|
9
|
+
require no new tests. If you are adding functionality or fixing a bug, we need
|
10
|
+
a test!
|
11
|
+
|
12
|
+
4. Make the test pass.
|
13
|
+
|
14
|
+
5. Push to your fork and submit a pull request.
|
15
|
+
|
16
|
+
At this point you're waiting on us. We like to at least comment on, if not
|
17
|
+
accept, pull requests within three business days (and, typically, one business
|
18
|
+
day). We may suggest some changes or improvements or alternatives.
|
19
|
+
|
20
|
+
Some things that will increase the chance that your pull request is accepted:
|
21
|
+
|
22
|
+
* Use Rails idioms and helpers
|
23
|
+
* Include tests that fail without your code, and pass with it
|
24
|
+
* Update the documentation and README for anything affected by your contribution
|
25
|
+
|
26
|
+
Syntax:
|
27
|
+
|
28
|
+
* Two spaces, no tabs.
|
29
|
+
* No trailing whitespace. Blank lines should not have any space.
|
30
|
+
* Prefer &&/|| over and/or.
|
31
|
+
* MyClass.my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
|
32
|
+
* a = b and not a=b.
|
33
|
+
* Follow the conventions you see used in the source already.
|
34
|
+
|
35
|
+
And in case we didn't emphasize it enough: we love tests!
|
36
|
+
|
37
|
+
NOTE: Adapted from https://raw.github.com/thoughtbot/factory_girl_rails/master/CONTRIBUTING.md
|
data/README.md
CHANGED
@@ -106,6 +106,7 @@ RABL is intended to require little to no configuration to get working. This is t
|
|
106
106
|
|
107
107
|
```ruby
|
108
108
|
# config/initializers/rabl_init.rb
|
109
|
+
require 'rabl'
|
109
110
|
Rabl.configure do |config|
|
110
111
|
# Commented as these are defaults
|
111
112
|
# config.cache_all_output = false
|
@@ -253,6 +254,13 @@ attributes :bar => :baz, :dog => :animal
|
|
253
254
|
# => # { baz : <bar value>, animal : <dog value> }
|
254
255
|
```
|
255
256
|
|
257
|
+
or show attributes only if a condition is true:
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
# m is the object being rendered, also supports :unless
|
261
|
+
attributes :foo, :bar, :if => lambda { |m| m.condition? }
|
262
|
+
```
|
263
|
+
|
256
264
|
Named and aliased attributes can not be combined on the same line. This currently does not work:
|
257
265
|
|
258
266
|
```ruby
|
@@ -495,16 +503,19 @@ Rails and Padrino. I recommend a before_filter on that controller or directly sp
|
|
495
503
|
## Resources ##
|
496
504
|
|
497
505
|
There are many resources available relating to RABL including the [RABL Wiki](https://github.com/nesquena/rabl/wiki),
|
498
|
-
and many tutorials and guides detailed below.
|
506
|
+
and many tutorials and guides detailed below.
|
507
|
+
You can check out the [RABL Site](http://nesquena.github.com/rabl) as well.
|
499
508
|
|
500
509
|
### Advanced Usage ###
|
501
510
|
|
502
511
|
Links to resources for advanced usage:
|
503
512
|
|
513
|
+
* Production Speed Optimizations: https://github.com/nesquena/rabl/wiki/Rabl-In-Production
|
504
514
|
* Grape Integration: https://github.com/nesquena/rabl/wiki/Using-Rabl-with-Grape
|
505
515
|
* Rendering JSON for a tree structure using RABL: https://github.com/nesquena/rabl/issues/70
|
506
516
|
* Layouts (erb, haml and rabl) in RABL: https://github.com/nesquena/rabl/wiki/Using-Layouts
|
507
517
|
* Backbone or [Ember.js](http://www.emberjs.com) Integration: https://github.com/nesquena/rabl/wiki/Backbone-Integration
|
518
|
+
* RABL with Rails Engines: https://github.com/nesquena/rabl/wiki/Setup-rabl-with-rails-engines
|
508
519
|
|
509
520
|
Please add your own usages and let me know so we can add them here! Also be sure to check out
|
510
521
|
the [RABL Wiki](https://github.com/nesquena/rabl/wiki) for other usages.
|
@@ -531,6 +542,8 @@ Let me know if there's any other useful resources not listed here.
|
|
531
542
|
There are other libraries that can either complement or extend the functionality of RABL:
|
532
543
|
|
533
544
|
* [gon](https://github.com/gazay/gon) - Exposes your Rails variables in JS with RABL support integrated.
|
545
|
+
* [rabl-rails](https://github.com/ccocchi/rabl-rails) - Reimplementation for RABL and Rails
|
546
|
+
[focused on speed](https://github.com/ccocchi/rabl-benchmark/blob/master/BENCHMARK).
|
534
547
|
|
535
548
|
Let me know if there's any other related libraries not listed here.
|
536
549
|
|
@@ -581,6 +594,8 @@ Check out the patches for [msgpack support](https://github.com/nesquena/rabl/pul
|
|
581
594
|
|
582
595
|
Please fork and contribute, any help in making this project better is appreciated!
|
583
596
|
|
597
|
+
This project is a member of the [OSS Manifesto](http://ossmanifesto.org).
|
598
|
+
|
584
599
|
## Inspirations ##
|
585
600
|
|
586
601
|
There are a few excellent libraries that helped inspire RABL and they are listed below:
|
data/fixtures/rails3_2/Gemfile
CHANGED
data/lib/rabl.rb
CHANGED
@@ -2,6 +2,7 @@ require 'active_support'
|
|
2
2
|
require 'active_support/core_ext/string/inflections'
|
3
3
|
require 'active_support/core_ext/object/blank'
|
4
4
|
require 'active_support/core_ext/hash/reverse_merge'
|
5
|
+
require 'active_support/core_ext/hash/except'
|
5
6
|
require 'active_support/core_ext/hash/slice'
|
6
7
|
|
7
8
|
require 'rabl/version'
|
data/lib/rabl/builder.rb
CHANGED
@@ -34,8 +34,8 @@ module Rabl
|
|
34
34
|
extends(settings[:file], settings[:options], &settings[:block])
|
35
35
|
end if @options.has_key?(:extends)
|
36
36
|
# Attributes
|
37
|
-
@options[:attributes].each_pair do |attribute,
|
38
|
-
attribute(attribute,
|
37
|
+
@options[:attributes].each_pair do |attribute, options|
|
38
|
+
attribute(attribute, options)
|
39
39
|
end if @options.has_key?(:attributes)
|
40
40
|
# Node
|
41
41
|
@options[:node].each do |settings|
|
@@ -63,14 +63,16 @@ module Rabl
|
|
63
63
|
|
64
64
|
# Indicates an attribute or method should be included in the json output
|
65
65
|
# attribute :foo, :as => "bar"
|
66
|
+
# attribute :foo, :as => "bar", :if => lambda { |m| m.foo }
|
66
67
|
def attribute(name, options={})
|
67
|
-
|
68
|
+
if @_object && @_object.respond_to?(name) && resolve_condition(options)
|
69
|
+
@_result[options[:as] || name] = data_object_attribute(name)
|
70
|
+
end
|
68
71
|
end
|
69
72
|
alias_method :attributes, :attribute
|
70
73
|
|
71
74
|
# Creates an arbitrary node that is included in the json output
|
72
75
|
# node(:foo) { "bar" }
|
73
|
-
# node(:foo) { "bar" }
|
74
76
|
# node(:foo, :if => lambda { |m| m.foo.present? }) { "bar" }
|
75
77
|
def node(name, options={}, &block)
|
76
78
|
return unless resolve_condition(options)
|
data/lib/rabl/engine.rb
CHANGED
@@ -135,7 +135,7 @@ module Rabl
|
|
135
135
|
@_collection_name = options[:root] if options[:root]
|
136
136
|
@_collection_name ||= data.values.first if data.respond_to?(:each_pair)
|
137
137
|
@_object_root_name = options[:object_root] if options.has_key?(:object_root)
|
138
|
-
self.object(data_object(data)
|
138
|
+
self.object(Array(data_object(data)))
|
139
139
|
end
|
140
140
|
|
141
141
|
# Sets the cache key to be used by ActiveSupport::Cache.expand_cache_key
|
@@ -152,13 +152,15 @@ module Rabl
|
|
152
152
|
|
153
153
|
# Indicates an attribute or method should be included in the json output
|
154
154
|
# attribute :foo, :as => "bar"
|
155
|
-
# attribute :foo => :bar
|
155
|
+
# attribute :foo => :bar, :bar => :baz
|
156
|
+
# attribute :foo => :bar, :bar => :baz, :if => lambda { |r| r.foo }
|
156
157
|
def attribute(*args)
|
157
158
|
if args.first.is_a?(Hash) # :foo => :bar, :bar => :baz
|
158
|
-
args.first.
|
159
|
+
attr_aliases, conds = args.first.except(:if, :unless), args.first.slice(:if, :unless)
|
160
|
+
attr_aliases.each_pair { |k,v| self.attribute(k, conds.merge(:as => v)) }
|
159
161
|
else # array of attributes i.e :foo, :bar, :baz
|
160
|
-
|
161
|
-
args.each { |name| @_options[:attributes][name] =
|
162
|
+
attr_options = args.extract_options!
|
163
|
+
args.each { |name| @_options[:attributes][name] = attr_options }
|
162
164
|
end
|
163
165
|
end
|
164
166
|
alias_method :attributes, :attribute
|
data/lib/rabl/helpers.rb
CHANGED
@@ -2,6 +2,8 @@ require 'active_support/inflector' # for the sake of pluralizing
|
|
2
2
|
|
3
3
|
module Rabl
|
4
4
|
module Helpers
|
5
|
+
# Set of class names known to be objects, not collections
|
6
|
+
KNOWN_OBJECT_CLASSES = ['Struct']
|
5
7
|
|
6
8
|
# data_object(data) => <AR Object>
|
7
9
|
# data_object(@user => :person) => @user
|
@@ -55,12 +57,16 @@ module Rabl
|
|
55
57
|
# is_object?([]) => false
|
56
58
|
# is_object?({}) => false
|
57
59
|
def is_object?(obj)
|
58
|
-
obj && (!data_object(obj).respond_to?(:map) || !data_object(obj).respond_to?(:each)
|
60
|
+
obj && (!data_object(obj).respond_to?(:map) || !data_object(obj).respond_to?(:each) ||
|
61
|
+
(KNOWN_OBJECT_CLASSES & obj.class.ancestors.map(&:name)).any?)
|
59
62
|
end
|
60
63
|
|
61
64
|
# Returns true if the obj is a collection of items
|
65
|
+
# is_collection?(@user) => false
|
66
|
+
# is_collection?([]) => true
|
62
67
|
def is_collection?(obj)
|
63
|
-
obj && data_object(obj).respond_to?(:map) && data_object(obj).respond_to?(:each)
|
68
|
+
obj && data_object(obj).respond_to?(:map) && data_object(obj).respond_to?(:each) &&
|
69
|
+
(KNOWN_OBJECT_CLASSES & obj.class.ancestors.map(&:name)).empty?
|
64
70
|
end
|
65
71
|
|
66
72
|
# Returns the scope wrapping this engine, used for retrieving data, invoking methods, etc
|
data/lib/rabl/version.rb
CHANGED
data/test/builder_test.rb
CHANGED
@@ -23,21 +23,21 @@ context "Rabl::Builder" do
|
|
23
23
|
|
24
24
|
context "#to_hash" do
|
25
25
|
context "when given a simple object" do
|
26
|
-
setup { builder({ :attributes => { :name =>
|
26
|
+
setup { builder({ :attributes => { :name => {} } }) }
|
27
27
|
asserts "that the object is set properly" do
|
28
28
|
topic.build(User.new, :root_name => "user")
|
29
29
|
end.equivalent_to({ "user" => { :name => "rabl" } })
|
30
30
|
end
|
31
31
|
|
32
32
|
context "when given an object alias" do
|
33
|
-
setup { builder({ :attributes => { :name => :
|
33
|
+
setup { builder({ :attributes => { :name => { :as => :foo } } }) }
|
34
34
|
asserts "that the object is set properly" do
|
35
35
|
topic.build(User.new, :root_name => "person")
|
36
|
-
end.equivalent_to({ "person" => { :
|
36
|
+
end.equivalent_to({ "person" => { :foo => "rabl" } })
|
37
37
|
end
|
38
38
|
|
39
39
|
context "when specified with no root" do
|
40
|
-
setup { builder({ :attributes => { :name => :name } }) }
|
40
|
+
setup { builder({ :attributes => { :name => { :as => :name } } }) }
|
41
41
|
asserts "that the object is set properly" do
|
42
42
|
topic.build(User.new, :root => false)
|
43
43
|
end.equivalent_to({ :name => "rabl" })
|
@@ -46,7 +46,7 @@ context "Rabl::Builder" do
|
|
46
46
|
|
47
47
|
context "#attribute" do
|
48
48
|
asserts "that the node" do
|
49
|
-
build_hash @user, :attributes => { :name =>
|
49
|
+
build_hash @user, :attributes => { :name => {}, :city => { :as => :city } }
|
50
50
|
end.equivalent_to({:name => 'rabl', :city => 'irvine'})
|
51
51
|
|
52
52
|
asserts "that with a non-existent attribute the node" do
|
data/test/engine_test.rb
CHANGED
@@ -427,7 +427,62 @@ context "Rabl::Engine" do
|
|
427
427
|
scope.instance_variable_set :@user, User.new(:name => 'irvine')
|
428
428
|
template.render(scope)
|
429
429
|
end.equals "{\"city\":\"irvine\"}"
|
430
|
-
|
430
|
+
|
431
|
+
asserts "that it handle structs correctly as child elements" do
|
432
|
+
template = rabl %{
|
433
|
+
object @user
|
434
|
+
child(:city) do
|
435
|
+
attributes :name
|
436
|
+
end
|
437
|
+
}
|
438
|
+
City = Struct.new(:name)
|
439
|
+
scope = Object.new
|
440
|
+
scope.instance_variable_set :@user, User.new(:city => City.new('San Francisco'))
|
441
|
+
template.render(scope)
|
442
|
+
end.equals "{\"city\":{\"name\":\"San Francisco\"}}"
|
443
|
+
|
444
|
+
asserts "that it can be passed an if cond for single real attr" do
|
445
|
+
template = rabl %{
|
446
|
+
object @user
|
447
|
+
attribute :name
|
448
|
+
attributes :age, :first, :if => lambda { |i| i.name != 'irvine' }
|
449
|
+
}
|
450
|
+
scope = Object.new
|
451
|
+
scope.instance_variable_set :@user, User.new(:name => 'irvine')
|
452
|
+
JSON.parse(template.render(scope))
|
453
|
+
end.equals JSON.parse("{\"name\":\"irvine\"}")
|
454
|
+
|
455
|
+
asserts "that it can be passed an if cond for aliased attrs" do
|
456
|
+
template = rabl %{
|
457
|
+
object @user
|
458
|
+
attributes :name => :title, :age => :year, :if => lambda { |i| i.name == 'irvine' }
|
459
|
+
}
|
460
|
+
scope = Object.new
|
461
|
+
scope.instance_variable_set :@user, User.new(:name => 'irvine')
|
462
|
+
JSON.parse(template.render(scope))
|
463
|
+
end.equals JSON.parse("{\"title\":\"irvine\",\"year\":24}")
|
464
|
+
|
465
|
+
asserts "that it can be passed an unless cond to hide attrs" do
|
466
|
+
template = rabl %{
|
467
|
+
object @user
|
468
|
+
attribute :name
|
469
|
+
attributes :age, :unless => lambda { |i| i.name == 'irvine' }
|
470
|
+
}
|
471
|
+
scope = Object.new
|
472
|
+
scope.instance_variable_set :@user, User.new(:name => 'irvine')
|
473
|
+
JSON.parse(template.render(scope))
|
474
|
+
end.equals JSON.parse("{\"name\":\"irvine\"}")
|
475
|
+
|
476
|
+
asserts "that it can be passed an unless cond for aliased attrs" do
|
477
|
+
template = rabl %{
|
478
|
+
object @user
|
479
|
+
attributes :name => :title, :age => :year, :unless => lambda { |i| i.name == 'irvine' }
|
480
|
+
}
|
481
|
+
scope = Object.new
|
482
|
+
scope.instance_variable_set :@user, User.new(:name => 'irvine')
|
483
|
+
JSON.parse(template.render(scope))
|
484
|
+
end.equals JSON.parse("{}")
|
485
|
+
end # attribute
|
431
486
|
|
432
487
|
context "#code" do
|
433
488
|
asserts "that it can create an arbitraty code node" do
|
data/test/helpers_test.rb
CHANGED
@@ -39,15 +39,20 @@ context "Rabl::Helpers" do
|
|
39
39
|
@helper_class.is_object?(@user)
|
40
40
|
end.equals(true)
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
asserts "returns true for an object with each" do
|
43
|
+
obj = Class.new { def each; end }
|
44
|
+
@helper_class.is_object?(obj.new)
|
45
|
+
end.equals(true)
|
46
46
|
|
47
47
|
asserts "returns true for a hash alias" do
|
48
48
|
@helper_class.is_object?(@user => :user)
|
49
49
|
end.equals(true)
|
50
50
|
|
51
|
+
asserts "returns true for a struct" do
|
52
|
+
obj = Struct.new(:name)
|
53
|
+
@helper_class.is_object?(obj.new('foo'))
|
54
|
+
end.equals(true)
|
55
|
+
|
51
56
|
asserts "returns false for an array" do
|
52
57
|
@helper_class.is_object?([@user])
|
53
58
|
end.equals(false)
|
@@ -58,14 +63,19 @@ context "Rabl::Helpers" do
|
|
58
63
|
@helper_class.is_collection?(nil)
|
59
64
|
end.equals(nil)
|
60
65
|
|
66
|
+
asserts "returns false for a struct" do
|
67
|
+
obj = Struct.new(:name)
|
68
|
+
@helper_class.is_collection?(obj.new('foo'))
|
69
|
+
end.equals(false)
|
70
|
+
|
61
71
|
asserts "returns false for an object" do
|
62
72
|
@helper_class.is_collection?(@user)
|
63
73
|
end.equals(false)
|
64
74
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
75
|
+
asserts "returns false for an object with each" do
|
76
|
+
obj = Class.new { def each; end }
|
77
|
+
@helper_class.is_collection?(obj.new)
|
78
|
+
end.equals(false)
|
69
79
|
|
70
80
|
asserts "returns false for a hash alias" do
|
71
81
|
@helper_class.is_collection?(@user => :user)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rabl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -181,6 +181,7 @@ files:
|
|
181
181
|
- .gitignore
|
182
182
|
- .travis.yml
|
183
183
|
- CHANGELOG.md
|
184
|
+
- CONTRIBUTING.md
|
184
185
|
- Gemfile
|
185
186
|
- Gemfile.ci
|
186
187
|
- MIT-LICENSE
|