yaoc 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Code Climate](https://codeclimate.com/github/slowjack2k/yaoc.png)](https://codeclimate.com/github/slowjack2k/yaoc) [![Build Status](https://travis-ci.org/slowjack2k/yaoc.png?branch=master)](https://travis-ci.org/slowjack2k/yaoc) [![Coverage Status](https://coveralls.io/repos/slowjack2k/yaoc/badge.png?branch=master)](https://coveralls.io/r/slowjack2k/yaoc?branch=master) [![Gem Version](https://badge.fury.io/rb/yaoc.png)](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
|