Permalink
Browse files

added DSL for configuring a fitler context

  • Loading branch information...
mkristian committed Nov 3, 2013
1 parent 3d5b233 commit f975935cc635bf75e6f8b8769f8afd5431491f21
@@ -51,8 +51,10 @@ def filter_data( data, context )
result[ k ] = filter_data( v,
context[ k ] ) if context.include?( k )
when Array
- result[ k ] = filter_array( v,
- context[ k ] ) if context.include?( k )
+ if context.allowed?( k ) || context.include?( k )
+ result[ k ] = filter_array( v,
+ context[ k ] )
+ end
else
result[ k ] = serialize( v ) if context.allowed?( k )
end
@@ -45,12 +45,42 @@ def self.default_context_key(default)
config.default_context_key(default)
end
- def self.add_context(key, options = {})
- config[key] = options
+ def self.add_context( key = :single, options = nil, &block )
+ current = config[key] = options || { :only => [] }
+ @context = key
+ yield if block
+ current[ :keep ] = @keep if @keep
+ current.merge!( @allow ) if @allow
+ current[ :root ] = @root
+ ensure
+ @context = nil
+ @allow = nil
+ @keep = nil
+ @root = nil
end
def self.root( root )
- config.root = root
+ if @context
+ @root = root
+ else
+ config.root = root
+ end
+ end
+
+ def self.keep( *args )
+ @keep = *args
+ end
+
+ def self.only( *args )
+ result = {}
+ if args.last.is_a? Hash
+ result[ :include ] = args.last
+ result[ :only ] = args[ 0..-2 ]
+ else
+ result[ :only ] = args
+ end
+ @allow = result
+ result
end
public
@@ -72,6 +102,10 @@ def new_model
@model.send( :new, params )
end
+ def []( key )
+ params[ key ]
+ end
+
def params
@data[ :params ]
end
@@ -105,6 +139,8 @@ def filter_it( data )
( filter.options[ :keep ] || [] ).each do |k|
keeps[ k.to_s ] = filtered_data.delete( k.to_s ) ||
filtered_data.delete( k.to_sym ) unless keeps.member?( k.to_s )
+ # just make sure we have an entry for each keeps key
+ keeps[ k.to_s ] ||= nil
end
FilterResult.new( @model_class, filtered_data, keeps )
end
@@ -77,12 +77,37 @@ def self.default_context_key(single = :single, collection = :collection)
config.default_context_key(single, collection)
end
- def self.add_context(key, options = {})
- config[key] = options
+ def self.add_context(key = :single, options = nil, &block)
+ current = config[key] = options || { :only => Array.new }
+ @only = nil
+ @root = nil
+ @context = key
+ yield if block
+ current.merge!( @only ) if @only
+ current[ :root ] = @root
+ ensure
+ @context = nil
+ end
+
+ def self.only( *args )
+ args.flatten!
+ result = { :only => Array.new }
+ if args.last.is_a? Hash
+ result[ :include ] = args.last
+ result[ :methods ] = args[ 0..-2 ]
+ else
+ result[ :methods ] = args
+ end
+ @only = result
+ result
end
def self.root( root )
- config.root = root
+ if @context
+ @root = root
+ else
+ config.root = root
+ end
end
public
View
@@ -4,7 +4,7 @@ class Hash
def attributes
self
end
- def method_missing(method)
+ def method_missing(method, *args)
self[method.to_s]
end
end
@@ -0,0 +1,173 @@
+require 'spec_helper'
+require 'virtus'
+
+class Address2
+ include Virtus
+
+ attribute :street, String
+ attribute :zipcode, String
+end
+class Area2
+ include Virtus
+
+ attribute :code, String
+ attribute :iso, String
+end
+class PhoneNumber2
+ include Virtus
+
+ attribute :prefix, Integer
+ attribute :number, String
+ attribute :area, Area2
+end
+class Person2
+ include Virtus
+
+ attribute :id, String
+ attribute :name, String
+ attribute :address, Address2
+
+ attr_accessor :phone_numbers, :age, :children_names
+
+ def phone_numbers
+ @phone_numbers ||= [PhoneNumber2.new(
+ :prefix => 12,
+ :number => '123',
+ :area => Area2.new( :code => '001', :iso => 'us' ) )]
+ end
+
+ def age
+ @age ||= 123
+ end
+
+ def children_names
+ @children_names ||= ['anna', 'jack', 'rama', 'mia']
+ end
+
+ def children_ages
+ @children_ages ||= [12, 3, 6, 9]
+ end
+end
+
+describe Ixtlan::Babel::ModelFilter.to_s + ':with_methods' do
+ let( :person ) do
+ Person2.new( :id => 987,
+ :name => 'me and the corner',
+ :address => Address2.new( :street => 'Foo 12',
+ :zipcode => '12345' ) )
+ end
+
+ let( :serializer ) { factory.new_serializer( person ) }
+
+ let( :factory ) { Ixtlan::Babel::Factory.new }
+
+ it 'should serialize and deserialize with methods' do
+ class Person2Serializer < Ixtlan::Babel::Serializer
+ add_context( :nested ) do
+ only :id, :name, :age, :children_names, :children_ages
+ end
+ end
+ json = serializer.use( :nested ).to_json
+ result = MultiJson.load(json)
+ result.must_equal Hash[ "id"=>"987",
+ "name"=>"me and the corner",
+ "age"=>123,
+ "children_names"=> [ "anna",
+ "jack",
+ "rama",
+ "mia" ],
+ "children_ages"=>[ 12, 3, 6, 9 ] ]
+ end
+
+ it 'should serialize and deserialize without root' do
+ class Person2Serializer < Ixtlan::Babel::Serializer
+ add_context( :plain ) do
+ only :id, :name
+ end
+ end
+ json = serializer.use( :plain ).to_json
+ result = MultiJson.load(json)
+ result.must_equal Hash[ "id"=>"987", "name"=>"me and the corner" ]
+ end
+
+ it 'should serialize and deserialize with root' do
+ class Person2Serializer < Ixtlan::Babel::Serializer
+ add_context( :root ) do
+ root 'my'
+ only :id, :name
+ end
+ end
+ json = serializer.use( :root ).to_json
+ result = MultiJson.load(json)[ 'my' ]
+ result.must_equal Hash[ "id"=>"987", "name"=>"me and the corner" ]
+ end
+
+ it 'should serialize and deserialize a hash with include list' do
+ class Person2Serializer < Ixtlan::Babel::Serializer
+ add_context( :deep_nested) do
+ only( :id, :name,
+ :address => only( :street, :zipcode ),
+ :phone_numbers => only( :prefix, :number ) )
+ end
+ end
+ json = serializer.use( :deep_nested ).to_json
+ result = MultiJson.load(json)
+ result.must_equal Hash[ "id"=>"987", "name"=>"me and the corner" ,
+ "address"=> {
+ "street"=>"Foo 12",
+ "zipcode"=>"12345"
+ },
+ "phone_numbers"=> [ { "prefix"=>12,
+ "number"=>"123" } ] ]
+ end
+
+ it 'should serialize and deserialize with only' do
+ class Person2Serializer < Ixtlan::Babel::Serializer
+ add_context( :only ) do
+ only :name
+ end
+ end
+ json = serializer.use( :only ).to_json
+ result = MultiJson.load(json)
+ result.must_equal Hash[ "name"=>"me and the corner" ]
+ end
+
+ it 'should serialize and deserialize with nested only' do
+ class Person2Serializer < Ixtlan::Babel::Serializer
+ add_context( :nested_only ) do
+ only :address => only( :street )
+ end
+ end
+ json = serializer.use( :nested_only ).to_json
+ result = MultiJson.load(json)
+ result.must_equal Hash[ "address"=> {
+ "street"=>"Foo 12"
+ } ]
+ end
+
+ it 'should serialize and deserialize with nested include' do
+ class Person2Serializer < Ixtlan::Babel::Serializer
+ add_context( :nested_deep ) do
+ only( :id, :name,
+ :address => only( :street, :zipcode ),
+ :phone_numbers => only( :prefix,
+ :number,
+ :area => only( :code, :iso) ) )
+ end
+ end
+ json = serializer.use( :nested_deep ).to_json
+ result = MultiJson.load(json)
+ result.must_equal Hash[ "id"=>"987", "name"=>"me and the corner" ,
+ "address"=> {
+ "street"=>"Foo 12",
+ "zipcode"=>"12345"
+ },
+ "phone_numbers"=> [ { "prefix"=>12,
+ "number"=>"123",
+ "area"=> {
+ "code"=>"001",
+ "iso"=>"us"
+ }
+ } ] ]
+ end
+end
Oops, something went wrong.

0 comments on commit f975935

Please sign in to comment.