fun-ruby 0.0.1

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.
@@ -0,0 +1,559 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FunRuby
4
+ # Module containing methods for hashes
5
+ module Hash
6
+ include Common::Helpers
7
+
8
+ extend self
9
+
10
+ # Returns a value stored by a given key.
11
+ # If there is no given key it return a default value
12
+ #
13
+ # @since 0.1.0
14
+ #
15
+ # @param key [#hash, #eql?]
16
+ # @param hash [#to_h]
17
+ #
18
+ # @return [Object]
19
+ #
20
+ # @example Base
21
+ # hash = { age: 20, name: 'John' }
22
+ # F::Hash.get(:age, hash) # => 20
23
+ # F::Hash.get(:name, hash) # => 'John'
24
+ # F::Hash.get(:email, hash) # => nil
25
+ #
26
+ # @example Curried
27
+ # hash = { age: 20, name: 'John' }
28
+ # curried = F::Hash.get
29
+ # curried.(:age, hash) # => 20
30
+ # curried.(:name).(hash) # => 'John'
31
+ #
32
+ # @example Curried
33
+ # hash = { age: 20, name: 'John' }
34
+ # curried = F::Hash.get
35
+ # curried.(:age, hash) # => 20
36
+ # curried.(:name).(hash) # => 'John'
37
+ #
38
+ # @example Curried with placeholders
39
+ # hash = { age: 20, name: 'John' }
40
+ # curried = F::Hash.get(F._, hash)
41
+ # curried.(:age) # => 20
42
+ # curried.(:name) # => 'John'
43
+ def get(key = F._, hash = F._)
44
+ curry_implementation(:get, key, hash)
45
+ end
46
+
47
+ # Returns a value stored by a given key.
48
+ # If there is no given key it raises error
49
+ #
50
+ # @since 0.1.0
51
+ #
52
+ # @param key [#hash, #eql?]
53
+ # @param hash [#to_h]
54
+ #
55
+ # @return [Object]
56
+ #
57
+ # @raise KeyError
58
+ #
59
+ # @example Base
60
+ # hash = { age: 20, name: 'John' }
61
+ # F::Hash.fetch(:age, hash) # => 20
62
+ # F::Hash.fetch(:name, hash) # => 'John'
63
+ # F::Hash.fetch(:email, hash) # => raise KeyError, "key not found: :email"
64
+ #
65
+ # @example Curried
66
+ # hash = { age: 20, name: 'John' }
67
+ # curried = F::Hash.fetch
68
+ # curried.(:age, hash) # => 20
69
+ # curried.(:name).(hash) # => 'John'
70
+ # curried.(:email).(hash) # => raise KeyError, "key not found: :email"
71
+ #
72
+ # @example Curried with placeholders
73
+ # hash = { age: 20, name: 'John' }
74
+ # curried = F::Hash.fetch(F._, hash)
75
+ # curried.(:age) # => 20
76
+ # curried.(:name) # => 'John'
77
+ def fetch(key = F._, hash = F._)
78
+ curry_implementation(:fetch, key, hash)
79
+ end
80
+
81
+ # Returns a value stored by a given key.
82
+ # If there is no given key it calls a given fallback.
83
+ #
84
+ # @since 0.1.0
85
+ #
86
+ # @param key [#hash, #eql?]
87
+ # @param fallback [#to_call]
88
+ # @param hash [#to_h]
89
+ #
90
+ # @return [Object]
91
+ #
92
+ # @example Base
93
+ # hash = { age: 20, name: 'John' }
94
+ # F::Hash.fetch_with(:age, ->(_) { :fallback }, hash) # => 20
95
+ # F::Hash.fetch_with(:name, ->(_) { :fallback }, hash) # => 'John'
96
+ # F::Hash.fetch_with(:email, ->(_) { :fallback }, hash) # => :fallback
97
+ #
98
+ # @example Curried
99
+ # hash = { age: 20, name: 'John' }
100
+ # curried = F::Hash.fetch_with
101
+ # curried.(:age, ->(_) { :fallback }, hash) # => 20
102
+ # curried.(:name).(->(_) { :fallback }).(hash) # => 'John'
103
+ # curried.(:email).(->(_) { :fallback }).(hash) # => :fallback
104
+ #
105
+ # @example Curried with placeholders
106
+ # hash = { age: 20, name: 'John' }
107
+ # curried = F::Hash.fetch_with(F._, F._, F._)
108
+ # curried.(:age).(->(_) { :fallback }).(hash) # => 20
109
+ #
110
+ # curried = F::Hash.fetch_with(F._, ->(_) { :fallback }, F._)
111
+ # curried.(:age).(hash) # => 20
112
+ # curried.(:email).(hash) # => :fallback
113
+ def fetch_with(key = F._, fallback = F._, hash = F._)
114
+ curry_implementation(:fetch_with, key, fallback, hash)
115
+ end
116
+
117
+ # Puts a value by a given key.
118
+ # If the key is already taken the current value will be replaced.
119
+ #
120
+ # @since 0.1.0
121
+ #
122
+ # @param key [#hash, #eql?]
123
+ # @param value [Object]
124
+ # @param hash [#to_h]
125
+ #
126
+ # @return [Hash]
127
+ #
128
+ # @example Base
129
+ # hash = { name: "John" }
130
+ # F::Hash.put(:age, 20, hash) # => { name: "John", age: 20 }
131
+ # F::Hash.put(:name, "Peter", hash) # => { name: "Peter" }
132
+ #
133
+ # @example Curried
134
+ # hash = { name: "John" }
135
+ # curried = F::Hash.put
136
+ # curried.(:age).(20).(hash) # => { name: "John", age: 20 }
137
+ # curried.(:name).("Peter").(hash) # => { name: "Peter" }
138
+ #
139
+ # @example Curried with placeholders
140
+ # hash = { name: "John" }
141
+ # curried = F::Hash.put(F._, 20, hash)
142
+ # curried.(:age) # => { name: "John", age: 20 }
143
+ #
144
+ # curried = F::Hash.put(F._, 20, F._)
145
+ # curried.(:age).(hash) # => { name: "John", age: 20 }
146
+ #
147
+ # curried = F::Hash.put(:age, F._, hash)
148
+ # curried.(20) # => { name: "John", age: 20 }
149
+ def put(key = F._, value = F._, hash = F._)
150
+ curry_implementation(:put, key, value, hash)
151
+ end
152
+
153
+ # Merges two hashes. The key-value pairs from the second to the first.
154
+ # If the key is already taken the current value will be replaced.
155
+ #
156
+ # @since 0.1.0
157
+ #
158
+ # @param first [#to_h]
159
+ # @param second [#to_h]
160
+ #
161
+ # @return [Hash]
162
+ #
163
+ # @example Base
164
+ # first = { name: "John" }
165
+ # second = { age: 20 }
166
+ # F::Hash.merge(first, second) # => { name: "John", age: 20 }
167
+ #
168
+ # first = { name: "John" }
169
+ # second = { name: "Bill", age: 20 }
170
+ # F::Hash.merge(first, second) # => { name: "Bill", age: 20 }
171
+ #
172
+ # @example Curried
173
+ # first = { name: "John" }
174
+ # second = { age: 20 }
175
+ # curried = F::Hash.merge
176
+ # curried.(first).(second) # => { name: "John", age: 20 }
177
+ #
178
+ # first = { name: "John" }
179
+ # second = { name: "Bill", age: 20 }
180
+ # curried = F::Hash.merge
181
+ # curried.(first).(second) # => { name: "Bill", age: 20 }
182
+ #
183
+ # @example Curried with placeholders
184
+ # first = { name: "John" }
185
+ # second = { age: 20 }
186
+ # curried = F::Hash.merge(F._, F._)
187
+ # curried.(first).(second) # => { name: "John", age: 20 }
188
+ #
189
+ # first = { name: "John" }
190
+ # second = { name: "Bill", age: 20 }
191
+ # curried = F::Hash.merge(F._, second)
192
+ # curried.(first) # => { name: "Bill", age: 20 }
193
+ def merge(first = F._, second = F._)
194
+ curry_implementation(:merge, first, second)
195
+ end
196
+
197
+ # Builds a new hash with only given keys from a given hash.
198
+ # If keys are missed in the given hash the corresponded key will be absent
199
+ # in the result hash.
200
+ #
201
+ # @since 0.1.0
202
+ #
203
+ # @param keys [::Array of (#hash, #eql?)]
204
+ # @param hash [#to_h]
205
+ #
206
+ # @return [Hash]
207
+ #
208
+ # @example Base
209
+ # hash = { name: "John", age: 20, email: "john@gmail.com", country: "USA" }
210
+ #
211
+ # F::Hash.slice([:name, :age, :country], hash) # => { name: "John", age: 20, country: "USA" }
212
+ # F::Hash.slice([:name, :age, :address], hash) # => { name: "John", age: 20 }
213
+ #
214
+ # @example Curried
215
+ # hash = { name: "John", age: 20, email: "john@gmail.com", country: "USA" }
216
+ # curried = F::Hash.slice
217
+ #
218
+ # curried.([:name, :age, :country]).(hash) # => { name: "John", age: 20, country: "USA" }
219
+ # curried.([:name, :age, :address]).(hash) # => { name: "John", age: 20 }
220
+ #
221
+ # @example Curried with placeholders
222
+ # hash = { name: "John", age: 20, email: "john@gmail.com", country: "USA" }
223
+ #
224
+ # curried = F::Hash.slice(F._, hash)
225
+ # curried.([:name, :age, :country]) # => { name: "John", age: 20, country: "USA" }
226
+ # curried.([:name, :age, :address]) # => { name: "John", age: 20 }
227
+ def slice(keys = F._, hash = F._)
228
+ curry_implementation(:slice, keys, hash)
229
+ end
230
+
231
+ # Builds a new hash with only given keys from a given hash.
232
+ # If keys are missed in the given hash KeyError is raised
233
+ #
234
+ # @since 0.1.0
235
+ #
236
+ # @param keys [::Array of (#hash, #eql?)]
237
+ # @param hash [#to_h]
238
+ #
239
+ # @return [Hash]
240
+ #
241
+ # @example Base
242
+ # hash = { name: "John", age: 20, country: "USA" }
243
+ #
244
+ # F::Hash.slice!([:name, :age, :country], hash) # => { name: "John", age: 20, country: "USA" }
245
+ # F::Hash.slice!([:address, :email], hash) # => raise KeyError, "keys not found: [:address, :email]"
246
+ def slice!(keys = F._, hash = F._)
247
+ curry_implementation(:slice!, keys, hash)
248
+ end
249
+
250
+ # Returns an array of values stored by given keys
251
+ # If any key is missed in the given hash KeyError is raised with the first missed key
252
+ #
253
+ # @since 0.1.0
254
+ #
255
+ # @param keys [::Array of (#hash, #eql?)]
256
+ # @param hash [#to_h]
257
+ #
258
+ # @return [::Array[Object]]
259
+ #
260
+ # @example Base
261
+ # hash = { name: "John", age: 20, country: "USA" }
262
+ #
263
+ # F::Hash.fetch_values([:name, :age, :country], hash) # => ["John", 20, "USA"]
264
+ # F::Hash.fetch_values([:address, :email], hash) # => raise KeyError, "key not found: :address"
265
+ def fetch_values(keys = F._, hash = F._)
266
+ curry_implementation(:fetch_values, keys, hash)
267
+ end
268
+
269
+ # Returns an array of values stored by given keys
270
+ # If a key is missed the default value is returned
271
+ #
272
+ # @since 0.1.0
273
+ #
274
+ # @param keys [::Array of (#hash, #eql?)]
275
+ # @param hash [#to_h]
276
+ #
277
+ # @return [::Array[Object]]
278
+ #
279
+ # @example Base
280
+ # hash = { name: "John", age: 20, country: "USA" }
281
+ #
282
+ # F::Hash.values_at([:name, :age, :country], hash) # => ["John", 20, "USA"]
283
+ # F::Hash.values_at([:address, :email, :country, :age], hash) # => [nil, nil, "USA", 20]
284
+ def values_at(keys = F._, hash = F._)
285
+ curry_implementation(:values_at, keys, hash)
286
+ end
287
+
288
+ # Returns an array of all stored values
289
+ #
290
+ # @since 0.1.0
291
+ #
292
+ # @param hash [#to_h]
293
+ #
294
+ # @return [::Array[Object]]
295
+ #
296
+ # @example Base
297
+ # F::Hash.values({}) # => []
298
+ # F::Hash.values({ age: 33 }) # => [33]
299
+ # F::Hash.values({ age: 33, name: "John"}) # => [33, "John"]
300
+ def values(hash = F._)
301
+ curry_implementation(:values, hash)
302
+ end
303
+
304
+ # Returns an array of all stored keys
305
+ #
306
+ # @since 0.1.0
307
+ #
308
+ # @param hash [#to_h]
309
+ #
310
+ # @return [::Array[Object]]
311
+ #
312
+ # @example Base
313
+ # F::Hash.keys({}) # => []
314
+ # F::Hash.keys({ age: 33 }) # => [:age]
315
+ # F::Hash.keys({ age: 33, name: "John"}) # => [:age, :name]
316
+ def keys(hash = F._)
317
+ curry_implementation(:keys, hash)
318
+ end
319
+
320
+ # Returns a new hash containing only pairs
321
+ # for which a given function returns true
322
+ #
323
+ # @since 0.1.0
324
+ #
325
+ # @param function [#call/2]
326
+ # @param hash [#to_h]
327
+ #
328
+ # @return [::Array[Object]]
329
+ #
330
+ # @example Base
331
+ # hash = { 'a' => 1, 'b' => 2, :c => 3, :d => 4 }
332
+ # F::Hash.select(->(key, _value) { key.is_a?(String) }, hash) # => { 'a' => 1, 'b' => 2 }
333
+ # F::Hash.select(->(_key, value) { value.odd? }, hash) # => { 'a' => 1, :c => 3 }
334
+ def select(function = F._, hash = F._)
335
+ curry_implementation(:select, function, hash)
336
+ end
337
+
338
+ # Returns a new hash excluding pairs
339
+ # for which a given function returns true
340
+ #
341
+ # @since 0.1.0
342
+ #
343
+ # @param function [#call/2]
344
+ # @param hash [#to_h]
345
+ #
346
+ # @return [::Array[Object]]
347
+ #
348
+ # @example Base
349
+ # hash = { 'a' => 1, 'b' => 2, :c => 3, :d => 4 }
350
+ # F::Hash.reject(->(key, _value) { key.is_a?(String) }, hash) # => { :c => 3, :d => 4 }
351
+ # F::Hash.reject(->(_key, value) { value.odd? }, hash) # => { 'b' => 2, :d =>4 }
352
+ def reject(function = F._, hash = F._)
353
+ curry_implementation(:reject, function, hash)
354
+ end
355
+
356
+ # Returns a value stored by a given chain of keys.
357
+ # If a value of any level key of the chain is not found nil is returned.
358
+ #
359
+ # @since 0.1.0
360
+ #
361
+ # @param keys [::Array of (#hash, #eql?)]
362
+ # @param hash [#to_h]
363
+ # @return [::Array[Object]]
364
+ #
365
+ # @example Base
366
+ # hash = { a: { b: { c: 3 } } }
367
+ # F::Hash.dig([:a], hash) # => { b: { c: 3 } }
368
+ # F::Hash.dig([:a, :b], hash) # => { c: 3 }
369
+ # F::Hash.dig([:a, :b, :c], hash) # => 3
370
+ # F::Hash.dig([:foo], hash) # => nil
371
+ # F::Hash.dig([:a, :foo], hash) # => nil
372
+ # F::Hash.dig([:a, :b, :foo], hash) # => nil
373
+ def dig(keys = F._, hash = F._)
374
+ curry_implementation(:dig, keys, hash)
375
+ end
376
+
377
+ # Returns a value stored by a given chain of keys.
378
+ # If a value of any level key of the chain is not found KeyError is raised
379
+ #
380
+ # @since 0.1.0
381
+ #
382
+ # @param keys [::Array of (#hash, #eql?)]
383
+ # @param hash [#to_h]
384
+ # @return [::Array[Object]]
385
+ #
386
+ # @example Base
387
+ # hash = { a: { b: { c: 3 } } }
388
+ # F::Hash.dig!([:a], hash) # => { b: { c: 3 } }
389
+ # F::Hash.dig!([:a, :b], hash) # => { c: 3 }
390
+ # F::Hash.dig!([:a, :b, :c], hash) # => 3
391
+ # F::Hash.dig!([:foo], hash) # => raise KeyError, "key not found: :foo"
392
+ # F::Hash.dig!([:a, :foo], hash) # => raise KeyError, "key not found: :foo"
393
+ # F::Hash.dig!([:a, :b, :foo], hash) # => raise KeyError, "key not found: :foo"
394
+ def dig!(keys = F._, hash = F._)
395
+ curry_implementation(:dig!, keys, hash)
396
+ end
397
+
398
+ # Returns a new hash without all key-valued pairs
399
+ #
400
+ # @since 0.1.0
401
+ #
402
+ # @param hash [#to_h]
403
+ #
404
+ # @example Base
405
+ # hash = { name: "John", age: 18, email: nil, country: nil }
406
+ # F::Hash.compact(hash) # => { name: "John", age: 18 }
407
+ def compact(keys = F._, hash = F._)
408
+ curry_implementation(:compact, keys, hash)
409
+ end
410
+
411
+ # Returns a new hash with updated keys calculated
412
+ # as a result returned from a given function
413
+ #
414
+ # @since 0.1.0
415
+ #
416
+ # @param function [#call/1]
417
+ # @param hash [#to_h]
418
+ #
419
+ # @example Base
420
+ # hash = { a: 1, b: 2, c: 3 }
421
+ # F::Hash.transform_keys(->(key) { key.to_s }, hash) #=> { 'a' => 1, 'b' => 2, 'c' => 3 }
422
+ def transform_keys(function = F._, hash = F._)
423
+ curry_implementation(:transform_keys, function, hash)
424
+ end
425
+
426
+ # Returns a new hash with updated values calculated
427
+ # as a result returned from a given function
428
+ #
429
+ # @since 0.1.0
430
+ #
431
+ # @param function [#call/1]
432
+ # @param hash [#to_h]
433
+ #
434
+ # @example Base
435
+ # hash = { a: 1, b: 2, c: 3 }
436
+ # F::Hash.transform_values(->(value) { value.to_s }, hash) #=> { a: '1', b: '2', c: '3' }
437
+ def transform_values(function = F._, hash = F._)
438
+ curry_implementation(:transform_values, function, hash)
439
+ end
440
+
441
+ private
442
+
443
+ def _get(key, hash)
444
+ _hash(hash)[key]
445
+ end
446
+
447
+ def _fetch(key, hash)
448
+ _hash(hash).fetch(key)
449
+ end
450
+
451
+ def _fetch_with(key, fallback, hash)
452
+ _hash(hash).fetch(key, &fallback)
453
+ end
454
+
455
+ def _put(key, value, hash)
456
+ _hash(hash).merge(key => value)
457
+ end
458
+
459
+ def _merge(first, second)
460
+ _hash(first).merge(_hash(second))
461
+ end
462
+
463
+ if RUBY_VERSION >= "2.5"
464
+ def _slice(keys, hash)
465
+ _hash(hash).slice(*keys)
466
+ end
467
+ else
468
+ def _slice(keys, hash)
469
+ hash = _hash(hash)
470
+ keys.each_with_object({}) do |key, new_hash|
471
+ new_hash[key] = hash[key] if hash.key?(key)
472
+ end
473
+ end
474
+ end
475
+
476
+ def _slice!(keys, hash)
477
+ hash = _hash(hash)
478
+ missed_keys = keys - hash.keys
479
+ raise KeyError, "keys not found: #{missed_keys.inspect}" if missed_keys.any?
480
+
481
+ _slice(keys, hash)
482
+ end
483
+
484
+ def _fetch_values(keys, hash)
485
+ _hash(hash).fetch_values(*keys)
486
+ end
487
+
488
+ def _values_at(keys, hash)
489
+ _hash(hash).values_at(*keys)
490
+ end
491
+
492
+ def _values(hash)
493
+ _hash(hash).values
494
+ end
495
+
496
+ def _keys(hash)
497
+ _hash(hash).keys
498
+ end
499
+
500
+ def _select(function, hash)
501
+ _hash(hash).select(&function)
502
+ end
503
+
504
+ def _reject(function, hash)
505
+ _hash(hash).reject(&function)
506
+ end
507
+
508
+ def _dig(keys, hash)
509
+ _hash(hash).dig(*keys)
510
+ end
511
+
512
+ def _dig!(keys, hash)
513
+ hash = _hash(hash)
514
+ keys.reduce(hash) { |current, key| current.fetch(key) }
515
+ end
516
+
517
+ if RUBY_VERSION >= "2.4"
518
+ def _compact(hash)
519
+ _hash(hash).compact
520
+ end
521
+ else
522
+ def _compact(hash)
523
+ _hash(hash).reject { |_key, value| value.nil? }
524
+ end
525
+ end
526
+
527
+ if RUBY_VERSION >= "2.5"
528
+ def _transform_keys(function, hash)
529
+ _hash(hash).transform_keys(&function)
530
+ end
531
+ else
532
+ def _transform_keys(function, hash)
533
+ hash = _hash(hash)
534
+ hash.each_with_object({}) do |(key, value), new_hash|
535
+ new_key = function.(key)
536
+ new_hash[new_key] = value
537
+ end
538
+ end
539
+ end
540
+
541
+ if RUBY_VERSION >= "2.4"
542
+ def _transform_values(function, hash)
543
+ _hash(hash).transform_values(&function)
544
+ end
545
+ else
546
+ def _transform_values(function, hash)
547
+ hash = _hash(hash)
548
+ hash.each_with_object({}) do |(key, value), new_hash|
549
+ new_value = function.(value)
550
+ new_hash[key] = new_value
551
+ end
552
+ end
553
+ end
554
+
555
+ def _hash(hash)
556
+ hash.to_h
557
+ end
558
+ end
559
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "common/helpers"
4
+
5
+ module FunRuby
6
+ # Module containing methods for strings
7
+ module String
8
+ include Common::Helpers
9
+
10
+ extend self
11
+
12
+ # Split a string by a passed delimiter
13
+ #
14
+ # @since 0.1.0
15
+ #
16
+ # @param splitter [::Array|::Regexp]
17
+ # @param string [::String]
18
+ #
19
+ # @return [::Array[::String]]
20
+ #
21
+ # @example Basics
22
+ # F::String.split("+", "1+2+3") #=> ["1", "2", "3"]
23
+ #
24
+ # @example Curried
25
+ # curried = F::String.split
26
+ # curried.("+").("1+2+3") #=> ["1", "2", "3"]
27
+ #
28
+ # @example Curried with placeholder
29
+ # curried = F::String.split(F._, "1+2+3")
30
+ # curried.("+") #=> ["1", "2", "3"]
31
+ def split(splitter = F._, string = F._)
32
+ curry_implementation(:split, splitter, string)
33
+ end
34
+
35
+ # Concats a string by a passed delimiter
36
+ #
37
+ # @since 0.1.0
38
+ #
39
+ # @param first [::String]
40
+ # @param second [::String]
41
+ #
42
+ # @return [::String]
43
+ #
44
+ # @example Basics
45
+ # F::String.concat("123", "456") #=> "123456"
46
+ #
47
+ # @example Curried
48
+ # curried = F::String.concat
49
+ # curried.("123").("456") #=> "123456"
50
+ #
51
+ # @example Curried with placeholder
52
+ # curried = F::String.concat(F._, "456")
53
+ # curried.("123") #=> "123456"
54
+ def concat(first = F._, second = F._)
55
+ curry_implementation(:concat, first, second)
56
+ end
57
+
58
+ private
59
+
60
+ def _split(splitter, string)
61
+ _string(string).split(splitter)
62
+ end
63
+
64
+ def _concat(first, second)
65
+ _string(first) + _string(second)
66
+ end
67
+
68
+ def _string(string)
69
+ string.to_s
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FunRuby
4
+ VERSION = "0.0.1"
5
+ end