key_dial 1.1.0 → 1.2.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: adcb8d79a70615b55ef7096cb21d1df639a35fa8e83e42eff35e59dbfa2b466a
4
- data.tar.gz: 5eed7fe134f7bf05227012c4a0242a5c89cc76d8c62afacc978ff17a1e09e76a
3
+ metadata.gz: 2dda856c325133404a9948a0a97d98009d5a46fdcbb916977f4b280094ff2b08
4
+ data.tar.gz: 387b760bf24b91add075b1c4a9a05ae01fa8fa134695bad0caf718fcbacc7d1e
5
5
  SHA512:
6
- metadata.gz: 28a754fba139b866e22a2184782ceba09aaed757384b92aa3607d4f9bff0b551162818dfac4ea01919509d9625e030a2b27c33184ca8c9aa938076995e2f0613
7
- data.tar.gz: cac3c202ca11e2c398d35cf89079e1ead4dc2e95e83f6aed0ea281b672f5b2916bbadd63d1241418c0f46cf757f3d6268f753f695770443873b725481a9f547f
6
+ metadata.gz: 45e32b32d08741ef44825ee3749fd45c29949ef35c101e8c490e1d980c7af6aea3cec12e5c443a6fbeab133aa1a11518e110ca22d5235206e215b13634cc4fd2
7
+ data.tar.gz: 002c925e1c2558a58d19d0ab2123f47a5d150d8ce06da692404b39fd5120e151a1834a8deb0cd198ca0fae6a9c353cba1627388d9f81d8eb2c21f7eb492708d0
@@ -2,13 +2,30 @@ module KeyDial
2
2
 
3
3
  module Coercion
4
4
 
5
- module Hashes
6
-
7
- # Convert a Hash to a Struct. {a: 1, b: 2, c: 3} will become <Struct :a=1, :b=2, :c=3>
8
- #
9
- def to_struct(type_class = nil)
10
- return Coercion::Structs.create(self, type_class)
5
+ module Coercer
6
+ def to(type)
7
+ if type.is_a?(Class)
8
+ if type == self.class || self.class < type
9
+ return self
10
+ elsif (type == Hash || type < Hash) && type.respond_to?(:from)
11
+ return type.from(self)
12
+ elsif (type == Array || type < Array) && type.respond_to?(:from)
13
+ return type.from(self)
14
+ elsif (type == Struct || type < Struct) && type.respond_to?(:from)
15
+ return type.from(self)
16
+ else
17
+ raise ArgumentError, "Cannot coerce to " + type.to_s
18
+ end
19
+ else
20
+ raise ArgumentError, "Must specify a class to coerce to."
21
+ end
11
22
  end
23
+ end
24
+
25
+ module Hashes
26
+
27
+ # Adds .to() method to instances of this class
28
+ include Coercer
12
29
 
13
30
  def self.included(base)
14
31
  base.extend ClassMethods
@@ -19,10 +36,30 @@ module KeyDial
19
36
  # Allows you to do Hash.from(obj) to create a Hash from any object intelligently.
20
37
  #
21
38
  def from(obj)
22
- return obj if obj.is_a?(Hash)
23
- return obj.to_hash if obj.is_a?(Array)
24
- return obj.to_h if obj.is_a?(Struct)
25
- return {0 => obj}
39
+ case obj
40
+ when Hash
41
+ return obj
42
+ when Array
43
+ # Hash from Array. Forgiving and avoids errors. ['a', 'b', 'c'] will become {0 => 'a', 1 => 'b', 2 => 'c'}
44
+ obj.each_with_index.map { |k, i|
45
+ if k.is_a?(Array)
46
+ if k.empty?
47
+ [i, nil]
48
+ elsif k.size == 2
49
+ k # k in this case is a keyval pair, e.g. [k, v]
50
+ else
51
+ [i, k]
52
+ end
53
+ else
54
+ [i, k]
55
+ end
56
+ }.to_h
57
+ when Struct
58
+ # Hash from Struct
59
+ return obj.to_h
60
+ else
61
+ {0 => obj}
62
+ end
26
63
  end
27
64
 
28
65
  end
@@ -31,31 +68,8 @@ module KeyDial
31
68
 
32
69
  module Arrays
33
70
 
34
- # Convert an Array to a Hash, providing an alternative to the native to_h() method. to_hash() is more forgiving and avoids errors. ['a', 'b', 'c'] will become {0 => 'a', 1 => 'b', 2 => 'c'}
35
- #
36
- def to_hash
37
- self.each_with_index.map { |k, i|
38
- if k.is_a?(Array)
39
- if k.empty?
40
- [i, nil]
41
- elsif k.size == 2
42
- k # k in this case is a keyval pair, e.g. [k, v]
43
- else
44
- [i, k]
45
- end
46
- else
47
- [i, k]
48
- end
49
- }.to_h
50
- end
51
-
52
- # Convert an Array to a Struct. ['a', 'b', 'c'] will become <Struct :'0'='a', :'1'='b', :'2'='c'>
53
- #
54
- # @param type_class If a sub-class of Struct is provided, this sub-class will be instantiated
55
- #
56
- def to_struct(type_class = nil)
57
- return Coercion::Structs.create(self, type_class)
58
- end
71
+ # Adds .to() method to instances of this class
72
+ include Coercer
59
73
 
60
74
  def self.included(base)
61
75
  base.extend ClassMethods
@@ -66,10 +80,18 @@ module KeyDial
66
80
  # Allows you to do Array.from(obj) to create an Array from any object intelligently.
67
81
  #
68
82
  def from(obj)
69
- return obj if obj.is_a?(Array)
70
- return obj.to_a if obj.is_a?(Hash)
71
- return obj.to_h.to_a if obj.is_a?(Struct)
72
- return [obj]
83
+ case obj
84
+ when Array
85
+ return obj
86
+ when Hash
87
+ # Array from Hash
88
+ return obj.to_a
89
+ when Struct
90
+ # Array from Struct
91
+ return obj.to_h.to_a
92
+ else
93
+ return [obj]
94
+ end
73
95
  end
74
96
 
75
97
  end
@@ -78,19 +100,10 @@ module KeyDial
78
100
 
79
101
  module Structs
80
102
 
81
- EMPTY = Struct.new(:'0').new.freeze
103
+ # Adds .to() method to instances of this class
104
+ include Coercer
82
105
 
83
- # Convert a Struct to another Struct.
84
- #
85
- # @param type_class If a sub-class of Struct is provided, the Struct will be converted to this sub-class
86
- #
87
- def to_struct(type_class = nil)
88
- if type_class.is_a?(Class) && type_class < Struct
89
- return Struct.from(self, type_class)
90
- else
91
- return self
92
- end
93
- end
106
+ EMPTY = Struct.new(:'0').new.freeze
94
107
 
95
108
  def self.included(base)
96
109
  base.extend ClassMethods
@@ -100,86 +113,73 @@ module KeyDial
100
113
 
101
114
  # Allows you to do Struct.from(obj) to instantiate a Struct using keys/values from any object intelligently.
102
115
  #
103
- # @param type_class If a sub-class of Struct is provided, this sub-class will be instantiated
104
- #
105
- def from(obj, type_class = nil)
106
- if !obj.is_a?(Struct) && !obj.is_a?(Hash) && !obj.is_a?(Array) && type_class == nil
107
- s = EMPTY.dup
108
- s[0] = obj
109
- return s
110
- else
111
- return Coercion::Structs.create(obj, type_class)
112
- end
113
- end
114
-
115
- end
116
-
117
- # Struct creation function not really meant to be used directly. Prefer Struct.from(obj).
118
- #
119
- # @param from_obj Keys/values from this object will be used to fill out the new Struct.
120
- # @param type_class If a sub-class of Struct is provided, this sub-class will be instantiated
121
- #
122
- def self.create(from_obj, type_class = nil)
123
- if from_obj.is_a?(Hash) || from_obj.is_a?(Array) || from_obj.is_a?(Struct)
124
- return EMPTY.dup if from_obj.empty? && type_class == nil
125
- from = from_obj
126
- else
127
- from = [from_obj]
128
- end
129
-
130
- # Has a specific type of Struct been specified?
131
- if type_class.is_a?(Class) && type_class < Struct
132
- if from.is_a?(type_class)
133
- # Has an instantiation of that type of Struct been passed in? If so, just return it
134
- return from
135
- else
136
- values = []
137
- if from.is_a?(Array)
138
- # Get as many elements of array as this Struct can handle - discard the rest
139
- values = from.first(type_class.members.size)
140
- else
141
- # Not an Array, so must be another Struct or Hash
142
- type_class.members.each { |key|
143
- if from.key?(key)
144
- # If the object has this expected key, use it
145
- values << from[key]
146
- else
147
- # Otherwise, fill this key with nil
148
- values << nil
149
- # Keys in the from object which don't match expected keys are discarded
150
- end
151
- }
152
- end
153
- # values now contains a value or nil for each of this class's expected keys
154
- return type_class.new(*values)
116
+ def from(_obj)
117
+ from_obj = _obj
118
+ if !from_obj.is_a?(Struct) && !from_obj.is_a?(Hash) && !from_obj.is_a?(Array)
119
+ return EMPTY if _obj == EMPTY[0]
120
+ return EMPTY if _obj.nil?
121
+ # For non-keyed objects, we will treat the whole object like it's a value to push into the first property of a struct
122
+ from_obj = [_obj]
155
123
  end
156
- else
157
- # Anonymous Struct
158
- new_values = from.is_a?(Array) ? from : from.values
159
- # Iterate over the keys of the from object
160
- # (Array.keys is monkeypatched in)
161
- new_keys = from.keys.each_with_index.map { |k, i|
162
- if k.respond_to?(:to_sym) && k != ''
163
- k.to_sym
164
- elsif k.respond_to?(:to_s) && !k.nil?
165
- k.to_s.to_sym
124
+
125
+ struct_class = self
126
+
127
+ # Are we operating on a defined type of Struct?
128
+ if struct_class < Struct
129
+ if from_obj.is_a?(struct_class)
130
+ # Has an instantiation of that type of Struct been passed in? If so, just return it
131
+ return from_obj
166
132
  else
167
- # If we can't construct a valid Struct key for this key, we discard the corresponding value
168
- new_values.delete_at(i)
169
- nil
133
+ # Get values
134
+ values = []
135
+ if from_obj.is_a?(Array)
136
+ # Get as many elements of array as this Struct can handle - discard the rest
137
+ values = from_obj.first(struct_class.members.size)
138
+ else
139
+ # Not an Array, so must be another Struct or Hash
140
+ struct_class.members.each { |key|
141
+ if from_obj.key?(key)
142
+ # If the object has this expected key, use it
143
+ values << from_obj[key]
144
+ else
145
+ # Otherwise, fill this key with nil
146
+ values << nil
147
+ # Keys in the from object which don't match expected keys are discarded
148
+ end
149
+ }
150
+ end
151
+ # values now contains a value or nil for each of this class's expected keys
152
+ return struct_class.new(*values)
170
153
  end
171
- }.reject(&:nil?)
172
- if new_keys.size > 0
173
- # Create anonymous Struct with the specified keys and values
174
- return Struct.new(*new_keys).new(*new_values)
175
154
  else
176
- # Return the Empty Struct
177
- return EMPTY.dup
155
+ # Anonymous Struct
156
+ new_values = from_obj.is_a?(Array) ? from_obj : from_obj.values
157
+ # Iterate over the keys of the from object
158
+ # (Array.keys is monkeypatched in)
159
+ new_keys = from_obj.keys.each_with_index.map { |k, i|
160
+ if k.respond_to?(:to_sym) && k != ''
161
+ k.to_sym
162
+ elsif k.respond_to?(:to_s) && !k.nil?
163
+ k.to_s.to_sym
164
+ else
165
+ # If we can't construct a valid Struct key for this key, we discard the corresponding value
166
+ new_values.delete_at(i)
167
+ nil
168
+ end
169
+ }.reject(&:nil?)
170
+ if new_keys.size > 0
171
+ # Create anonymous Struct with the specified keys and values
172
+ return Struct.new(*new_keys).new(*new_values)
173
+ else
174
+ # Return the Empty Struct
175
+ return EMPTY
176
+ end
178
177
  end
178
+
179
+ rescue
180
+ return EMPTY
179
181
  end
180
182
 
181
- rescue
182
- return EMPTY.dup
183
183
  end
184
184
 
185
185
  end
@@ -380,7 +380,7 @@ module KeyDial
380
380
  # Why would you do this?
381
381
  deep_obj[key[:this][:value]] = Struct.from(deep_obj[key[:this][:value]])
382
382
  elsif type_class.is_a?(Class) && type_class < Struct
383
- deep_obj[key[:this][:value]] = Struct.from(deep_obj[key[:this][:value]], type_class)
383
+ deep_obj[key[:this][:value]] = type_class.from(deep_obj[key[:this][:value]])
384
384
  elsif type_class == String && deep_obj[key[:this][:value]].respond_to?(:to_s)
385
385
  deep_obj[key[:this][:value]] = deep_obj[key[:this][:value]].to_s
386
386
  elsif type_class == Symbol
@@ -1,3 +1,3 @@
1
1
  module KeyDial
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: key_dial
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Convincible
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-25 00:00:00.000000000 Z
11
+ date: 2019-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler