flatpack_core 1.1 → 1.3
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.
- 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
|