rabl 0.7.6 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,12 @@
1
1
  # CHANGELOG
2
2
 
3
- ## 0.7.7 (unreleased)
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
 
@@ -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:
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'rails', '~> 3.2.8'
3
+ gem 'rails', '~> 3.2.9.rc3'
4
4
 
5
5
  # Bundle edge Rails instead:
6
6
  # gem 'rails', :git => 'git://github.com/rails/rails.git'
@@ -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'
@@ -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, name|
38
- attribute(attribute, :as => name)
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
- @_result[options[:as] || name] = data_object_attribute(name) if @_object && @_object.respond_to?(name)
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)
@@ -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).to_a)
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.each_pair { |k,v| self.attribute(k, :as => v) }
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
- options = args.extract_options!
161
- args.each { |name| @_options[:attributes][name] = options[:as] || 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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Rabl
2
- VERSION = "0.7.6"
2
+ VERSION = "0.7.7"
3
3
  end
@@ -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 => :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 => :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" => { :name => "rabl" } })
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 => :name, :city => :city }
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
@@ -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
- end
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
@@ -39,15 +39,20 @@ context "Rabl::Helpers" do
39
39
  @helper_class.is_object?(@user)
40
40
  end.equals(true)
41
41
 
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)
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
- # asserts "returns false for an object with each" do
66
- # obj = Class.new { def each; end }
67
- # @helper_class.is_collection?(obj.new)
68
- # end.equals(false)
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.6
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-10-30 00:00:00.000000000 Z
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