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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 969c799e73735d2f2a1ba0d275e7e45edf8bb1350d7e41987899858ecd8a02b8
4
- data.tar.gz: 40bb387e611607dd18aebeed78ae7946b4a03b6f57f7b3b69dfe9efd74d05abf
3
+ metadata.gz: 3d4af5366336487b70c0894885b432aef53d24e5e0b5ef383fc17c3e5b68c47f
4
+ data.tar.gz: c35c0e3e2a246d8ee62ca2f75dc98723dbca65495a3f40c620af31295fba1dd6
5
5
  SHA512:
6
- metadata.gz: 40e61c0558617201a4d4eaac5baa71d3cbb6035898dc0478ddd9c86e9396eb06ff7f31085d6dde24bd4a3f5c3da6c2fe1d3d394ad3d0fbe0006d4e82a3107157
7
- data.tar.gz: 5377db7d4c8006e8eb6e2ab89fd6cf2516f10fe0d4b58563584ec870b9f80fda28475c3a442b2e208d12538897f645df5349042b9c57f3a0561e744762484fb2
6
+ metadata.gz: bda18ea4b63120d0162453973e11802aa08d81c34f86f9cf7f9fea30e6d1c85ced5f12204d194062fe471d23e416273d2e610b8b785bf2a48c169d3614789f44
7
+ data.tar.gz: '068828bf2970c33abdfe8e95a149f6383ee82a36c628e4e955b60b666649a1c641500d8f247ae56e4f8949cac4694a1d7b20b31afa61e23e65c2f773f23ea419'
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- key_mapable (0.4.0)
4
+ key_mapable (0.5.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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 MyClass
45
+ class Espresso
25
46
  extend KeyMapable
47
+ end
48
+ ```
26
49
 
27
- # Define a method called `#to_h` that use the provided map. The keys
28
- # will be accessed on the provided subject. Transform the resulting hash
29
- # with the provided lambda.
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
- # Map the value of `#maybe_value` to the key 'GuaranteedValue'.
35
- # Transform the value by calling `#to_s` first.
36
- key_map(:maybe_value, 'GuaranteedValue', transform: ->(val) { val.to_s })
54
+ ```ruby
55
+ class Espresso
56
+ extend KeyMapable
37
57
 
38
- # Map the key 'Name' to the value provided by the block.
39
- key_value('AConstant') { 'Foo' }
58
+ attr_accessor :strength
40
59
 
41
- # Map every item returned from `#rows`.
42
- array_key_map(:rows, 'Rows') do
43
- # Map the value of `#id` to the key 'Id'.
44
- key_map(:id, 'Id')
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.
@@ -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, resolve: ->(val) { val }, subject: :itself, &block)
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
- mapper = Mapper.new(value)
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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class KeyMapable::Accessor::Method
4
+ def self.access(subject, key)
5
+ subject.public_send(key)
6
+ end
7
+ end
@@ -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 = subject.public_send(original_key)
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 = subject.public_send(original_key)
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
@@ -1,3 +1,3 @@
1
1
  module KeyMapable
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
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.5.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-17 00:00:00.000000000 Z
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