yaoc 0.0.6 → 0.0.7
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/README.md +52 -1
- data/Rakefile +1 -1
- data/examples/06_lazy_loading.rb +47 -0
- data/examples/all_examples.rb +7 -0
- data/lib/yaoc.rb +0 -1
- data/lib/yaoc/converter_builder.rb +55 -44
- data/lib/yaoc/helper/to_proc_delegator.rb +33 -0
- data/lib/yaoc/mapping_base.rb +29 -7
- data/lib/yaoc/mapping_to_class.rb +7 -3
- data/lib/yaoc/object_mapper.rb +44 -37
- data/lib/yaoc/version.rb +1 -1
- data/spec/acceptance/map_to_objects_with_lazy_loading_spec.rb +59 -0
- data/spec/spec_helper.rb +3 -4
- data/spec/unit/lib/yaoc/converter_builder_spec.rb +49 -13
- data/spec/unit/lib/yaoc/helper/to_proc_delegator_spec.rb +44 -0
- data/spec/unit/lib/yaoc/mapping_base_spec.rb +36 -8
- data/spec/unit/lib/yaoc/mapping_to_class_spec.rb +9 -0
- data/spec/unit/lib/yaoc/object_mapper_spec.rb +2 -1
- data/spec/unit/lib/yaoc/strategies/to_array_mapping_spec.rb +8 -8
- data/spec/unit/lib/yaoc/strategies/to_hash_mapping_spec.rb +10 -10
- data/yaoc.gemspec +0 -2
- metadata +9 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 115be6510d49cc1ed39509369d8a13b35574afff
|
4
|
+
data.tar.gz: 77bc38e239f5ee0dad8a86e4e4e22fa6fa294c46
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49986fe1421711286cbc6e67ac58285fb625ad143e5f00bd280807a900884936d43b62fe7e5921cfb40f01603f1393c1c9eefc654b4b5fdd142c3f8b5db3f2b3
|
7
|
+
data.tar.gz: 41ccc8c0e963f2839e7f610fe313b371e8199fdd9ac521a132ae01bbe6a5ff50336148b4bdb158e3e74d271031f89a2a7db640c93b451d1e318ec4ffd3c8e2ec
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Yaoc [](https://codeclimate.com/github/slowjack2k/yaoc) [](https://travis-ci.org/slowjack2k/yaoc) [](https://coveralls.io/r/slowjack2k/yaoc?branch=master) [](http://badge.fury.io/rb/yaoc)
|
2
2
|
|
3
|
-
|
3
|
+
Converting one ruby object into another with some rules.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -307,6 +307,57 @@ puts new_user5
|
|
307
307
|
|
308
308
|
```
|
309
309
|
|
310
|
+
### How can I lazy load some expensive to convert attributes?
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
require 'yaoc'
|
314
|
+
|
315
|
+
include Yaoc::Helper
|
316
|
+
|
317
|
+
puts "\n" * 5
|
318
|
+
|
319
|
+
|
320
|
+
OldUser6 = StructHE(:id) do
|
321
|
+
|
322
|
+
def names=(new_names)
|
323
|
+
@names = new_names
|
324
|
+
end
|
325
|
+
|
326
|
+
def names
|
327
|
+
puts 'some expensive operation in progress ...'
|
328
|
+
sleep 10
|
329
|
+
@names
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
333
|
+
User6 = StructHE(:id, :names)
|
334
|
+
|
335
|
+
|
336
|
+
user_mapper = Yaoc::ObjectMapper.new(User6, OldUser6).tap do |mapper|
|
337
|
+
mapper.add_mapping do
|
338
|
+
fetcher :public_send
|
339
|
+
rule to: [:id, :names],
|
340
|
+
lazy_loading: [false, true]
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
old_user6 = OldUser6.new(id: 'my_id_1', names: ['one', 'two', 'three', 'four'])
|
345
|
+
new_user6 = user_mapper.load(old_user6)
|
346
|
+
|
347
|
+
puts new_user6.id.inspect
|
348
|
+
puts new_user6.names.inspect
|
349
|
+
puts new_user6
|
350
|
+
|
351
|
+
|
352
|
+
puts "\n" * 5
|
353
|
+
|
354
|
+
# "my_id_1"
|
355
|
+
# some expensive operation in progress ...
|
356
|
+
# ["one", "two", "three", "four"]
|
357
|
+
#<struct User6 id="my_id_1", names=["one", "two", "three", "four"]>
|
358
|
+
|
359
|
+
```
|
360
|
+
|
310
361
|
## Contributing
|
311
362
|
|
312
363
|
1. Fork it ( http://github.com/slowjack2k/yaoc/fork )
|
data/Rakefile
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
Bundler.require(:development)
|
3
|
+
|
4
|
+
require 'yaoc'
|
5
|
+
|
6
|
+
include Yaoc::Helper
|
7
|
+
|
8
|
+
puts "\n" * 5
|
9
|
+
|
10
|
+
|
11
|
+
OldUser6 = StructHE(:id) do
|
12
|
+
|
13
|
+
def names=(new_names)
|
14
|
+
@names = new_names
|
15
|
+
end
|
16
|
+
|
17
|
+
def names
|
18
|
+
puts 'some expensive operation in progress ...'
|
19
|
+
sleep 10
|
20
|
+
@names
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
User6 = StructHE(:id, :names)
|
25
|
+
|
26
|
+
|
27
|
+
user_mapper = Yaoc::ObjectMapper.new(User6, OldUser6).tap do |mapper|
|
28
|
+
mapper.add_mapping do
|
29
|
+
fetcher :public_send
|
30
|
+
rule to: [:id, :names],
|
31
|
+
lazy_loading: [false, true]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
old_user6 = OldUser6.new(id: 'my_id_1', names: ['one', 'two', 'three', 'four'])
|
36
|
+
new_user6 = user_mapper.load(old_user6)
|
37
|
+
|
38
|
+
puts new_user6.id.inspect
|
39
|
+
puts new_user6.names.inspect
|
40
|
+
puts new_user6
|
41
|
+
|
42
|
+
|
43
|
+
puts "\n" * 5
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
data/lib/yaoc.rb
CHANGED
@@ -1,22 +1,28 @@
|
|
1
1
|
module Yaoc
|
2
2
|
|
3
3
|
class NormalizedParameters
|
4
|
-
attr_accessor :to_s, :from_s, :converter_s
|
4
|
+
attr_accessor :to_s, :from_s, :converter_s, :lazy_loading_s
|
5
5
|
|
6
|
-
def initialize(to, from, converter, object_converter, is_collection)
|
6
|
+
def initialize(to, from, converter, object_converter, is_collection, lazy_loading)
|
7
7
|
self.to_s = Array(to)
|
8
8
|
self.from_s = Array(from)
|
9
9
|
self.converter_s = Array(converter)
|
10
|
+
self.lazy_loading_s = Array(lazy_loading)
|
10
11
|
|
11
12
|
object_converter_s = Array(object_converter)
|
12
13
|
is_collection_s = Array(is_collection)
|
13
14
|
|
14
15
|
self.to_s.each_with_index do |to, index|
|
15
16
|
from_s[index] ||= to
|
17
|
+
lazy_loading_s[index] ||= false
|
16
18
|
end
|
17
19
|
|
18
20
|
object_converter_s.each_with_index do |object_converter, index|
|
19
|
-
converter_s[index] = converter_to_proc(to_s[index],
|
21
|
+
converter_s[index] = converter_to_proc(to_s[index],
|
22
|
+
from_s[index],
|
23
|
+
object_converter,
|
24
|
+
!!is_collection_s[index],
|
25
|
+
!!lazy_loading_s[index])
|
20
26
|
end
|
21
27
|
|
22
28
|
end
|
@@ -25,30 +31,64 @@ module Yaoc
|
|
25
31
|
return to_enum(__callee__) unless block_given?
|
26
32
|
|
27
33
|
self.to_s.each_with_index do |to, index|
|
28
|
-
yield to, from_s[index] , converter_s[index]
|
34
|
+
yield to, from_s[index] , converter_s[index], lazy_loading_s[index]
|
29
35
|
end
|
30
36
|
end
|
31
37
|
|
32
|
-
def converter_to_proc(to, from, converter, is_collection)
|
38
|
+
def converter_to_proc(to, from, converter, is_collection, deferred)
|
33
39
|
->(source, result){
|
34
|
-
|
35
|
-
|
40
|
+
get_value_with = ->{
|
41
|
+
object_to_convert = source.public_send(fetcher, from)
|
42
|
+
|
43
|
+
if is_collection
|
44
|
+
object_to_convert.map(&converter)
|
45
|
+
else
|
46
|
+
converter_as_proc = converter.to_proc
|
47
|
+
converter_as_proc.call(object_to_convert)
|
48
|
+
end
|
49
|
+
}
|
50
|
+
|
51
|
+
fill_result_from_proc(result, to, get_value_with, deferred)
|
52
|
+
}
|
53
|
+
end
|
36
54
|
|
37
|
-
|
38
|
-
converted_object = object_to_convert.map(&converter)
|
39
|
-
else
|
40
|
-
converter_as_proc = converter.to_proc
|
41
|
-
converted_object = converter_as_proc.call(object_to_convert)
|
42
|
-
end
|
55
|
+
end
|
43
56
|
|
44
|
-
|
45
|
-
|
57
|
+
module BuilderDSLMethods
|
58
|
+
def add_mapping(&block)
|
59
|
+
instance_eval &block
|
60
|
+
apply_commands!
|
46
61
|
end
|
47
62
|
|
63
|
+
def rule(to: nil, from: to, converter: nil, object_converter: nil, is_collection: nil, lazy_loading: nil)
|
64
|
+
self.all_commands_applied = false
|
65
|
+
|
66
|
+
NormalizedParameters.new(to, from, converter, object_converter, is_collection, lazy_loading).each do |to, from, converter, lazy_loading|
|
67
|
+
build_commands.push ->{ converter_class.map(to: to, from: from , converter: converter, lazy_loading: lazy_loading) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def fetch_with(new_fetcher)
|
72
|
+
self.fetcher = new_fetcher
|
73
|
+
end
|
74
|
+
|
75
|
+
def with_strategy(new_strategy)
|
76
|
+
self.strategy = new_strategy
|
77
|
+
end
|
78
|
+
|
79
|
+
def build_commands_ordered
|
80
|
+
if command_order == :recorded_order
|
81
|
+
build_commands
|
82
|
+
else
|
83
|
+
build_commands.reverse
|
84
|
+
end
|
85
|
+
end
|
48
86
|
end
|
49
87
|
|
50
88
|
|
51
89
|
class ConverterBuilder
|
90
|
+
include BuilderDSLMethods
|
91
|
+
|
52
92
|
attr_accessor :build_commands, :command_order,
|
53
93
|
:strategy, :all_commands_applied
|
54
94
|
|
@@ -60,19 +100,6 @@ module Yaoc
|
|
60
100
|
self.all_commands_applied = false
|
61
101
|
end
|
62
102
|
|
63
|
-
def add_mapping(&block)
|
64
|
-
instance_eval &block
|
65
|
-
apply_commands!
|
66
|
-
end
|
67
|
-
|
68
|
-
def rule(to: nil, from: to, converter: nil, object_converter: nil, is_collection: nil)
|
69
|
-
self.all_commands_applied = false
|
70
|
-
|
71
|
-
NormalizedParameters.new(to, from, converter, object_converter, is_collection).each do |to, from, converter|
|
72
|
-
build_commands.push ->{ converter_class.map(to, from , converter) }
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
103
|
def apply_commands!
|
77
104
|
reset_converters!
|
78
105
|
self.all_commands_applied = true
|
@@ -120,22 +147,6 @@ module Yaoc
|
|
120
147
|
@fetcher ||= :fetch
|
121
148
|
end
|
122
149
|
|
123
|
-
def fetch_with(new_fetcher)
|
124
|
-
self.fetcher = new_fetcher
|
125
|
-
end
|
126
|
-
|
127
|
-
def with_strategy(new_strategy)
|
128
|
-
self.strategy = new_strategy
|
129
|
-
end
|
130
|
-
|
131
|
-
def build_commands_ordered
|
132
|
-
if command_order == :recorded_order
|
133
|
-
build_commands
|
134
|
-
else
|
135
|
-
build_commands.reverse
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
150
|
def reset_converters!
|
140
151
|
@converter_class = nil
|
141
152
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Yaoc
|
2
|
+
module Helper
|
3
|
+
class ToProcDelegator < SimpleDelegator
|
4
|
+
attr_accessor :_initialisation_proc, :_initialisation_proc_loaded
|
5
|
+
|
6
|
+
def initialize(_initialisation_proc)
|
7
|
+
super(nil).tap do
|
8
|
+
self._initialisation_proc = _initialisation_proc
|
9
|
+
self._initialisation_proc_loaded = false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def __getobj__
|
15
|
+
unless self._initialisation_proc_loaded
|
16
|
+
self._initialisation_proc_loaded = true
|
17
|
+
__setobj__(self._initialisation_proc.call())
|
18
|
+
end
|
19
|
+
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def class
|
24
|
+
__getobj__.class
|
25
|
+
end
|
26
|
+
|
27
|
+
def kind_of?(some_class)
|
28
|
+
super || __getobj__.kind_of?(some_class)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/yaoc/mapping_base.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
module Yaoc
|
2
2
|
module MappingBase
|
3
|
-
include AbstractType
|
4
3
|
|
5
4
|
def self.included(other)
|
6
5
|
other.extend(ClassMethods)
|
@@ -19,13 +18,31 @@ module Yaoc
|
|
19
18
|
end
|
20
19
|
|
21
20
|
def call
|
22
|
-
|
21
|
+
unless to_convert.nil?
|
22
|
+
self.class.mapping_strategy.call(self)
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
end
|
23
26
|
end
|
24
27
|
|
25
28
|
def fill_result_with_value(result, key, value)
|
26
29
|
result.tap{|taped_result| taped_result[key] = value}
|
27
30
|
end
|
28
31
|
|
32
|
+
def fill_result_from_proc(result, key, proc, deferred=false)
|
33
|
+
value = if deferred
|
34
|
+
deferrer_strategy(proc)
|
35
|
+
else
|
36
|
+
proc.call
|
37
|
+
end
|
38
|
+
|
39
|
+
fill_result_with_value(result, key, value)
|
40
|
+
end
|
41
|
+
|
42
|
+
def deferrer_strategy(proc)
|
43
|
+
Yaoc::Helper::ToProcDelegator.new(proc)
|
44
|
+
end
|
45
|
+
|
29
46
|
|
30
47
|
def converter_methods
|
31
48
|
self.class.converter_methods
|
@@ -36,11 +53,14 @@ module Yaoc
|
|
36
53
|
end
|
37
54
|
|
38
55
|
module ClassMethods
|
39
|
-
include AbstractType
|
40
56
|
|
41
|
-
def converter_proc(to, from)
|
57
|
+
def converter_proc(to, from, deferred=false)
|
42
58
|
-> (to_convert, result){
|
43
|
-
|
59
|
+
get_value_with = ->{
|
60
|
+
to_convert.public_send(fetcher, from)
|
61
|
+
}
|
62
|
+
|
63
|
+
fill_result_from_proc(result, to, get_value_with, deferred)
|
44
64
|
}
|
45
65
|
end
|
46
66
|
|
@@ -52,9 +72,11 @@ module Yaoc
|
|
52
72
|
@mapping_strategy
|
53
73
|
end
|
54
74
|
|
55
|
-
def map(to, from,
|
75
|
+
def map(to: nil, from: to, converter: nil, lazy_loading: false)
|
56
76
|
class_private_module(:Mapping).tap do |mod|
|
57
|
-
|
77
|
+
method_implementation = converter || converter_proc(to, from, lazy_loading)
|
78
|
+
|
79
|
+
mod.send :define_method, "map_#{"%04d" %[converter_methods.count]}_#{from}_to_#{to}".to_sym, method_implementation
|
58
80
|
include mod
|
59
81
|
end
|
60
82
|
end
|
@@ -9,10 +9,14 @@ module Yaoc
|
|
9
9
|
module InstanceMethods
|
10
10
|
def call(pre_created_object=nil)
|
11
11
|
source_converted_to_hash_or_array = super()
|
12
|
-
|
13
|
-
|
12
|
+
unless source_converted_to_hash_or_array.nil?
|
13
|
+
if pre_created_object.nil?
|
14
|
+
create_target_from_class(source_converted_to_hash_or_array)
|
15
|
+
else
|
16
|
+
fill_target_object(source_converted_to_hash_or_array, pre_created_object)
|
17
|
+
end
|
14
18
|
else
|
15
|
-
|
19
|
+
nil
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
data/lib/yaoc/object_mapper.rb
CHANGED
@@ -1,47 +1,18 @@
|
|
1
1
|
module Yaoc
|
2
2
|
|
3
|
-
|
4
|
-
attr_accessor :load_result_source, :dump_result_source
|
5
|
-
|
6
|
-
def initialize(load_result_source, dump_result_source=nil)
|
7
|
-
self.load_result_source = load_result_source
|
8
|
-
self.dump_result_source = dump_result_source
|
9
|
-
end
|
10
|
-
|
11
|
-
def load(fetch_able, object_to_fill=nil)
|
12
|
-
converter(fetch_able).call(object_to_fill)
|
13
|
-
end
|
14
|
-
|
15
|
-
def dump(object, object_to_fill=nil)
|
16
|
-
reverse_converter(object).call(object_to_fill)
|
17
|
-
end
|
18
|
-
|
3
|
+
module MapperDSLMethods
|
19
4
|
def add_mapping(&block)
|
20
5
|
instance_eval &block
|
21
|
-
apply_commands
|
22
|
-
end
|
23
|
-
|
24
|
-
def converter(fetch_able=nil)
|
25
|
-
converter_builder.converter(fetch_able, load_result_source)
|
26
|
-
end
|
27
|
-
|
28
|
-
def reverse_converter(fetch_able=nil)
|
29
|
-
reverse_converter_builder.converter(fetch_able, dump_result_source)
|
30
|
-
end
|
31
|
-
|
32
|
-
protected
|
33
|
-
|
34
|
-
def apply_commands
|
35
|
-
converter_builder.apply_commands!
|
36
|
-
reverse_converter_builder.apply_commands!
|
6
|
+
apply_commands!
|
37
7
|
end
|
38
8
|
|
39
9
|
def rule(to: nil, from: to, converter: nil,
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
10
|
+
reverse_to: from,
|
11
|
+
reverse_from: to,
|
12
|
+
reverse_converter: nil,
|
13
|
+
object_converter: nil,
|
14
|
+
is_collection: nil,
|
15
|
+
lazy_loading: nil)
|
45
16
|
|
46
17
|
object_converter = Array(object_converter)
|
47
18
|
|
@@ -51,6 +22,7 @@ module Yaoc
|
|
51
22
|
converter: converter,
|
52
23
|
object_converter: object_converter.map(&:converter),
|
53
24
|
is_collection: is_collection,
|
25
|
+
lazy_loading: lazy_loading
|
54
26
|
)
|
55
27
|
|
56
28
|
reverse_converter_builder.rule(
|
@@ -59,6 +31,7 @@ module Yaoc
|
|
59
31
|
converter: reverse_converter,
|
60
32
|
object_converter: object_converter.map(&:reverse_converter),
|
61
33
|
is_collection: is_collection,
|
34
|
+
lazy_loading: lazy_loading
|
62
35
|
)
|
63
36
|
end
|
64
37
|
|
@@ -77,6 +50,40 @@ module Yaoc
|
|
77
50
|
def reverse_strategy(new_strategy)
|
78
51
|
reverse_converter_builder.strategy = new_strategy
|
79
52
|
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class ObjectMapper
|
56
|
+
include MapperDSLMethods
|
57
|
+
|
58
|
+
attr_accessor :load_result_source, :dump_result_source
|
59
|
+
|
60
|
+
def initialize(load_result_source, dump_result_source=nil)
|
61
|
+
self.load_result_source = load_result_source
|
62
|
+
self.dump_result_source = dump_result_source
|
63
|
+
end
|
64
|
+
|
65
|
+
def load(fetch_able, object_to_fill=nil)
|
66
|
+
converter(fetch_able).call(object_to_fill)
|
67
|
+
end
|
68
|
+
|
69
|
+
def dump(object, object_to_fill=nil)
|
70
|
+
reverse_converter(object).call(object_to_fill)
|
71
|
+
end
|
72
|
+
|
73
|
+
def converter(fetch_able=nil)
|
74
|
+
converter_builder.converter(fetch_able, load_result_source)
|
75
|
+
end
|
76
|
+
|
77
|
+
def reverse_converter(fetch_able=nil)
|
78
|
+
reverse_converter_builder.converter(fetch_able, dump_result_source)
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
def apply_commands!
|
84
|
+
converter_builder.apply_commands!
|
85
|
+
reverse_converter_builder.apply_commands!
|
86
|
+
end
|
80
87
|
|
81
88
|
def converter_builder
|
82
89
|
@converter_builder ||= Yaoc::ConverterBuilder.new()
|
data/lib/yaoc/version.rb
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
feature "Map objects to classes with lazy loading", %q{
|
4
|
+
In order to defer object mapping
|
5
|
+
as a lib user
|
6
|
+
I want to map object from an input object to an output object with lazy loading support
|
7
|
+
} do
|
8
|
+
|
9
|
+
given(:mapper){
|
10
|
+
Yaoc::ObjectMapper.new(new_user_class, old_user_class).tap do |mapper|
|
11
|
+
mapper.add_mapping do
|
12
|
+
fetcher :public_send
|
13
|
+
rule to: [:id, :names],
|
14
|
+
lazy_loading: [false, true]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
}
|
18
|
+
|
19
|
+
given(:new_user_class){
|
20
|
+
Yaoc::Helper::StructHE(:id, :names)
|
21
|
+
}
|
22
|
+
|
23
|
+
given(:old_user_class){
|
24
|
+
Yaoc::Helper::StructHE(:id, :names)
|
25
|
+
}
|
26
|
+
|
27
|
+
given(:existing_old_user){
|
28
|
+
old_user_class.new(
|
29
|
+
id: 'existing_user_2',
|
30
|
+
names: ['first_name', 'second_name']
|
31
|
+
)
|
32
|
+
}
|
33
|
+
|
34
|
+
given(:existing_user){
|
35
|
+
new_user_class.new(
|
36
|
+
id: 'existing_user_2',
|
37
|
+
names: ['first_name', 'second_name']
|
38
|
+
)
|
39
|
+
}
|
40
|
+
|
41
|
+
scenario "creates an result object from an input_object deferred" do
|
42
|
+
converted_user = mapper.load(existing_old_user)
|
43
|
+
new_names = ["new_name1", "new_name2"]
|
44
|
+
|
45
|
+
existing_old_user.names = new_names # show defer through changes after loading an object
|
46
|
+
|
47
|
+
expect(converted_user.names).to eq new_names
|
48
|
+
end
|
49
|
+
|
50
|
+
scenario "dumps an result object as source object defered" do
|
51
|
+
converted_user = mapper.dump(existing_user)
|
52
|
+
new_names = ["new_name1", "new_name2"]
|
53
|
+
|
54
|
+
existing_user.names = new_names # show defer through changes after loading an object
|
55
|
+
|
56
|
+
expect(converted_user.names).to eq new_names
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
require 'bundler/setup'
|
2
2
|
Bundler.require(:development)
|
3
3
|
|
4
|
+
require 'coveralls'
|
5
|
+
Coveralls.wear! unless ENV["SIMPLE_COVERAGE"]
|
4
6
|
|
5
7
|
begin
|
6
|
-
if ENV["
|
8
|
+
if ENV["SIMPLE_COVERAGE"]
|
7
9
|
require 'simplecov'
|
8
10
|
SimpleCov.start do
|
9
11
|
add_group "Lib", "lib"
|
10
12
|
|
11
13
|
add_filter "/spec/"
|
12
14
|
end
|
13
|
-
else
|
14
|
-
require 'coveralls'
|
15
|
-
Coveralls.wear!
|
16
15
|
end
|
17
16
|
rescue LoadError
|
18
17
|
warn "=" * 80
|
@@ -16,13 +16,27 @@ describe Yaoc::ConverterBuilder do
|
|
16
16
|
double("converter", call: nil)
|
17
17
|
}
|
18
18
|
|
19
|
+
let(:default_map_args){
|
20
|
+
{
|
21
|
+
to: :id,
|
22
|
+
from: :id,
|
23
|
+
converter: nil,
|
24
|
+
lazy_loading: false
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
19
28
|
describe "#command_order" do
|
20
29
|
|
21
30
|
it "applies command in recorded order as default" do
|
22
31
|
subject.command_order = :recorded_order
|
23
32
|
|
24
|
-
|
25
|
-
|
33
|
+
expected_args_first = default_map_args.clone
|
34
|
+
expected_args_second = default_map_args.clone
|
35
|
+
|
36
|
+
expected_args_second[:to] = expected_args_second[:from] = :name
|
37
|
+
|
38
|
+
expect(converter_class).to receive(:map).ordered.with(expected_args_first)
|
39
|
+
expect(converter_class).to receive(:map).ordered.with(expected_args_second)
|
26
40
|
|
27
41
|
subject.add_mapping do
|
28
42
|
rule to: :id
|
@@ -34,8 +48,11 @@ describe Yaoc::ConverterBuilder do
|
|
34
48
|
it "applies command in reverse recorded order when wanted" do
|
35
49
|
subject.command_order = :reverse_order
|
36
50
|
|
37
|
-
|
38
|
-
|
51
|
+
expected_args_first = default_map_args.clone.merge({to: :name, from: :name})
|
52
|
+
expected_args_second = default_map_args.clone
|
53
|
+
|
54
|
+
expect(converter_class).to receive(:map).ordered.with(expected_args_first)
|
55
|
+
expect(converter_class).to receive(:map).ordered.with(expected_args_second)
|
39
56
|
|
40
57
|
subject.add_mapping do
|
41
58
|
rule to: :id
|
@@ -64,8 +81,7 @@ describe Yaoc::ConverterBuilder do
|
|
64
81
|
|
65
82
|
describe "#rule" do
|
66
83
|
it "creates a converter" do
|
67
|
-
|
68
|
-
expect(converter_class).to receive(:map).with(:id, :id2, :some_proc)
|
84
|
+
expect(converter_class).to receive(:map).with(to: :id, from: :id2, converter: :some_proc, lazy_loading: false)
|
69
85
|
|
70
86
|
subject.add_mapping do
|
71
87
|
rule to: :id,
|
@@ -76,7 +92,7 @@ describe Yaoc::ConverterBuilder do
|
|
76
92
|
end
|
77
93
|
|
78
94
|
it "uses defaults" do
|
79
|
-
expect(converter_class).to receive(:map).with(
|
95
|
+
expect(converter_class).to receive(:map).with(default_map_args)
|
80
96
|
|
81
97
|
subject.add_mapping do
|
82
98
|
rule to: :id
|
@@ -85,8 +101,11 @@ describe Yaoc::ConverterBuilder do
|
|
85
101
|
end
|
86
102
|
|
87
103
|
it "allows to use array of attributes" do
|
88
|
-
|
89
|
-
|
104
|
+
expected_args_first = default_map_args.clone
|
105
|
+
expected_args_second = default_map_args.clone.merge({to: :name, from: :name})
|
106
|
+
|
107
|
+
expect(converter_class).to receive(:map).ordered.with(expected_args_first)
|
108
|
+
expect(converter_class).to receive(:map).ordered.with(expected_args_second)
|
90
109
|
|
91
110
|
subject.add_mapping do
|
92
111
|
rule to: [:id, :name]
|
@@ -94,8 +113,12 @@ describe Yaoc::ConverterBuilder do
|
|
94
113
|
end
|
95
114
|
|
96
115
|
it "use the right 'to' when 'from' in arrays is missing" do
|
97
|
-
|
98
|
-
|
116
|
+
expected_args_first = default_map_args.clone.merge({from: :r_id})
|
117
|
+
expected_args_second = default_map_args.clone.merge({to: :name, from: :name})
|
118
|
+
|
119
|
+
|
120
|
+
expect(converter_class).to receive(:map).ordered.with(expected_args_first)
|
121
|
+
expect(converter_class).to receive(:map).ordered.with(expected_args_second)
|
99
122
|
|
100
123
|
subject.add_mapping do
|
101
124
|
rule to: [:id, :name],
|
@@ -104,7 +127,7 @@ describe Yaoc::ConverterBuilder do
|
|
104
127
|
end
|
105
128
|
|
106
129
|
it "supports the use of a object converter" do
|
107
|
-
expect(converter_class).to receive(:map).ordered.with(:id, :id, kind_of(Proc))
|
130
|
+
expect(converter_class).to receive(:map).ordered.with(to: :id, from: :id, converter: kind_of(Proc), lazy_loading: false)
|
108
131
|
other_converter = :some_converter
|
109
132
|
|
110
133
|
subject.add_mapping do
|
@@ -115,7 +138,9 @@ describe Yaoc::ConverterBuilder do
|
|
115
138
|
end
|
116
139
|
|
117
140
|
it "supports the collection flag for object converters" do
|
118
|
-
|
141
|
+
expected_args = default_map_args.clone.merge({converter: kind_of(Proc)})
|
142
|
+
|
143
|
+
expect(converter_class).to receive(:map).ordered.with(expected_args)
|
119
144
|
other_converter = :some_converter
|
120
145
|
|
121
146
|
subject.add_mapping do
|
@@ -125,6 +150,17 @@ describe Yaoc::ConverterBuilder do
|
|
125
150
|
end
|
126
151
|
|
127
152
|
end
|
153
|
+
|
154
|
+
it "supports lazy loading" do
|
155
|
+
expected_args = default_map_args.clone.merge({lazy_loading: true})
|
156
|
+
|
157
|
+
expect(converter_class).to receive(:map).ordered.with(expected_args)
|
158
|
+
|
159
|
+
subject.add_mapping do
|
160
|
+
rule to: :id,
|
161
|
+
lazy_loading: true
|
162
|
+
end
|
163
|
+
end
|
128
164
|
end
|
129
165
|
|
130
166
|
describe "#converter" do
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Yaoc::Helper::ToProcDelegator do
|
4
|
+
subject{
|
5
|
+
Yaoc::Helper::ToProcDelegator.new(lazy_proc)
|
6
|
+
}
|
7
|
+
|
8
|
+
let(:lazy_proc){
|
9
|
+
->{
|
10
|
+
[:some_value]
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
it 'evaluates a proc not with initialisation' do
|
15
|
+
expect(lazy_proc).not_to receive :call
|
16
|
+
Yaoc::Helper::ToProcDelegator.new(lazy_proc)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'evaluates a proc when methods are delegated' do
|
20
|
+
expect(lazy_proc).to receive(:call)
|
21
|
+
subject.respond_to? :some_method_name
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'delegates to the proc result' do
|
25
|
+
expect(subject.first).to eq :some_value
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'kind_of?' do
|
29
|
+
|
30
|
+
it 'returns true when class is "real class"' do
|
31
|
+
expect(subject).to be_kind_of Yaoc::Helper::ToProcDelegator
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'returns true when class is delegated class' do
|
35
|
+
expect(subject).to be_kind_of lazy_proc.call.class
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns false for other classes' do
|
39
|
+
expect(subject).not_to be_kind_of String
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -17,7 +17,7 @@ describe Yaoc::MappingBase do
|
|
17
17
|
|
18
18
|
describe "created module" do
|
19
19
|
it "can be inspected" do
|
20
|
-
subject.map(:foo, :bar)
|
20
|
+
subject.map(to: :foo, from: :bar)
|
21
21
|
expect(subject.class_private_module.inspect).to include("map_0000_bar_to_foo")
|
22
22
|
end
|
23
23
|
end
|
@@ -25,24 +25,44 @@ describe Yaoc::MappingBase do
|
|
25
25
|
describe ".map" do
|
26
26
|
|
27
27
|
it "creates a bunch of mapping methods" do
|
28
|
-
subject.map(:foo, :bar)
|
29
|
-
subject.map(:bar, :foo)
|
28
|
+
subject.map(to: :foo, from: :bar)
|
29
|
+
subject.map(to: :bar, from: :foo)
|
30
30
|
|
31
31
|
expect(subject.new({bar: :my_to_convert, foo: :my_result}).call()).to eq [{:foo=>:my_to_convert, :bar=>:my_result},
|
32
32
|
{:foo=>:my_to_convert, :bar=>:my_result}]
|
33
33
|
end
|
34
34
|
|
35
35
|
it "uses my converter when provided" do
|
36
|
-
subject.map(:bar, :foo, ->(*){})
|
36
|
+
subject.map(to: :bar, from: :foo, converter: ->(*){})
|
37
37
|
|
38
38
|
expect(subject.new(:my_to_convert).call()).to eq [nil]
|
39
39
|
end
|
40
|
+
|
41
|
+
it 'supports deferred mappings' do
|
42
|
+
subject.map(to: :bar, from: :foo, lazy_loading: true)
|
43
|
+
object_to_convert = {foo: [:my_result]}
|
44
|
+
|
45
|
+
expect(object_to_convert).not_to receive :fetch
|
46
|
+
|
47
|
+
subject.new(object_to_convert).call()
|
48
|
+
end
|
49
|
+
|
50
|
+
it "returns results for deferred mappings" do
|
51
|
+
subject.map(to: :bar, from: :foo, lazy_loading: true)
|
52
|
+
object_to_convert = double("object_to_convert")
|
53
|
+
|
54
|
+
result = subject.new(object_to_convert).call()
|
55
|
+
|
56
|
+
expect(object_to_convert).to receive(:fetch).with(:foo).and_return([:my_result])
|
57
|
+
|
58
|
+
expect(result.first[:bar].first).to eq :my_result
|
59
|
+
end
|
40
60
|
end
|
41
61
|
|
42
62
|
describe "#converter_methods" do
|
43
63
|
it "preserves method order" do
|
44
|
-
subject.map(0, 1, ->(*){})
|
45
|
-
subject.map(1, :a, ->(*){})
|
64
|
+
subject.map(to: 0, from: 1, converter: ->(*){})
|
65
|
+
subject.map(to: 1, from: :a, converter: ->(*){})
|
46
66
|
|
47
67
|
expect(subject.converter_methods).to eq [:map_0000_1_to_0, :map_0001_a_to_1]
|
48
68
|
end
|
@@ -71,13 +91,21 @@ describe Yaoc::MappingBase do
|
|
71
91
|
end
|
72
92
|
|
73
93
|
describe "#call" do
|
74
|
-
|
75
|
-
|
94
|
+
let(:mapper){
|
95
|
+
subject.new(:some_thing)
|
96
|
+
}
|
76
97
|
|
98
|
+
it "delegates execution to strategy" do
|
77
99
|
expect(subject.mapping_strategy).to receive(:call).with mapper
|
78
100
|
|
79
101
|
mapper.call
|
80
102
|
end
|
103
|
+
|
104
|
+
it "return nil when to_convert is nil" do
|
105
|
+
mapper.to_convert = nil
|
106
|
+
expect(mapper.call).to be_nil
|
107
|
+
end
|
108
|
+
|
81
109
|
end
|
82
110
|
|
83
111
|
describe "#to_proc" do
|
@@ -25,6 +25,10 @@ describe Yaoc::MappingToClass do
|
|
25
25
|
{:name => :new_name}
|
26
26
|
}
|
27
27
|
|
28
|
+
def to_convert
|
29
|
+
:some_thing
|
30
|
+
end
|
31
|
+
|
28
32
|
end.new(expected_class)
|
29
33
|
}
|
30
34
|
|
@@ -61,6 +65,11 @@ describe Yaoc::MappingToClass do
|
|
61
65
|
expect(obj.name).to eq :new_name
|
62
66
|
expect(obj.id).to eq :my_id
|
63
67
|
end
|
68
|
+
|
69
|
+
it "returns nil when nothing to convert" do
|
70
|
+
subject.stub(to_convert: nil)
|
71
|
+
expect(subject.call).to be_nil
|
72
|
+
end
|
64
73
|
end
|
65
74
|
|
66
75
|
describe "#to_a" do
|
@@ -23,16 +23,16 @@ describe Yaoc::Strategies::ToArrayMapping do
|
|
23
23
|
describe ".call" do
|
24
24
|
|
25
25
|
it "creates a hash from a object" do
|
26
|
-
subject.map(0, :id)
|
27
|
-
subject.map(1, :name)
|
26
|
+
subject.map(to: 0, from: :id)
|
27
|
+
subject.map(to: 1, from: :name)
|
28
28
|
|
29
29
|
expect(mapper.call).to eq(expected_array)
|
30
30
|
end
|
31
31
|
|
32
32
|
|
33
33
|
it "uses my converter proc" do
|
34
|
-
subject.map(0, :id)
|
35
|
-
subject.map(3, :fullname, ->(source, result){ fill_result_with_value(result, 3, "#{source.fetch(:name)} Hello World") })
|
34
|
+
subject.map(to: 0, from: :id)
|
35
|
+
subject.map(to: 3, from: :fullname, converter: ->(source, result){ fill_result_with_value(result, 3, "#{source.fetch(:name)} Hello World") })
|
36
36
|
|
37
37
|
ext_expectation = expected_array.clone
|
38
38
|
ext_expectation[3] = "#{ext_expectation[1]} Hello World"
|
@@ -48,8 +48,8 @@ describe Yaoc::Strategies::ToArrayMapping do
|
|
48
48
|
}
|
49
49
|
|
50
50
|
it "uses custom fetcher methods" do
|
51
|
-
subject.map(0, :id)
|
52
|
-
subject.map(1, :name)
|
51
|
+
subject.map(to: 0, from: :id)
|
52
|
+
subject.map(to: 1, from: :name)
|
53
53
|
|
54
54
|
def mapper.fetcher
|
55
55
|
:public_send
|
@@ -59,8 +59,8 @@ describe Yaoc::Strategies::ToArrayMapping do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it "works with arrays" do
|
62
|
-
subject.map(1, 0)
|
63
|
-
subject.map(0, 1)
|
62
|
+
subject.map(to: 1, from: 0)
|
63
|
+
subject.map(to: 0, from: 1)
|
64
64
|
|
65
65
|
def mapper.fetcher
|
66
66
|
:[]
|
@@ -23,15 +23,15 @@ describe Yaoc::Strategies::ToHashMapping do
|
|
23
23
|
describe "#call" do
|
24
24
|
|
25
25
|
it "creates a hash from a object" do
|
26
|
-
subject.map(:id, :id)
|
27
|
-
subject.map(:name, :name)
|
26
|
+
subject.map(to: :id, from: :id)
|
27
|
+
subject.map(to: :name, from: :name)
|
28
28
|
|
29
29
|
expect(mapper.call).to eq(expected_hash)
|
30
30
|
end
|
31
31
|
|
32
32
|
it "renames attributes" do
|
33
|
-
subject.map(:
|
34
|
-
subject.map(:fullname, :name)
|
33
|
+
subject.map(to: :id)
|
34
|
+
subject.map(to: :fullname, from: :name)
|
35
35
|
|
36
36
|
renamed_expectation = expected_hash.clone
|
37
37
|
renamed_expectation[:fullname] = renamed_expectation.delete :name
|
@@ -40,8 +40,8 @@ describe Yaoc::Strategies::ToHashMapping do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
it "uses my converter proc" do
|
43
|
-
subject.map(:
|
44
|
-
subject.map(:name, :fullname, ->(source, result){ fill_result_with_value(result, :name, source.fetch(:name) + " Hello World") })
|
43
|
+
subject.map(to: :id)
|
44
|
+
subject.map(to: :name, from: :fullname, converter: ->(source, result){ fill_result_with_value(result, :name, source.fetch(:name) + " Hello World") })
|
45
45
|
|
46
46
|
ext_expectation = expected_hash.clone
|
47
47
|
ext_expectation[:name] += " Hello World"
|
@@ -55,8 +55,8 @@ describe Yaoc::Strategies::ToHashMapping do
|
|
55
55
|
}
|
56
56
|
|
57
57
|
it "uses custom fetcher methods" do
|
58
|
-
subject.map(:
|
59
|
-
subject.map(:
|
58
|
+
subject.map(to: :id)
|
59
|
+
subject.map(to: :name)
|
60
60
|
|
61
61
|
def mapper.fetcher
|
62
62
|
:public_send
|
@@ -66,8 +66,8 @@ describe Yaoc::Strategies::ToHashMapping do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
it "works with arrays" do
|
69
|
-
subject.map(:id, 0)
|
70
|
-
subject.map(:name, 1)
|
69
|
+
subject.map(to: :id, from: 0)
|
70
|
+
subject.map(to: :name, from: 1)
|
71
71
|
|
72
72
|
def mapper.fetcher
|
73
73
|
:[]
|
data/yaoc.gemspec
CHANGED
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yaoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dieter Späth
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: abstract_type
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 0.0.7
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 0.0.7
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: bundler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -225,9 +211,12 @@ files:
|
|
225
211
|
- examples/03_positional_constructors.rb
|
226
212
|
- examples/04_compositions.rb
|
227
213
|
- examples/05_fill_existing_objects.rb
|
214
|
+
- examples/06_lazy_loading.rb
|
215
|
+
- examples/all_examples.rb
|
228
216
|
- lib/yaoc.rb
|
229
217
|
- lib/yaoc/converter_builder.rb
|
230
218
|
- lib/yaoc/helper/struct_hash_constructor.rb
|
219
|
+
- lib/yaoc/helper/to_proc_delegator.rb
|
231
220
|
- lib/yaoc/mapping_base.rb
|
232
221
|
- lib/yaoc/mapping_to_class.rb
|
233
222
|
- lib/yaoc/object_mapper.rb
|
@@ -237,12 +226,14 @@ files:
|
|
237
226
|
- spec/acceptance/fill_existing_objects_spec.rb
|
238
227
|
- spec/acceptance/map_objects_spec.rb
|
239
228
|
- spec/acceptance/map_to_objects_using_other_converters_spec.rb
|
229
|
+
- spec/acceptance/map_to_objects_with_lazy_loading_spec.rb
|
240
230
|
- spec/acceptance/map_to_objects_with_positional_constructors_spec.rb
|
241
231
|
- spec/integration/lib/yaoc/converter_builder_spec.rb
|
242
232
|
- spec/spec_helper.rb
|
243
233
|
- spec/support/feature.rb
|
244
234
|
- spec/unit/lib/yaoc/converter_builder_spec.rb
|
245
235
|
- spec/unit/lib/yaoc/helper/struct_hash_constructor_spec.rb
|
236
|
+
- spec/unit/lib/yaoc/helper/to_proc_delegator_spec.rb
|
246
237
|
- spec/unit/lib/yaoc/mapping_base_spec.rb
|
247
238
|
- spec/unit/lib/yaoc/mapping_to_class_spec.rb
|
248
239
|
- spec/unit/lib/yaoc/object_mapper_spec.rb
|
@@ -277,12 +268,14 @@ test_files:
|
|
277
268
|
- spec/acceptance/fill_existing_objects_spec.rb
|
278
269
|
- spec/acceptance/map_objects_spec.rb
|
279
270
|
- spec/acceptance/map_to_objects_using_other_converters_spec.rb
|
271
|
+
- spec/acceptance/map_to_objects_with_lazy_loading_spec.rb
|
280
272
|
- spec/acceptance/map_to_objects_with_positional_constructors_spec.rb
|
281
273
|
- spec/integration/lib/yaoc/converter_builder_spec.rb
|
282
274
|
- spec/spec_helper.rb
|
283
275
|
- spec/support/feature.rb
|
284
276
|
- spec/unit/lib/yaoc/converter_builder_spec.rb
|
285
277
|
- spec/unit/lib/yaoc/helper/struct_hash_constructor_spec.rb
|
278
|
+
- spec/unit/lib/yaoc/helper/to_proc_delegator_spec.rb
|
286
279
|
- spec/unit/lib/yaoc/mapping_base_spec.rb
|
287
280
|
- spec/unit/lib/yaoc/mapping_to_class_spec.rb
|
288
281
|
- spec/unit/lib/yaoc/object_mapper_spec.rb
|