kanade 0.1.0.beta1 → 0.1.0.beta2
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.
- checksums.yaml +4 -4
- data/.editorconfig +1 -0
- data/.gitignore +4 -2
- data/Gemfile.lock +1 -1
- data/lib/kanade/converter/bool.rb +24 -22
- data/lib/kanade/converter/dto.rb +17 -0
- data/lib/kanade/converter/list.rb +22 -5
- data/lib/kanade/converter/time.rb +26 -25
- data/lib/kanade/dto.rb +56 -47
- data/lib/kanade/engine.rb +149 -87
- data/lib/kanade/version.rb +1 -1
- data/spec/fixtures/catalog_camel_case.json +20 -19
- data/spec/fixtures/refund_report.json +5 -0
- data/spec/fixtures/refund_report.rb +2 -1
- data/spec/integration/ignore_unknown_field_spec.rb +5 -0
- data/spec/integration/simple_deserialization_integration_spec.rb +66 -0
- data/spec/integration/simple_serialization_integration_spec.rb +54 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25723d77b3f99e8994da9fd4aa44eba091198831
|
4
|
+
data.tar.gz: 9458dddba1f8fdff1041ab11cd79a5c83e9c8183
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66d8f6cdb94ce27c648957e5089d7884101b0087a5916da253acfab3f4c2905b31ac8117282c1b73785fcad7d0589ce4c0692e6147609402e0f0cbdbffe4ddd1
|
7
|
+
data.tar.gz: b5b0884a344d5f26b314231d569e6c300ead110eac7dd47217f396378c9ecc9573c35af615c23bbe0779880c03e5bee3973e9692ce813fa4ecdc6d84a7a38390
|
data/.editorconfig
CHANGED
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,22 +1,24 @@
|
|
1
|
-
module Kanade
|
2
|
-
module Converter
|
3
|
-
class Bool < Base
|
4
|
-
Engine.register_converter!(self)
|
5
|
-
|
6
|
-
def serialize(term, _)
|
7
|
-
return nil if term.nil?
|
8
|
-
term.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
return
|
14
|
-
term ?
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
1
|
+
module Kanade
|
2
|
+
module Converter
|
3
|
+
class Bool < Base
|
4
|
+
Engine.register_converter!(self)
|
5
|
+
|
6
|
+
def serialize(term, _)
|
7
|
+
return nil if term.nil?
|
8
|
+
return true if term.is_a?(TrueClass)
|
9
|
+
return false if term.is_a?(FalseClass)
|
10
|
+
raise NotSupportedError.new("Trying to serialize a bool, but given unknown object")
|
11
|
+
end
|
12
|
+
def deserialize(term, _)
|
13
|
+
return nil if term.nil?
|
14
|
+
return term if term.is_a?(FalseClass)
|
15
|
+
return term if term.is_a?(TrueClass)
|
16
|
+
term ? true : false
|
17
|
+
end
|
18
|
+
|
19
|
+
def from_string(term)
|
20
|
+
term.downcase === 'true'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Kanade
|
2
|
+
module Converter
|
3
|
+
class Dto < Base
|
4
|
+
Engine.register_converter!(self)
|
5
|
+
|
6
|
+
def serialize(term, field_info)
|
7
|
+
term
|
8
|
+
end
|
9
|
+
|
10
|
+
def deserialize(term, field_info)
|
11
|
+
return nil if term.nil?
|
12
|
+
raise NotSupportedError.new('DTO-based field only can be filled with nil / respective DTO object') unless term.is_a?(field_info.options[:of])
|
13
|
+
return term
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -3,14 +3,31 @@ module Kanade
|
|
3
3
|
class List < Base
|
4
4
|
Engine.register_converter!(self)
|
5
5
|
|
6
|
-
def serialize(term,
|
6
|
+
def serialize(term, field_info)
|
7
7
|
return nil if term.nil?
|
8
|
-
term.to_s
|
9
8
|
end
|
10
|
-
def deserialize(term,
|
9
|
+
def deserialize(term, field_info)
|
11
10
|
return nil if term.nil?
|
12
|
-
|
13
|
-
|
11
|
+
#binding.pry unless term.is_a?(Array)
|
12
|
+
raise NotSupportedError.new("Value must be array or nil!") unless term.is_a?(Array)
|
13
|
+
|
14
|
+
term.map do |t|
|
15
|
+
conversion_method =
|
16
|
+
if field_info.options[:of].is_a?(Class) and field_info.options[:of] < Kanade::Dto
|
17
|
+
:dto
|
18
|
+
else
|
19
|
+
field_info.options[:of]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Kalau begini caranya, field_info bisa enggak konsisten.
|
23
|
+
# Ada yang nyimpen informasinya dirinya sendiri, ada juga
|
24
|
+
# yang nyimpen informasi parent-nya.
|
25
|
+
converter = Engine.converter(conversion_method)
|
26
|
+
binding.pry if converter.nil?
|
27
|
+
raise NotSupportedError.new("Unregistered conversion method: #{conversion_method}") if converter.nil?
|
28
|
+
converter.deserialize(t, field_info)
|
29
|
+
end
|
30
|
+
|
14
31
|
end
|
15
32
|
end
|
16
33
|
end
|
@@ -1,25 +1,26 @@
|
|
1
|
-
require 'time'
|
2
|
-
|
3
|
-
module Kanade
|
4
|
-
module Converter
|
5
|
-
class Time < Base
|
6
|
-
Engine.register_converter!(self)
|
7
|
-
|
8
|
-
def serialize(term, _)
|
9
|
-
return nil if term.nil?
|
10
|
-
term.iso8601(0)
|
11
|
-
end
|
12
|
-
def deserialize(term, _)
|
13
|
-
return nil if term.nil?
|
14
|
-
return term if term.is_a?(Time)
|
15
|
-
return term if term.is_a?(Date)
|
16
|
-
# WARNING: Parse does not really parse TZ!
|
17
|
-
# Consider using ActiveSupport?
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
configurable :
|
23
|
-
|
24
|
-
|
25
|
-
end
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module Kanade
|
4
|
+
module Converter
|
5
|
+
class Time < Base
|
6
|
+
Engine.register_converter!(self)
|
7
|
+
|
8
|
+
def serialize(term, _)
|
9
|
+
return nil if term.nil?
|
10
|
+
term.iso8601(0)
|
11
|
+
end
|
12
|
+
def deserialize(term, _)
|
13
|
+
return nil if term.nil?
|
14
|
+
return term if term.is_a?(::Time)
|
15
|
+
return term if term.is_a?(Date)
|
16
|
+
# WARNING: Parse does not really parse TZ!
|
17
|
+
# Consider using ActiveSupport?
|
18
|
+
|
19
|
+
::Time.parse(term)
|
20
|
+
end
|
21
|
+
|
22
|
+
configurable :time_format, :iso8601
|
23
|
+
configurable :time_msec_round, 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/kanade/dto.rb
CHANGED
@@ -1,47 +1,56 @@
|
|
1
|
-
module Kanade
|
2
|
-
class Dto
|
3
|
-
class_attribute :__fields
|
4
|
-
class_attribute :__definer
|
5
|
-
|
6
|
-
def self.field(name_sym, *options)
|
7
|
-
raise NotSupportedError.new('Field must be a symbol!') unless name_sym.is_a?(Symbol)
|
8
|
-
raise NotSupportedError.new('Cant use reserved name (__fields)') if name == :__fields
|
9
|
-
|
10
|
-
if self.__definer != self.name
|
11
|
-
self.__fields = array_dup(self.__fields) || []
|
12
|
-
self.__definer = self.name
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
|
1
|
+
module Kanade
|
2
|
+
class Dto
|
3
|
+
class_attribute :__fields
|
4
|
+
class_attribute :__definer
|
5
|
+
|
6
|
+
def self.field(name_sym, *options)
|
7
|
+
raise NotSupportedError.new('Field must be a symbol!') unless name_sym.is_a?(Symbol)
|
8
|
+
raise NotSupportedError.new('Cant use reserved name (__fields)') if name == :__fields
|
9
|
+
|
10
|
+
if self.__definer != self.name
|
11
|
+
self.__fields = array_dup(self.__fields) || []
|
12
|
+
self.__definer = self.name
|
13
|
+
end
|
14
|
+
|
15
|
+
option = options.last
|
16
|
+
|
17
|
+
conversion_method = option[:as]
|
18
|
+
|
19
|
+
if option[:as].is_a?(Class) and option[:as] < Dto
|
20
|
+
conversion_method = :dto
|
21
|
+
option[:of] = option[:as]
|
22
|
+
option[:as] = :dto
|
23
|
+
end
|
24
|
+
|
25
|
+
name = name_sym.to_s.freeze
|
26
|
+
variable_ref = "@#{name}".freeze
|
27
|
+
converter = Engine.converter(conversion_method)
|
28
|
+
key_name = option[:with]
|
29
|
+
|
30
|
+
raise Kanade::NotSupportedError.new("Converter #{conversion_method} is not registered") if converter.nil?
|
31
|
+
|
32
|
+
field = FieldInfo.new
|
33
|
+
field.converter = converter
|
34
|
+
field.key_json = key_name
|
35
|
+
field.key_ruby = name
|
36
|
+
field.sym = name_sym
|
37
|
+
field.options = option
|
38
|
+
|
39
|
+
define_method "#{name}=" do |value|
|
40
|
+
instance_variable_set(variable_ref, field.convert(value))
|
41
|
+
end
|
42
|
+
|
43
|
+
define_method "#{name}" do
|
44
|
+
instance_variable_get(variable_ref)
|
45
|
+
end
|
46
|
+
|
47
|
+
self.__fields << field
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def self.array_dup(arr)
|
52
|
+
return nil if arr.nil?
|
53
|
+
arr.map(&:dup)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/kanade/engine.rb
CHANGED
@@ -1,87 +1,149 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
module Kanade
|
4
|
-
class Engine
|
5
|
-
@@converters = {}
|
6
|
-
@@name_resolvers = {}
|
7
|
-
|
8
|
-
def initialize(configuration=nil)
|
9
|
-
@config = configuration || Kanade::Config.default
|
10
|
-
end
|
11
|
-
|
12
|
-
def configure
|
13
|
-
yield @config
|
14
|
-
end
|
15
|
-
|
16
|
-
def serialize(object)
|
17
|
-
traverse_field(object).to_json
|
18
|
-
end
|
19
|
-
|
20
|
-
def traverse_field(object)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
result = {}
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
result
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Kanade
|
4
|
+
class Engine
|
5
|
+
@@converters = {}
|
6
|
+
@@name_resolvers = {}
|
7
|
+
|
8
|
+
def initialize(configuration=nil)
|
9
|
+
@config = configuration || Kanade::Config.default
|
10
|
+
end
|
11
|
+
|
12
|
+
def configure
|
13
|
+
yield @config
|
14
|
+
end
|
15
|
+
|
16
|
+
def serialize(object)
|
17
|
+
traverse_field(object).to_json
|
18
|
+
end
|
19
|
+
|
20
|
+
def traverse_field(object)
|
21
|
+
return nil if object.nil?
|
22
|
+
raise NotSupportedError.new("Serializer only works for Kanade::Dto, and #{object.class.name} does not extend Kanade::Dto") unless object.class < Kanade::Dto
|
23
|
+
|
24
|
+
result = {}
|
25
|
+
|
26
|
+
object.__fields.each do |field|
|
27
|
+
name = field.key_json || name_to_json(field.sym)
|
28
|
+
|
29
|
+
if field.options[:as] == :list
|
30
|
+
value = serialize_list(object.send(field.sym), field)
|
31
|
+
elsif field.options[:as] == :dto
|
32
|
+
value = traverse_field(object.send(field.sym))
|
33
|
+
else
|
34
|
+
value = field.converter.serialize(object.send(field.sym), field)
|
35
|
+
end
|
36
|
+
result[name] = value
|
37
|
+
end
|
38
|
+
|
39
|
+
result
|
40
|
+
end
|
41
|
+
|
42
|
+
def serialize_list(list, field_info)
|
43
|
+
return nil if list.nil?
|
44
|
+
list.map do |entry|
|
45
|
+
if field_info.options[:of].is_a?(Class) and field_info.options[:of] < Dto
|
46
|
+
traverse_field(entry)
|
47
|
+
else
|
48
|
+
conversion_method = field_info.options[:of]
|
49
|
+
# TODO how to refer to static field?
|
50
|
+
converter = Engine.converter(conversion_method)
|
51
|
+
|
52
|
+
raise NotSupportedError.new("Can not process unknown converter! #{conversion_method}") if converter.nil?
|
53
|
+
|
54
|
+
converter.serialize(entry, field_info)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def deserialize(definition, json)
|
60
|
+
raise NotSupportedError.new("Can not process non-class!") unless definition.is_a?(Class)
|
61
|
+
raise NotSupportedError.new("Can not process other than DTO!") unless definition < Dto
|
62
|
+
|
63
|
+
hash = JSON.parse(json)
|
64
|
+
deserialize_object(definition, hash)
|
65
|
+
end
|
66
|
+
|
67
|
+
# IF engine contains deserialization logic, we can no more
|
68
|
+
# unit test the converters. Seems like, the conversion logic
|
69
|
+
# must be outsourced to its respective converter
|
70
|
+
def deserialize_object(definition, hash)
|
71
|
+
return nil if hash.nil?
|
72
|
+
result = definition.new
|
73
|
+
result.__fields.each do |field|
|
74
|
+
name = field.key_json || name_to_json(field.sym)
|
75
|
+
|
76
|
+
if field.options[:as] == :list
|
77
|
+
value = deserialize_list(hash[name], field)
|
78
|
+
elsif field.options[:as] == :dto
|
79
|
+
value = deserialize_object(field.options[:of], hash[name])
|
80
|
+
else
|
81
|
+
value = hash[name]
|
82
|
+
end
|
83
|
+
|
84
|
+
next if value.nil?
|
85
|
+
|
86
|
+
result.send("#{field.key_ruby}=", value)
|
87
|
+
end
|
88
|
+
result
|
89
|
+
end
|
90
|
+
|
91
|
+
def deserialize_list(value, field_info)
|
92
|
+
return nil if value.nil?
|
93
|
+
|
94
|
+
# Catatan pribadi: Jadi "of" itu harusnya mengandung field definition?
|
95
|
+
# bukan of: Product, tapi of: {as: :dto, of: Product}
|
96
|
+
# dengan field definition ini, kita bisa membuat hal yang lebih konfleks, misal:
|
97
|
+
# of: {as: :symbol, mapping: {success: 'RES_SUCCESS'}}
|
98
|
+
value.map do |v|
|
99
|
+
if field_info.options[:of].is_a?(Class) and field_info.options[:of] < Dto
|
100
|
+
deserialize_object(field_info.options[:of], v)
|
101
|
+
else
|
102
|
+
conversion_method = field_info.options[:of]
|
103
|
+
# TODO how to refer to static field?
|
104
|
+
converter = Engine.converter(conversion_method)
|
105
|
+
|
106
|
+
raise NotSupportedError.new("Can not process unknown converter! #{conversion_method}") if converter.nil?
|
107
|
+
|
108
|
+
converter.deserialize(v, field_info)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.register_converter!(klass)
|
114
|
+
key = klass.name.split('::').last.underscore.to_sym
|
115
|
+
|
116
|
+
return if key === :base
|
117
|
+
|
118
|
+
# We don't support multiple converter for now
|
119
|
+
raise NotSupportedError.new("#{key} registered twice") if not @@converters[key].nil?
|
120
|
+
|
121
|
+
@@converters[key] = klass.new
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.register_name_resolver!(klass)
|
125
|
+
key = klass.name.split('::').last.underscore.to_sym
|
126
|
+
|
127
|
+
return if key === :base
|
128
|
+
|
129
|
+
# We don't support multiple converter for now
|
130
|
+
raise NotSupportedError.new("#{key} registered twice") if not @@name_resolvers[key].nil?
|
131
|
+
|
132
|
+
@@name_resolvers[key] = klass.new
|
133
|
+
end
|
134
|
+
|
135
|
+
def name_to_ruby(string)
|
136
|
+
strategy = @config.contract
|
137
|
+
@@name_resolvers[strategy].deserialize(string)
|
138
|
+
end
|
139
|
+
|
140
|
+
def name_to_json(sym)
|
141
|
+
strategy = @config.contract
|
142
|
+
@@name_resolvers[strategy].serialize(sym)
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.converter(sym)
|
146
|
+
@@converters[sym]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/lib/kanade/version.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
1
|
-
{
|
2
|
-
"id": 3,
|
3
|
-
"
|
4
|
-
|
5
|
-
|
6
|
-
"
|
7
|
-
"
|
8
|
-
"
|
9
|
-
"
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
"
|
14
|
-
"
|
15
|
-
"
|
16
|
-
"
|
17
|
-
|
18
|
-
|
19
|
-
|
1
|
+
{
|
2
|
+
"id": 3,
|
3
|
+
"serials": [100, 105, 444],
|
4
|
+
"products": [
|
5
|
+
{
|
6
|
+
"id": 100,
|
7
|
+
"name": "Cat Plushie",
|
8
|
+
"expireAt": null,
|
9
|
+
"price": "19.95",
|
10
|
+
"available": true
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"id": 101,
|
14
|
+
"name": "Taco",
|
15
|
+
"expireAt": "2016-09-21T13:52:44+07:00",
|
16
|
+
"price": "5.0",
|
17
|
+
"available": true
|
18
|
+
}
|
19
|
+
]
|
20
|
+
}
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require_relative '../fixtures/product'
|
3
3
|
require_relative '../fixtures/product_wrong'
|
4
|
+
require_relative '../fixtures/refund_report'
|
5
|
+
require_relative '../fixtures/catalog'
|
4
6
|
|
5
7
|
RSpec.describe 'Deserialization Integration' do
|
6
8
|
|
@@ -53,6 +55,70 @@ RSpec.describe 'Deserialization Integration' do
|
|
53
55
|
end
|
54
56
|
|
55
57
|
context 'Array of products' do
|
58
|
+
let(:object) do
|
59
|
+
@engine.deserialize(Catalog, json_of(:catalog_camel_case))
|
60
|
+
end
|
61
|
+
|
62
|
+
subject do
|
63
|
+
object
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'has correct id' do
|
67
|
+
expect(subject.id).to eq(3)
|
68
|
+
expect(subject.id).to_not eq('3')
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'has serials of fixnum' do
|
72
|
+
expect(subject.serials).to eq([100, 105, 444])
|
73
|
+
expect(subject.serials).to_not eq([100, '105', 444])
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'has multiple products' do
|
77
|
+
expect(subject.products.count).to eq(2)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'has correct order of products' do
|
81
|
+
expect(subject.products[0].id).to eq(100)
|
82
|
+
expect(subject.products[0].name).to eq('Cat Plushie')
|
83
|
+
expect(subject.products[0].expire_at).to be_nil
|
84
|
+
expect(subject.products[0].price).to eq(BigDecimal.new('19.95'))
|
85
|
+
expect(subject.products[0].price).to_not eq('19.95')
|
86
|
+
expect(subject.products[0].available).to eq(true)
|
87
|
+
|
88
|
+
expect(subject.products[1].id).to eq(101)
|
89
|
+
expect(subject.products[1].name).to eq('Taco')
|
90
|
+
expect(subject.products[1].expire_at).to eq(Time.parse('2016-09-21T13:52:44+07:00'))
|
91
|
+
expect(subject.products[1].price).to eq(BigDecimal.new('5.0'))
|
92
|
+
expect(subject.products[1].price).to_not eq('5.0')
|
93
|
+
expect(subject.products[1].available).to eq(true)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'Nested object' do
|
98
|
+
let(:object) do
|
99
|
+
@engine.deserialize(RefundReport, json_of(:refund_report))
|
100
|
+
end
|
101
|
+
|
102
|
+
subject do
|
103
|
+
object
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'has correct ID' do
|
107
|
+
expect(subject.refund_id).to eq(9321)
|
108
|
+
end
|
56
109
|
|
110
|
+
it 'has correct nested product' do
|
111
|
+
expect(subject.affected_product.id).to eq(451)
|
112
|
+
expect(subject.affected_product.name).to eq('Digital Camera')
|
113
|
+
expect(subject.affected_product.expire_at).to eq(Time.parse('2019-03-30T06:52:44+09:00'))
|
114
|
+
expect(subject.affected_product.price).to eq(BigDecimal.new('99.95'))
|
115
|
+
expect(subject.affected_product.available).to eq(true)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'has correct addendum report' do
|
119
|
+
expect(subject.addendum_report.refund_id).to eq(1234)
|
120
|
+
expect(subject.addendum_report.affected_product).to be_nil
|
121
|
+
expect(subject.addendum_report.addendum_report).to be_nil
|
122
|
+
end
|
57
123
|
end
|
58
124
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require_relative '../fixtures/catalog'
|
2
3
|
require_relative '../fixtures/product'
|
3
4
|
require_relative '../fixtures/product_wrong'
|
5
|
+
require_relative '../fixtures/refund_report'
|
4
6
|
|
5
7
|
RSpec.describe 'Serialization Integration' do
|
6
8
|
|
@@ -69,6 +71,58 @@ RSpec.describe 'Serialization Integration' do
|
|
69
71
|
end
|
70
72
|
|
71
73
|
context 'Array of products' do
|
74
|
+
subject { @engine.serialize(target) }
|
72
75
|
|
76
|
+
let(:target) do
|
77
|
+
catalog = Catalog.new
|
78
|
+
catalog.serials = [100, 105, 444]
|
79
|
+
catalog.id = 3
|
80
|
+
|
81
|
+
product1 = Product.new
|
82
|
+
product1.id = 100
|
83
|
+
product1.name = 'Cat Plushie'
|
84
|
+
product1.expire_at = nil
|
85
|
+
product1.price = '19.95'
|
86
|
+
product1.available = true
|
87
|
+
|
88
|
+
product2 = Product.new
|
89
|
+
product2.id = 101
|
90
|
+
product2.name = 'Taco'
|
91
|
+
product2.expire_at = '2016-09-21T13:52:44+07:00'
|
92
|
+
product2.price = 5
|
93
|
+
product2.available = true
|
94
|
+
|
95
|
+
catalog.products = []
|
96
|
+
catalog.products << product1
|
97
|
+
catalog.products << product2
|
98
|
+
catalog
|
99
|
+
end
|
100
|
+
|
101
|
+
it { is_expected.to be_json_of(:catalog_camel_case) }
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'Nested object' do
|
105
|
+
subject { @engine.serialize(target) }
|
106
|
+
|
107
|
+
let(:target) do
|
108
|
+
report = RefundReport.new
|
109
|
+
report.refund_id = '9321'
|
110
|
+
|
111
|
+
product = Product.new
|
112
|
+
product.id = 451
|
113
|
+
product.name = 'Digital Camera'
|
114
|
+
product.expire_at = Time.parse('2019-03-30T06:52:44+09:00')
|
115
|
+
product.price = BigDecimal.new('99.95')
|
116
|
+
product.available = true
|
117
|
+
|
118
|
+
addendum_report = RefundReport.new
|
119
|
+
addendum_report.refund_id = 1234
|
120
|
+
|
121
|
+
report.addendum_report = addendum_report
|
122
|
+
report.affected_product = product
|
123
|
+
report
|
124
|
+
end
|
125
|
+
|
126
|
+
it { is_expected.to be_json_of :refund_report }
|
73
127
|
end
|
74
128
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kanade
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.
|
4
|
+
version: 0.1.0.beta2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mufid Afif
|
@@ -133,6 +133,7 @@ files:
|
|
133
133
|
- lib/kanade/converter/base.rb
|
134
134
|
- lib/kanade/converter/big_decimal.rb
|
135
135
|
- lib/kanade/converter/bool.rb
|
136
|
+
- lib/kanade/converter/dto.rb
|
136
137
|
- lib/kanade/converter/fixnum.rb
|
137
138
|
- lib/kanade/converter/float.rb
|
138
139
|
- lib/kanade/converter/list.rb
|
@@ -157,6 +158,7 @@ files:
|
|
157
158
|
- spec/fixtures/refund_report.rb
|
158
159
|
- spec/fixtures/simple_product.json
|
159
160
|
- spec/integration/class_consistency_spec.rb
|
161
|
+
- spec/integration/ignore_unknown_field_spec.rb
|
160
162
|
- spec/integration/simple_deserialization_integration_spec.rb
|
161
163
|
- spec/integration/simple_serialization_integration_spec.rb
|
162
164
|
- spec/matchers/json_matcher.rb
|
@@ -200,6 +202,7 @@ test_files:
|
|
200
202
|
- spec/fixtures/refund_report.rb
|
201
203
|
- spec/fixtures/simple_product.json
|
202
204
|
- spec/integration/class_consistency_spec.rb
|
205
|
+
- spec/integration/ignore_unknown_field_spec.rb
|
203
206
|
- spec/integration/simple_deserialization_integration_spec.rb
|
204
207
|
- spec/integration/simple_serialization_integration_spec.rb
|
205
208
|
- spec/matchers/json_matcher.rb
|