Permalink
Browse files

More transparency. Ensure scopes are applied even in overridden methods.

  • Loading branch information...
1 parent 5cdfb5f commit 55b96eeb65b41775fc62a4a4d6e7b38288e647f8 @dim dim committed Apr 20, 2011
Showing with 60 additions and 34 deletions.
  1. +1 −1 .gitignore
  2. +1 −1 VERSION
  3. +33 −19 lib/serialization_scopes.rb
  4. +25 −13 spec/serialization_scopes_spec.rb
View
@@ -1 +1 @@
-pkg/
+*.gem
View
@@ -1 +1 @@
-0.3.0
+0.8.0
@@ -2,42 +2,56 @@ module SerializationScopes
extend ActiveSupport::Concern
included do
- class_inheritable_reader :serialization_scopes
- write_inheritable_attribute :serialization_scopes, {}
+ class_attribute :serialization_scopes, :instance_writer => false
+ alias_method_chain :to_xml, :scopes
+ alias_method_chain :as_json, :scopes
end
module ClassMethods
def serialization_scope(name, options = {})
+ self.serialization_scopes ||= {}
serialization_scopes[name.to_sym] = options
end
def scoped_serialization_options(options = {})
- options ||= {}
- name = (options || {})[:scope]
- scopes = name.present? && serialization_scopes[name.to_sym] ? serialization_scopes[name.to_sym] : serialization_scopes[:default]
- options = options.dup
- scopes.each do |key, scope_options|
- custom_options = options[key]
- options[key] = if key == :except
- custom_options ? (Array.wrap(custom_options) + Array.wrap(scope_options)).uniq : Array.wrap(scope_options)
- elsif [:only, :methods, :include].include?(key)
- custom_options ? Array.wrap(custom_options) & Array.wrap(scope_options) : Array.wrap(scope_options)
- else
- custom_options ? custom_options : scope_options
- end
+ options = options.try(:clone) || {}
+ name = options[:scope].try(:to_sym)
+ scopes = name.present? && serialization_scopes.key?(name) ? serialization_scopes[name] : serialization_scopes[:default]
+
+ scopes.each do |key, defaults|
+ options[key] = options[key] ? Resolver.scope(key, defaults, options[key]) : defaults
end if scopes
+
options
end
end
- def to_xml(options = {})
- super self.class.scoped_serialization_options(options)
+ module Resolver
+
+ def self.scope(key, defaults, settings)
+ defaults = Array.wrap(defaults)
+ settings = Array.wrap(settings)
+
+ case key
+ when :except
+ (settings + defaults).uniq
+ when :only, :methods, :include
+ settings & defaults
+ else
+ settings
+ end
+ end
+
+ end
+
+ def to_xml_with_scopes(options = {})
+ to_xml_without_scopes self.class.scoped_serialization_options(options)
end
- def as_json(options = {})
- super self.class.scoped_serialization_options(options)
+ def as_json_with_scopes(options = {})
+ as_json_without_scopes self.class.scoped_serialization_options(options)
end
end
@@ -38,17 +38,23 @@ def another
end
class AnotherModel < ActiveRecord::Base
- serialization_scope :default, :only => :another
+ serialization_scope :default, :only => :name
after_initialize :set_defaults
def self.columns
@columns ||= [
- ActiveRecord::ConnectionAdapters::Column.new('another', nil, 'string')
+ ActiveRecord::ConnectionAdapters::Column.new('id', nil, 'integer'),
+ ActiveRecord::ConnectionAdapters::Column.new('name', nil, 'string')
]
end
+ # Method override
+ def to_json(options={})
+ super(options)
+ end
+
def set_defaults
- self.another = 'val'
+ self.name = 'val'
end
end
@@ -73,8 +79,12 @@ class SomeResource < ActiveResource::Base
)
end
+ def serialize(object, options = {})
+ ActiveSupport::JSON.decode(object.to_json(options))
+ end
+
def as_hash(options = {})
- ActiveSupport::JSON.decode(SomeModel.new.to_json(options))
+ serialize(SomeModel.new, options)
end
it 'should constraint to_json' do
@@ -118,26 +128,28 @@ def options_for(custom_options)
end
it 'should use default serialization scope when serialized as part of another object' do
- i = SomeModel.new
- ActiveSupport::JSON.decode([i].to_json).should == [{ "name" => "Any", "currency" => "USD", "id" => 1 }]
- ActiveSupport::JSON.decode({:k => i}.to_json).should == { 'k' => { "name" => "Any", "currency" => "USD", "id" => 1 } }
+ serialize(:k => SomeModel.new).should == { 'k' => { "name" => "Any", "currency" => "USD", "id" => 1 } }
end
it 'should not fail when passed nil options' do
- options_for(nil).should == { :only => [:id, :name], :methods => [:currency] }
+ options_for(nil).should == { :only => [:id, :name], :methods => :currency }
end
it 'should keep scope option' do
options_for(:scope => :nested)[:scope].should == :nested
end
it 'should pass the scope to the nested object so that they can use own settings' do
- as_hash(:scope => :nested)['another'].should == { 'another' => 'val' }
+ as_hash(:scope => :nested)['another'].should == { 'name' => 'val' }
end
it 'should be enabled on ActiveResource models' do
- json = SomeResource.new(:id => 1, :name => 'a name', :secret => 'some secret').to_json
- ActiveSupport::JSON.decode(json).should == { 'some_resource' => { 'id' => 1, 'name' => 'a name' } }
+ res = SomeResource.new(:id => 1, :name => 'a name', :secret => 'some secret')
+ serialize(res).should == { 'some_resource' => { 'id' => 1, 'name' => 'a name' } }
+ end
+
+ it 'should allow custom serialization methods' do
+ serialize(AnotherModel.new).should == {'name' => 'val'}
end
it 'should not tamper options' do
@@ -147,9 +159,9 @@ def options_for(custom_options)
end
it 'should not tamper nested options' do
- original = { :only => [:secret] }
+ original = { :only => :secret }
SomeModel.new.to_json(original)
- original.should == { :only => [:secret] }
+ original.should == { :only => :secret }
end
end

0 comments on commit 55b96ee

Please sign in to comment.