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.
@@ -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