nrser 0.0.25 → 0.0.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +39 -11
- data/lib/nrser.rb +5 -1
- data/lib/nrser/array.rb +10 -53
- data/lib/nrser/enumerable.rb +21 -0
- data/lib/nrser/hash.rb +13 -476
- data/lib/nrser/hash/bury.rb +154 -0
- data/lib/nrser/hash/deep_merge.rb +57 -0
- data/lib/nrser/hash/except_keys.rb +42 -0
- data/lib/nrser/hash/guess_label_key_type.rb +37 -0
- data/lib/nrser/hash/slice_keys.rb +41 -0
- data/lib/nrser/hash/stringify_keys.rb +37 -0
- data/lib/nrser/hash/symbolize_keys.rb +41 -0
- data/lib/nrser/hash/transform_keys.rb +45 -0
- data/lib/nrser/merge_by.rb +26 -0
- data/lib/nrser/message.rb +125 -0
- data/lib/nrser/meta/props.rb +2 -2
- data/lib/nrser/meta/props/prop.rb +5 -2
- data/lib/nrser/object.rb +5 -0
- data/lib/nrser/object/as_array.rb +37 -0
- data/lib/nrser/object/as_hash.rb +101 -0
- data/lib/nrser/{truthy.rb → object/truthy.rb} +0 -0
- data/lib/nrser/proc.rb +132 -0
- data/lib/nrser/refinements.rb +1 -2
- data/lib/nrser/refinements/array.rb +94 -5
- data/lib/nrser/refinements/enumerable.rb +5 -0
- data/lib/nrser/refinements/hash.rb +43 -6
- data/lib/nrser/refinements/object.rb +22 -2
- data/lib/nrser/refinements/symbol.rb +12 -0
- data/lib/nrser/refinements/tree.rb +41 -0
- data/lib/nrser/rspex.rb +329 -0
- data/lib/nrser/string.rb +3 -0
- data/lib/nrser/string/looks_like.rb +51 -0
- data/lib/nrser/temp/where.rb +52 -0
- data/lib/nrser/tree.rb +86 -0
- data/lib/nrser/tree/leaves.rb +92 -0
- data/lib/nrser/tree/map_leaves.rb +63 -0
- data/lib/nrser/tree/transform.rb +30 -0
- data/lib/nrser/types.rb +9 -4
- data/lib/nrser/types/any.rb +1 -1
- data/lib/nrser/types/array.rb +167 -25
- data/lib/nrser/types/{hash.rb → hashes.rb} +19 -5
- data/lib/nrser/types/in.rb +47 -0
- data/lib/nrser/types/is_a.rb +2 -2
- data/lib/nrser/types/labels.rb +49 -0
- data/lib/nrser/types/numbers.rb +63 -27
- data/lib/nrser/types/pairs.rb +109 -0
- data/lib/nrser/types/responds.rb +2 -3
- data/lib/nrser/types/strings.rb +17 -18
- data/lib/nrser/types/symbols.rb +39 -0
- data/lib/nrser/types/trees.rb +93 -0
- data/lib/nrser/types/tuples.rb +116 -0
- data/lib/nrser/types/type.rb +26 -2
- data/lib/nrser/version.rb +1 -1
- data/spec/nrser/hash/{guess_name_type_spec.rb → guess_label_key_type_spec.rb} +3 -3
- data/spec/nrser/hash_spec.rb +0 -20
- data/spec/nrser/merge_by_spec.rb +73 -0
- data/spec/nrser/meta/props_spec.rb +136 -43
- data/spec/nrser/op/message_spec.rb +62 -0
- data/spec/nrser/refinements/array_spec.rb +36 -0
- data/spec/nrser/refinements/hash_spec.rb +34 -0
- data/spec/nrser/string/looks_like_spec.rb +31 -0
- data/spec/nrser/tree/each_branch_spec.rb +82 -0
- data/spec/nrser/tree/leaves_spec.rb +112 -0
- data/spec/nrser/tree/transform_spec.rb +165 -0
- data/spec/nrser/types/array_spec.rb +82 -0
- data/spec/nrser/types/attrs_spec.rb +4 -4
- data/spec/nrser/types/pairs_spec.rb +41 -0
- data/spec/nrser/types/paths_spec.rb +3 -3
- data/spec/nrser/types/strings_spec.rb +66 -0
- data/spec/nrser/types/symbols_spec.rb +38 -0
- data/spec/nrser/types/tuples_spec.rb +37 -0
- data/spec/nrser/types_spec.rb +0 -13
- data/spec/spec_helper.rb +71 -22
- metadata +58 -10
- data/lib/nrser/spex.rb +0 -68
- data/lib/nrser/types/symbol.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5695621d94d38882e9dcce612c022ac723febf5e
|
4
|
+
data.tar.gz: 825fe26548e53f4f8a72138fabb9554832392c8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35da0260954c54d63cb02aadd26d110810bdcf776bfc9e7dfe5966512411d9b42b6a2d49474e4db3025891b976b9d8c72f140c440f96a402931b5141811b2fd6
|
7
|
+
data.tar.gz: 17a5658d7d56c4a93a8f1eda5fa8782f41452fbc64a4fb195daeca9e1b22fe5e34f6329b595db6e73a23651e61f2b3ab47cec66e74e90a20a2d3d37819ada1b5
|
data/README.md
CHANGED
@@ -1,18 +1,22 @@
|
|
1
|
-
|
1
|
+
NRSER Ruby lib
|
2
|
+
========================================================================
|
2
3
|
|
3
|
-
|
4
|
+
Basic Ruby utilities I use in a lot of stuff.
|
4
5
|
|
5
|
-
|
6
|
+
These tools are hastily written or copied from other sources.
|
6
7
|
|
7
|
-
|
8
|
+
They are not fast.
|
8
9
|
|
9
|
-
|
10
|
+
They are not optimized.
|
10
11
|
|
11
|
-
|
12
|
+
They are largely untested. Though this *is* slowly getting better.
|
12
13
|
|
13
|
-
|
14
|
+
Proceed with caution.
|
14
15
|
|
15
|
-
|
16
|
+
|
17
|
+
------------------------------------------------------------------------
|
18
|
+
Installation
|
19
|
+
------------------------------------------------------------------------
|
16
20
|
|
17
21
|
Add this line to your application's Gemfile:
|
18
22
|
|
@@ -27,6 +31,30 @@ Or install it yourself as:
|
|
27
31
|
$ gem install nrser
|
28
32
|
|
29
33
|
|
30
|
-
|
31
|
-
|
32
|
-
|
34
|
+
------------------------------------------------------------------------
|
35
|
+
Design
|
36
|
+
------------------------------------------------------------------------
|
37
|
+
|
38
|
+
1. No monkey-patching (`core_ext` kinda stuff).
|
39
|
+
|
40
|
+
All language extension is done with refinements.
|
41
|
+
|
42
|
+
Refinements are funky in a few ways, but they make me feel better.
|
43
|
+
|
44
|
+
2. As a corollary, (pretty-much) all refinement methods are implemented functionally so they can be used in older Rubies (2.0 and before I think?).
|
45
|
+
|
46
|
+
This is pretty much only an issue with the current system Ruby version on macOS, which is `2.0.0`.
|
47
|
+
|
48
|
+
I don't run into it much, but it's nice to have it when you need it, and has panned-out to be a decent design philosophy.
|
49
|
+
|
50
|
+
3. This means that code in the `NRSER` gem itself can't use the refinements it provides.
|
51
|
+
|
52
|
+
Which sucks, but I can live with it, because the times that I need some Ruby when I've only got the macOS system installation available I really wants it.
|
53
|
+
|
54
|
+
- The exception is the types system, which uses the refinements, and will thus be unavailable in old-ass rubies.
|
55
|
+
|
56
|
+
4. Basically all these methods are defined directly on the `NRSER` module for the sake of brevity and connivence, though their definitions are split up across many files and directories by subject.
|
57
|
+
|
58
|
+
I like this because I like small files. They make it easier to see what's changing in commits at a glance, and I find them easier to work with in the GUI editors that I use.
|
59
|
+
|
60
|
+
The fact that Ruby does not tie source file location to API path is one of my favorite parts of the language.
|
data/lib/nrser.rb
CHANGED
@@ -6,8 +6,10 @@ end
|
|
6
6
|
|
7
7
|
require_relative './nrser/version'
|
8
8
|
require_relative './nrser/no_arg'
|
9
|
+
require_relative './nrser/message'
|
10
|
+
require_relative './nrser/proc'
|
9
11
|
require_relative './nrser/collection'
|
10
|
-
require_relative './nrser/
|
12
|
+
require_relative './nrser/object'
|
11
13
|
require_relative './nrser/string'
|
12
14
|
require_relative './nrser/binding'
|
13
15
|
require_relative './nrser/exception'
|
@@ -17,3 +19,5 @@ require_relative './nrser/array'
|
|
17
19
|
require_relative './nrser/types'
|
18
20
|
require_relative './nrser/meta'
|
19
21
|
require_relative './nrser/open_struct'
|
22
|
+
require_relative './nrser/merge_by'
|
23
|
+
require_relative './nrser/tree'
|
data/lib/nrser/array.rb
CHANGED
@@ -1,58 +1,15 @@
|
|
1
1
|
module NRSER
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
3
|
+
# Functional implementation of "rest" for arrays. Used when refining `#rest`
|
4
|
+
# into {Array}.
|
5
5
|
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# 3. If `value` responds to `#to_a`, try calling it. If it succeeds, return
|
15
|
-
# that.
|
16
|
-
#
|
17
|
-
# 4. Return an array with `value` as it's only item.
|
18
|
-
#
|
19
|
-
# Refinement
|
20
|
-
# ----------
|
21
|
-
#
|
22
|
-
# Added to `Object` in `nrser/refinements`.
|
23
|
-
#
|
24
|
-
# @param [Object] value
|
25
|
-
#
|
26
|
-
# @return [Array]
|
27
|
-
#
|
28
|
-
def as_array value
|
29
|
-
return value if value.is_a? Array
|
30
|
-
return [] if value.nil?
|
31
|
-
|
32
|
-
if value.respond_to? :to_a
|
33
|
-
begin
|
34
|
-
return value.to_a
|
35
|
-
rescue
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
[value]
|
40
|
-
end # #as_array
|
41
|
-
|
42
|
-
|
43
|
-
# Functional implementation of "rest" for arrays. Used when refining `#rest`
|
44
|
-
# into {Array}.
|
45
|
-
#
|
46
|
-
# @param [Array] array
|
47
|
-
#
|
48
|
-
# @return [return_type]
|
49
|
-
# New array consisting of all elements after the first.
|
50
|
-
#
|
51
|
-
def rest array
|
52
|
-
array[1..-1]
|
53
|
-
end # #rest
|
54
|
-
|
55
|
-
|
56
|
-
end # class << self (Eigenclass)
|
6
|
+
# @param [Array] array
|
7
|
+
#
|
8
|
+
# @return [return_type]
|
9
|
+
# New array consisting of all elements after the first.
|
10
|
+
#
|
11
|
+
def self.rest array
|
12
|
+
array[1..-1]
|
13
|
+
end # .rest
|
57
14
|
|
58
15
|
end # module NRSER
|
data/lib/nrser/enumerable.rb
CHANGED
@@ -107,6 +107,27 @@ module NRSER
|
|
107
107
|
end # #find_only
|
108
108
|
|
109
109
|
|
110
|
+
|
111
|
+
# @todo Document only method.
|
112
|
+
#
|
113
|
+
# @param [type] arg_name
|
114
|
+
# @todo Add name param description.
|
115
|
+
#
|
116
|
+
# @return [return_type]
|
117
|
+
# @todo Document return value.
|
118
|
+
#
|
119
|
+
def only! enum
|
120
|
+
unless enum.length == 1
|
121
|
+
raise TypeError.new squish <<-END
|
122
|
+
Expected enumerable #{ enum.inspect } to have exactly one entry.
|
123
|
+
END
|
124
|
+
end
|
125
|
+
|
126
|
+
enum.first
|
127
|
+
end # #only
|
128
|
+
|
129
|
+
|
130
|
+
|
110
131
|
# @todo Document to_h_by method.
|
111
132
|
#
|
112
133
|
# @param [type] arg_name
|
data/lib/nrser/hash.rb
CHANGED
@@ -1,476 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
results
|
16
|
-
end # .leaves
|
17
|
-
|
18
|
-
|
19
|
-
# Treat the value as the value for `key` in a hash if it's not already a
|
20
|
-
# hash and can't be converted to one:
|
21
|
-
#
|
22
|
-
# 1. If the value is a `Hash`, return it.
|
23
|
-
#
|
24
|
-
# 2. If `value` is `nil`, return `{}`.
|
25
|
-
#
|
26
|
-
# 3. If the value responds to `#to_h` and `#to_h` succeeds, return the
|
27
|
-
# resulting hash.
|
28
|
-
#
|
29
|
-
# 4. Otherwise, return a new hash where `key` points to the value.
|
30
|
-
# **`key` MUST be provided in this case.**
|
31
|
-
#
|
32
|
-
# Useful in method overloading and similar situations where you expect a
|
33
|
-
# hash that may specify a host of options, but want to allow the method
|
34
|
-
# to be called with a single value that corresponds to a default key in that
|
35
|
-
# option hash.
|
36
|
-
#
|
37
|
-
# Refinement
|
38
|
-
# ----------
|
39
|
-
#
|
40
|
-
# Added to `Object` in `nrser/refinements`.
|
41
|
-
#
|
42
|
-
#
|
43
|
-
# Example Time!
|
44
|
-
# -------------
|
45
|
-
#
|
46
|
-
# Say you have a method `m` that handles a hash of HTML options that can
|
47
|
-
# look something like
|
48
|
-
#
|
49
|
-
# {class: 'address', data: {confirm: 'Really?'}}
|
50
|
-
#
|
51
|
-
# And can call `m` like
|
52
|
-
#
|
53
|
-
# m({class: 'address', data: {confirm: 'Really?'}})
|
54
|
-
#
|
55
|
-
# but often you are just dealing with the `:class` option. You can use
|
56
|
-
# {NRSER.as_hash} to accept a string and treat it as the `:class` key:
|
57
|
-
#
|
58
|
-
# using NRSER
|
59
|
-
#
|
60
|
-
# def m opts
|
61
|
-
# opts = opts.as_hash :class
|
62
|
-
# # ...
|
63
|
-
# end
|
64
|
-
#
|
65
|
-
# If you pass a hash, everything works normally, but if you pass a string
|
66
|
-
# `'address'` it will be converted to `{class: 'address'}`.
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# About `#to_h` Support
|
70
|
-
# ---------------------
|
71
|
-
#
|
72
|
-
# Right now, {.as_hash} also tests if `value` responds to `#to_h`, and will
|
73
|
-
# try to call it, using the result if it doesn't raise. This lets it deal
|
74
|
-
# with Ruby's "I used to be a Hash until someone mapped me" values like
|
75
|
-
# `[[:class, 'address']]`. I'm not sure if this is the best approach, but
|
76
|
-
# I'm going to try it for now and see how it pans out in actual usage.
|
77
|
-
#
|
78
|
-
# @todo
|
79
|
-
# It might be nice to have a `check` option that ensures the resulting
|
80
|
-
# hash has a value for `key`.
|
81
|
-
#
|
82
|
-
# @param [Object] value
|
83
|
-
# The value that we want to be a hash.
|
84
|
-
#
|
85
|
-
# @param [Object] key [default nil]
|
86
|
-
# The key that `value` will be stored under in the result if `value` is
|
87
|
-
# not a hash or can't be turned into one via `#to_h`. If this happens
|
88
|
-
# this value can **NOT** be `nil` or an `ArgumentError` is raised.
|
89
|
-
#
|
90
|
-
# @return [Hash]
|
91
|
-
#
|
92
|
-
# @raise [ArgumentError]
|
93
|
-
# If it comes to constructing a new Hash with `value` as a value and no
|
94
|
-
# argument was provided
|
95
|
-
#
|
96
|
-
def self.as_hash value, key = nil
|
97
|
-
return value if value.is_a? Hash
|
98
|
-
return {} if value.nil?
|
99
|
-
|
100
|
-
if value.respond_to? :to_h
|
101
|
-
begin
|
102
|
-
return value.to_h
|
103
|
-
rescue
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# at this point we need a key argument
|
108
|
-
if key.nil?
|
109
|
-
raise ArgumentError,
|
110
|
-
"Need key to construct hash with value #{ value.inspect }, " +
|
111
|
-
"found nil."
|
112
|
-
end
|
113
|
-
|
114
|
-
{key => value}
|
115
|
-
end # .as_hash
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
# Lifted from ActiveSupport
|
120
|
-
# =====================================================================
|
121
|
-
#
|
122
|
-
# Not sure *why* I didn't want to depend on ActiveSupport in the first place,
|
123
|
-
# but I'm guessing it's many other things depending on it and the potential
|
124
|
-
# for dependency hell, but anyways, I didn't, and I'm going to keep it that
|
125
|
-
# way for the moment.
|
126
|
-
#
|
127
|
-
# However, I do want some of that functionality, and I think it makes sense
|
128
|
-
# to keep the names and behaviors the same since ActiveSupport is so wide
|
129
|
-
# spread.
|
130
|
-
#
|
131
|
-
# The methods are modified to operate functionally since we use refinements
|
132
|
-
# instead of global monkey-patching, and Ruby versions before 2.1 (I think)
|
133
|
-
# don't support refinements, so these are useful in environments where you
|
134
|
-
# don't want to mess with the global built-ins and you don't have
|
135
|
-
# refinements available.
|
136
|
-
#
|
137
|
-
|
138
|
-
# Removes the given keys from hash and returns it.
|
139
|
-
#
|
140
|
-
# Lifted from ActiveSupport.
|
141
|
-
#
|
142
|
-
# @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:except!
|
143
|
-
#
|
144
|
-
# @param [Hash] hash
|
145
|
-
# Hash to mutate.
|
146
|
-
#
|
147
|
-
# @return [Hash]
|
148
|
-
#
|
149
|
-
def self.except_keys! hash, *keys
|
150
|
-
keys.each { |key| hash.delete(key) }
|
151
|
-
hash
|
152
|
-
end
|
153
|
-
|
154
|
-
singleton_class.send :alias_method, :omit_keys!, :except_keys!
|
155
|
-
|
156
|
-
|
157
|
-
# Returns a new hash without `keys`.
|
158
|
-
#
|
159
|
-
# Lifted from ActiveSupport.
|
160
|
-
#
|
161
|
-
# @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:except
|
162
|
-
#
|
163
|
-
# @param [Hash] hash
|
164
|
-
# Source hash.
|
165
|
-
#
|
166
|
-
# @return [Hash]
|
167
|
-
#
|
168
|
-
def self.except_keys hash, *keys
|
169
|
-
except_keys! hash.dup, *keys
|
170
|
-
end
|
171
|
-
|
172
|
-
singleton_class.send :alias_method, :omit_keys, :except_keys
|
173
|
-
|
174
|
-
|
175
|
-
# Lifted from ActiveSupport.
|
176
|
-
#
|
177
|
-
# @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:transform_keys!
|
178
|
-
#
|
179
|
-
# @param [Hash] hash
|
180
|
-
# Hash to mutate keys.
|
181
|
-
#
|
182
|
-
# @return [Hash]
|
183
|
-
# The mutated hash.
|
184
|
-
#
|
185
|
-
def self.transform_keys! hash
|
186
|
-
# File 'lib/active_support/core_ext/hash/keys.rb', line 23
|
187
|
-
hash.keys.each do |key|
|
188
|
-
hash[yield(key)] = hash.delete(key)
|
189
|
-
end
|
190
|
-
hash
|
191
|
-
end
|
192
|
-
|
193
|
-
|
194
|
-
# Returns a new hash with each key transformed by the provided block.
|
195
|
-
#
|
196
|
-
# Lifted from ActiveSupport.
|
197
|
-
#
|
198
|
-
# @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:transform_keys
|
199
|
-
#
|
200
|
-
# @param [Hash] hash
|
201
|
-
#
|
202
|
-
# @return [Hash]
|
203
|
-
# New hash with transformed keys.
|
204
|
-
#
|
205
|
-
def self.transform_keys hash, &block
|
206
|
-
# File 'lib/active_support/core_ext/hash/keys.rb', line 12
|
207
|
-
result = {}
|
208
|
-
hash.each_key do |key|
|
209
|
-
result[yield(key)] = hash[key]
|
210
|
-
end
|
211
|
-
result
|
212
|
-
end
|
213
|
-
|
214
|
-
# My-style name
|
215
|
-
singleton_class.send :alias_method, :map_keys, :transform_keys
|
216
|
-
|
217
|
-
|
218
|
-
# Mutates `hash` by converting all keys that respond to `#to_sym` to symbols.
|
219
|
-
#
|
220
|
-
# Lifted from ActiveSupport.
|
221
|
-
#
|
222
|
-
# @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:symbolize_keys!
|
223
|
-
#
|
224
|
-
# @param [Hash] hash
|
225
|
-
#
|
226
|
-
# @return [Hash]
|
227
|
-
#
|
228
|
-
def self.symbolize_keys! hash
|
229
|
-
transform_keys!(hash) { |key| key.to_sym rescue key }
|
230
|
-
end # .symbolize_keys!
|
231
|
-
|
232
|
-
|
233
|
-
# Returns a new hash with all keys that respond to `#to_sym` converted to
|
234
|
-
# symbols.
|
235
|
-
#
|
236
|
-
# Lifted from ActiveSupport.
|
237
|
-
#
|
238
|
-
# @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:symbolize_keys
|
239
|
-
#
|
240
|
-
# @param [Hash] hash
|
241
|
-
#
|
242
|
-
# @return [Hash]
|
243
|
-
#
|
244
|
-
def self.symbolize_keys hash
|
245
|
-
# File 'lib/active_support/core_ext/hash/keys.rb', line 54
|
246
|
-
transform_keys(hash) { |key| key.to_sym rescue key }
|
247
|
-
end
|
248
|
-
|
249
|
-
|
250
|
-
# Converts all keys into strings by calling `#to_s` on them. **Mutates the
|
251
|
-
# hash.**
|
252
|
-
#
|
253
|
-
# Lifted from ActiveSupport.
|
254
|
-
#
|
255
|
-
# @param [Hash] hash
|
256
|
-
#
|
257
|
-
# @return [Hash<String, *>]
|
258
|
-
#
|
259
|
-
def self.stringify_keys! hash
|
260
|
-
transform_keys! hash, &:to_s
|
261
|
-
end
|
262
|
-
|
263
|
-
|
264
|
-
# Returns a new hash with all keys transformed to strings by calling `#to_s`
|
265
|
-
# on them.
|
266
|
-
#
|
267
|
-
# Lifted from ActiveSupport.
|
268
|
-
#
|
269
|
-
# @param [Hash] hash
|
270
|
-
#
|
271
|
-
# @return [Hash<String, *>]
|
272
|
-
#
|
273
|
-
def self.stringify_keys hash
|
274
|
-
transform_keys hash, &:to_s
|
275
|
-
end
|
276
|
-
|
277
|
-
|
278
|
-
# Lifted from ActiveSupport.
|
279
|
-
#
|
280
|
-
# @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:slice
|
281
|
-
#
|
282
|
-
#
|
283
|
-
def self.slice_keys hash, *keys
|
284
|
-
# We're not using this, but, whatever, leave it in...
|
285
|
-
if hash.respond_to?(:convert_key, true)
|
286
|
-
keys.map! { |key| hash.send :convert_key, key }
|
287
|
-
end
|
288
|
-
|
289
|
-
keys.each_with_object(hash.class.new) { |k, new_hash|
|
290
|
-
new_hash[k] = hash[k] if hash.has_key?(k)
|
291
|
-
}
|
292
|
-
end
|
293
|
-
|
294
|
-
|
295
|
-
# Eigenclass (Singleton Class)
|
296
|
-
# ========================================================================
|
297
|
-
#
|
298
|
-
class << self
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
# @todo Document select_map method.
|
303
|
-
#
|
304
|
-
# @param [type] arg_name
|
305
|
-
# @todo Add name param description.
|
306
|
-
#
|
307
|
-
# @return [return_type]
|
308
|
-
# @todo Document return value.
|
309
|
-
#
|
310
|
-
def select_map arg_name
|
311
|
-
# method body...
|
312
|
-
end # #select_map
|
313
|
-
|
314
|
-
|
315
|
-
# Guess which type of "name" key - strings or symbols - a hash (or other
|
316
|
-
# object that responds to `#keys` and `#empty`) uses.
|
317
|
-
#
|
318
|
-
# @param [#keys & #empty] keyed
|
319
|
-
# Hash or similar object that responds to `#keys` and `#empty` to guess
|
320
|
-
# about.
|
321
|
-
#
|
322
|
-
# @return [nil]
|
323
|
-
# If we can't determine the type of name keys used.
|
324
|
-
#
|
325
|
-
# @return [Class]
|
326
|
-
# If we can determine that {String} or {Symbol} keys are exclusively
|
327
|
-
# used returns that class.
|
328
|
-
#
|
329
|
-
def guess_name_type keyed
|
330
|
-
# We can't tell shit if the hash is empty
|
331
|
-
return nil if keyed.empty?
|
332
|
-
|
333
|
-
name_types = keyed.
|
334
|
-
keys.
|
335
|
-
map( &:class ).
|
336
|
-
select { |klass| klass == String || klass == Symbol }.
|
337
|
-
uniq
|
338
|
-
|
339
|
-
return name_types[0] if name_types.length == 1
|
340
|
-
|
341
|
-
# There are both string and symbol keys present, we can't guess
|
342
|
-
nil
|
343
|
-
end # #guess_key_type
|
344
|
-
|
345
|
-
|
346
|
-
# @todo Document bury method.
|
347
|
-
#
|
348
|
-
# @param [Hash] hash
|
349
|
-
# Hash to bury the value in.
|
350
|
-
#
|
351
|
-
# @param [Array | #to_s] key_path
|
352
|
-
# - When an {Array}, each entry is used exactly as-is for each key.
|
353
|
-
#
|
354
|
-
# - Otherwise, the `key_path` is converted to a string and split by
|
355
|
-
# `.` to produce the key array, and the actual keys used depend on
|
356
|
-
# the `parsed_key_type` option.
|
357
|
-
#
|
358
|
-
# @param [Object] value
|
359
|
-
# The value to set at the end of the path.
|
360
|
-
#
|
361
|
-
# @param [Class | :guess] parsed_key_type:
|
362
|
-
# How to handle parsed key path segments:
|
363
|
-
#
|
364
|
-
# - `String` - use the strings that naturally split from a parsed
|
365
|
-
# key path.
|
366
|
-
#
|
367
|
-
# Note that this is the *String class itself, **not** a value that
|
368
|
-
# is a String*.
|
369
|
-
#
|
370
|
-
# - `Symbol` - convert the strings that are split from the key path
|
371
|
-
# to symbols.
|
372
|
-
#
|
373
|
-
# Note that this is the *Symbol class itself, **not** a value that
|
374
|
-
# is a Symbol*.``
|
375
|
-
#
|
376
|
-
# - `:guess` (default) -
|
377
|
-
#
|
378
|
-
# @return [return_type]
|
379
|
-
# @todo Document return value.
|
380
|
-
#
|
381
|
-
def bury! hash,
|
382
|
-
key_path,
|
383
|
-
value,
|
384
|
-
parsed_key_type: :guess,
|
385
|
-
clobber: false
|
386
|
-
|
387
|
-
# Parse the key if it's not an array
|
388
|
-
unless key_path.is_a?( Array )
|
389
|
-
key_path = key_path.to_s.split '.'
|
390
|
-
|
391
|
-
# Convert the keys to symbols now if that's what we want to use
|
392
|
-
if parsed_key_type == Symbol
|
393
|
-
key_path.map! &:to_sym
|
394
|
-
end
|
395
|
-
end
|
396
|
-
|
397
|
-
_internal_bury! \
|
398
|
-
hash,
|
399
|
-
key_path,
|
400
|
-
value,
|
401
|
-
guess_key_type: ( parsed_key_type == :guess ),
|
402
|
-
clobber: clobber
|
403
|
-
end # #bury
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
private
|
408
|
-
# ========================================================================
|
409
|
-
|
410
|
-
|
411
|
-
# @todo Document _internal_bury! method.
|
412
|
-
#
|
413
|
-
# @param [type] arg_name
|
414
|
-
# @todo Add name param description.
|
415
|
-
#
|
416
|
-
# @return [return_type]
|
417
|
-
# @todo Document return value.
|
418
|
-
#
|
419
|
-
def _internal_bury! hash,
|
420
|
-
key_path,
|
421
|
-
value,
|
422
|
-
guess_key_type:,
|
423
|
-
clobber:
|
424
|
-
|
425
|
-
# Split the key path into the current key and the rest of the keys
|
426
|
-
key, *rest = key_path
|
427
|
-
|
428
|
-
# If we are guessing the key type and the hash uses some {Symbol}
|
429
|
-
# (and no {String}) keys then convert the key to a symbol.
|
430
|
-
if guess_key_type && guess_name_type( hash ) == Symbol
|
431
|
-
key = key.to_sym
|
432
|
-
end
|
433
|
-
|
434
|
-
# Terminating case: we're at the last segment
|
435
|
-
if rest.empty?
|
436
|
-
# Set the value
|
437
|
-
hash[key] = value
|
438
|
-
|
439
|
-
else
|
440
|
-
# Go deeper...
|
441
|
-
|
442
|
-
# See if there is a hash in place
|
443
|
-
unless hash[key].is_a?( Hash )
|
444
|
-
# There is not... so we need to do some figurin'
|
445
|
-
|
446
|
-
# If we're clobbering or the hash has no value, we're good:
|
447
|
-
# assign a new hash to set in
|
448
|
-
if clobber || ! hash.key?( key )
|
449
|
-
hash[key] = {}
|
450
|
-
|
451
|
-
else
|
452
|
-
# We've got an intractable state conflict; raise
|
453
|
-
raise NRSER::ConflictError.new squish <<-END
|
454
|
-
can not set key #{ key.inspect } due to conflicting value
|
455
|
-
#{ hash[key].inspect } in hash #{ hash.inspect } (:clobber
|
456
|
-
option not set)
|
457
|
-
END
|
458
|
-
|
459
|
-
end
|
460
|
-
end # unless hash[key].is_a?( Hash )
|
461
|
-
|
462
|
-
# Dive in...
|
463
|
-
bury! hash[key], rest, value
|
464
|
-
|
465
|
-
end # if rest.empty? / else
|
466
|
-
end # #_internal_bury!
|
467
|
-
|
468
|
-
|
469
|
-
# end private
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
end # class << self (Eigenclass)
|
474
|
-
|
475
|
-
|
476
|
-
end # module NRSER
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Project / Package
|
5
|
+
# -----------------------------------------------------------------------
|
6
|
+
require_relative './hash/except_keys'
|
7
|
+
require_relative './hash/transform_keys'
|
8
|
+
require_relative './hash/symbolize_keys'
|
9
|
+
require_relative './hash/stringify_keys'
|
10
|
+
require_relative './hash/slice_keys'
|
11
|
+
require_relative './hash/guess_label_key_type'
|
12
|
+
require_relative './hash/bury'
|
13
|
+
require_relative './hash/deep_merge'
|