rabl 0.7.6 → 0.7.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|