key_mapable 0.5.0 → 0.6.0
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/Gemfile.lock +1 -1
- data/README.md +120 -16
- data/lib/key_mapable.rb +7 -2
- data/lib/key_mapable/accessor.rb +24 -0
- data/lib/key_mapable/accessor/method.rb +7 -0
- data/lib/key_mapable/mapper.rb +15 -8
- data/lib/key_mapable/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d4af5366336487b70c0894885b432aef53d24e5e0b5ef383fc17c3e5b68c47f
|
4
|
+
data.tar.gz: c35c0e3e2a246d8ee62ca2f75dc98723dbca65495a3f40c620af31295fba1dd6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bda18ea4b63120d0162453973e11802aa08d81c34f86f9cf7f9fea30e6d1c85ced5f12204d194062fe471d23e416273d2e610b8b785bf2a48c169d3614789f44
|
7
|
+
data.tar.gz: '068828bf2970c33abdfe8e95a149f6383ee82a36c628e4e955b60b666649a1c641500d8f247ae56e4f8949cac4694a1d7b20b31afa61e23e65c2f773f23ea419'
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -18,35 +18,139 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
$ gem install key_mapable
|
20
20
|
|
21
|
+
## A quick example
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
class Espresso
|
25
|
+
extend KeyMapable
|
26
|
+
|
27
|
+
define_map(:to_h) do
|
28
|
+
key_map(:strength, 'Strength')
|
29
|
+
key_map(:temperature, 'Temperature, transform: ->(value) { value.to_i })
|
30
|
+
key_value('IsHot') { |espresso| espresso.temperature >= 80 }
|
31
|
+
array_key_map(:sips, 'Sips') do
|
32
|
+
key_map(:sipper, 'Sipper')
|
33
|
+
key_map(:temperature, 'Temperature')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
21
39
|
## Usage
|
22
40
|
|
41
|
+
To map keys from one format to another. You must first extend the `KeyMapable`
|
42
|
+
module. This will add the necessary methods to define a map.
|
43
|
+
|
23
44
|
```ruby
|
24
|
-
class
|
45
|
+
class Espresso
|
25
46
|
extend KeyMapable
|
47
|
+
end
|
48
|
+
```
|
26
49
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
define_map(:to_h, resolve: ->(val) { val }, subject: :my_reader) do
|
31
|
-
# Map the value of `#name` to the key 'Name'.
|
32
|
-
key_map(:name, 'Name')
|
50
|
+
The `.define_map` method lets you define a method that will return a hash from
|
51
|
+
the given map rules defined in the block. The following example will map
|
52
|
+
`#strength` to the key `'Strength'` in the hash returned from `#to_h`.
|
33
53
|
|
34
|
-
|
35
|
-
|
36
|
-
|
54
|
+
```ruby
|
55
|
+
class Espresso
|
56
|
+
extend KeyMapable
|
37
57
|
|
38
|
-
|
39
|
-
key_value('AConstant') { 'Foo' }
|
58
|
+
attr_accessor :strength
|
40
59
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
60
|
+
define_map(:to_h) do
|
61
|
+
key_map(:strength, 'Strength')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
You can then use the `#to_h` method like so:
|
67
|
+
```ruby
|
68
|
+
espresso = Espresso.new
|
69
|
+
espresso.strength = 10
|
70
|
+
espresso.to_h
|
71
|
+
#=> { 'Strength' => 10 }
|
72
|
+
```
|
73
|
+
|
74
|
+
The map definition can be arbitrarily nested as long as the returned objects
|
75
|
+
respond to the described methods.
|
76
|
+
```ruby
|
77
|
+
define_map(:to_h) do
|
78
|
+
key_map(:manufacturer, 'Manufacturer') do
|
79
|
+
key_map(:location, 'Location') do
|
80
|
+
key_map(:country, 'Country')
|
45
81
|
end
|
46
82
|
end
|
47
83
|
end
|
48
84
|
```
|
49
85
|
|
86
|
+
If you wish to transform the value you can provide a third argument which must
|
87
|
+
be a lambda and return the transformed value.
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
define_map(:to_h) do
|
91
|
+
key_map(:temperature, 'Temperature', transform: ->(value) { value.to_i })
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
You can define a structure for a custom key by using the `#key` method.
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
define_map(:to_h) do
|
99
|
+
key('Coffee') do
|
100
|
+
key_map(:brand, 'Brand')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
Use `#array_key_map` to define maps over arrays:
|
106
|
+
```ruby
|
107
|
+
define_map(:to_h) do
|
108
|
+
array_key_map(:sips, 'Sips') do
|
109
|
+
key_map(:sipper, 'Sipper')
|
110
|
+
key_map(:temperature, 'Temperature')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
```
|
114
|
+
|
115
|
+
Use `#key_value` to define a key that will have a manufactured value. The block
|
116
|
+
is yielded the subject and must return the manufactured value.
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
define_map(:to_h) do
|
120
|
+
key_value('IsHot') { |espresso| espresso.temperature >= 80 }
|
121
|
+
end
|
122
|
+
```
|
123
|
+
|
124
|
+
By default the object the keys are read on is the object itself. If you want to
|
125
|
+
use another object you can set the `:subject` keyword to a reader method on the
|
126
|
+
object.
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
define_map(:to_h, subject: :my_reader) do
|
130
|
+
# ...
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
Sometimes you do not want to return a hash. Provide the `:resolve` keyword to
|
135
|
+
transform the resulting hash to your own format.
|
136
|
+
```ruby
|
137
|
+
define_map(:to_h, resolve: ->(value) { OpenStruct.new(value)}) do
|
138
|
+
# ...
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
If the object itself is an hash you might want to use hash notation to access
|
143
|
+
the values. In that case pass `:hash` as the `:access` argument.
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
define_map(:to_h, access: :hash) do
|
147
|
+
# ...
|
148
|
+
end
|
149
|
+
```
|
150
|
+
|
151
|
+
You can also pass a custom accessor. The accessor must respond to `#access`. It
|
152
|
+
will then be passed the subject and key.
|
153
|
+
|
50
154
|
## Development
|
51
155
|
|
52
156
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/key_mapable.rb
CHANGED
@@ -1,13 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "key_mapable/version"
|
4
|
+
require "key_mapable/accessor"
|
4
5
|
require "key_mapable/mapper"
|
5
6
|
|
6
7
|
module KeyMapable
|
7
|
-
def define_map(method_name,
|
8
|
+
def define_map(method_name,
|
9
|
+
resolve: ->(val) { val },
|
10
|
+
subject: :itself,
|
11
|
+
access: :method, &block)
|
8
12
|
define_method(method_name) do
|
9
13
|
value = public_send(subject)
|
10
|
-
|
14
|
+
accessor = Accessor.for(access)
|
15
|
+
mapper = Mapper.new(value, accessor)
|
11
16
|
mapper.instance_eval(&block)
|
12
17
|
resolve.call(mapper.structure)
|
13
18
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class KeyMapable::Accessor
|
4
|
+
class Method
|
5
|
+
def self.access(subject, key)
|
6
|
+
subject.public_send(key)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Hash
|
11
|
+
def self.access(subject, key)
|
12
|
+
subject[key]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ACCESSORS = {
|
17
|
+
method: Method,
|
18
|
+
hash: Hash
|
19
|
+
}
|
20
|
+
|
21
|
+
def self.for(accessor_or_name)
|
22
|
+
ACCESSORS.fetch(accessor_or_name, accessor_or_name)
|
23
|
+
end
|
24
|
+
end
|
data/lib/key_mapable/mapper.rb
CHANGED
@@ -2,28 +2,29 @@
|
|
2
2
|
|
3
3
|
# Used internally by the KeyMapable concern.
|
4
4
|
class KeyMapable::Mapper
|
5
|
-
attr_reader :subject, :structure
|
5
|
+
attr_reader :subject, :structure, :accessor
|
6
6
|
|
7
|
-
def initialize(subject)
|
7
|
+
def initialize(subject, accessor = KeyMapable::Accessor::Method)
|
8
8
|
@subject = subject
|
9
9
|
@structure = {}
|
10
|
+
@accessor = accessor
|
10
11
|
end
|
11
12
|
|
12
13
|
def key_value(key)
|
13
|
-
@structure[key] = yield()
|
14
|
+
@structure[key] = yield(subject)
|
14
15
|
end
|
15
16
|
|
16
17
|
def key(name, &block)
|
17
|
-
child_mapper = self.class.new(subject)
|
18
|
+
child_mapper = self.class.new(subject, accessor)
|
18
19
|
child_mapper.instance_eval(&block)
|
19
20
|
@structure[name] = child_mapper.resolve
|
20
21
|
end
|
21
22
|
|
22
23
|
def key_map(original_key, new_key, transform: ->(val) { val }, &block)
|
23
|
-
original_subject =
|
24
|
+
original_subject = access(original_key)
|
24
25
|
transformed_subject = transform.call(original_subject)
|
25
26
|
if block_given?
|
26
|
-
child_mapper = self.class.new(transformed_subject)
|
27
|
+
child_mapper = self.class.new(transformed_subject, accessor)
|
27
28
|
child_mapper.instance_eval &block
|
28
29
|
@structure[new_key] = child_mapper.resolve
|
29
30
|
else
|
@@ -32,9 +33,9 @@ class KeyMapable::Mapper
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def array_key_map(original_key, new_key, &block)
|
35
|
-
original_subject =
|
36
|
+
original_subject = access(original_key)
|
36
37
|
@structure[new_key] = original_subject.map do |item|
|
37
|
-
child_mapper = self.class.new(item)
|
38
|
+
child_mapper = self.class.new(item, accessor)
|
38
39
|
child_mapper.instance_eval(&block)
|
39
40
|
child_mapper.resolve
|
40
41
|
end
|
@@ -43,4 +44,10 @@ class KeyMapable::Mapper
|
|
43
44
|
def resolve
|
44
45
|
@structure
|
45
46
|
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def access(key)
|
51
|
+
accessor.access(subject, key)
|
52
|
+
end
|
46
53
|
end
|
data/lib/key_mapable/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: key_mapable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Emric
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -71,6 +71,8 @@ files:
|
|
71
71
|
- bin/setup
|
72
72
|
- key_mapable.gemspec
|
73
73
|
- lib/key_mapable.rb
|
74
|
+
- lib/key_mapable/accessor.rb
|
75
|
+
- lib/key_mapable/accessor/method.rb
|
74
76
|
- lib/key_mapable/mapper.rb
|
75
77
|
- lib/key_mapable/version.rb
|
76
78
|
homepage: https://github.com/istanful/key_mapable
|