nrser 0.0.30 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nrser.rb +56 -12
- data/lib/nrser/collection.rb +4 -7
- data/lib/nrser/ext.rb +5 -0
- data/lib/nrser/{refinements → ext}/enumerable.rb +11 -9
- data/lib/nrser/ext/pathname.rb +74 -0
- data/lib/nrser/{refinements → ext}/tree.rb +2 -26
- data/lib/nrser/functions.rb +18 -0
- data/lib/nrser/{array.rb → functions/array.rb} +2 -3
- data/lib/nrser/{binding.rb → functions/binding.rb} +0 -2
- data/lib/nrser/functions/enumerable.rb +355 -0
- data/lib/nrser/functions/enumerable/find_all_map.rb +33 -0
- data/lib/nrser/functions/enumerable/find_map.rb +53 -0
- data/lib/nrser/functions/exception.rb +17 -0
- data/lib/nrser/{hash.rb → functions/hash.rb} +0 -0
- data/lib/nrser/functions/hash/bury.rb +147 -0
- data/lib/nrser/{hash → functions/hash}/deep_merge.rb +5 -5
- data/lib/nrser/{hash → functions/hash}/except_keys.rb +2 -0
- data/lib/nrser/{hash → functions/hash}/guess_label_key_type.rb +3 -1
- data/lib/nrser/{hash → functions/hash}/slice_keys.rb +3 -1
- data/lib/nrser/{hash → functions/hash}/stringify_keys.rb +2 -0
- data/lib/nrser/{hash → functions/hash}/symbolize_keys.rb +3 -1
- data/lib/nrser/{hash → functions/hash}/transform_keys.rb +3 -1
- data/lib/nrser/functions/merge_by.rb +29 -0
- data/lib/nrser/{object.rb → functions/object.rb} +0 -0
- data/lib/nrser/{object → functions/object}/as_array.rb +2 -0
- data/lib/nrser/{object → functions/object}/as_hash.rb +7 -5
- data/lib/nrser/{object → functions/object}/truthy.rb +46 -7
- data/lib/nrser/{open_struct.rb → functions/open_struct.rb} +0 -0
- data/lib/nrser/functions/path.rb +150 -0
- data/lib/nrser/{proc.rb → functions/proc.rb} +1 -22
- data/lib/nrser/functions/string.rb +297 -0
- data/lib/nrser/functions/string/looks_like.rb +44 -0
- data/lib/nrser/{text.rb → functions/text.rb} +0 -0
- data/lib/nrser/{text → functions/text}/indentation.rb +2 -16
- data/lib/nrser/{text → functions/text}/lines.rb +1 -2
- data/lib/nrser/{text → functions/text}/word_wrap.rb +2 -4
- data/lib/nrser/{tree.rb → functions/tree.rb} +0 -0
- data/lib/nrser/{tree → functions/tree}/each_branch.rb +6 -7
- data/lib/nrser/functions/tree/leaves.rb +92 -0
- data/lib/nrser/{tree → functions/tree}/map_branches.rb +31 -32
- data/lib/nrser/functions/tree/map_leaves.rb +56 -0
- data/lib/nrser/{tree → functions/tree}/map_tree.rb +9 -20
- data/lib/nrser/{tree → functions/tree}/transform.rb +0 -10
- data/lib/nrser/logger.rb +9 -10
- data/lib/nrser/message.rb +3 -7
- data/lib/nrser/meta.rb +2 -0
- data/lib/nrser/meta/class_attrs.rb +3 -9
- data/lib/nrser/meta/props.rb +19 -19
- data/lib/nrser/meta/props/base.rb +4 -10
- data/lib/nrser/meta/props/prop.rb +12 -28
- data/lib/nrser/no_arg.rb +1 -3
- data/lib/nrser/refinements.rb +5 -0
- data/lib/nrser/refinements/array.rb +5 -17
- data/lib/nrser/refinements/enumerator.rb +1 -3
- data/lib/nrser/refinements/hash.rb +3 -15
- data/lib/nrser/refinements/object.rb +2 -2
- data/lib/nrser/refinements/open_struct.rb +0 -2
- data/lib/nrser/refinements/pathname.rb +3 -46
- data/lib/nrser/refinements/set.rb +2 -6
- data/lib/nrser/refinements/string.rb +2 -2
- data/lib/nrser/rspex.rb +16 -13
- data/lib/nrser/types.rb +6 -20
- data/lib/nrser/types/any.rb +0 -1
- data/lib/nrser/types/booleans.rb +1 -1
- data/lib/nrser/types/combinators.rb +5 -5
- data/lib/nrser/types/in.rb +0 -21
- data/lib/nrser/types/responds.rb +1 -0
- data/lib/nrser/types/trees.rb +1 -0
- data/lib/nrser/version.rb +2 -3
- data/spec/nrser/{template_spec.rb → functions/binding/template_spec.rb} +0 -0
- data/spec/nrser/functions/enumerable/find_all_map_spec.rb +28 -0
- data/spec/nrser/functions/enumerable/find_bounded_spec.rb +70 -0
- data/spec/nrser/functions/enumerable/find_map_spec.rb +38 -0
- data/spec/nrser/functions/enumerable/find_only_spec.rb +25 -0
- data/spec/nrser/functions/enumerable/to_h_by_spec.rb +28 -0
- data/spec/nrser/{format_exception_spec.rb → functions/exception/format_exception_spec.rb} +0 -0
- data/spec/nrser/{hash → functions/hash}/bury_spec.rb +0 -0
- data/spec/nrser/{hash → functions/hash}/guess_label_key_type_spec.rb +0 -0
- data/spec/nrser/{hash_spec.rb → functions/hash_spec.rb} +0 -7
- data/spec/nrser/{merge_by_spec.rb → functions/merge_by_spec.rb} +0 -0
- data/spec/nrser/{truthy_spec.rb → functions/object/truthy_spec.rb} +0 -0
- data/spec/nrser/{open_struct_spec.rb → functions/open_struct_spec.rb} +0 -0
- data/spec/nrser/{string → functions/string}/common_prefix_spec.rb +0 -0
- data/spec/nrser/{string → functions/string}/looks_like_spec.rb +0 -0
- data/spec/nrser/{truncate_spec.rb → functions/string/truncate_spec.rb} +0 -0
- data/spec/nrser/{text → functions/text}/dedent/gotchas_spec.rb +0 -0
- data/spec/nrser/{text → functions/text}/dedent_spec.rb +0 -0
- data/spec/nrser/{indent_spec.rb → functions/text/indent_spec.rb} +0 -0
- data/spec/nrser/{tree → functions/tree}/each_branch_spec.rb +0 -0
- data/spec/nrser/{tree → functions/tree}/leaves_spec.rb +0 -0
- data/spec/nrser/{tree → functions/tree}/map_branch_spec.rb +0 -0
- data/spec/nrser/{tree → functions/tree}/map_tree_spec.rb +0 -0
- data/spec/nrser/{tree → functions/tree}/transform_spec.rb +0 -0
- data/spec/nrser/{tree → functions/tree}/transformer_spec.rb +0 -0
- data/spec/nrser/meta/class_attrs_spec.rb +12 -14
- data/spec/spec_helper.rb +2 -3
- metadata +136 -110
- data/lib/nrser/enumerable.rb +0 -288
- data/lib/nrser/exception.rb +0 -7
- data/lib/nrser/hash/bury.rb +0 -154
- data/lib/nrser/merge_by.rb +0 -26
- data/lib/nrser/string.rb +0 -294
- data/lib/nrser/string/looks_like.rb +0 -51
- data/lib/nrser/tree/leaves.rb +0 -92
- data/lib/nrser/tree/map_leaves.rb +0 -63
- data/spec/nrser/enumerable_spec.rb +0 -111
data/lib/nrser/merge_by.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module NRSER
|
4
|
-
|
5
|
-
# Eigenclass (Singleton Class)
|
6
|
-
# ========================================================================
|
7
|
-
#
|
8
|
-
class << self
|
9
|
-
|
10
|
-
# @todo Document merge_by method.
|
11
|
-
#
|
12
|
-
# @param [type] arg_name
|
13
|
-
# @todo Add name param description.
|
14
|
-
#
|
15
|
-
# @return [return_type]
|
16
|
-
# @todo Document return value.
|
17
|
-
#
|
18
|
-
def merge_by current, *updates, &getter
|
19
|
-
updates.reduce( to_h_by current, &getter ) { |result, update|
|
20
|
-
deep_merge! result, to_h_by(update, &getter)
|
21
|
-
}.values
|
22
|
-
end # #merge_by
|
23
|
-
|
24
|
-
end # class << self (Eigenclass)
|
25
|
-
|
26
|
-
end # module NRSER
|
data/lib/nrser/string.rb
DELETED
@@ -1,294 +0,0 @@
|
|
1
|
-
require_relative './string/looks_like'
|
2
|
-
|
3
|
-
module NRSER
|
4
|
-
# @!group String Functions
|
5
|
-
|
6
|
-
WHITESPACE_RE = /\A[[:space:]]*\z/
|
7
|
-
|
8
|
-
UNICODE_ELLIPSIS = '…'
|
9
|
-
|
10
|
-
|
11
|
-
def self.whitespace? string
|
12
|
-
string =~ WHITESPACE_RE
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
class << self
|
17
|
-
|
18
|
-
# Functions the operate on strings.
|
19
|
-
|
20
|
-
# turn a multi-line string into a single line, collapsing whitespace
|
21
|
-
# to a single space.
|
22
|
-
#
|
23
|
-
# same as ActiveSupport's String.squish, adapted from there.
|
24
|
-
def squish str
|
25
|
-
str.gsub(/[[:space:]]+/, ' ').strip
|
26
|
-
end # squish
|
27
|
-
|
28
|
-
alias_method :unblock, :squish
|
29
|
-
|
30
|
-
|
31
|
-
def common_prefix strings
|
32
|
-
raise ArgumentError.new("argument can't be empty") if strings.empty?
|
33
|
-
|
34
|
-
sorted = strings.sort
|
35
|
-
|
36
|
-
i = 0
|
37
|
-
|
38
|
-
while sorted.first[i] == sorted.last[i] &&
|
39
|
-
i < [sorted.first.length, sorted.last.length].min
|
40
|
-
i = i + 1
|
41
|
-
end
|
42
|
-
|
43
|
-
sorted.first[0...i]
|
44
|
-
end # common_prefix
|
45
|
-
|
46
|
-
|
47
|
-
def filter_repeated_blank_lines str, remove_leading: false
|
48
|
-
out = []
|
49
|
-
lines = str.lines
|
50
|
-
skipping = remove_leading
|
51
|
-
str.lines.each do |line|
|
52
|
-
if line =~ /^\s*$/
|
53
|
-
unless skipping
|
54
|
-
out << line
|
55
|
-
end
|
56
|
-
skipping = true
|
57
|
-
else
|
58
|
-
skipping = false
|
59
|
-
out << line
|
60
|
-
end
|
61
|
-
end
|
62
|
-
out.join
|
63
|
-
end # filter_repeated_blank_lines
|
64
|
-
|
65
|
-
|
66
|
-
def lazy_filter_repeated_blank_lines source, remove_leading: false
|
67
|
-
skipping = remove_leading
|
68
|
-
|
69
|
-
source = source.each_line if source.is_a? String
|
70
|
-
|
71
|
-
Enumerator::Lazy.new source do |yielder, line|
|
72
|
-
if line =~ /^\s*$/
|
73
|
-
unless skipping
|
74
|
-
yielder << line
|
75
|
-
end
|
76
|
-
skipping = true
|
77
|
-
else
|
78
|
-
skipping = false
|
79
|
-
yielder << line
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
end # filter_repeated_blank_lines
|
84
|
-
|
85
|
-
|
86
|
-
# Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
|
87
|
-
#
|
88
|
-
# 'Once upon a time in a world far far away'.truncate(27)
|
89
|
-
# # => "Once upon a time in a wo..."
|
90
|
-
#
|
91
|
-
# Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break:
|
92
|
-
#
|
93
|
-
# 'Once upon a time in a world far far away'.truncate(27, separator: ' ')
|
94
|
-
# # => "Once upon a time in a..."
|
95
|
-
#
|
96
|
-
# 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
|
97
|
-
# # => "Once upon a time in a..."
|
98
|
-
#
|
99
|
-
# The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
|
100
|
-
# for a total length not exceeding <tt>length</tt>:
|
101
|
-
#
|
102
|
-
# 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
|
103
|
-
# # => "And they f... (continued)"
|
104
|
-
#
|
105
|
-
# adapted from
|
106
|
-
#
|
107
|
-
# <https://github.com/rails/rails/blob/7847a19f476fb9bee287681586d872ea43785e53/activesupport/lib/active_support/core_ext/string/filters.rb#L46>
|
108
|
-
#
|
109
|
-
def truncate(str, truncate_at, options = {})
|
110
|
-
return str.dup unless str.length > truncate_at
|
111
|
-
|
112
|
-
omission = options[:omission] || '...'
|
113
|
-
length_with_room_for_omission = truncate_at - omission.length
|
114
|
-
stop = \
|
115
|
-
if options[:separator]
|
116
|
-
str.rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
|
117
|
-
else
|
118
|
-
length_with_room_for_omission
|
119
|
-
end
|
120
|
-
|
121
|
-
"#{str[0, stop]}#{omission}"
|
122
|
-
end
|
123
|
-
|
124
|
-
|
125
|
-
# Cut the middle out of a string and stick an ellipsis in there instead.
|
126
|
-
#
|
127
|
-
# @param [String] string
|
128
|
-
# Source string.
|
129
|
-
#
|
130
|
-
# @param [Fixnum] max
|
131
|
-
# Max length to allow for the output string.
|
132
|
-
#
|
133
|
-
# @param [String] omission:
|
134
|
-
# The string to stick in the middle where original contents were
|
135
|
-
# removed. Defaults to the unicode ellipsis since I'm targeting the CLI
|
136
|
-
# at the moment and it saves precious characters.
|
137
|
-
#
|
138
|
-
# @return [String]
|
139
|
-
# String of at most `max` length with the middle chopped out if needed
|
140
|
-
# to do so.
|
141
|
-
def ellipsis string, max, omission: UNICODE_ELLIPSIS
|
142
|
-
return string unless string.length > max
|
143
|
-
|
144
|
-
trim_to = max - omission.length
|
145
|
-
|
146
|
-
start = string[0, (trim_to / 2) + (trim_to % 2)]
|
147
|
-
finish = string[-( (trim_to / 2) - (trim_to % 2) )..-1]
|
148
|
-
|
149
|
-
start + omission + finish
|
150
|
-
end
|
151
|
-
|
152
|
-
|
153
|
-
# **EXPERIMENTAL!**
|
154
|
-
#
|
155
|
-
# Try to do "smart" job adding ellipsis to the middle of strings by
|
156
|
-
# splitting them by a separator `split` - that defaults to `, ` - then
|
157
|
-
# building the result up by bouncing back and forth between tokens at the
|
158
|
-
# beginning and end of the string until we reach the `max` length limit.
|
159
|
-
#
|
160
|
-
# Intended to be used with possibly long single-line strings like
|
161
|
-
# `#inspect` returns for complex objects, where tokens are commonly
|
162
|
-
# separated by `, `, and producing a reasonably nice result that will fit
|
163
|
-
# in a reasonable amount of space, like `rspec` output (which was the
|
164
|
-
# motivation).
|
165
|
-
#
|
166
|
-
# If `string` is already less than `max` then it is just returned.
|
167
|
-
#
|
168
|
-
# If `string` doesn't contain `split` or just the first and last tokens
|
169
|
-
# alone would push the result over `max` then falls back to
|
170
|
-
# {NRSER.ellipsis}.
|
171
|
-
#
|
172
|
-
# If `max` is too small it's going to fall back nearly always... around
|
173
|
-
# `64` has seemed like a decent place to start from screwing around on
|
174
|
-
# the REPL a bit.
|
175
|
-
#
|
176
|
-
# @param [String] string
|
177
|
-
# Source string.
|
178
|
-
#
|
179
|
-
# @param [Fixnum] max
|
180
|
-
# Max length to allow for the output string. Result will usually be
|
181
|
-
# *less* than this unless the fallback to {NRSER.ellipsis} kicks in.
|
182
|
-
#
|
183
|
-
# @param [String] omission:
|
184
|
-
# The string to stick in the middle where original contents were
|
185
|
-
# removed. Defaults to the unicode ellipsis since I'm targeting the CLI
|
186
|
-
# at the moment and it saves precious characters.
|
187
|
-
#
|
188
|
-
# @param [String] split:
|
189
|
-
# The string to tokenize the `string` parameter by. If you pass a
|
190
|
-
# {Regexp} here it might work, it might loop out, maybe.
|
191
|
-
#
|
192
|
-
# @return [String]
|
193
|
-
# String of at most `max` length with the middle chopped out if needed
|
194
|
-
# to do so.
|
195
|
-
#
|
196
|
-
def smart_ellipsis string, max, omission: UNICODE_ELLIPSIS, split: ', '
|
197
|
-
return string unless string.length > max
|
198
|
-
|
199
|
-
unless string.include? split
|
200
|
-
return ellipsis string, max, omission: omission
|
201
|
-
end
|
202
|
-
|
203
|
-
tokens = string.split split
|
204
|
-
|
205
|
-
char_budget = max - omission.length
|
206
|
-
start = tokens[0] + split
|
207
|
-
finish = tokens[tokens.length - 1]
|
208
|
-
|
209
|
-
if start.length + finish.length > char_budget
|
210
|
-
return ellipsis string, max, omission: omission
|
211
|
-
end
|
212
|
-
|
213
|
-
next_start_index = 1
|
214
|
-
next_finish_index = tokens.length - 2
|
215
|
-
next_index_is = :start
|
216
|
-
next_index = next_start_index
|
217
|
-
|
218
|
-
while (
|
219
|
-
start.length +
|
220
|
-
finish.length +
|
221
|
-
tokens[next_index].length +
|
222
|
-
split.length
|
223
|
-
) <= char_budget do
|
224
|
-
if next_index_is == :start
|
225
|
-
start += tokens[next_index] + split
|
226
|
-
next_start_index += 1
|
227
|
-
next_index = next_finish_index
|
228
|
-
next_index_is = :finish
|
229
|
-
else # == :finish
|
230
|
-
finish = tokens[next_index] + split + finish
|
231
|
-
next_finish_index -= 1
|
232
|
-
next_index = next_start_index
|
233
|
-
next_index_is = :start
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
start + omission + finish
|
238
|
-
|
239
|
-
end # #method_name
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
# Get the constant identified by a string.
|
244
|
-
#
|
245
|
-
# @example
|
246
|
-
#
|
247
|
-
# SomeClass == NRSER.constantize(SomeClass.name)
|
248
|
-
#
|
249
|
-
# Lifted from ActiveSupport.
|
250
|
-
#
|
251
|
-
# @param [String] camel_cased_word
|
252
|
-
# The constant's camel-cased, double-colon-separated "name",
|
253
|
-
# like "NRSER::Types::Array".
|
254
|
-
#
|
255
|
-
# @return [Object]
|
256
|
-
#
|
257
|
-
# @raise [NameError]
|
258
|
-
# When the name is not in CamelCase or is not initialized.
|
259
|
-
#
|
260
|
-
def constantize(camel_cased_word)
|
261
|
-
names = camel_cased_word.split('::')
|
262
|
-
|
263
|
-
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
264
|
-
Object.const_get(camel_cased_word) if names.empty?
|
265
|
-
|
266
|
-
# Remove the first blank element in case of '::ClassName' notation.
|
267
|
-
names.shift if names.size > 1 && names.first.empty?
|
268
|
-
|
269
|
-
names.inject(Object) do |constant, name|
|
270
|
-
if constant == Object
|
271
|
-
constant.const_get(name)
|
272
|
-
else
|
273
|
-
candidate = constant.const_get(name)
|
274
|
-
next candidate if constant.const_defined?(name, false)
|
275
|
-
next candidate unless Object.const_defined?(name)
|
276
|
-
|
277
|
-
# Go down the ancestors to check if it is owned directly. The check
|
278
|
-
# stops when we reach Object or the end of ancestors tree.
|
279
|
-
constant = constant.ancestors.inject do |const, ancestor|
|
280
|
-
break const if ancestor == Object
|
281
|
-
break ancestor if ancestor.const_defined?(name, false)
|
282
|
-
const
|
283
|
-
end
|
284
|
-
|
285
|
-
# owner is in Object, so raise
|
286
|
-
constant.const_get(name, false)
|
287
|
-
end
|
288
|
-
end
|
289
|
-
end # constantize
|
290
|
-
|
291
|
-
alias_method :to_const, :constantize
|
292
|
-
|
293
|
-
end # class << self
|
294
|
-
end # module NRSER
|
@@ -1,51 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# Functional methods that try to tell what format a string that
|
3
|
-
# is presumed to encode structural data is encoded in.
|
4
|
-
##
|
5
|
-
|
6
|
-
# Requirements
|
7
|
-
# =======================================================================
|
8
|
-
|
9
|
-
# Stdlib
|
10
|
-
# -----------------------------------------------------------------------
|
11
|
-
|
12
|
-
# Deps
|
13
|
-
# -----------------------------------------------------------------------
|
14
|
-
|
15
|
-
# Project / Package
|
16
|
-
# -----------------------------------------------------------------------
|
17
|
-
|
18
|
-
|
19
|
-
# Definitions
|
20
|
-
# =======================================================================
|
21
|
-
|
22
|
-
module NRSER
|
23
|
-
|
24
|
-
# Constants
|
25
|
-
# =====================================================================
|
26
|
-
|
27
|
-
JSON_ARRAY_RE = /\A\s*\[.*\]\s*\z/m
|
28
|
-
|
29
|
-
# Eigenclass (Singleton Class)
|
30
|
-
# ========================================================================
|
31
|
-
#
|
32
|
-
class << self
|
33
|
-
|
34
|
-
# Test if a string looks like it might encode an array in JSON format by
|
35
|
-
# seeing if it's first non-whitespace character is `[` and last
|
36
|
-
# non-whitespace character is `]`.
|
37
|
-
#
|
38
|
-
# @param [String] string
|
39
|
-
# String to test.
|
40
|
-
#
|
41
|
-
# @return [Boolean]
|
42
|
-
# `true` if we think `string` encodes a JSON array.
|
43
|
-
#
|
44
|
-
def looks_like_json_array? string
|
45
|
-
!!( string =~ JSON_ARRAY_RE )
|
46
|
-
end # #looks_like_json_array
|
47
|
-
|
48
|
-
end # class << self (Eigenclass)
|
49
|
-
|
50
|
-
end # module NRSER
|
51
|
-
|
data/lib/nrser/tree/leaves.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
module NRSER
|
2
|
-
|
3
|
-
# Eigenclass (Singleton Class)
|
4
|
-
# ========================================================================
|
5
|
-
#
|
6
|
-
class << self
|
7
|
-
|
8
|
-
# Create a new hash where all the values are the scalar "leaves" of the
|
9
|
-
# possibly nested `hash` param. Leaves are keyed by "key path" arrays
|
10
|
-
# representing the sequence of keys to dig that leaf out of the has param.
|
11
|
-
#
|
12
|
-
# In abstract, if `h` is the `hash` param and
|
13
|
-
#
|
14
|
-
# l = NRSER.leaves h
|
15
|
-
#
|
16
|
-
# then for each key `k` and corresponding value `v` in `l`
|
17
|
-
#
|
18
|
-
# h.dig( *k ) == v
|
19
|
-
#
|
20
|
-
# @example Simple "flat" hash
|
21
|
-
#
|
22
|
-
# NRSER.leaves( {a: 1, b: 2} )
|
23
|
-
# => {
|
24
|
-
# [:a] => 1,
|
25
|
-
# [:b] => 2,
|
26
|
-
# }
|
27
|
-
#
|
28
|
-
# @example Nested hash
|
29
|
-
#
|
30
|
-
# NRSER.leaves(
|
31
|
-
# 1 => {
|
32
|
-
# name: 'Neil',
|
33
|
-
# fav_color: 'blue',
|
34
|
-
# },
|
35
|
-
# 2 => {
|
36
|
-
# name: 'Mica',
|
37
|
-
# fav_color: 'red',
|
38
|
-
# }
|
39
|
-
# )
|
40
|
-
# # => {
|
41
|
-
# # [1, :name] => 'Neil',
|
42
|
-
# # [1, :fav_color] => 'blue',
|
43
|
-
# # [2, :name] => 'Mica',
|
44
|
-
# # [2, :fav_color] => 'red',
|
45
|
-
# # }
|
46
|
-
#
|
47
|
-
# @param [#each_pair | (#each_index & #each_with_index)] tree
|
48
|
-
#
|
49
|
-
# @return [Hash<Array, Object>]
|
50
|
-
#
|
51
|
-
def leaves tree
|
52
|
-
{}.tap { |results|
|
53
|
-
_internal_leaves tree, path: [], results: results
|
54
|
-
}
|
55
|
-
end # #leaves
|
56
|
-
|
57
|
-
|
58
|
-
private
|
59
|
-
# ========================================================================
|
60
|
-
|
61
|
-
# Internal recursive implementation for {NRSER.leaves}.
|
62
|
-
#
|
63
|
-
# @param [#each_pair | (#each_index & #each_with_index)] tree
|
64
|
-
# Tree to walk.
|
65
|
-
#
|
66
|
-
# @param [Array] path
|
67
|
-
# Key path down to `tree`.
|
68
|
-
#
|
69
|
-
# @param [Hash<Array, Object>] results
|
70
|
-
# New hash to stick results in.
|
71
|
-
#
|
72
|
-
# @return [nil]
|
73
|
-
#
|
74
|
-
def _internal_leaves tree, path:, results:
|
75
|
-
NRSER.each_branch( tree ) { |key, value|
|
76
|
-
new_path = [*path, key]
|
77
|
-
|
78
|
-
if NRSER::Types.tree.test value
|
79
|
-
_internal_leaves value, path: new_path, results: results
|
80
|
-
else
|
81
|
-
results[new_path] = value
|
82
|
-
end
|
83
|
-
}
|
84
|
-
|
85
|
-
nil
|
86
|
-
end # #_internal_leaves
|
87
|
-
|
88
|
-
# end private
|
89
|
-
|
90
|
-
end # class << self (Eigenclass)
|
91
|
-
|
92
|
-
end # module NRSER
|