Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

big refactoring

  • Loading branch information...
commit a7a0037d03b2c85b7e18b5ee26f421a9d38af17b 1 parent e0e140c
@mkristian authored
View
1  ixtlan-babel.gemspec
@@ -20,4 +20,5 @@ Gem::Specification.new do |s|
s.add_development_dependency 'rake', '~> 10.0.0'
s.add_development_dependency 'json_pure', '~> 1.6.1'
s.add_development_dependency 'minitest', '2.11.3'
+ s.add_development_dependency 'virtus', '~> 0.5.0'
end
View
11 lib/ixtlan/babel/config.rb
@@ -15,16 +15,25 @@ def initialize( options )
else
[]
end
+ @methods = (options[:methods] || []).collect { |m| m.to_s }
+ end
+
+ def methods
+ @methods + ( @include.is_a?( Array ) ? @include : @include.keys )
end
def allowed?( key )
- ( @only && @only.include?( key ) ) || ( @only.nil? && !@except.include?( key ) )
+ ( @only && @only.include?( key ) ) || ( @only.nil? && !@except.include?( key ) ) || @methods.include?( key )
end
def include?( key )
@include.include? key
end
+ def array?
+ @include.is_a?( Array )
+ end
+
def []( key )
self.class.new( @include.is_a?( Array ) ? {} : @include[ key ] )
end
View
7 lib/ixtlan/babel/hash_only_filter.rb → lib/ixtlan/babel/hash_filter.rb
@@ -15,7 +15,7 @@ def context
public
- def add_custom_serializers(map)
+ def add_custom_serializers( map )
@map = map
end
@@ -48,11 +48,10 @@ def use( context_or_options )
self
end
- def filter(hash = {}, model = nil, &block)
+ def filter( hash = {} )
if hash
filter_data( hash,
- Config.new( options_for( hash ) ),
- &block)
+ Config.new( options_for( hash ) ) )
end
end
View
87 lib/ixtlan/babel/model_filter.rb
@@ -0,0 +1,87 @@
+module Ixtlan
+ module Babel
+ class ModelFilter < HashFilter
+
+ def filter( model, &block )
+ if model
+ data = block.call( model )
+ filter_data( model, data,
+ Config.new( options_for( data ) ),
+ &block )
+ end
+ end
+
+ private
+
+ def filter_array( models, options, &block )
+ models.collect do |i|
+ if i.respond_to? :attributes
+ filter_data(i, block.call(i), options, &block)
+ else
+ i
+ end
+ end
+ end
+
+ def filter_data(model, data, config, &block)
+#puts "-" * 80
+#p data
+ #methods = (options[:methods] || []).collect { |e| e.to_s }
+ #config.methods.each do |m|
+ # data[ m ] = model.send( m )
+ #end
+
+ #include_methods = include.is_a?(Array) ? include : include.keys
+
+ config.methods.each do |m|
+ unless data.include?(m)
+ data[ m ] = model.send( m.to_sym )
+ end
+ end
+ # config.methods.each do |m|
+ # unless data.include?(m)
+ # val = model.send( m.to_sym )
+ # if val.is_a?(Array) && val.first.is_a?( String )
+ # data[ m ] = val
+ # elsif val.respond_to?( :collect )
+ # data[ m ] = val.collect { |i| block.call( i ) }
+ # else
+ # case val
+ # when Fixnum
+ # data[ m ] = val
+ # when String
+ # data[ m ] = val
+ # when TrueClass
+ # data[ m ] = val
+ # else
+ # data[ m ]= block.call( val )
+ # end
+ # end
+ # end
+ # end
+
+ result = {}
+ data.each do |k,v|
+ k = k.to_s
+ if v.respond_to? :attributes
+ result[ k ] = filter_data( v, block.call(v), config[ k ], &block ) if config.include?( k )
+
+ # if include.include?(k.to_s)
+ # case include
+ # when Array
+ # result[k.to_s] = filter_data(model.send(k), v, &block)
+ # when Hash
+ # result[k.to_s] = filter_data(model.send(k), v, include[k.to_s], &block)
+ # end
+ # end
+ elsif v.is_a? Array
+ result[ k ] = filter_array( v, config[ k ], &block ) if config.include?( k )
+ else
+ result[ k ] = serialize( v ) if config.allowed?( k ) && ! v.respond_to?( :attributes )
+ end
+ end
+ result
+ end
+ end
+ end
+end
View
17 lib/ixtlan/babel/serializer.rb
@@ -1,4 +1,5 @@
-require 'ixtlan/babel/hash_only_filter'
+require 'ixtlan/babel/hash_filter'
+require 'ixtlan/babel/model_filter'
module Ixtlan
module Babel
class Serializer
@@ -30,11 +31,11 @@ def add_custom_serializers(map)
private
def self.filter
- @filter ||= HashFilter.new
+ @filter ||= ModelFilter.new
end
def filter
- @filter ||= self.class.filter.dup
+ @filter ||= @model_or_models.is_a?( Hash ) ? HashFilter.new : self.class.filter.dup
end
protected
@@ -69,10 +70,10 @@ def to_hash(options = nil)
setup_filter( options )
if collection?
@model_or_models.collect do |m|
- filter_model(attr(m), m)
+ filter_model( m )
end
else
- filter_model(attr(@model_or_models), @model_or_models)
+ filter_model( @model_or_models )
end
end
@@ -120,11 +121,11 @@ def attr(model)
private
- def filter_model(model, data)
+ def filter_model( model )
if root = filter.single_options[:root]
- {root.to_s => filter.filter(model, data){ |model| attr(model) } }
+ {root.to_s => filter.filter( model ){ |model| attr(model) } }
else
- filter.filter(model, data){ |model| attr(model) }
+ filter.filter( model ){ |model| attr(model) }
end
end
end
View
2  spec/filter_spec.rb → spec/hash_filter_spec.rb
@@ -9,7 +9,7 @@ def method_missing(method)
end
end
-describe Ixtlan::Babel do
+describe Ixtlan::Babel::HashFilter do
let(:data) do
data = {
'id' => 987,
View
167 spec/model_filter_spec.rb
@@ -0,0 +1,167 @@
+require 'spec_helper'
+require 'virtus'
+
+class Address
+ include Virtus
+
+ attribute :street, String
+ attribute :zipcode, String
+end
+class Area
+ include Virtus
+
+ attribute :code, String
+ attribute :iso, String
+end
+class PhoneNumber
+ include Virtus
+
+ attribute :prefix, Integer
+ attribute :number, String
+ attribute :area, Area
+end
+class Person
+ include Virtus
+
+ attribute :id, String
+ attribute :name, String
+ attribute :address, Address
+ attribute :phone_numbers, Array[PhoneNumber]
+end
+
+describe Ixtlan::Babel::ModelFilter do
+ let( :person ) do
+ Person.new(
+ :id => 987,
+ :name => 'me and the corner',
+ :address => Address.new( :street => 'Foo 12', :zipcode => '12345' ),
+ :phone_numbers => [PhoneNumber.new(
+ :prefix => 12,
+ :number => '123',
+ :area => Area.new( :code => '001', :iso => 'us' )
+ )]
+ )
+ end
+
+ let(:serializer) { Ixtlan::Babel::Serializer.new( person ) }
+ let(:deserializer) { Ixtlan::Babel::Deserializer.new( Person ) }
+
+ it 'should serialize and deserialize without root' do
+ json = serializer.to_json
+ result = deserializer.from_json(json)
+ attributes = result.attributes.delete_if { |k,v| v.nil? }
+ attributes.must_equal Hash[:id => person['id'], :name => person['name']]
+ end
+
+ it 'should serialize and deserialize with root' do
+ json = serializer.to_json :root => :my
+ result = deserializer.from_json(json, :root => :my)
+ attributes = result.attributes.delete_if { |k,v| v.nil? }
+ attributes.must_equal Hash[:id => person['id'], :name => person['name']]
+ end
+
+ it 'should serialize and deserialize a hash with include list' do
+ json = serializer.to_json(:include => ['address', 'phone_numbers'])
+ result = deserializer.from_json(json, :include => ['address', 'phone_numbers'])
+ result.object_id.wont_equal person.object_id
+ result.address.attributes.must_equal person.address.attributes
+ result.phone_numbers[0].area.must_be_nil
+ person.phone_numbers[0].area = nil
+ result.phone_numbers[0].attributes.must_equal person.phone_numbers[0].attributes
+ result.name.must_equal person.name
+ result.id.must_equal person.id
+ end
+
+ it 'shouldserialize and deserialize with except' do
+ json = serializer.to_json(:except => ['id'])
+ result = deserializer.from_json(json, :except => ['id'])
+ result.attributes.must_equal Hash[:name => person['name'], :address=>nil, :phone_numbers=>nil, :id => nil]
+ result = deserializer.from_json(json)
+ result.attributes.must_equal Hash[:name => person['name'], :address=>nil, :phone_numbers=>nil, :id => nil]
+ end
+
+ it 'should serialize and deserialize with only' do
+ json = serializer.to_json(:only => ['name'])
+ result = deserializer.from_json(json, :only => ['name'])
+ result.attributes.must_equal Hash[:name => person['name'], :address=>nil, :phone_numbers=>nil, :id => nil]
+ result = deserializer.from_json(json)
+ result.attributes.must_equal Hash[:name => person['name'], :address=>nil, :phone_numbers=>nil, :id => nil]
+ end
+
+ it 'should serialize and deserialize with nested only' do
+ json = serializer.to_json(:include => { 'address' => {:only => ['street']}})
+ result = deserializer.from_json(json, :include => { 'address' => {:only => ['street']}})
+
+ result.phone_numbers.must_be_nil
+ result.phone_numbers = nil
+ person.phone_numbers = nil
+
+ result.address.zipcode.must_be_nil
+ result.address.zipcode = nil
+ person.address.zipcode = nil
+
+ result.name.must_equal person.name
+ result.id.must_equal person.id
+ end
+
+ it 'should serialize and deserialize with nested only (array includes)' do
+ json = serializer.to_json(:include => { 'address' => {:only => ['street']}})
+ result = deserializer.from_json(json, :include => ['address'])
+
+ result.phone_numbers.must_be_nil
+ result.phone_numbers = nil
+ person.phone_numbers = nil
+
+ result.address.zipcode.must_be_nil
+ result.address.zipcode = nil
+ person.address.zipcode = nil
+
+ result.name.must_equal person.name
+ result.id.must_equal person.id
+ end
+
+ it 'should serialize and deserialize with nested except' do
+ json = serializer.to_json(:include => { 'address' => {:except => ['zipcode']}})
+ result = deserializer.from_json(json, :include => { 'address' => {:except => ['zipcode']}})
+
+ result.phone_numbers.must_be_nil
+ result.phone_numbers = nil
+ person.phone_numbers = nil
+
+ result.address.zipcode.must_be_nil
+ result.address.zipcode = nil
+ person.address.zipcode = nil
+
+ result.name.must_equal person.name
+ result.id.must_equal person.id
+ end
+
+ it 'should serialize and deserialize with nested except (array includes)' do
+ json = serializer.to_json(:include => { 'address' => {:except => ['zipcode']}})
+ result = deserializer.from_json(json, :include => ['address'])
+
+ result.phone_numbers.must_be_nil
+ result.phone_numbers = nil
+ person.phone_numbers = nil
+
+ result.address.zipcode.must_be_nil
+ result.address.zipcode = nil
+ person.address.zipcode = nil
+
+ result.name.must_equal person.name
+ result.id.must_equal person.id
+ end
+
+ it 'should serialize and deserialize with nested include' do
+ json = serializer.to_json(:include => { 'address' => {}, 'phone_numbers' => { :include => ['area']}})
+ result = deserializer.from_json(json, :include => { 'address' => {}, 'phone_numbers' => { :include => ['area']}})
+
+ result.object_id.wont_equal person.object_id
+ result.address.attributes.must_equal person.address.attributes
+ result.phone_numbers[0].area.attributes.must_equal person.phone_numbers[0].area.attributes
+ result.phone_numbers[0].prefix.must_equal person.phone_numbers[0].prefix
+ result.phone_numbers[0].number.must_equal person.phone_numbers[0].number
+ result.name.must_equal person.name
+ result.id.must_equal person.id
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.