tash 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTING.md +45 -0
- data/LICENSE.txt +21 -0
- data/README.md +112 -0
- data/lib/tash/version.rb +5 -0
- data/lib/tash.rb +1230 -0
- data/sig/tash.rbs +178 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/tash_spec.rb +1148 -0
- metadata +63 -0
data/lib/tash.rb
ADDED
@@ -0,0 +1,1230 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
require_relative 'tash/version'
|
6
|
+
|
7
|
+
# A Tash is a hash with transformed keys.
|
8
|
+
class Tash
|
9
|
+
extend Forwardable
|
10
|
+
include Enumerable
|
11
|
+
|
12
|
+
def self.current_ruby_version
|
13
|
+
@current_ruby_version ||= RUBY_VERSION[/\A(\d+\.\d+)/, 1]
|
14
|
+
end
|
15
|
+
private_class_method :current_ruby_version
|
16
|
+
|
17
|
+
# Returns a new Tash object populated with the given objects, if any. If
|
18
|
+
# a Tash is passed with no block it returns a duplicate with the
|
19
|
+
# transform block from the original. If a Tash is passed with a block it is
|
20
|
+
# treated as a Hash.
|
21
|
+
#
|
22
|
+
# @example Empty
|
23
|
+
# Tash[] # => {}
|
24
|
+
#
|
25
|
+
# @example Given a Tash with no block
|
26
|
+
# t = Tash[FOO: 1, BAR: 2, &:downcase]
|
27
|
+
# t2 = Tash[t]
|
28
|
+
# t2[:BAZ] = 3
|
29
|
+
# t2 # => {:foo=>1, :bar=>2, :baz=>3}
|
30
|
+
#
|
31
|
+
# @example Given a Hash
|
32
|
+
# Tash[FOO: 1, BAR: 2, &:downcase] # => {:foo=>1, :bar=>2}
|
33
|
+
#
|
34
|
+
# @example Given an even number of objects
|
35
|
+
# Tash[:FOO, 1, :BAR, 2, &:downcase] # => {:foo=>1, :bar=>2}
|
36
|
+
#
|
37
|
+
# @param *objects [Array<Objects>] A Tash, Hash, or even number of objects
|
38
|
+
#
|
39
|
+
# @return [Tash]
|
40
|
+
def self.[](*objects, &transform) # rubocop:disable Metrics/PerceivedComplexity
|
41
|
+
if objects.empty?
|
42
|
+
new(&transform)
|
43
|
+
elsif objects.size == 1 && !transform && objects.first.is_a?(self)
|
44
|
+
objects.first.dup
|
45
|
+
elsif objects.size == 1 && objects.first.respond_to?(:to_hash)
|
46
|
+
from_hash(objects.first.to_hash, &transform)
|
47
|
+
elsif objects.size.even?
|
48
|
+
from_array(objects, &transform)
|
49
|
+
else
|
50
|
+
raise ArgumentError, "odd number of arguments for #{name}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.from_hash(hash, &transform)
|
55
|
+
hash.each_with_object(new(&transform)) do |(k, v), tash|
|
56
|
+
tash[k] = v
|
57
|
+
end
|
58
|
+
end
|
59
|
+
private_class_method :from_hash
|
60
|
+
|
61
|
+
def self.from_array(array, &transform)
|
62
|
+
array.each_slice(2).with_object(new(&transform)) do |(k, v), tash|
|
63
|
+
tash[k] = v
|
64
|
+
end
|
65
|
+
end
|
66
|
+
private_class_method :from_array
|
67
|
+
|
68
|
+
# Returns a new empty Tash object.
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# Tash.new { |key| key.to_s.downcase }
|
72
|
+
#
|
73
|
+
# @param transform [Proc] receives a key and transforms it as desired
|
74
|
+
# before using the key
|
75
|
+
#
|
76
|
+
# @return [Tash]
|
77
|
+
def initialize(&transform)
|
78
|
+
@transform = transform
|
79
|
+
@ir = {} # internal representation - @ir[transformed key] = value
|
80
|
+
@default_proc = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def_delegators :@ir,
|
84
|
+
:<,
|
85
|
+
:<=,
|
86
|
+
:>,
|
87
|
+
:>=,
|
88
|
+
:compare_by_identity,
|
89
|
+
:default=,
|
90
|
+
:empty?,
|
91
|
+
:flatten,
|
92
|
+
:hash,
|
93
|
+
:inspect,
|
94
|
+
:key,
|
95
|
+
:keys,
|
96
|
+
:rassoc,
|
97
|
+
:rehash,
|
98
|
+
:shift,
|
99
|
+
:size,
|
100
|
+
:to_a,
|
101
|
+
:value?,
|
102
|
+
:values
|
103
|
+
|
104
|
+
alias has_value? value?
|
105
|
+
alias length size
|
106
|
+
alias to_s inspect
|
107
|
+
|
108
|
+
# @!method < other
|
109
|
+
# Returns `true` if tash is a proper subset of other, `false` otherwise.
|
110
|
+
#
|
111
|
+
# @example
|
112
|
+
# t1 = Tash[foo: 0, bar: 1]
|
113
|
+
# t2 = Tash[foo: 0, bar: 1, baz: 2]
|
114
|
+
# t1 < t2 # => true
|
115
|
+
# t2 < t1 # => false
|
116
|
+
# t1 < t1 # => false
|
117
|
+
#
|
118
|
+
# @param other [Tash, Hash]
|
119
|
+
#
|
120
|
+
# @return [true or false]
|
121
|
+
|
122
|
+
# @!method <= other
|
123
|
+
# Returns `true` if tash is a subset of other, `false` otherwise.
|
124
|
+
#
|
125
|
+
# @example
|
126
|
+
# t1 = Tash[foo: 0, bar: 1]
|
127
|
+
# t2 = Tash[foo: 0, bar: 1, baz: 2]
|
128
|
+
# t1 <= t2 # => true
|
129
|
+
# t2 <= t1 # => false
|
130
|
+
# t1 <= t1 # => true
|
131
|
+
#
|
132
|
+
# @param other [Tash, Hash]
|
133
|
+
#
|
134
|
+
# @return [true or false]
|
135
|
+
|
136
|
+
# Returns `true` if all of the following are true:
|
137
|
+
#
|
138
|
+
# * object is a Tash object.
|
139
|
+
# * tash and object have the same keys (regardless of order).
|
140
|
+
# * For each key `key`, `tash[key] == other[key]`.
|
141
|
+
#
|
142
|
+
# Otherwise, returns `false`.
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
# t1 = Tash[foo: 0, bar: 1, baz: 2]
|
146
|
+
# t2 = Tash[foo: 0, bar: 1, baz: 2]
|
147
|
+
# t1 == t2 # => true
|
148
|
+
# h3 = Tash[baz: 2, bar: 1, foo: 0]
|
149
|
+
# t1 == h3 # => true
|
150
|
+
#
|
151
|
+
# @param other [Object]
|
152
|
+
#
|
153
|
+
# @return [true or false]
|
154
|
+
def ==(other)
|
155
|
+
return false unless other.is_a?(self.class)
|
156
|
+
|
157
|
+
@ir == other.to_hash
|
158
|
+
end
|
159
|
+
|
160
|
+
# @!method > other
|
161
|
+
# Returns `true` if tash is a proper superset of other, `false` otherwise.
|
162
|
+
#
|
163
|
+
# @example
|
164
|
+
# t1 = Tash[foo: 0, bar: 1, baz: 2]
|
165
|
+
# t2 = Tash[foo: 0, bar: 1]
|
166
|
+
# t1 > t2 # => true
|
167
|
+
# t2 > t1 # => false
|
168
|
+
# t1 > t1 # => false
|
169
|
+
#
|
170
|
+
# @param other [Tash, Hash]
|
171
|
+
#
|
172
|
+
# @return [true or false]
|
173
|
+
|
174
|
+
# @!method >= other
|
175
|
+
# Returns `true` if tash is a superset of other, `false` otherwise.
|
176
|
+
#
|
177
|
+
# @example
|
178
|
+
# t1 = Tash[foo: 0, bar: 1, baz: 2]
|
179
|
+
# t2 = Tash[foo: 0, bar: 1]
|
180
|
+
# t1 >= t2 # => true
|
181
|
+
# t2 >= t1 # => false
|
182
|
+
# t1 >= t1 # => true
|
183
|
+
#
|
184
|
+
# @param other [Tash, Hash]
|
185
|
+
#
|
186
|
+
# @return [true or false]
|
187
|
+
|
188
|
+
# Returns the value associated with the given `key` after transformation, if
|
189
|
+
# found.
|
190
|
+
#
|
191
|
+
# @example
|
192
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
193
|
+
# t[:FOO] # => 0
|
194
|
+
#
|
195
|
+
# @example Not found key with a default value
|
196
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
197
|
+
# t.default = 1_000
|
198
|
+
# t[:nosuch] # => 1_000
|
199
|
+
#
|
200
|
+
# @param key [Object]
|
201
|
+
#
|
202
|
+
# @return [value]
|
203
|
+
def [](key)
|
204
|
+
@ir[transform(key)]
|
205
|
+
end
|
206
|
+
|
207
|
+
# Associates the given `value` with the given `key` after transformation. If
|
208
|
+
# the given post transformation `key` exists, replaces its value with the
|
209
|
+
# given `value`; the ordering is not affected. If post transformation `key`
|
210
|
+
# does not exist, adds the transformed `key` and `value`; the new entry is
|
211
|
+
# last in the order.
|
212
|
+
#
|
213
|
+
# @example
|
214
|
+
# t = Tash[Foo: 0, Bar: 1, &:downcase]
|
215
|
+
# t[:FOO] = 2 # => 2
|
216
|
+
# t.store(:bar, 3) # => 3
|
217
|
+
# t[:Bat] = 4 # => 4
|
218
|
+
# t # => {:foo=>2, :bar=>3, :bat=>4}
|
219
|
+
#
|
220
|
+
# @param key [Object]
|
221
|
+
# @param value [Object]
|
222
|
+
#
|
223
|
+
# @return [value]
|
224
|
+
def []=(key, value)
|
225
|
+
@ir[transform(key)] = value
|
226
|
+
end
|
227
|
+
alias store []=
|
228
|
+
|
229
|
+
# If the given transformed `key` is found, returns a 2-element Array
|
230
|
+
# containing that key and its value. Returns `nil` if the tranformed key
|
231
|
+
# `key` is not found.
|
232
|
+
#
|
233
|
+
# @example
|
234
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
235
|
+
# t.assoc(:bar) # => [:bar, 1]
|
236
|
+
#
|
237
|
+
# @param key [Object]
|
238
|
+
#
|
239
|
+
# @return [Array<K,V> or nil]
|
240
|
+
def assoc(key)
|
241
|
+
@ir.assoc(transform(key))
|
242
|
+
end
|
243
|
+
|
244
|
+
# Removes all tash entries.
|
245
|
+
#
|
246
|
+
# @return [self]
|
247
|
+
def clear
|
248
|
+
@ir.clear
|
249
|
+
self
|
250
|
+
end
|
251
|
+
|
252
|
+
# Returns a copy of `self` with all `nil`-valued entries removed.
|
253
|
+
#
|
254
|
+
# @example
|
255
|
+
# t = Tash[foo: 0, bar: nil, baz: 2, bat: nil]
|
256
|
+
# t1 = t.compact
|
257
|
+
# t1 # => {:foo=>0, :baz=>2}
|
258
|
+
#
|
259
|
+
# @return [Tash]
|
260
|
+
def compact
|
261
|
+
new_from_self(@ir.compact)
|
262
|
+
end
|
263
|
+
|
264
|
+
# Returns `self` with all its `nil`-valued entries removed.
|
265
|
+
#
|
266
|
+
# @example
|
267
|
+
# t = Tash[foo: 0, bar: nil, baz: 2, bat: nil]
|
268
|
+
# t.compact! # => {:foo=>0, :baz=>2}
|
269
|
+
#
|
270
|
+
# @return [self or nil]
|
271
|
+
def compact!
|
272
|
+
self if @ir.compact!
|
273
|
+
end
|
274
|
+
|
275
|
+
# Sets `self` to consider only identity in comparing keys; two keys are
|
276
|
+
# considered the same only if they are the same object.
|
277
|
+
#
|
278
|
+
# @example Before being set
|
279
|
+
# s0 = 'x'
|
280
|
+
# s1 = 'x'
|
281
|
+
# t = Tash.new
|
282
|
+
# t.compare_by_identity? # => false
|
283
|
+
# t[s0] = 0
|
284
|
+
# t[s1] = 1
|
285
|
+
# t # => {"x"=>1}
|
286
|
+
#
|
287
|
+
# @example After being set
|
288
|
+
# t = Tash.new
|
289
|
+
# t.compare_by_identity # => {}
|
290
|
+
# t.compare_by_identity? # => true
|
291
|
+
# t[s0] = 0
|
292
|
+
# t[s1] = 1
|
293
|
+
# t # => {"x"=>0, "x"=>1}
|
294
|
+
#
|
295
|
+
# @return [self]
|
296
|
+
def compare_by_identity
|
297
|
+
@ir.compare_by_identity
|
298
|
+
self
|
299
|
+
end
|
300
|
+
|
301
|
+
# @!method compare_by_identity?
|
302
|
+
# Returns `true` if {#compare_by_identity} has been called, `false`
|
303
|
+
# otherwise.
|
304
|
+
#
|
305
|
+
# @return [Boolean]
|
306
|
+
|
307
|
+
# Provides support for pattern matching using a Tash. Pattern keys will be
|
308
|
+
# transformed before matching.
|
309
|
+
#
|
310
|
+
# @example
|
311
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
312
|
+
# case t
|
313
|
+
# in { foo: x, BAR: 1 }
|
314
|
+
# x
|
315
|
+
# else
|
316
|
+
# nil
|
317
|
+
# end # => 0
|
318
|
+
#
|
319
|
+
# @return [Hash]
|
320
|
+
def deconstruct_keys(keys)
|
321
|
+
return {} if keys.nil?
|
322
|
+
|
323
|
+
keys.to_h { |key| [key, self[key]] }
|
324
|
+
end
|
325
|
+
|
326
|
+
# @overload default
|
327
|
+
# @overload default(key)
|
328
|
+
#
|
329
|
+
# Returns the default value for the given transformed `key`. The returned
|
330
|
+
# value will be determined either by the default proc or by the default
|
331
|
+
# value.
|
332
|
+
#
|
333
|
+
# @example
|
334
|
+
# t = Tash.new
|
335
|
+
# t.default # => nil
|
336
|
+
#
|
337
|
+
# @example With a key
|
338
|
+
# t = Tash[Foo: 0]
|
339
|
+
# t.default_proc = proc { |tash, key| tash[k] = "No key #{key}" }
|
340
|
+
# t[:foo] = "Hello"
|
341
|
+
# t.default(:FOO) # => "No key foo"
|
342
|
+
#
|
343
|
+
# @param key [Object]
|
344
|
+
#
|
345
|
+
# @return [Object]
|
346
|
+
def default(*key)
|
347
|
+
case key.size
|
348
|
+
when 0
|
349
|
+
@ir.default
|
350
|
+
when 1
|
351
|
+
@ir.default(transform(key.first))
|
352
|
+
else
|
353
|
+
@ir.default(*key)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
# @!method default=(value)
|
358
|
+
# Sets the default value to `value`.
|
359
|
+
#
|
360
|
+
# @example
|
361
|
+
# t = Tash.new
|
362
|
+
# t.default # => nil
|
363
|
+
# t.default = false # => false
|
364
|
+
# t.default # => false
|
365
|
+
#
|
366
|
+
# @param value [Object]
|
367
|
+
#
|
368
|
+
# @return [Object]
|
369
|
+
|
370
|
+
# Returns the default proc for `self`.
|
371
|
+
#
|
372
|
+
# @example
|
373
|
+
# t = Tash.new
|
374
|
+
# t.default_proc # => nil
|
375
|
+
# t.default_proc = proc { |tash, key| "Default value for #{key}" }
|
376
|
+
# t.default_proc.class # => Proc
|
377
|
+
#
|
378
|
+
# @return [Proc or nil]
|
379
|
+
def default_proc # rubocop:disable Style/TrivialAccessors (I want it to show as a method in the docs.)
|
380
|
+
@default_proc
|
381
|
+
end
|
382
|
+
|
383
|
+
# @overload default_proc=(proc)
|
384
|
+
#
|
385
|
+
# Sets the default proc for `self` to `proc`.
|
386
|
+
#
|
387
|
+
# @example
|
388
|
+
# t = Tash.new
|
389
|
+
# t.default_proc # => nil
|
390
|
+
# t.default_proc = proc { |tash, key| "Default value for #{key}" }
|
391
|
+
# t.default_proc.class # => Proc
|
392
|
+
# t.default_proc = nil
|
393
|
+
# t.default_proc # => nil
|
394
|
+
#
|
395
|
+
# @param proc [Proc] receives self and a transformed key
|
396
|
+
#
|
397
|
+
# @return [Proc]
|
398
|
+
def default_proc=(prok)
|
399
|
+
@default_proc = prok
|
400
|
+
|
401
|
+
@ir.default_proc = proc { |_, k| prok.call(self, transform(k)) }
|
402
|
+
end
|
403
|
+
|
404
|
+
# Deletes the entry for the given transformed `key` and returns its
|
405
|
+
# associated value.
|
406
|
+
#
|
407
|
+
# @example
|
408
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
409
|
+
# t.delete(:bar) # => 1
|
410
|
+
# t.delete(:bar) # => nil
|
411
|
+
# t # => {:foo=>0, :baz=>2}
|
412
|
+
#
|
413
|
+
# @example With a block and a `key` found.
|
414
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
415
|
+
# t.delete(:baz) { |key| raise 'Will never happen'} # => 2
|
416
|
+
# t # => {:foo=>0, :bar=>1}
|
417
|
+
#
|
418
|
+
# @example With a block and no `key` found.
|
419
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
420
|
+
# t.delete(:nosuch) { |key| "Key #{key} not found" } # => "Key nosuch not found"
|
421
|
+
# t # => {:foo=>0, :bar=>1, :baz=>2}
|
422
|
+
#
|
423
|
+
# @param key [Object]
|
424
|
+
# @param block [Proc] receives a transformed key
|
425
|
+
#
|
426
|
+
# @return [value or nil, Object]
|
427
|
+
def delete(key, &block)
|
428
|
+
@ir.delete(transform(key), &block)
|
429
|
+
end
|
430
|
+
|
431
|
+
# If a block given, calls the block with each key-value pair; deletes each
|
432
|
+
# entry for which the block returns a truthy value.
|
433
|
+
#
|
434
|
+
# @example Without block
|
435
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
436
|
+
# e = t.delete_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:delete_if>
|
437
|
+
# e.each { |key, value| value > 0 } # => {:foo=>0}
|
438
|
+
#
|
439
|
+
# @example With block
|
440
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
441
|
+
# t.delete_if { |key, value| value > 0 } # => {:foo=>0}
|
442
|
+
#
|
443
|
+
# @param block [Proc] receives a transformed key and value
|
444
|
+
#
|
445
|
+
# @return [Enumerator, self]
|
446
|
+
def delete_if(&block)
|
447
|
+
return to_enum(:delete_if) unless block
|
448
|
+
|
449
|
+
@ir.delete_if(&block)
|
450
|
+
self
|
451
|
+
end
|
452
|
+
|
453
|
+
# Finds and returns the object in nested objects that is specified by
|
454
|
+
# transformed `key` and `identifiers`. The nested objects may be instances of
|
455
|
+
# various classes. This method will use the default values for keys that are
|
456
|
+
# not present.
|
457
|
+
#
|
458
|
+
# @example Nested Tashes
|
459
|
+
# t = Tash[Foo: Tash[Bar: 2, &:downcase], &:downcase]
|
460
|
+
# t.dig(:foo) # => {:bar=>2}
|
461
|
+
# t.dig(:foo, :bar) # => 2
|
462
|
+
# t.dig(:foo, :bar, :BAZ) # => nil
|
463
|
+
#
|
464
|
+
# @example Nested Arrays
|
465
|
+
# t = Tash[foo: [:a, :b, :c]]
|
466
|
+
# t.dig(:foo, 2) # => :c
|
467
|
+
#
|
468
|
+
# @example Default values
|
469
|
+
# t = Tash[foo: Tash[bar: [:a, :b, :c]]]
|
470
|
+
# t.dig(:hello) # => nil
|
471
|
+
# t.default_proc = -> (tash, _key) { tash }
|
472
|
+
# t.dig(:hello, :world) # => t
|
473
|
+
# t.dig(:hello, :world, :foo, :bar, 2) # => :c
|
474
|
+
#
|
475
|
+
# @param key [Object]
|
476
|
+
# @param *identifiers [Object]
|
477
|
+
#
|
478
|
+
# @return [Object]
|
479
|
+
def dig(key, *identifiers)
|
480
|
+
@ir.dig(transform(key), *identifiers)
|
481
|
+
end
|
482
|
+
|
483
|
+
# Calls the given block with each key-value pair. Returns a new Enumerator if
|
484
|
+
# no block is given.
|
485
|
+
#
|
486
|
+
# @example Without block
|
487
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
488
|
+
# t.each # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each>
|
489
|
+
#
|
490
|
+
# @example With block
|
491
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
492
|
+
# t.each {|key, value| puts "#{key}: #{value}"}
|
493
|
+
# #=> foo: 0
|
494
|
+
# #=> bar: 1
|
495
|
+
# #=> baz: 2
|
496
|
+
#
|
497
|
+
# @param block [Proc] receives a transformed key and the value
|
498
|
+
#
|
499
|
+
# @return [Enumerator, self]
|
500
|
+
def each(&block)
|
501
|
+
return to_enum(:each) unless block
|
502
|
+
|
503
|
+
@ir.each(&block)
|
504
|
+
self
|
505
|
+
end
|
506
|
+
alias each_pair each
|
507
|
+
|
508
|
+
# Calls the given block with each key.
|
509
|
+
#
|
510
|
+
# @example Without block
|
511
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
512
|
+
# t.each_key # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_key>
|
513
|
+
#
|
514
|
+
# @example With block
|
515
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
516
|
+
# t.each_key {|key| puts key}
|
517
|
+
# #=> foo
|
518
|
+
# #=> bar
|
519
|
+
# #=> baz
|
520
|
+
#
|
521
|
+
# @param block [Proc] receives a transformed key
|
522
|
+
#
|
523
|
+
# @return [Enumerator, self]
|
524
|
+
def each_key(&block)
|
525
|
+
return to_enum(:each_key) unless block
|
526
|
+
|
527
|
+
@ir.each_key(&block)
|
528
|
+
self
|
529
|
+
end
|
530
|
+
|
531
|
+
# Calls the given block with each value.
|
532
|
+
#
|
533
|
+
# @example Without block
|
534
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
535
|
+
# t.each_value # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_value>
|
536
|
+
#
|
537
|
+
# @example With block
|
538
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
539
|
+
# t.each_value {|value| puts value}
|
540
|
+
# #=> 0
|
541
|
+
# #=> 1
|
542
|
+
# #=> 2
|
543
|
+
#
|
544
|
+
# @param block [Proc] receives a value
|
545
|
+
#
|
546
|
+
# @return [Enumerator, self]
|
547
|
+
def each_value(&block)
|
548
|
+
return to_enum(:each_value) unless block
|
549
|
+
|
550
|
+
@ir.each_value(&block)
|
551
|
+
self
|
552
|
+
end
|
553
|
+
|
554
|
+
# @!method empty?
|
555
|
+
# Returns `true` if there are no tash entries, `false` otherwise.
|
556
|
+
#
|
557
|
+
# @example
|
558
|
+
# Tash[].empty? # => true
|
559
|
+
# Tash[foo: 0, bar: 1, baz: 2].empty? # => false
|
560
|
+
#
|
561
|
+
# @return [true or false]
|
562
|
+
|
563
|
+
# Returns `true` if all of the following are true:
|
564
|
+
#
|
565
|
+
# * object is a Tash object.
|
566
|
+
# * tash and object have the same keys (regardless of order).
|
567
|
+
# * For each key `key`, `tash[key] eql? other[key]`.
|
568
|
+
#
|
569
|
+
# Otherwise, returns `false`.
|
570
|
+
#
|
571
|
+
# @example
|
572
|
+
# t1 = Tash[foo: 0, bar: 1, baz: 2]
|
573
|
+
# t2 = Tash[foo: 0, bar: 1, baz: 2]
|
574
|
+
# t1.eql? t2 # => true
|
575
|
+
# h3 = Tash[baz: 2, bar: 1, foo: 0]
|
576
|
+
# t1.eql? h3 # => true
|
577
|
+
#
|
578
|
+
# @param other [Object]
|
579
|
+
#
|
580
|
+
# @return [true or false]
|
581
|
+
def eql?(other)
|
582
|
+
return false unless other.is_a?(self.class)
|
583
|
+
|
584
|
+
@ir.eql?(other.to_hash)
|
585
|
+
end
|
586
|
+
|
587
|
+
# Returns a new Tash excluding entries for the given `keys`. Any given keys
|
588
|
+
# that are not found are ignored. The transform proc is copied to the new
|
589
|
+
# Tash.
|
590
|
+
#
|
591
|
+
# @example
|
592
|
+
# t = Tash[a: 100, b: 200, c: 300]
|
593
|
+
# t.except(:a) #=> {:b=>200, :c=>300}
|
594
|
+
#
|
595
|
+
# @param *keys [Array<Object>]
|
596
|
+
#
|
597
|
+
# @return [Tash]
|
598
|
+
def except(*keys)
|
599
|
+
new_from_self(@ir.except(*keys))
|
600
|
+
end if current_ruby_version > '2.7'
|
601
|
+
|
602
|
+
# @overload fetch(key)
|
603
|
+
# @overload fetch(key, default_value)
|
604
|
+
#
|
605
|
+
# Returns the value for the given `key`, if found. Raises `KeyError` if
|
606
|
+
# neither `default_value` nor a block was given.
|
607
|
+
#
|
608
|
+
# @note This method does not use the values of either `default` or
|
609
|
+
# `default_proc`.
|
610
|
+
#
|
611
|
+
# @example
|
612
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
613
|
+
# t.fetch(:bar) # => 1
|
614
|
+
#
|
615
|
+
# @example With a default
|
616
|
+
# Tash.new.fetch(:nosuch, :default) # => :default
|
617
|
+
#
|
618
|
+
# @example With a default block
|
619
|
+
# Tash.new.fetch(:NOSUCH) {|key| "No key #{key}"} # => "No key nosuch"
|
620
|
+
#
|
621
|
+
# @param key [Object]
|
622
|
+
# @param default_value [Object]
|
623
|
+
# @param block [Proc] receives a transformed `key`
|
624
|
+
#
|
625
|
+
# @return [Object]
|
626
|
+
#
|
627
|
+
# @raise [KeyError] When `key` is not found and no default is provided.
|
628
|
+
def fetch(key, *default_value, &block)
|
629
|
+
if block
|
630
|
+
@ir.fetch(transform(key), &block)
|
631
|
+
else
|
632
|
+
@ir.fetch(transform(key), *default_value)
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
# Returns a new Array containing the values associated with the given keys
|
637
|
+
# *keys. When a block is given, calls the block with each missing transformed
|
638
|
+
# key, treating the block's return value as the value for that key.
|
639
|
+
#
|
640
|
+
# @example Without a block
|
641
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
642
|
+
# t.fetch_values(:baz, :foo) # => [2, 0]
|
643
|
+
#
|
644
|
+
# @example With a block
|
645
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
646
|
+
# values = t.fetch_values(:bar, :foo, :bad, :bam) {|key| key.to_s}
|
647
|
+
# values # => [1, 0, "bad", "bam"]
|
648
|
+
#
|
649
|
+
# @param *keys [Array<Object>]
|
650
|
+
# @param block [Proc] receives a transformed `key`
|
651
|
+
#
|
652
|
+
# @return [Array]
|
653
|
+
def fetch_values(*keys, &block)
|
654
|
+
@ir.fetch_values(*keys.map { |k| transform(k) }, &block)
|
655
|
+
end
|
656
|
+
|
657
|
+
# @!method flatten
|
658
|
+
# @overload flatten
|
659
|
+
# @overload flatten(level)
|
660
|
+
#
|
661
|
+
# Returns a new Array object that is a 1-dimensional flattening of `self`.
|
662
|
+
#
|
663
|
+
# @example
|
664
|
+
# t = Tash[foo: 0, bar: [:bat, 3], baz: 2]
|
665
|
+
# t.flatten # => [:foo, 0, :bar, [:bat, 3], :baz, 2]
|
666
|
+
#
|
667
|
+
# @example level > 1
|
668
|
+
# t = Tash[foo: 0, bar: [:bat, [:baz, [:bat, ]]]]
|
669
|
+
# t.flatten(1) # => [:foo, 0, :bar, [:bat, [:baz, [:bat]]]]
|
670
|
+
# t.flatten(2) # => [:foo, 0, :bar, :bat, [:baz, [:bat]]]
|
671
|
+
# t.flatten(3) # => [:foo, 0, :bar, :bat, :baz, [:bat]]
|
672
|
+
# t.flatten(4) # => [:foo, 0, :bar, :bat, :baz, :bat]
|
673
|
+
#
|
674
|
+
# @example negative levels flatten everything
|
675
|
+
# t = Tash[foo: 0, bar: [:bat, [:baz, [:bat, ]]]]
|
676
|
+
# t.flatten(-1) # => [:foo, 0, :bar, :bat, :baz, :bat]
|
677
|
+
# t.flatten(-2) # => [:foo, 0, :bar, :bat, :baz, :bat]
|
678
|
+
#
|
679
|
+
# @example level == 0 is the same as to_a
|
680
|
+
# t = Tash[foo: 0, bar: [:bat, 3], baz: 2]
|
681
|
+
# t.flatten(0) # => [[:foo, 0], [:bar, [:bat, 3]], [:baz, 2]]
|
682
|
+
# t.flatten(0) == t.to_a # => true
|
683
|
+
#
|
684
|
+
# @param level [Integer]
|
685
|
+
#
|
686
|
+
# @return [Array]
|
687
|
+
|
688
|
+
# @!method hash
|
689
|
+
# Returns the Integer hash-code for the hash. Two Hash objects have the
|
690
|
+
# same hash-code if their content is the same (regardless or order).
|
691
|
+
#
|
692
|
+
# @example
|
693
|
+
# t1 = Tash[foo: 0, bar: 1, baz: 2]
|
694
|
+
# t2 = Tash[baz: 2, bar: 1, foo: 0]
|
695
|
+
# t2.hash == t1.hash # => true
|
696
|
+
# t2.eql? h1 # => true
|
697
|
+
#
|
698
|
+
# @return [Integer]
|
699
|
+
|
700
|
+
# @!method inspect
|
701
|
+
# Returns a new String containing the tash entries.
|
702
|
+
#
|
703
|
+
# @example
|
704
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
705
|
+
# t.inspect # => "{:foo=>0, :bar=>1, :baz=>2}"
|
706
|
+
#
|
707
|
+
# @return [String]
|
708
|
+
|
709
|
+
# Returns a new Tash object with the each key-value pair inverted. The values
|
710
|
+
# will be processed using the key transformation.
|
711
|
+
#
|
712
|
+
# @example
|
713
|
+
# t = Tash[foo: 'Foo', bar: 'Bar', baz: 'Baz', &:downcase]
|
714
|
+
# t1 = t.invert
|
715
|
+
# t1 # => {'foo'=>:foo, 'bar'=>:bar, 'baz'=>:baz}
|
716
|
+
#
|
717
|
+
# @return [Tash]
|
718
|
+
def invert
|
719
|
+
new_ir = @ir.invert
|
720
|
+
new_ir.transform_keys! { |k| transform(k) }
|
721
|
+
|
722
|
+
new_from_self(new_ir)
|
723
|
+
end
|
724
|
+
|
725
|
+
# Calls the block for each key-value pair; retains the entry if the block
|
726
|
+
# returns a truthy value; otherwise deletes the entry.
|
727
|
+
#
|
728
|
+
# @example Without block
|
729
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
730
|
+
# e = t.keep_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:keep_if>
|
731
|
+
# e.each { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
|
732
|
+
#
|
733
|
+
# @example With block
|
734
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
735
|
+
# t.keep_if { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
|
736
|
+
#
|
737
|
+
# @param block [Proc] receives a transformed key and value
|
738
|
+
#
|
739
|
+
# @return [Enumerator, self]
|
740
|
+
def keep_if(&block)
|
741
|
+
return to_enum(:keep_if) unless block
|
742
|
+
|
743
|
+
@ir.keep_if(&block)
|
744
|
+
self
|
745
|
+
end
|
746
|
+
|
747
|
+
# @!method key(value)
|
748
|
+
# Returns the transformed key for the first-found entry with the given
|
749
|
+
# `value`. Returns `nil` if the key is not found.
|
750
|
+
#
|
751
|
+
# @example
|
752
|
+
# t = Tash[foo: 0, bar: 2, baz: 2]
|
753
|
+
# t.key(0) # => :foo
|
754
|
+
# t.key(2) # => :bar
|
755
|
+
#
|
756
|
+
# @param value [Object]
|
757
|
+
#
|
758
|
+
# @return [key or nil]
|
759
|
+
|
760
|
+
# Returns `true` if `key` after transformation is a key in `self`, otherwise
|
761
|
+
# `false`.
|
762
|
+
#
|
763
|
+
# @example
|
764
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
765
|
+
# t.key?(:FOO) # => true
|
766
|
+
# t.key?(:bat) # => false
|
767
|
+
#
|
768
|
+
# @param key [Object]
|
769
|
+
#
|
770
|
+
# @return [true or false]
|
771
|
+
def key?(key)
|
772
|
+
@ir.key?(transform(key))
|
773
|
+
end
|
774
|
+
alias has_key? key?
|
775
|
+
alias include? key?
|
776
|
+
alias member? key?
|
777
|
+
|
778
|
+
# @!method keys
|
779
|
+
# Returns a new Array containing all keys in `self`.
|
780
|
+
#
|
781
|
+
# @example
|
782
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
783
|
+
# t.keys # => [:foo, :bar, :baz]
|
784
|
+
#
|
785
|
+
# @return [Array]
|
786
|
+
|
787
|
+
# Returns the new Tash formed by merging each of `other_tashes_or_hashes`
|
788
|
+
# into a copy of `self`.
|
789
|
+
#
|
790
|
+
# Each argument in `other_tashes_or_hashes` must be a Tash or Hash.
|
791
|
+
#
|
792
|
+
# With arguments and no block:
|
793
|
+
#
|
794
|
+
# * Returns the new Tash object formed by merging each successive item in
|
795
|
+
# other_tashes_or_hashes into self.
|
796
|
+
# * Each new-key entry is added at the end.
|
797
|
+
# * Each duplicate-key entry's value overwrites the previous value.
|
798
|
+
#
|
799
|
+
# With arguments and a block:
|
800
|
+
#
|
801
|
+
# * Returns a new Tash object that is the merge of self and each given
|
802
|
+
# tash or hash.
|
803
|
+
# * The given tashes or hashes are merged left to right.
|
804
|
+
# * Each new-key entry is added at the end.
|
805
|
+
# * For each duplicate key:
|
806
|
+
# * Calls the block with the transformed key and the old and new values.
|
807
|
+
# * The block's return value becomes the new value for the entry.
|
808
|
+
#
|
809
|
+
# With no arguments:
|
810
|
+
#
|
811
|
+
# * Returns a copy of self.
|
812
|
+
# * The block, if given, is ignored.
|
813
|
+
#
|
814
|
+
# @example With arguments and no block
|
815
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
816
|
+
# t1 = Tash[bat: 3, bar: 4]
|
817
|
+
# h = {BAM: 5, BAT: 6}
|
818
|
+
# t.merge(t1, h) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5}
|
819
|
+
#
|
820
|
+
# @example With arguments and a block
|
821
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
822
|
+
# t1 = Tash[bat: 3, bar: 4]
|
823
|
+
# h = {BAM: 5, BAT: 6}
|
824
|
+
# t2 = t.merge(t1, h) { |key, old_value, new_value| old_value + new_value }
|
825
|
+
# t2 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5}
|
826
|
+
#
|
827
|
+
# @example With no arguments
|
828
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
829
|
+
# t.merge # => {:foo=>0, :bar=>1, :baz=>2}
|
830
|
+
# t1 = t.merge { |key, old_value, new_value| raise 'Cannot happen' }
|
831
|
+
# t1 # => {:foo=>0, :bar=>1, :baz=>2}
|
832
|
+
#
|
833
|
+
# @param *others [Tash or Hash]
|
834
|
+
# @param block [Proc] receives a transformed key, the old value, and the new
|
835
|
+
# value
|
836
|
+
#
|
837
|
+
# @return [Tash]
|
838
|
+
def merge(*others, &block)
|
839
|
+
new_ir = others.each_with_object(@ir.dup) do |other, ir|
|
840
|
+
ir.merge!(other.to_hash.transform_keys { |k| transform(k) }, &block)
|
841
|
+
end
|
842
|
+
new_from_self(new_ir)
|
843
|
+
end
|
844
|
+
|
845
|
+
# Merges each of `other_tashes_or_hashes` into `self`.
|
846
|
+
#
|
847
|
+
# Each argument in `other_tashes_or_hashes` must be a Tash or Hash.
|
848
|
+
#
|
849
|
+
# With arguments and no block:
|
850
|
+
#
|
851
|
+
# * Returns `self`, after the given tashes and hashes are merged into it.
|
852
|
+
# * The given tashes and hashes are merged left to right.
|
853
|
+
# * Each new entry is added at the end.
|
854
|
+
# * Each duplicate-key entry's value overwrites the previous value.
|
855
|
+
#
|
856
|
+
# With arguments and a block:
|
857
|
+
#
|
858
|
+
# * Returns `self`, after the given tashes and hashes are merged.
|
859
|
+
# * The given tashes and hashes are merged left to right.
|
860
|
+
# * Each new-key entry is added at the end.
|
861
|
+
# * For each duplicate key:
|
862
|
+
# * Calls the block with the transformed key and the old and new values.
|
863
|
+
# * The block's return value becomes the new value for the entry.
|
864
|
+
#
|
865
|
+
# With no arguments:
|
866
|
+
#
|
867
|
+
# * Returns `self`, unmodified.
|
868
|
+
# * The block, if given, is ignored.
|
869
|
+
#
|
870
|
+
# @example With arguments and no block
|
871
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
872
|
+
# t1 = Tash[bat: 3, bar: 4]
|
873
|
+
# h = {BAM: 5, BAT: 6}
|
874
|
+
# t.merge!(t1, h) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5}
|
875
|
+
#
|
876
|
+
# @example With arguments and a block
|
877
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
878
|
+
# t1 = Tash[bat: 3, bar: 4]
|
879
|
+
# h = {BAM: 5, BAT: 6}
|
880
|
+
# t2 = t.merge!(t1, h) { |key, old_value, new_value| old_value + new_value }
|
881
|
+
# t2 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5}
|
882
|
+
#
|
883
|
+
# @example With no arguments
|
884
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
885
|
+
# t.merge # => {:foo=>0, :bar=>1, :baz=>2}
|
886
|
+
# t1 = t.merge! { |key, old_value, new_value| raise 'Cannot happen' }
|
887
|
+
# t1 # => {:foo=>0, :bar=>1, :baz=>2}
|
888
|
+
#
|
889
|
+
# @param *others [Tash or Hash]
|
890
|
+
# @param block [Proc] receives a transformed key, the old value, and the new
|
891
|
+
# value
|
892
|
+
#
|
893
|
+
# @return [self]
|
894
|
+
def merge!(*others, &block)
|
895
|
+
others.each do |other|
|
896
|
+
@ir.merge!(other.to_hash.transform_keys { |k| transform(k) }, &block)
|
897
|
+
end
|
898
|
+
self
|
899
|
+
end
|
900
|
+
alias update merge!
|
901
|
+
|
902
|
+
# @!method rassoc(value)
|
903
|
+
# Returns a new 2-element Array consisting of the key and value of the
|
904
|
+
# first-found entry whose value is `==` to value. Returns `nil` if no such
|
905
|
+
# value found.
|
906
|
+
#
|
907
|
+
# @example
|
908
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
909
|
+
# t.rassoc(1) # => [:bar, 1]
|
910
|
+
#
|
911
|
+
# @param value [Object]
|
912
|
+
#
|
913
|
+
# @return [Array<K,V> or nil]
|
914
|
+
|
915
|
+
# @!method rehash
|
916
|
+
# Rebuilds the hash table by recomputing the hash index for each key. The
|
917
|
+
# hash table becomes invalid if the hash value of a key has changed after
|
918
|
+
# the entry was created.
|
919
|
+
#
|
920
|
+
# @return [self]
|
921
|
+
|
922
|
+
# Returns a new Tash object whose entries are all those from `self` for which
|
923
|
+
# the block returns `false` or `nil`. Returns a new Enumerator if no block
|
924
|
+
# given.
|
925
|
+
#
|
926
|
+
# @example Without a block
|
927
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
928
|
+
# e = t.reject # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject>
|
929
|
+
# t1 = e.each { |key, value| key.start_with?('b') }
|
930
|
+
# t1 # => {:foo=>0}
|
931
|
+
#
|
932
|
+
# @example With a block
|
933
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
934
|
+
# t1 = t.reject { |key, value| key.start_with?('b') }
|
935
|
+
# t1 # => {:foo=>0}
|
936
|
+
#
|
937
|
+
# @param block [Proc] receives a transformed key and value
|
938
|
+
#
|
939
|
+
# @return [Enumerator, Tash]
|
940
|
+
def reject(&block)
|
941
|
+
return to_enum(:reject) unless block
|
942
|
+
|
943
|
+
new_from_self(@ir.reject(&block))
|
944
|
+
end
|
945
|
+
|
946
|
+
# Returns `self`, whose remaining entries are those for which the block
|
947
|
+
# returns `false` or `nil`. Returns `nil` if no entries are removed.
|
948
|
+
#
|
949
|
+
# @example Without a block
|
950
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
951
|
+
# e = t.reject! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject!>
|
952
|
+
# t1 = e.each { |key, value| key.start_with?('b') } # => {:foo=>0}
|
953
|
+
#
|
954
|
+
# @example With a block
|
955
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
956
|
+
# t.reject! { |key, value| value < 2 } # => {:foo=>0, :bar=>1}
|
957
|
+
#
|
958
|
+
# @param block [Proc] receives a transformed key and value
|
959
|
+
#
|
960
|
+
# @return [Enumerator, self or nil]
|
961
|
+
def reject!(&block)
|
962
|
+
return to_enum(:reject!) unless block
|
963
|
+
|
964
|
+
self if @ir.reject!(&block)
|
965
|
+
end
|
966
|
+
|
967
|
+
# Replaces the entire contents of `self` with the contents of `other`. If
|
968
|
+
# `other` is a tash it also replaces the transform block.
|
969
|
+
#
|
970
|
+
# @example With a hash
|
971
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
972
|
+
# t.replace({Bat: 3, Bam: 4}) # => {:bat=>3, :bam=>4}
|
973
|
+
#
|
974
|
+
# @example With a tash
|
975
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
976
|
+
# t.replace(Tash[Bat: 3, Bam: 4, &:upcase]) # => {:BAT=>3, :BAM=>4}
|
977
|
+
#
|
978
|
+
# @param other [Tash, Hash]
|
979
|
+
#
|
980
|
+
# @return [self]
|
981
|
+
def replace(other)
|
982
|
+
if other.is_a?(self.class)
|
983
|
+
@ir.replace(other.to_hash)
|
984
|
+
@transform = other.transform_proc
|
985
|
+
else
|
986
|
+
@ir.replace(other.to_hash.transform_keys { |k| transform(k) })
|
987
|
+
end
|
988
|
+
|
989
|
+
self
|
990
|
+
end
|
991
|
+
|
992
|
+
# Returns a new Tash object whose entries are those for which the block
|
993
|
+
# returns a truthy value. Returns a new Enumerator if no block given.
|
994
|
+
#
|
995
|
+
# @example Without a block
|
996
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
997
|
+
# e = t.select # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select>
|
998
|
+
# e.each { |key, value| value < 2 } # => {:foo=>0, :bar=>1}
|
999
|
+
#
|
1000
|
+
# @example With a block
|
1001
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
1002
|
+
# t.select { |key, value| value < 2 } # => {:foo=>0, :bar=>1}
|
1003
|
+
#
|
1004
|
+
# @param block [Proc] receives a transformed key and value
|
1005
|
+
#
|
1006
|
+
# @return [Enumerator, Tash]
|
1007
|
+
def select(&block)
|
1008
|
+
return to_enum(:select) unless block
|
1009
|
+
|
1010
|
+
new_from_self(@ir.select(&block))
|
1011
|
+
end
|
1012
|
+
alias filter select
|
1013
|
+
|
1014
|
+
# Returns `self`, whose entries are those for which the block returns a truthy
|
1015
|
+
# value. When given a block, it returns `nil` if no entries are removed.
|
1016
|
+
#
|
1017
|
+
# @example Without a block
|
1018
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
1019
|
+
# e = t.select! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select!>
|
1020
|
+
# e.each { |key, value| value < 2 } # => {:foo=>0, :bar=>1}
|
1021
|
+
#
|
1022
|
+
# @example With a block
|
1023
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
1024
|
+
# t.select! { |key, value| value < 2 } # => {:foo=>0, :bar=>1}
|
1025
|
+
#
|
1026
|
+
# @param block [Proc] receives a transformed key and value
|
1027
|
+
#
|
1028
|
+
# @return [Enumerator, self or nil]
|
1029
|
+
def select!(&block)
|
1030
|
+
return to_enum(:select!) unless block
|
1031
|
+
|
1032
|
+
self if @ir.select!(&block)
|
1033
|
+
end
|
1034
|
+
alias filter! select!
|
1035
|
+
|
1036
|
+
# @!method shift
|
1037
|
+
# Removes the first tash entry and returns a 2-element Array containing the
|
1038
|
+
# removed key and value. Returns the default value if the hash is empty.
|
1039
|
+
#
|
1040
|
+
# @example
|
1041
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
1042
|
+
# t.shift # => [:foo, 0]
|
1043
|
+
# t # => {:bar=>1, :baz=>2}
|
1044
|
+
#
|
1045
|
+
# @return [[key, value] or default value]
|
1046
|
+
|
1047
|
+
# @!method size
|
1048
|
+
# Returns the count of entries in `self`.
|
1049
|
+
#
|
1050
|
+
# @example
|
1051
|
+
# Tash[foo: 0, bar: 1, baz: 2].size # => 3
|
1052
|
+
#
|
1053
|
+
# @return [Integer]
|
1054
|
+
|
1055
|
+
# Returns a new Tash object containing the entries for the given transformed
|
1056
|
+
# `keys`. Any given `keys` that are not found are ignored.
|
1057
|
+
#
|
1058
|
+
# @example
|
1059
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
1060
|
+
# t.slice(:BAZ, :foo) # => {:baz=>2, :foo=>0}
|
1061
|
+
#
|
1062
|
+
# @param *keys [Array<Object>]
|
1063
|
+
#
|
1064
|
+
# @return [Tash]
|
1065
|
+
def slice(*keys)
|
1066
|
+
new_from_self(@ir.slice(*keys.map { |k| transform(k) }))
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
# @!method to_a
|
1070
|
+
# Returns a new Array of 2-element Array objects; each nested Array
|
1071
|
+
# contains a key-value pair from `self`.
|
1072
|
+
#
|
1073
|
+
# @example
|
1074
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
1075
|
+
# t.to_a # => [[:foo, 0], [:bar, 1], [:baz, 2]]
|
1076
|
+
#
|
1077
|
+
# @return [Array]
|
1078
|
+
|
1079
|
+
# Returns a Hash containing the content of `self`. When a block is given,
|
1080
|
+
# returns a Hash object whose content is based on the block; the block should
|
1081
|
+
# return a 2-element Array object specifying the key-value pair to be
|
1082
|
+
# included in the returned Array.
|
1083
|
+
#
|
1084
|
+
# @example
|
1085
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
1086
|
+
# h1 = t.to_h { |key, value| [value, key] }
|
1087
|
+
# h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
|
1088
|
+
#
|
1089
|
+
# @param block [Proc]
|
1090
|
+
#
|
1091
|
+
# @return [Hash]
|
1092
|
+
def to_h(&block)
|
1093
|
+
if block
|
1094
|
+
@ir.to_h(&block)
|
1095
|
+
else
|
1096
|
+
to_hash
|
1097
|
+
end
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
# Returns tash as a Hash.
|
1101
|
+
#
|
1102
|
+
# @return [Hash]
|
1103
|
+
def to_hash
|
1104
|
+
@ir.dup
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
# Returns a Proc object that maps a key to its value.
|
1108
|
+
#
|
1109
|
+
# @example
|
1110
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
1111
|
+
# proc = t.to_proc
|
1112
|
+
# proc.class # => Proc
|
1113
|
+
# proc.call(:foo) # => 0
|
1114
|
+
# proc.call(:BAR) # => 1
|
1115
|
+
# proc.call(:nosuch) # => nil
|
1116
|
+
#
|
1117
|
+
# @return [Proc]
|
1118
|
+
def to_proc
|
1119
|
+
p = @ir.to_proc
|
1120
|
+
lambda do |key|
|
1121
|
+
p.call(transform(key))
|
1122
|
+
end
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
# Returns the transform proc for `self`.
|
1126
|
+
#
|
1127
|
+
# @example
|
1128
|
+
# t = Tash.new
|
1129
|
+
# t.transform_proc # => nil
|
1130
|
+
# t = Tash.new(&:to_s)
|
1131
|
+
# t.transform_proc.class # => Proc
|
1132
|
+
# t.transform_proc.call(:a) # => "a"
|
1133
|
+
#
|
1134
|
+
# @return [Proc or nil]
|
1135
|
+
def transform_proc
|
1136
|
+
@transform
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
# Returns a new Tash object; each entry has:
|
1140
|
+
#
|
1141
|
+
# * A key from `self`.
|
1142
|
+
# * A value provided by the block.
|
1143
|
+
#
|
1144
|
+
# @example Without block
|
1145
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
1146
|
+
# e = t.transform_values # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_values>
|
1147
|
+
# t1 = e.each { |value| value * 100 }
|
1148
|
+
# t1 # => {:foo=>0, :bar=>100, :baz=>200}
|
1149
|
+
#
|
1150
|
+
# @example With a block
|
1151
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
1152
|
+
# t1 = t.transform_values { |value| value * 100 }
|
1153
|
+
# t1 # => {:foo=>0, :bar=>100, :baz=>200}
|
1154
|
+
#
|
1155
|
+
# @return [Tash]
|
1156
|
+
def transform_values(&block)
|
1157
|
+
return to_enum(:transform_values) unless block
|
1158
|
+
|
1159
|
+
new_from_self(@ir.transform_values(&block))
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
# Returns `self`, whose keys are unchanged, and whose values are determined by
|
1163
|
+
# the given block.
|
1164
|
+
#
|
1165
|
+
# @example Without a block
|
1166
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
1167
|
+
# e = t.transform_values! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_values!>
|
1168
|
+
# t1 = e.each { |value| value * 100 }
|
1169
|
+
# t1 # => {:foo=>0, :bar=>100, :baz=>200}
|
1170
|
+
#
|
1171
|
+
# @example With a block
|
1172
|
+
# t = Tash[Foo: 0, Bar: 1, Baz: 2, &:downcase]
|
1173
|
+
# t.transform_values! { |value| value * 100 } # => {:foo=>0, :bar=>100, :baz=>200}
|
1174
|
+
#
|
1175
|
+
# @return [self]
|
1176
|
+
def transform_values!(&block)
|
1177
|
+
return to_enum(:transform_values!) unless block
|
1178
|
+
|
1179
|
+
self if @ir.transform_values!(&block)
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
# @!method value?
|
1183
|
+
# Returns `true` if `value` is a value in `self`, otherwise `false`.
|
1184
|
+
#
|
1185
|
+
# @return [Boolean]
|
1186
|
+
|
1187
|
+
# @!method values
|
1188
|
+
# Returns a new Array containing all values in `self`.
|
1189
|
+
#
|
1190
|
+
# @example
|
1191
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
1192
|
+
# t.values # => [0, 1, 2]
|
1193
|
+
#
|
1194
|
+
# @return [Array]
|
1195
|
+
|
1196
|
+
# Returns a new Array containing values for the given transformed `keys`. The
|
1197
|
+
# default values are returned for any keys that are not found.
|
1198
|
+
#
|
1199
|
+
# @example
|
1200
|
+
# t = Tash[foo: 0, bar: 1, baz: 2]
|
1201
|
+
# t.values_at(:baz, :FOO) # => [2, 0]
|
1202
|
+
#
|
1203
|
+
# @example keys not found
|
1204
|
+
# t.values_at(:hello, :foo) # => [nil, 0]
|
1205
|
+
#
|
1206
|
+
# @return [Array]
|
1207
|
+
def values_at(*keys)
|
1208
|
+
@ir.values_at(*keys.map { |k| transform(k) })
|
1209
|
+
end
|
1210
|
+
|
1211
|
+
protected
|
1212
|
+
|
1213
|
+
attr_writer :ir
|
1214
|
+
|
1215
|
+
private
|
1216
|
+
|
1217
|
+
def transform(key)
|
1218
|
+
return key unless @transform
|
1219
|
+
|
1220
|
+
@transform.call(key)
|
1221
|
+
end
|
1222
|
+
|
1223
|
+
def new_from_self(new_ir)
|
1224
|
+
self.class.new(&@transform).tap { |tash| tash.ir = new_ir }
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
def current_ruby_version
|
1228
|
+
self.class.send(:current_ruby_version)
|
1229
|
+
end
|
1230
|
+
end
|