ixtlan-babel 0.1.2 → 0.2.0

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.
@@ -4,13 +4,9 @@ module Ixtlan
4
4
  class NoTimestampSerializer < Serializer
5
5
 
6
6
  def self.add_defaults(root = nil)
7
- if root
8
- add_context(:default, :root => root)
9
- add_no_timestamp_context(:collection, :root => root)
10
- else
11
- add_context(:default)
12
- add_no_timestamp_context(:collection)
13
- end
7
+ self.root root
8
+ add_context(:default)
9
+ add_no_timestamp_context(:collection)
14
10
  end
15
11
 
16
12
  def self.add_no_timestamp_context(key, options = {})
@@ -1,4 +1,6 @@
1
1
  require 'ixtlan/babel/hash_filter'
2
+ require 'ixtlan/babel/model_filter'
3
+ require 'ixtlan/babel/filter_config'
2
4
  module Ixtlan
3
5
  module Babel
4
6
  class Serializer
@@ -29,12 +31,12 @@ module Ixtlan
29
31
 
30
32
  private
31
33
 
32
- def self.filter
33
- @filter ||= HashFilter.new
34
+ def self.config
35
+ @config ||= FilterConfig.new
34
36
  end
35
37
 
36
38
  def filter
37
- @filter ||= self.class.filter.dup
39
+ @filter ||= @model_or_models.is_a?( Hash ) ? HashFilter.new : ModelFilter.new
38
40
  end
39
41
 
40
42
  protected
@@ -50,29 +52,33 @@ module Ixtlan
50
52
  model.model_name
51
53
  end
52
54
 
53
- def self.default_context_key(default)
54
- filter.default_context_key(default)
55
+ def self.default_context_key(single = :single, collection = :collection)
56
+ config.default_context_key(single, collection)
55
57
  end
56
58
 
57
59
  def self.add_context(key, options = {})
58
- filter[key] = options
60
+ config[key] = options
61
+ end
62
+
63
+ def self.root( root )
64
+ config.root = root
59
65
  end
60
66
 
61
67
  public
62
68
 
63
- def use(context_or_options)
64
- filter.use(context_or_options)
69
+ def use( context_or_options )
70
+ @context_or_options = context_or_options
65
71
  self
66
72
  end
67
73
 
68
74
  def to_hash(options = nil)
69
- filter.use(filter.options.dup.merge!(options)) if options
70
- if @model_or_models.respond_to?(:collect) && ! @model_or_models.is_a?(Hash)
75
+ setup_filter( options )
76
+ if collection?
71
77
  @model_or_models.collect do |m|
72
- filter_model(attr(m), m)
78
+ filter_model( m )
73
79
  end
74
80
  else
75
- filter_model(attr(@model_or_models), @model_or_models)
81
+ filter_model( @model_or_models )
76
82
  end
77
83
  end
78
84
 
@@ -80,13 +86,31 @@ module Ixtlan
80
86
  to_hash(options).to_json
81
87
  end
82
88
 
83
- def to_xml(options = {})
84
- opts = filter.options.dup.merge!(options)
85
- root = opts.delete :root
86
- fitler.use(opts)
89
+ def setup_filter(options)
90
+ o = if collection?
91
+ self.class.config.collection_options( @context_or_options )
92
+ else
93
+ self.class.config.single_options( @context_or_options )
94
+ end
95
+ filter.options = o.merge!( options || {} )
96
+ filter.options[:root] ||= self.class.config.root
97
+ end
98
+ private :setup_filter
99
+
100
+ def collection?
101
+ @is_collection ||= @model_or_models.respond_to?(:collect) && ! @model_or_models.is_a?(Hash)
102
+ end
103
+ private :collection?
104
+
105
+ def to_xml(options = nil)
106
+ setup_filter
107
+
87
108
  result = to_hash
109
+
110
+ root = config.root
111
+
88
112
  if root && result.is_a?(Array) && root.respond_to?(:pluralize)
89
- root = root.to_s.pluralize
113
+ root = root.pluralize
90
114
  end
91
115
  result.to_xml :root => root
92
116
  end
@@ -103,11 +127,11 @@ module Ixtlan
103
127
 
104
128
  private
105
129
 
106
- def filter_model(model, data)
130
+ def filter_model( model )
107
131
  if root = filter.options[:root]
108
- {root.to_s => filter.filter(model, data){ |model| attr(model) } }
132
+ { root.to_s => filter.filter( model ){ |model| attr(model) } }
109
133
  else
110
- filter.filter(model, data){ |model| attr(model) }
134
+ filter.filter( model ){ |model| attr(model) }
111
135
  end
112
136
  end
113
137
  end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ class Hash
4
+ def attributes
5
+ self
6
+ end
7
+ def method_missing(method)
8
+ self[method.to_s]
9
+ end
10
+ end
11
+
12
+ describe Ixtlan::Babel::HashFilter do
13
+ let(:data) do
14
+ data = {
15
+ 'id' => 987,
16
+ 'name' => 'me and the corner',
17
+ 'address' => { 'street' => 'Foo 12', 'zipcode' => '12345' },
18
+ 'phone_numbers' => {
19
+ 'prefix' => 12,
20
+ 'number' => '123',
21
+ 'area' => { 'code' => '001', 'iso' => 'us'}
22
+ }
23
+ }
24
+ class Hash
25
+ def self.new(hash = nil, &block)
26
+ if hash
27
+ self[hash]
28
+ else
29
+ super &block
30
+ end
31
+ end
32
+ end
33
+ data
34
+ end
35
+
36
+ let(:serializer) { Ixtlan::Babel::Serializer.new(data) }
37
+ let(:deserializer) { Ixtlan::Babel::Deserializer.new(Hash) }
38
+
39
+ it 'should serialize and deserialize a hash' do
40
+ json = serializer.to_json
41
+ result = deserializer.from_json(json)
42
+ result.must_equal Hash['id' => data['id'], 'name' => data['name']]
43
+ end
44
+
45
+ it 'should serialize and deserialize a hash with root' do
46
+ json = serializer.to_json :root => 'my'
47
+ result = deserializer.from_json(json, :root => 'my')
48
+ result.must_equal Hash['id' => data['id'], 'name' => data['name']]
49
+ end
50
+
51
+ it 'should serialize and deserialize a hash with include list' do
52
+ json = serializer.to_json(:include => ['address', 'phone_numbers'])
53
+ result = deserializer.from_json(json, :include => ['address', 'phone_numbers'])
54
+ data['phone_numbers'].delete('area')
55
+ result.must_equal Hash[data]
56
+ end
57
+
58
+ it 'should serialize and deserialize a hash with except' do
59
+ json = serializer.to_json(:except => ['id'])
60
+ result = deserializer.from_json(json, :except => ['id'])
61
+ result.must_equal Hash['name' => data['name']]
62
+ result = deserializer.from_json(json)
63
+ result.must_equal Hash['name' => data['name']]
64
+ end
65
+
66
+ it 'should serialize and deserialize a hash with only' do
67
+ json = serializer.to_json(:only => ['name'])
68
+ result = deserializer.from_json(json, :only => ['name'])
69
+ result.must_equal Hash['name' => data['name']]
70
+ result = deserializer.from_json(json)
71
+ result.must_equal Hash['name' => data['name']]
72
+ end
73
+
74
+ it 'should serialize and deserialize a hash with nested only' do
75
+ json = serializer.to_json(:include => { 'address' => {:only => ['street']}})
76
+ data.delete('phone_numbers')
77
+ data['address'].delete('zipcode')
78
+ result = deserializer.from_json(json, :include => { 'address' => {:only => ['street']}})
79
+ result.must_equal data
80
+ result = deserializer.from_json(json, :include => ['address'])
81
+ result.must_equal data
82
+ end
83
+
84
+ it 'should serialize and deserialize a hash with nested except' do
85
+ json = serializer.to_json(:include => { 'address' => {:except => ['zipcode']}})
86
+ data.delete('phone_numbers')
87
+ data['address'].delete('zipcode')
88
+ result = deserializer.from_json(json, :include => { 'address' => {:except => ['zipcode']}})
89
+ result.must_equal data
90
+ result = deserializer.from_json(json, :include => ['address'])
91
+ result.must_equal data
92
+ end
93
+
94
+ it 'should serialize and deserialize a hash with nested include' do
95
+ json = serializer.to_json(:include => { 'address' => {}, 'phone_numbers' => { :include => ['area']}})
96
+ result = deserializer.from_json(json, :include => { 'address' => {}, 'phone_numbers' => { :include => ['area']}})
97
+ result.must_equal data
98
+ end
99
+ end
@@ -0,0 +1,163 @@
1
+ require 'spec_helper'
2
+ require 'virtus'
3
+
4
+ class Address
5
+ include Virtus
6
+
7
+ attribute :street, String
8
+ attribute :zipcode, String
9
+ end
10
+ class Area
11
+ include Virtus
12
+
13
+ attribute :code, String
14
+ attribute :iso, String
15
+ end
16
+ class PhoneNumber
17
+ include Virtus
18
+
19
+ attribute :prefix, Integer
20
+ attribute :number, String
21
+ attribute :area, Area
22
+ end
23
+ class Person
24
+ include Virtus
25
+
26
+ attribute :id, String
27
+ attribute :name, String
28
+ attribute :address, Address
29
+ attribute :phone_numbers, Array[PhoneNumber]
30
+ end
31
+
32
+ describe Ixtlan::Babel::ModelFilter do
33
+ let( :person ) do
34
+ Person.new(
35
+ :id => 987,
36
+ :name => 'me and the corner',
37
+ :address => Address.new( :street => 'Foo 12', :zipcode => '12345' ),
38
+ :phone_numbers => [PhoneNumber.new(
39
+ :prefix => 12,
40
+ :number => '123',
41
+ :area => Area.new( :code => '001', :iso => 'us' )
42
+ )]
43
+ )
44
+ end
45
+
46
+ let(:serializer) { Ixtlan::Babel::Serializer.new( person ) }
47
+ let(:deserializer) { Ixtlan::Babel::Deserializer.new( Person ) }
48
+
49
+ it 'should serialize and deserialize without root' do
50
+ json = serializer.to_json
51
+ result = deserializer.from_json(json)
52
+ attributes = result.attributes.delete_if { |k,v| v.nil? }
53
+ attributes.must_equal Hash[:id => person['id'], :name => person['name']]
54
+ end
55
+
56
+ it 'should serialize and deserialize with root' do
57
+ json = serializer.to_json :root => 'my'
58
+ result = deserializer.from_json(json, :root => 'my')
59
+ attributes = result.attributes.delete_if { |k,v| v.nil? }
60
+ attributes.must_equal Hash[:id => person['id'], :name => person['name']]
61
+ end
62
+
63
+ it 'should serialize and deserialize a hash with include list' do
64
+ json = serializer.to_json(:include => ['address', 'phone_numbers'])
65
+ result = deserializer.from_json(json, :include => ['address', 'phone_numbers'])
66
+ result.object_id.wont_equal person.object_id
67
+ result.address.attributes.must_equal person.address.attributes
68
+ result.phone_numbers[0].area.must_be_nil
69
+ person.phone_numbers[0].area = nil
70
+ result.phone_numbers[0].attributes.must_equal person.phone_numbers[0].attributes
71
+ result.name.must_equal person.name
72
+ result.id.must_equal person.id
73
+ end
74
+
75
+ it 'shouldserialize and deserialize with except' do
76
+ json = serializer.to_json(:except => ['id'])
77
+ result = deserializer.from_json(json, :except => ['id'])
78
+ result.attributes.must_equal Hash[:name => person['name'], :address=>nil, :phone_numbers=>nil, :id => nil]
79
+ result = deserializer.from_json(json)
80
+ result.attributes.must_equal Hash[:name => person['name'], :address=>nil, :phone_numbers=>nil, :id => nil]
81
+ end
82
+
83
+ it 'should serialize and deserialize with only' do
84
+ json = serializer.to_json(:only => ['name'])
85
+ result = deserializer.from_json(json, :only => ['name'])
86
+ result.attributes.must_equal Hash[:name => person['name'], :address=>nil, :phone_numbers=>nil, :id => nil]
87
+ result = deserializer.from_json(json)
88
+ result.attributes.must_equal Hash[:name => person['name'], :address=>nil, :phone_numbers=>nil, :id => nil]
89
+ end
90
+
91
+ it 'should serialize and deserialize with nested only' do
92
+ json = serializer.to_json(:include => { 'address' => {:only => ['street']}})
93
+ result = deserializer.from_json(json, :include => { 'address' => {:only => ['street']}})
94
+
95
+ json['phone_numbers'].must_be_nil
96
+ json['address']['zipcode'].must_be_nil
97
+
98
+ result.phone_numbers.must_be_nil
99
+
100
+ result.address.zipcode.must_be_nil
101
+
102
+ result.name.must_equal person.name
103
+ result.id.must_equal person.id
104
+ end
105
+
106
+ it 'should serialize and deserialize with nested only (array includes)' do
107
+ json = serializer.to_json(:include => { 'address' => {:only => ['street']}})
108
+ result = deserializer.from_json(json, :include => ['address'])
109
+
110
+ json['phone_numbers'].must_be_nil
111
+ json['address']['zipcode'].must_be_nil
112
+
113
+ result.phone_numbers.must_be_nil
114
+
115
+ result.address.zipcode.must_be_nil
116
+
117
+ result.name.must_equal person.name
118
+ result.id.must_equal person.id
119
+ end
120
+
121
+ it 'should serialize and deserialize with nested except' do
122
+ json = serializer.to_json(:include => { 'address' => {:except => ['zipcode']}})
123
+ result = deserializer.from_json(json, :include => { 'address' => {:except => ['zipcode']}})
124
+
125
+ json['phone_numbers'].must_be_nil
126
+ json['address']['zipcode'].must_be_nil
127
+
128
+ result.phone_numbers.must_be_nil
129
+
130
+ result.address.zipcode.must_be_nil
131
+
132
+ result.name.must_equal person.name
133
+ result.id.must_equal person.id
134
+ end
135
+
136
+ it 'should serialize and deserialize with nested except (array includes)' do
137
+ json = serializer.to_json(:include => { 'address' => {:except => ['zipcode']}})
138
+ result = deserializer.from_json(json, :include => ['address'])
139
+
140
+ json['phone_numbers'].must_be_nil
141
+ json['address']['zipcode'].must_be_nil
142
+
143
+ result.phone_numbers.must_be_nil
144
+
145
+ result.address.zipcode.must_be_nil
146
+
147
+ result.name.must_equal person.name
148
+ result.id.must_equal person.id
149
+ end
150
+
151
+ it 'should serialize and deserialize with nested include' do
152
+ json = serializer.to_json(:include => { 'address' => {}, 'phone_numbers' => { :include => ['area']}})
153
+ result = deserializer.from_json(json, :include => { 'address' => {}, 'phone_numbers' => { :include => ['area']}})
154
+
155
+ result.object_id.wont_equal person.object_id
156
+ result.address.attributes.must_equal person.address.attributes
157
+ result.phone_numbers[0].area.attributes.must_equal person.phone_numbers[0].area.attributes
158
+ result.phone_numbers[0].prefix.must_equal person.phone_numbers[0].prefix
159
+ result.phone_numbers[0].number.must_equal person.phone_numbers[0].number
160
+ result.name.must_equal person.name
161
+ result.id.must_equal person.id
162
+ end
163
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ class Hash
4
+ def attributes
5
+ self
6
+ end
7
+ def method_missing(method)
8
+ self[method.to_s]
9
+ end
10
+ end
11
+
12
+ describe Ixtlan::Babel do
13
+ let(:data) do
14
+ data = {
15
+ 'id' => 987,
16
+ 'name' => 'me and the corner',
17
+ 'address' => { 'street' => 'Foo 12', 'zipcode' => '12345' },
18
+ 'phone_numbers' => {
19
+ 'prefix' => 12,
20
+ 'number' => '123',
21
+ 'area' => { 'code' => '001', 'iso' => 'us'}
22
+ }
23
+ }
24
+ class Hash
25
+ def self.new(hash = nil, &block)
26
+ if hash
27
+ self[hash]
28
+ else
29
+ super &block
30
+ end
31
+ end
32
+ end
33
+ data
34
+ end
35
+
36
+ let(:serializer) { Ixtlan::Babel::Serializer.new(data) }
37
+ let(:deserializer) { Ixtlan::Babel::Deserializer.new(Hash) }
38
+
39
+ it 'should serialize and deserialize a hash' do
40
+ json = serializer.to_json
41
+ result = deserializer.from_json(json)
42
+ result.must_equal Hash['id' => data['id'], 'name' => data['name']]
43
+ end
44
+
45
+ it 'should serialize and deserialize a hash with root' do
46
+ json = serializer.to_json :root => :my
47
+ result = deserializer.from_json(json, :root => :my)
48
+ result.must_equal Hash['id' => data['id'], 'name' => data['name']]
49
+ end
50
+
51
+ it 'should serialize and deserialize a hash with include list' do
52
+ json = serializer.to_json(:include => ['address', 'phone_numbers'])
53
+ result = deserializer.from_json(json, :include => ['address', 'phone_numbers'])
54
+ data['phone_numbers'].delete('area')
55
+ result.must_equal Hash[data]
56
+ end
57
+
58
+ it 'should serialize and deserialize a hash with except' do
59
+ json = serializer.to_json(:except => ['id'])
60
+ result = deserializer.from_json(json, :except => ['id'])
61
+ result.must_equal Hash['name' => data['name']]
62
+ result = deserializer.from_json(json)
63
+ result.must_equal Hash['name' => data['name']]
64
+ end
65
+
66
+ it 'should serialize and deserialize a hash with only' do
67
+ json = serializer.to_json(:only => ['name'])
68
+ result = deserializer.from_json(json, :only => ['name'])
69
+ result.must_equal Hash['name' => data['name']]
70
+ result = deserializer.from_json(json)
71
+ result.must_equal Hash['name' => data['name']]
72
+ end
73
+
74
+ it 'should serialize and deserialize a hash with nested only' do
75
+ json = serializer.to_json(:include => { 'address' => {:only => ['street']}})
76
+ data.delete('phone_numbers')
77
+ data['address'].delete('zipcode')
78
+ result = deserializer.from_json(json, :include => { 'address' => {:only => ['street']}})
79
+ result.must_equal data
80
+ result = deserializer.from_json(json, :include => ['address'])
81
+ result.must_equal data
82
+ end
83
+
84
+ it 'should serialize and deserialize a hash with nested except' do
85
+ json = serializer.to_json(:include => { 'address' => {:except => ['zipcode']}})
86
+ data.delete('phone_numbers')
87
+ data['address'].delete('zipcode')
88
+ result = deserializer.from_json(json, :include => { 'address' => {:except => ['zipcode']}})
89
+ result.must_equal data
90
+ result = deserializer.from_json(json, :include => ['address'])
91
+ result.must_equal data
92
+ end
93
+
94
+ it 'should serialize and deserialize a hash with nested include' do
95
+ json = serializer.to_json(:include => { 'address' => {}, 'phone_numbers' => { :include => ['area']}})
96
+ result = deserializer.from_json(json, :include => { 'address' => {}, 'phone_numbers' => { :include => ['area']}})
97
+ result.must_equal data
98
+ end
99
+ end