flatpack_core 1.1 → 1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/flatpack_core.gemspec +1 -1
- data/lib/flatpack/core/base_has_uuid.rb +5 -0
- data/lib/flatpack/core/packer.rb +45 -31
- data/lib/flatpack/core/unpacker.rb +58 -29
- data/lib/flatpack/core/version.rb +1 -1
- data/spec/core_spec.rb +135 -60
- data/spec/merchant.json +94 -0
- data/spec/merchant_location.json +24 -0
- metadata +12 -7
data/flatpack_core.gemspec
CHANGED
@@ -16,6 +16,6 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.version = Flatpack::Core::VERSION
|
17
17
|
gem.add_dependency('json', '~> 1.7')
|
18
18
|
gem.add_dependency('uuidtools', '~> 2.1')
|
19
|
-
gem.add_dependency('activesupport', "
|
19
|
+
gem.add_dependency('activesupport', "= 2.3.8")
|
20
20
|
gem.add_development_dependency "rspec", "~> 2.6"
|
21
21
|
end
|
@@ -41,6 +41,11 @@ module Flatpack
|
|
41
41
|
name = self.class.name.gsub(/^.*::/,'')
|
42
42
|
name[0,1].downcase + name[1..-1]
|
43
43
|
end
|
44
|
+
|
45
|
+
# Equality should be based solely on uuid
|
46
|
+
def <=>(other)
|
47
|
+
@uuid <=> other.uuid
|
48
|
+
end
|
44
49
|
|
45
50
|
def class_for_property(property)
|
46
51
|
klass=self.class
|
data/lib/flatpack/core/packer.rb
CHANGED
@@ -4,92 +4,106 @@ require 'json'
|
|
4
4
|
module Flatpack
|
5
5
|
module Core
|
6
6
|
class Packer
|
7
|
-
|
7
|
+
|
8
8
|
include MapInitialize
|
9
|
-
|
9
|
+
|
10
10
|
attr_accessor :verbose, :pretty
|
11
|
-
|
11
|
+
|
12
12
|
# Generate a FlatPack JSON string from the given entity
|
13
13
|
def pack(entity)
|
14
14
|
return {} unless entity
|
15
|
-
|
15
|
+
|
16
16
|
@uuid_stack = []
|
17
17
|
@all_entities = {}
|
18
18
|
@data = {}
|
19
|
-
|
19
|
+
|
20
20
|
recursive_pack(entity)
|
21
|
-
|
21
|
+
|
22
22
|
json = {
|
23
|
-
|
24
|
-
|
23
|
+
:data => @data,
|
24
|
+
:value => entity.uuid
|
25
25
|
}
|
26
26
|
json = @pretty ? JSON.pretty_generate(json) : json.to_json
|
27
|
-
|
27
|
+
|
28
28
|
if(@verbose)
|
29
29
|
puts "*** Serializing #{entity.entity_name} to FlatPack ***"
|
30
30
|
puts json
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
json
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
private
|
37
|
-
|
37
|
+
|
38
38
|
def recursive_pack(entity)
|
39
|
-
# we only proceed if the entity has a uuid property,
|
39
|
+
# we only proceed if the entity has a uuid property,
|
40
40
|
# and we haven't seen it before
|
41
41
|
uuid = entity.uuid
|
42
|
+
|
42
43
|
return if !entity.respond_to?(:uuid) or @all_entities.keys.include?(uuid)
|
43
|
-
|
44
|
+
|
44
45
|
@all_entities[uuid] = entity
|
45
46
|
parent_uuid = @uuid_stack.length > 0 ? @uuid_stack.last : nil
|
46
47
|
@uuid_stack.push(uuid)
|
47
|
-
|
48
|
-
# walk through our properties
|
49
48
|
json = entity.properties
|
49
|
+
|
50
|
+
# if the entity has some embedded properties, we walk throught them
|
51
|
+
if(entity.class.const_defined?(:EMBEDDED_PROPERTY_NAMES))
|
52
|
+
entity.class::EMBEDDED_PROPERTY_NAMES.each do |embedded_property_name|
|
53
|
+
embedded = entity.send(embedded_property_name)
|
54
|
+
|
55
|
+
# Each property of the embedded value should be added to our top level JSON
|
56
|
+
if(embedded.class.const_defined?(:PROPERTY_NAMES))
|
57
|
+
embedded.class::PROPERTY_NAMES.each do |name|
|
58
|
+
json[name] = embedded.send(name)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# walk through our properties
|
50
65
|
json.keys.each do |name|
|
51
66
|
camel_name = name.to_s.camelize
|
52
67
|
camel_name = camel_name[0,1].downcase + camel_name[1..-1]
|
53
|
-
|
54
68
|
value = json[name]
|
55
69
|
uuid_name = "#{camel_name}Uuid"
|
56
|
-
|
57
|
-
# The name we're working with will be replaced with a
|
70
|
+
|
71
|
+
# The name we're working with will be replaced with a
|
58
72
|
# properly cased name or uuid reference
|
59
73
|
json.delete(name)
|
60
|
-
|
74
|
+
|
61
75
|
# property is another entity
|
62
76
|
if(value.respond_to?(:uuid))
|
63
77
|
recursive_pack(value)
|
64
78
|
json[uuid_name] = value.uuid
|
65
|
-
|
66
|
-
|
79
|
+
|
80
|
+
# property is a collection of (potentially) other entities
|
67
81
|
elsif(value.is_a?(Array))
|
68
|
-
|
82
|
+
|
69
83
|
# we'll recurse down to each referenced value
|
70
84
|
value.each do |referenced_value|
|
71
85
|
recursive_pack(referenced_value)
|
72
86
|
referenced_value.uuid
|
73
87
|
end
|
74
|
-
|
88
|
+
|
75
89
|
# and add our uuid reference
|
76
90
|
json[uuid_name] = value.map {|v| v.uuid}
|
77
|
-
|
78
|
-
|
91
|
+
|
92
|
+
# property is a plain old property
|
79
93
|
else
|
80
|
-
# TODO how to handle local..At dates?
|
94
|
+
# TODO how to handle local..At dates?
|
81
95
|
# Pass a timezone into the pack function as an option?
|
82
96
|
|
83
97
|
json[camel_name] = value
|
84
98
|
end
|
85
99
|
end
|
86
|
-
|
100
|
+
|
87
101
|
# add our parent uuid reference if neccessary
|
88
102
|
if parent_uuid
|
89
103
|
parent = @all_entities[parent_uuid]
|
90
104
|
json["#{parent.entity_name}Uuid"] = parent_uuid
|
91
105
|
end
|
92
|
-
|
106
|
+
|
93
107
|
# add the resulting json to the correct bucket in our data hash
|
94
108
|
bucket = @data[entity.entity_name]
|
95
109
|
if(!bucket)
|
@@ -97,10 +111,10 @@ module Flatpack
|
|
97
111
|
@data[entity.entity_name] = bucket
|
98
112
|
end
|
99
113
|
bucket.push(json)
|
100
|
-
|
114
|
+
|
101
115
|
@uuid_stack.pop
|
102
116
|
end
|
103
|
-
|
117
|
+
|
104
118
|
end
|
105
119
|
end
|
106
120
|
end
|
@@ -3,20 +3,20 @@ require 'active_support/inflector'
|
|
3
3
|
module Flatpack
|
4
4
|
module Core
|
5
5
|
class Unpacker
|
6
|
-
|
6
|
+
|
7
7
|
include MapInitialize
|
8
|
-
|
8
|
+
|
9
9
|
attr_accessor :verbose, :entity_module
|
10
10
|
|
11
11
|
# Returns a Reified FlatPack entity from the given JSON data
|
12
12
|
def unpack(json_map)
|
13
13
|
@all_entities = {}
|
14
|
-
|
14
|
+
|
15
15
|
if(@verbose)
|
16
16
|
puts "** Deserializing entity from FlatPack **"
|
17
17
|
puts JSON.pretty_generate(json_map)
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
# Make a first pass through the data to ensure stub entities exist
|
21
21
|
uuid_to_data = {}
|
22
22
|
(json_map['data'] || []).each do |entity_name, entities|
|
@@ -29,59 +29,74 @@ module Flatpack
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
# Then ingest
|
34
34
|
uuid_to_data.each { |uuid, data| ingest_item(uuid, data) }
|
35
|
-
|
35
|
+
|
36
36
|
# Return the unpacked entities corresponding to those in the value section
|
37
37
|
value = json_map['value']
|
38
38
|
value.is_a?(Array) ? value.map{|v| @all_entities[v]} : @all_entities[value]
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
private
|
42
|
-
|
42
|
+
|
43
43
|
# ingests the given data into the entity associated with the given uuid
|
44
44
|
def ingest_item(uuid, data)
|
45
45
|
entity = @all_entities[uuid]
|
46
46
|
collection_key = entity.entity_name.underscore.pluralize
|
47
47
|
reified_properties = {}
|
48
|
-
|
48
|
+
embedded_entities = [];
|
49
|
+
|
50
|
+
# if this entity has some embedded properties, we'll associate each with
|
51
|
+
# a new instance of the defined type
|
52
|
+
if(entity.class.const_defined?(:EMBEDDED_PROPERTY_NAMES))
|
53
|
+
entity.class::EMBEDDED_PROPERTY_NAMES.each do |embedded_property_name|
|
54
|
+
klass = entity.class_for_property(embedded_property_name)
|
55
|
+
setter = "#{embedded_property_name}="
|
56
|
+
if(entity.respond_to?(setter))
|
57
|
+
embedded_entity = klass.new
|
58
|
+
entity.send(setter, embedded_entity)
|
59
|
+
embedded_entities.push(embedded_entity)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
49
64
|
data.each do |key, value|
|
50
|
-
|
65
|
+
|
51
66
|
# fooBarsUuid -> foo_bars
|
52
67
|
key = key.underscore
|
53
|
-
|
68
|
+
|
54
69
|
# If the key name ends in _date or _at, we assume this is a date property
|
55
70
|
if(key.end_with?('_date') or key.end_with?('_at'))
|
56
71
|
reified_properties[key] = Time.parse(value).utc
|
57
72
|
end
|
58
|
-
|
73
|
+
|
59
74
|
# The value is referencing another entity or collection of entities
|
60
75
|
if(key.end_with?('uuid'))
|
61
|
-
|
76
|
+
|
62
77
|
# foo_bar_uuid -> foo_bar
|
63
78
|
key = key[0..-6]
|
64
|
-
|
79
|
+
|
65
80
|
if(value.is_a?(Array))
|
66
81
|
reified_properties[key] = value.map { |uuid| @all_entities[uuid] }
|
67
|
-
|
82
|
+
|
68
83
|
else
|
69
84
|
referent = @all_entities[value]
|
70
|
-
|
85
|
+
|
71
86
|
# If the referent doesn't exist, it's because the server has sent us a sparse
|
72
|
-
# payload with a dangling fooUuid reference. We'll attempt to unpack this
|
87
|
+
# payload with a dangling fooUuid reference. We'll attempt to unpack this
|
73
88
|
# reference using the type informtion encoded within each entity description
|
74
89
|
unless referent
|
75
90
|
referent_class = entity.class_for_property(key)
|
76
91
|
referent = referent_class.new(:uuid => value) if referent_class
|
77
92
|
end
|
78
|
-
|
93
|
+
|
79
94
|
# If a referent was not included in the payload, and no type information exists
|
80
95
|
# for this property name, we simply drop the property
|
81
96
|
next unless referent
|
82
|
-
|
97
|
+
|
83
98
|
reified_properties[key] = referent
|
84
|
-
|
99
|
+
|
85
100
|
# Find or create a collection in the referent to establish a bidirectional mapping.
|
86
101
|
# For example a foo.bar property should contain a bar.foos collection.
|
87
102
|
if(referent.respond_to?(collection_key))
|
@@ -93,32 +108,46 @@ module Flatpack
|
|
93
108
|
referent.send(collection_setter, collection)
|
94
109
|
end
|
95
110
|
end
|
96
|
-
collection.push(entity)
|
111
|
+
collection.push(entity) unless collection.include?(entity)
|
97
112
|
end
|
98
113
|
end
|
99
|
-
|
100
|
-
|
114
|
+
|
115
|
+
# The value is just a plain old property
|
101
116
|
else
|
102
|
-
|
117
|
+
|
118
|
+
# if the entity accepts a property with this key directly, we add it
|
119
|
+
if(entity.respond_to?(key))
|
120
|
+
reified_properties[key] = value
|
121
|
+
|
122
|
+
# otherwise, we attempt to set the property on to one of our
|
123
|
+
# embedded entity properties
|
124
|
+
else
|
125
|
+
embedded_entities.each do |embedded_entity|
|
126
|
+
setter = "#{key}=".to_sym
|
127
|
+
if embedded_entity.respond_to?(setter)
|
128
|
+
embedded_entity.send(setter, value)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
103
132
|
end
|
104
133
|
end
|
105
|
-
|
134
|
+
|
106
135
|
entity.set_properties(reified_properties)
|
107
136
|
end
|
108
|
-
|
137
|
+
|
109
138
|
# Finds the existing entity associated with the given uuid in the local
|
110
139
|
# entity store, or stores and returns a new one
|
111
140
|
def allocate_or_get_entity(entity_name, uuid)
|
112
141
|
entity = @all_entities[uuid]
|
113
142
|
return entity if entity
|
114
|
-
|
143
|
+
|
115
144
|
klass = entity_class_for_name(entity_name)
|
116
145
|
if(klass != nil)
|
117
146
|
@all_entities[uuid] = klass.new({:uuid => uuid})
|
118
147
|
end
|
119
148
|
klass
|
120
149
|
end
|
121
|
-
|
150
|
+
|
122
151
|
# Finds the Ruby class associated with the given entity name
|
123
152
|
def entity_class_for_name(name)
|
124
153
|
class_name = "#{name[0,1].capitalize}#{name[1..-1]}"
|
@@ -134,7 +163,7 @@ module Flatpack
|
|
134
163
|
puts "could not create class for name #{class_name}"
|
135
164
|
end
|
136
165
|
|
137
|
-
result
|
166
|
+
result
|
138
167
|
end
|
139
168
|
end
|
140
169
|
end
|
data/spec/core_spec.rb
CHANGED
@@ -1,130 +1,153 @@
|
|
1
1
|
require 'flatpack_core'
|
2
2
|
|
3
|
+
class Merchant < Flatpack::Core::BaseHasUuid
|
4
|
+
attr_accessor :uuid, :merchant_locations;
|
5
|
+
end
|
6
|
+
|
7
|
+
class StreetAddress < Flatpack::Core::BaseHasUuid
|
8
|
+
PROPERTY_NAMES = [:address, :city, :state, :zip]
|
9
|
+
attr_accessor *PROPERTY_NAMES
|
10
|
+
end
|
11
|
+
|
12
|
+
class MerchantLocation < Flatpack::Core::BaseHasUuid
|
13
|
+
PROPERTY_NAMES = [:uuid, :merchant]
|
14
|
+
attr_accessor *PROPERTY_NAMES
|
15
|
+
|
16
|
+
EMBEDDED_PROPERTY_NAMES = [
|
17
|
+
:street_address
|
18
|
+
]
|
19
|
+
attr_accessor *EMBEDDED_PROPERTY_NAMES
|
20
|
+
|
21
|
+
TYPE_MAP = {
|
22
|
+
:street_address => StreetAddress,
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
3
26
|
class TestEntity < Flatpack::Core::BaseHasUuid
|
4
27
|
PROPERTY_NAMES = [
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
28
|
+
:one,
|
29
|
+
:two,
|
30
|
+
:test_sub_entities,
|
31
|
+
:test_entities,
|
32
|
+
:test_entity
|
10
33
|
]
|
11
34
|
attr_accessor *PROPERTY_NAMES
|
12
35
|
end
|
13
36
|
|
14
37
|
class TestSubEntity < TestEntity
|
15
38
|
PROPERTY_NAMES = [
|
16
|
-
|
39
|
+
:three
|
17
40
|
]
|
18
41
|
attr_accessor *PROPERTY_NAMES
|
19
42
|
end
|
20
43
|
|
21
44
|
describe Flatpack::Core do
|
22
|
-
|
45
|
+
|
23
46
|
before(:all) do
|
24
47
|
@flatpack = Flatpack::Core::Flatpack.new({
|
25
|
-
|
26
|
-
|
27
|
-
|
48
|
+
:pretty => true,
|
49
|
+
:verbose => true
|
50
|
+
})
|
28
51
|
end
|
29
|
-
|
52
|
+
|
30
53
|
it "serializes a simple entity" do
|
31
|
-
|
54
|
+
|
32
55
|
root = TestEntity.new({
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
56
|
+
:one => 'first',
|
57
|
+
:two => 'second'
|
58
|
+
})
|
59
|
+
|
37
60
|
json = @flatpack.packer.pack(root)
|
38
|
-
|
61
|
+
|
39
62
|
map = JSON.parse(json)
|
40
63
|
map['data'].keys.length.should eq(1)
|
41
64
|
entities = map['data']['testEntity']
|
42
65
|
entities.length.should eq(1)
|
43
66
|
entity = entities[0]
|
44
|
-
|
67
|
+
|
45
68
|
entity.keys.length.should eq(3)
|
46
69
|
entity['one'].should eq('first')
|
47
70
|
entity['two'].should eq('second')
|
48
71
|
entity['uuid'].should be_true
|
49
72
|
end
|
50
|
-
|
73
|
+
|
51
74
|
it "serializes an entity with forward references" do
|
52
|
-
|
75
|
+
|
53
76
|
root = TestEntity.new({
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
77
|
+
:one => 'first',
|
78
|
+
:two => [
|
79
|
+
TestSubEntity.new({:one => 'first', :three => 'third'}),
|
80
|
+
TestSubEntity.new({:one => 'first', :three => 'third'})
|
81
|
+
]
|
82
|
+
})
|
83
|
+
|
61
84
|
json = @flatpack.packer.pack(root)
|
62
|
-
|
85
|
+
|
63
86
|
map = JSON.parse(json)
|
64
|
-
|
87
|
+
|
65
88
|
map['data'].keys.length.should eq(2)
|
66
|
-
|
89
|
+
|
67
90
|
# we should have 1 TestEntity at our root
|
68
91
|
root_entities = map['data']['testEntity']
|
69
92
|
root_entities.length.should eq(1)
|
70
93
|
root_entity = root_entities[0]
|
71
94
|
root_entity['one'].should eq('first')
|
72
|
-
|
95
|
+
|
73
96
|
# our collection reference at :two should have been flattened away
|
74
97
|
root_entity['two'].should be_nil
|
75
98
|
root_entity_uuid = root_entity['uuid']
|
76
|
-
|
99
|
+
|
77
100
|
# two TestSubEntities under our root
|
78
101
|
sub_entities = map['data']['testSubEntity']
|
79
102
|
sub_entities.length.should eq(2)
|
80
103
|
sub_entity_one = sub_entities[0]
|
81
104
|
sub_entity_two = sub_entities[1]
|
82
|
-
|
105
|
+
|
83
106
|
# sub entities should have a reference to the parent
|
84
107
|
sub_entity_one['testEntityUuid'].should eq(root_entity_uuid)
|
85
108
|
sub_entity_two['testEntityUuid'].should eq(root_entity_uuid)
|
86
|
-
|
109
|
+
|
87
110
|
# and 3 additional properties
|
88
111
|
sub_entity_one.length.should eq(4)
|
89
112
|
sub_entity_one['one'].should eq('first')
|
90
113
|
sub_entity_one['three'].should eq('third')
|
91
114
|
sub_entity_one['two'].should be_nil
|
92
|
-
|
115
|
+
|
93
116
|
sub_entity_two.length.should eq(4)
|
94
117
|
sub_entity_two['one'].should eq('first')
|
95
118
|
sub_entity_two['three'].should eq('third')
|
96
119
|
sub_entity_two['two'].should be_nil
|
97
120
|
end
|
98
|
-
|
121
|
+
|
99
122
|
it "serializes an entity with back reference" do
|
100
|
-
|
123
|
+
|
101
124
|
sibling_one = TestEntity.new({
|
102
|
-
|
103
|
-
|
104
|
-
|
125
|
+
:one => 'first_sibling'
|
126
|
+
})
|
127
|
+
|
105
128
|
sibling_two = TestEntity.new({
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
129
|
+
:one => 'second_sibling',
|
130
|
+
:two => sibling_one
|
131
|
+
})
|
132
|
+
|
110
133
|
json = @flatpack.packer.pack(sibling_two)
|
111
|
-
|
134
|
+
|
112
135
|
map = JSON.parse(json)
|
113
|
-
|
136
|
+
|
114
137
|
map['data'].keys.length.should eq(1)
|
115
138
|
entities = map['data']['testEntity']
|
116
139
|
entities.each do |e|
|
117
|
-
if(e['uuid'].eql?(sibling_one.uuid.to_s))
|
140
|
+
if(e['uuid'].eql?(sibling_one.uuid.to_s))
|
118
141
|
e['testEntityUuid'].should eq(sibling_two.uuid.to_s)
|
119
142
|
else
|
120
143
|
e['testEntityUuid'].should be_nil
|
121
144
|
end
|
122
145
|
end
|
123
|
-
|
146
|
+
|
124
147
|
end
|
125
|
-
|
148
|
+
|
126
149
|
it "de-serializes a simple entity" do
|
127
|
-
|
150
|
+
|
128
151
|
json = '{'\
|
129
152
|
'"value": "b2197fc8-42df-4d8c-9890-0f37a4f99fc7",'\
|
130
153
|
'"data": {'\
|
@@ -138,17 +161,17 @@ describe Flatpack::Core do
|
|
138
161
|
']'\
|
139
162
|
'}'\
|
140
163
|
'}'
|
141
|
-
|
164
|
+
|
142
165
|
# the unpacking should succeed even when an unknown
|
143
166
|
# entity type (unknownEntity) is present
|
144
167
|
entity = @flatpack.unpacker.unpack(JSON.parse(json))
|
145
|
-
|
168
|
+
|
146
169
|
entity.one.should eq('first')
|
147
170
|
entity.two.should eq('second')
|
148
171
|
entity.uuid.should eq('b2197fc8-42df-4d8c-9890-0f37a4f99fc7')
|
149
|
-
|
172
|
+
|
150
173
|
end
|
151
|
-
|
174
|
+
|
152
175
|
it "de-serializes an entity with a collection reference" do
|
153
176
|
json = '{'\
|
154
177
|
'"value": "d1c958ba-e6ea-4b12-8335-347289e404ac",'\
|
@@ -175,21 +198,73 @@ describe Flatpack::Core do
|
|
175
198
|
']'\
|
176
199
|
'}'\
|
177
200
|
'}'\
|
178
|
-
|
201
|
+
|
179
202
|
entity = @flatpack.unpacker.unpack(JSON.parse(json))
|
180
|
-
|
203
|
+
|
181
204
|
entity.uuid.should eq('d1c958ba-e6ea-4b12-8335-347289e404ac')
|
182
205
|
entity.one.should eq('first')
|
183
|
-
|
206
|
+
|
184
207
|
# entity should have both sub entities within the test_entities property
|
185
208
|
entity.test_sub_entities.length.should eq(2)
|
186
209
|
entity.test_sub_entities[0].three.should eq('third')
|
187
210
|
entity.test_sub_entities[0].one.should eq('first')
|
188
211
|
entity.test_sub_entities[1].three.should eq('third')
|
189
212
|
entity.test_sub_entities[1].one.should eq('first')
|
190
|
-
|
213
|
+
|
191
214
|
entity.test_sub_entities[0].test_entity.uuid.should eq('d1c958ba-e6ea-4b12-8335-347289e404ac')
|
192
|
-
|
193
215
|
end
|
194
|
-
|
216
|
+
|
217
|
+
it "deserializes a complex object graph" do
|
218
|
+
json = File.open("#{File.dirname(__FILE__)}/merchant.json", "r").read
|
219
|
+
merchant = @flatpack.unpacker.unpack(JSON.parse(json))
|
220
|
+
|
221
|
+
# ensure we have the proper number of merchant locations
|
222
|
+
merchant.merchant_locations.size.should eq(4)
|
223
|
+
|
224
|
+
# with the proper uuids...
|
225
|
+
|
226
|
+
merchant.merchant_locations.detect do |ml|
|
227
|
+
ml.uuid == 'e988f216-aca6-490d-ad45-4840e05da352'
|
228
|
+
end.should_not be_nil
|
229
|
+
|
230
|
+
merchant.merchant_locations.detect do |ml|
|
231
|
+
ml.uuid == '08ab924a-9742-4e9b-8444-ffc9b43f8566'
|
232
|
+
end.should_not be_nil
|
233
|
+
|
234
|
+
merchant.merchant_locations.detect do |ml|
|
235
|
+
ml.uuid == 'f77333aa-a66c-4944-9b95-53efc3657418'
|
236
|
+
end.should_not be_nil
|
237
|
+
|
238
|
+
merchant.merchant_locations.detect do |ml|
|
239
|
+
ml.uuid == '5f72a832-02af-4dd9-8b30-7cef87f37833'
|
240
|
+
end.should_not be_nil
|
241
|
+
end
|
242
|
+
|
243
|
+
it "tests embeddable properties" do
|
244
|
+
json = File.open("#{File.dirname(__FILE__)}/merchant_location.json", "r").read
|
245
|
+
location = @flatpack.unpacker.unpack(JSON.parse(json))
|
246
|
+
|
247
|
+
# no address information should be available directly on the location entity
|
248
|
+
location.respond_to?(:address).should be_false
|
249
|
+
location.respond_to?(:city).should be_false
|
250
|
+
location.respond_to?(:state).should be_false
|
251
|
+
location.respond_to?(:zip).should be_false
|
252
|
+
|
253
|
+
# instead, they should be within an embedded StreetAddress property
|
254
|
+
location.street_address.address.should eq("1 Embarcadero Center")
|
255
|
+
location.street_address.city.should eq("San Francisco")
|
256
|
+
location.street_address.state.should eq("CA")
|
257
|
+
location.street_address.zip.should eq("94111")
|
258
|
+
|
259
|
+
# now we'll pack our location back to JSON, which should fold the
|
260
|
+
# embedded address properties onto the location directly, then unpack
|
261
|
+
# that JSON again to ensure that the address information has been preserved
|
262
|
+
location = @flatpack.unpacker.unpack(JSON.parse(@flatpack.packer.pack(location)))
|
263
|
+
location.street_address.address.should eq("1 Embarcadero Center")
|
264
|
+
location.street_address.city.should eq("San Francisco")
|
265
|
+
location.street_address.state.should eq("CA")
|
266
|
+
location.street_address.zip.should eq("94111")
|
267
|
+
|
268
|
+
end
|
269
|
+
|
195
270
|
end
|
data/spec/merchant.json
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
{
|
2
|
+
"value": "a7ae48c9-c0ad-4f2c-a0ca-484f2f5b351c",
|
3
|
+
"status_code": "200",
|
4
|
+
"data": {
|
5
|
+
"merchant": [
|
6
|
+
{
|
7
|
+
"merchantLocationsUuid": [
|
8
|
+
"e988f216-aca6-490d-ad45-4840e05da352",
|
9
|
+
"08ab924a-9742-4e9b-8444-ffc9b43f8566",
|
10
|
+
"f77333aa-a66c-4944-9b95-53efc3657418",
|
11
|
+
"5f72a832-02af-4dd9-8b30-7cef87f37833"
|
12
|
+
],
|
13
|
+
"visitExpirationMinutes": 30,
|
14
|
+
"name": "The Melt (new)",
|
15
|
+
"updatedAt": "2012-09-17T20:33:02.000Z",
|
16
|
+
"pointsSignupBonus": 0,
|
17
|
+
"merchantCapabilitiesUuid": [
|
18
|
+
|
19
|
+
],
|
20
|
+
"merchantState": "LIVE",
|
21
|
+
"headline": "Free Cheese is Awesome",
|
22
|
+
"createdAt": "2012-09-12T17:17:43.000Z",
|
23
|
+
"loyaltyType": "PUNCHCARD",
|
24
|
+
"uuid": "a7ae48c9-c0ad-4f2c-a0ca-484f2f5b351c"
|
25
|
+
}
|
26
|
+
],
|
27
|
+
"merchantLocation": [
|
28
|
+
{
|
29
|
+
"longitude": -122.3994071,
|
30
|
+
"latitude": 37.795027,
|
31
|
+
"combinedAddress": "1 Embarcadero Center",
|
32
|
+
"merchantUuid": "a7ae48c9-c0ad-4f2c-a0ca-484f2f5b351c",
|
33
|
+
"country": "US",
|
34
|
+
"state": "CA",
|
35
|
+
"address": "1 Embarcadero Center",
|
36
|
+
"timezone": "America/Los_Angeles",
|
37
|
+
"createdAt": "2012-09-12T17:17:44.000Z",
|
38
|
+
"city": "San Francisco",
|
39
|
+
"neighborhoodName": "San Francisco",
|
40
|
+
"zip": "94111",
|
41
|
+
"smsId": "melt1",
|
42
|
+
"uuid": "e988f216-aca6-490d-ad45-4840e05da352"
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"longitude": -122.4001066,
|
46
|
+
"latitude": 37.7872407,
|
47
|
+
"combinedAddress": "115 New Montgomery St",
|
48
|
+
"merchantUuid": "a7ae48c9-c0ad-4f2c-a0ca-484f2f5b351c",
|
49
|
+
"country": "US",
|
50
|
+
"state": "CA",
|
51
|
+
"address": "115 New Montgomery St",
|
52
|
+
"timezone": "America/Los_Angeles",
|
53
|
+
"createdAt": "2012-09-12T17:17:44.000Z",
|
54
|
+
"city": "San Francisco",
|
55
|
+
"neighborhoodName": "San Francisco",
|
56
|
+
"zip": "94105",
|
57
|
+
"smsId": "melt2",
|
58
|
+
"uuid": "08ab924a-9742-4e9b-8444-ffc9b43f8566"
|
59
|
+
},
|
60
|
+
{
|
61
|
+
"longitude": -122.3901921,
|
62
|
+
"latitude": 37.7897624,
|
63
|
+
"combinedAddress": "345 Spear St",
|
64
|
+
"merchantUuid": "a7ae48c9-c0ad-4f2c-a0ca-484f2f5b351c",
|
65
|
+
"country": "US",
|
66
|
+
"state": "CA",
|
67
|
+
"address": "345 Spear St",
|
68
|
+
"timezone": "America/Los_Angeles",
|
69
|
+
"createdAt": "2012-09-12T17:17:44.000Z",
|
70
|
+
"city": "San Francisco",
|
71
|
+
"neighborhoodName": "San Francisco",
|
72
|
+
"zip": "94105",
|
73
|
+
"smsId": "melt3",
|
74
|
+
"uuid": "f77333aa-a66c-4944-9b95-53efc3657418"
|
75
|
+
},
|
76
|
+
{
|
77
|
+
"longitude": -122.170764,
|
78
|
+
"latitude": 37.4442964,
|
79
|
+
"combinedAddress": "180 El Camino Real",
|
80
|
+
"merchantUuid": "a7ae48c9-c0ad-4f2c-a0ca-484f2f5b351c",
|
81
|
+
"country": "US",
|
82
|
+
"state": "California",
|
83
|
+
"address": "180 El Camino Real",
|
84
|
+
"timezone": "America/Los_Angeles",
|
85
|
+
"createdAt": "2012-09-12T17:17:44.000Z",
|
86
|
+
"city": "Palo Alto",
|
87
|
+
"neighborhoodName": "Palo Alto",
|
88
|
+
"zip": "94304",
|
89
|
+
"smsId": "melt4",
|
90
|
+
"uuid": "5f72a832-02af-4dd9-8b30-7cef87f37833"
|
91
|
+
}
|
92
|
+
]
|
93
|
+
}
|
94
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"value": "e988f216-aca6-490d-ad45-4840e05da352",
|
3
|
+
"status_code": "200",
|
4
|
+
"data": {
|
5
|
+
"merchantLocation": [
|
6
|
+
{
|
7
|
+
"longitude": -122.3994071,
|
8
|
+
"latitude": 37.795027,
|
9
|
+
"combinedAddress": "1 Embarcadero Center",
|
10
|
+
"merchantUuid": "a7ae48c9-c0ad-4f2c-a0ca-484f2f5b351c",
|
11
|
+
"country": "US",
|
12
|
+
"state": "CA",
|
13
|
+
"address": "1 Embarcadero Center",
|
14
|
+
"timezone": "America/Los_Angeles",
|
15
|
+
"createdAt": "2012-09-12T17:17:44.000Z",
|
16
|
+
"city": "San Francisco",
|
17
|
+
"neighborhoodName": "San Francisco",
|
18
|
+
"zip": "94111",
|
19
|
+
"smsId": "melt1",
|
20
|
+
"uuid": "e988f216-aca6-490d-ad45-4840e05da352"
|
21
|
+
}
|
22
|
+
]
|
23
|
+
}
|
24
|
+
}
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flatpack_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 9
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: "1.
|
8
|
+
- 3
|
9
|
+
version: "1.3"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Joe Stelmach
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-09
|
17
|
+
date: 2012-10-09 00:00:00 +05:30
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -53,13 +53,14 @@ dependencies:
|
|
53
53
|
requirement: &id003 !ruby/object:Gem::Requirement
|
54
54
|
none: false
|
55
55
|
requirements:
|
56
|
-
- -
|
56
|
+
- - "="
|
57
57
|
- !ruby/object:Gem::Version
|
58
|
-
hash:
|
58
|
+
hash: 19
|
59
59
|
segments:
|
60
60
|
- 2
|
61
61
|
- 3
|
62
|
-
|
62
|
+
- 8
|
63
|
+
version: 2.3.8
|
63
64
|
type: :runtime
|
64
65
|
version_requirements: *id003
|
65
66
|
- !ruby/object:Gem::Dependency
|
@@ -100,6 +101,8 @@ files:
|
|
100
101
|
- lib/flatpack/core/version.rb
|
101
102
|
- lib/flatpack_core.rb
|
102
103
|
- spec/core_spec.rb
|
104
|
+
- spec/merchant.json
|
105
|
+
- spec/merchant_location.json
|
103
106
|
has_rdoc: true
|
104
107
|
homepage: ""
|
105
108
|
licenses: []
|
@@ -136,3 +139,5 @@ specification_version: 3
|
|
136
139
|
summary: Write a gem summary
|
137
140
|
test_files:
|
138
141
|
- spec/core_spec.rb
|
142
|
+
- spec/merchant.json
|
143
|
+
- spec/merchant_location.json
|