rb-kgy-fp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/rb-kgy-fp/curry_fun.rb +351 -0
- data/lib/rb-kgy-fp/fun.rb +378 -0
- data/lib/rb-kgy-fp/lib.rb +1 -0
- data/lib/rb-kgy-fp/special.rb +27 -0
- data/lib/rb-kgy-fp/std_ext/array.rb +25 -0
- data/lib/rb-kgy-fp/std_ext/string.rb +19 -0
- data/lib/rb-kgy-fp/trait/alternative.rb +14 -0
- data/lib/rb-kgy-fp/trait/applicative.rb +32 -0
- data/lib/rb-kgy-fp/trait/bi_functor.rb +19 -0
- data/lib/rb-kgy-fp/trait/functor.rb +15 -0
- data/lib/rb-kgy-fp/trait/monad.rb +20 -0
- data/lib/rb-kgy-fp/trait/monoid.rb +24 -0
- data/lib/rb-kgy-fp/trait/semi_group.rb +8 -0
- data/lib/rb-kgy-fp/typeclass/either.rb +114 -0
- data/lib/rb-kgy-fp/typeclass/maybe.rb +113 -0
- data/lib/rb-kgy-fp/typeclass/reader.rb +64 -0
- data/lib/rb-kgy-fp/typeclass/state.rb +63 -0
- data/lib/rb-kgy-fp/typeclass/writer.rb +53 -0
- metadata +61 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1d187603140145361013f2277fb3d89ec9a2a49373a5b1d2d0839e48f9b53f48
|
4
|
+
data.tar.gz: 1eb4b34145b0ac7ce815cd4c4d55e4f82bb10b3469705ff4dd28fcc5e80a00f0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b4bfb2827314527f15092992d70c25332c703660a85c14f5038a0179667190c0773a9d0341a51ed78491a4119ab3fbc117bf954c2056090874360a128582ff75
|
7
|
+
data.tar.gz: 1ddb718352d5eaf953c21280573b1086a00da7b0d627d46c1130f66f6db995df7985928f2c85f23115ec672b16553421b16c493ecff5554609e0e9e94c49acf6
|
@@ -0,0 +1,351 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lib/special'
|
4
|
+
|
5
|
+
PH = Special::PH
|
6
|
+
OPT = Special::OPT
|
7
|
+
|
8
|
+
module CurryFun
|
9
|
+
def self.eq?(t, u = PH)
|
10
|
+
if u == PH
|
11
|
+
->(u) { eq? t, u }
|
12
|
+
else
|
13
|
+
t == u
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.ne?(t, u = PH)
|
18
|
+
if u == PH
|
19
|
+
->(u) { ne? t, u }
|
20
|
+
else
|
21
|
+
t != u
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.gt?(t, u = PH)
|
26
|
+
if u == PH
|
27
|
+
->(u) { gt? t, u }
|
28
|
+
elsif t.respond_to? :>
|
29
|
+
t > u
|
30
|
+
else
|
31
|
+
(t <=> u) == 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.ge?(t, u = PH)
|
36
|
+
if u == PH
|
37
|
+
->(u) { ge? t, u }
|
38
|
+
elsif t.respond_to? :>=
|
39
|
+
t >= u
|
40
|
+
else
|
41
|
+
(t <=> u) >= 0
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.lt?(t, u = PH)
|
46
|
+
if u == PH
|
47
|
+
->(u) { lt? t, u }
|
48
|
+
elsif t.respond_to? :<
|
49
|
+
t < u
|
50
|
+
else
|
51
|
+
(t <=> u) == -1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.le?(t, u = PH)
|
56
|
+
if u == PH
|
57
|
+
->(u) { le? t, u }
|
58
|
+
elsif t.respond_to? :<=
|
59
|
+
t <= u
|
60
|
+
else
|
61
|
+
(t <=> u) <= 0
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.const(a, _ = PH)
|
66
|
+
if _ == PH
|
67
|
+
->(_) { a }
|
68
|
+
else
|
69
|
+
a
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.pipe(*fns)
|
74
|
+
->(arg) { fns.reduce(arg) { |acc, fn| fn.(acc) } }
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.compose(*fns)
|
78
|
+
->(arg) { fns.reverse.reduce(arg) { |acc, fn| fn.(acc) } }
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.not? & fn
|
82
|
+
->(*args, **kwargs) { !fn.(*args, **kwargs) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.nil_or fallback, value = PH
|
86
|
+
if value == PH
|
87
|
+
->(value) { nil_or fallback, value }
|
88
|
+
else
|
89
|
+
value.nil? ? fallback : value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.nil_or_else get_fallback: OPT, value: PH, &blk
|
94
|
+
if (!blk && get_fallback == OPT) || (blk && get_fallback.class == Proc)
|
95
|
+
raise ArgumentError.new "Either get_fallback or blk must be provided"
|
96
|
+
end
|
97
|
+
_fn = blk || get_fallback
|
98
|
+
if value == PH
|
99
|
+
->(value) { nil_or_else get_fallback: _fn, value: value }
|
100
|
+
else
|
101
|
+
value.nil? ? _fn.() : value
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.not_nil_or fallback, value = PH
|
106
|
+
if value == PH
|
107
|
+
->(value) { not_nil_or fallback, value }
|
108
|
+
else
|
109
|
+
value.nil? ? value : fallback
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.not_nil_or_else get_fallback: OPT, value: PH, &blk
|
114
|
+
if (!blk && get_fallback == OPT) || (blk && get_fallback.class == Proc)
|
115
|
+
raise ArgumentError.new "Either get_fallback or blk must be provided"
|
116
|
+
end
|
117
|
+
_fn = blk || get_fallback
|
118
|
+
if value == PH
|
119
|
+
->(value) { not_nil_or_else get_fallback: _fn, value: value }
|
120
|
+
else
|
121
|
+
value.nil? ? value : _fn.()
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.not_nil_map mapper: OPT, value: PH, &blk
|
126
|
+
if (!blk && mapper == OPT) || (blk && (mapper.class == Proc || mapper.class == Symbol))
|
127
|
+
raise ArgumentError.new "Either mapper or blk must be provided"
|
128
|
+
end
|
129
|
+
_fn = blk || (mapper.class == Proc ? mapper : ->(obj) { obj.method(mapper).() })
|
130
|
+
if value == PH
|
131
|
+
->(value) { not_nil_map mapper: _fn, value: value }
|
132
|
+
else
|
133
|
+
value.nil? ? value : _fn.(value)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.add a, b = PH
|
138
|
+
if b == PH
|
139
|
+
->(b) { add a, b }
|
140
|
+
else
|
141
|
+
a + b
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.minus a, b = PH
|
146
|
+
if b == PH
|
147
|
+
->(b) { minus a, b }
|
148
|
+
else
|
149
|
+
a - b
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.mul a, b = PH
|
154
|
+
if b == PH
|
155
|
+
->(b) { mul a, b }
|
156
|
+
else
|
157
|
+
a * b
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.div a, b = PH
|
162
|
+
if b == PH
|
163
|
+
->(b) { div a, b }
|
164
|
+
else
|
165
|
+
a / b
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.mod a, b = PH
|
170
|
+
if b == PH
|
171
|
+
->(b) { mod a, b }
|
172
|
+
else
|
173
|
+
a % b
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def self.flip a, b = PH, &fn
|
178
|
+
if b == PH && !fn
|
179
|
+
->(b = PH, &fn) { flip(a, b, &fn) }
|
180
|
+
elsif b == PH && fn
|
181
|
+
->(b) { flip(a, b, &fn) }
|
182
|
+
elsif b != PH && !fn
|
183
|
+
->(&fn) { flip(a, b, &fn) }
|
184
|
+
else
|
185
|
+
fn.(b, a)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.all? fn: OPT, args: PH, &blk
|
190
|
+
if (fn == OPT && !blk) || ((fn.class == Proc || fn.class == Symbol) && blk)
|
191
|
+
raise ArgumentError.new("Either fn or blk must be provided")
|
192
|
+
end
|
193
|
+
_fn = blk || (fn.class == Proc ? fn : ->(obj) { obj.method(fn).() })
|
194
|
+
if args == PH
|
195
|
+
->(*args) { all?(fn: _fn, args: args) }
|
196
|
+
else
|
197
|
+
args.reduce(true) { |result, arg| result && _fn.(arg) }
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def self.any? fn: OPT, args: PH, &blk
|
202
|
+
if (fn == OPT && !blk) || ((fn.class == Proc || fn.class == Symbol) && blk)
|
203
|
+
raise ArgumentError.new("Either fn or blk must be provided")
|
204
|
+
end
|
205
|
+
_fn = blk || (fn.class == Proc ? fn : ->(obj) { obj.method(fn).() })
|
206
|
+
if args == PH
|
207
|
+
->(*args) { any?(fn: _fn, args: args) }
|
208
|
+
else
|
209
|
+
args.reduce(false) { |result, arg| result || _fn.(arg) }
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.and? a, b = PH
|
214
|
+
if b == PH
|
215
|
+
->(b) { and?(a, b) }
|
216
|
+
else
|
217
|
+
a && b
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def self.or? a, b = PH
|
222
|
+
if b == PH
|
223
|
+
->(b) { or?(a, b) }
|
224
|
+
else
|
225
|
+
a || b
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def self.xor? a, b = PH
|
230
|
+
if b == PH
|
231
|
+
->(b) { xor? a, b }
|
232
|
+
else
|
233
|
+
(!a && b) || (a && !b)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def self.clamp lower, upper = PH, value = PH
|
238
|
+
if upper == PH
|
239
|
+
->(upper = PH, value = PH) { clamp lower, upper, value }
|
240
|
+
elsif value == PH
|
241
|
+
->(value) { clamp lower, upper, value }
|
242
|
+
else
|
243
|
+
if lower > value
|
244
|
+
lower
|
245
|
+
elsif upper < value
|
246
|
+
upper
|
247
|
+
else
|
248
|
+
value
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def self.cond cond_mappers
|
254
|
+
-> (*args, **kwargs) {
|
255
|
+
return nil if args.length == 0 && kwargs.size == 0
|
256
|
+
cond_mappers.each do |fns|
|
257
|
+
fns => [cond, mapper]
|
258
|
+
return mapper.(*args, **kwargs) if cond.(*args, **kwargs)
|
259
|
+
end
|
260
|
+
nil
|
261
|
+
}
|
262
|
+
end
|
263
|
+
|
264
|
+
def self.desc(&comparator)
|
265
|
+
-> (values) {
|
266
|
+
if values.class == Hash
|
267
|
+
Hash[values.sort_by { |k, v| comparator.(k, v) }.reverse]
|
268
|
+
elsif values.class == Array
|
269
|
+
values.sort_by { |v| comparator.(v) }.reverse
|
270
|
+
end
|
271
|
+
}
|
272
|
+
end
|
273
|
+
|
274
|
+
def self.asc(&comparator)
|
275
|
+
-> (values) {
|
276
|
+
if values.class == Hash
|
277
|
+
Hash[values.sort_by { |k, v| comparator.(k, v) }]
|
278
|
+
elsif values.class == Array
|
279
|
+
values.sort_by { |v| comparator.(v) }
|
280
|
+
end
|
281
|
+
}
|
282
|
+
end
|
283
|
+
|
284
|
+
def self.diff obj1, obj2 = PH
|
285
|
+
if obj2 == PH
|
286
|
+
->(obj2) { diff obj1, obj2 }
|
287
|
+
else
|
288
|
+
get_diff = ->(arr1, arr2) {
|
289
|
+
arr1.size > arr2.size ? arr1 - arr2 : arr2 - arr1
|
290
|
+
}
|
291
|
+
if obj1.class != obj2.class
|
292
|
+
raise ArgumentError.new "obj1 is not same type with obj2"
|
293
|
+
elsif obj1.class == Hash
|
294
|
+
diff = get_diff.(obj1.to_a, obj2.to_a)
|
295
|
+
Hash[*diff.flatten]
|
296
|
+
else
|
297
|
+
get_diff.(obj1, obj2)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def self.intersect obj1, obj2 = PH
|
303
|
+
if obj2 == PH
|
304
|
+
->(obj2) { intersect obj1, obj2 }
|
305
|
+
else
|
306
|
+
get_inte = ->(arr1, arr2) {
|
307
|
+
arr1.size > arr2.size ? arr1 - (arr1 - arr2) : arr2 - (arr2 - arr1)
|
308
|
+
}
|
309
|
+
if obj1.class != obj2.class
|
310
|
+
raise ArgumentError.new "obj1 is not same type with obj2"
|
311
|
+
elsif obj1.class == Hash
|
312
|
+
inte = get_inte.(obj1.to_a, obj2.to_a)
|
313
|
+
Hash[*inte.flatten]
|
314
|
+
else
|
315
|
+
get_inte.(obj1, obj2)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def self.non_intersect obj1, obj2 = PH
|
321
|
+
if obj2 == PH
|
322
|
+
->(obj2) { non_intersect obj1, obj2 }
|
323
|
+
else
|
324
|
+
if obj1.class != obj2.class
|
325
|
+
raise ArgumentError.new "obj1 is not same type with obj2"
|
326
|
+
elsif obj1.class == Hash
|
327
|
+
left = obj1.to_a - obj2.to_a
|
328
|
+
right = obj2.to_a - obj1.to_a
|
329
|
+
Hash[*left.flatten, *right.flatten]
|
330
|
+
else
|
331
|
+
left = obj1 - obj2
|
332
|
+
right = obj2 - obj1
|
333
|
+
(left + right).uniq
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def self.union obj1, obj2 = PH
|
339
|
+
if obj2 == PH
|
340
|
+
->(obj2) { union obj1, obj2 }
|
341
|
+
else
|
342
|
+
if obj1.class != obj2.class
|
343
|
+
raise ArgumentError.new "obj1 is not same type with obj2"
|
344
|
+
elsif obj1.class == Hash
|
345
|
+
obj1.merge(obj2)
|
346
|
+
else
|
347
|
+
(obj1 + obj2).uniq
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
@@ -0,0 +1,378 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fun
|
4
|
+
def self.eq?(a, b)
|
5
|
+
a == b
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.ne?(a, b)
|
9
|
+
a != b
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.gt?(a, b)
|
13
|
+
if a.respond_to?(:>)
|
14
|
+
a > b
|
15
|
+
else
|
16
|
+
(a <=> b) == 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.ge?(a, b)
|
21
|
+
if a.respond_to?(:>=)
|
22
|
+
a >= b
|
23
|
+
else
|
24
|
+
(a <=> b) >= 0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.lt?(a, b)
|
29
|
+
if a.respond_to?(:<)
|
30
|
+
a < b
|
31
|
+
else
|
32
|
+
(a <=> b) == -1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.le?(a, b)
|
37
|
+
if a.respond_to?(:<=)
|
38
|
+
a <= b
|
39
|
+
else
|
40
|
+
(a <=> b) <= 0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.id t
|
45
|
+
t
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.const(a, _)
|
49
|
+
a
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.pipe(arg, *fns)
|
53
|
+
fns.reduce(arg) { |acc, fn| fn.(acc) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.compose(arg, *fns)
|
57
|
+
fns.reverse.reduce(arg) { |acc, fn| fn.(acc) }
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.not?(fn, *args, **kwargs)
|
61
|
+
!fn.(*args, **kwargs)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.nil_or(value, fallback)
|
65
|
+
value.nil? ? fallback : value
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.nil_or_else(value, &get_fallback)
|
69
|
+
if value.nil?
|
70
|
+
get_fallback.()
|
71
|
+
else
|
72
|
+
value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.not_nil_or(value, fallback)
|
77
|
+
if !value.nil?
|
78
|
+
fallback
|
79
|
+
else
|
80
|
+
value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.not_nil_or_else(value, &get_fallback)
|
85
|
+
if !value.nil?
|
86
|
+
get_fallback.()
|
87
|
+
else
|
88
|
+
value
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.not_nil_map(value, &mapper)
|
93
|
+
value.nil? ? value : mapper.(value)
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.add(a, b)
|
97
|
+
a + b
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.minus(a, b)
|
101
|
+
a - b
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.mul(a, b)
|
105
|
+
a * b
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.div(a, b)
|
109
|
+
a / b
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.mod(a, b)
|
113
|
+
a % b
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.flip(b, a, &fn)
|
117
|
+
fn.(a, b)
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.all?(fst, *snd)
|
121
|
+
if fst.class == Proc
|
122
|
+
snd.all?(&fst)
|
123
|
+
else
|
124
|
+
snd.reduce(true) { |result, fn| result && fn.(fst) }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.any?(fst, *snd)
|
129
|
+
if fst.class == Proc
|
130
|
+
snd.all?(&fst)
|
131
|
+
else
|
132
|
+
snd.reduce(false) { |result, fn| result || fn.(fst) }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.clamp(lower, upper, value)
|
137
|
+
if lower > value
|
138
|
+
lower
|
139
|
+
elsif upper < value
|
140
|
+
upper
|
141
|
+
else
|
142
|
+
value
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.cond(cond_mappers, *args, **kwargs)
|
147
|
+
return nil if args.length == 0 && kwargs.size == 0
|
148
|
+
cond_mappers.each { |fns|
|
149
|
+
fns => [cond, mapper]
|
150
|
+
return mapper.(*args, **kwargs) if cond.(*args, **kwargs)
|
151
|
+
}
|
152
|
+
nil
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.curry(&fn)
|
156
|
+
require "special"
|
157
|
+
|
158
|
+
req = 1 << 0
|
159
|
+
opt = 1 << 1
|
160
|
+
rest = 1 << 2
|
161
|
+
kreq = 1 << 3
|
162
|
+
kopt = 1 << 4
|
163
|
+
krest = 1 << 5
|
164
|
+
block = 1 << 6
|
165
|
+
|
166
|
+
core = ->(this, fn, c_params = [], c_remain_param_count = 0) do
|
167
|
+
->(*args, **kwargs, &proc) do
|
168
|
+
cp_c_params = Marshal.load(Marshal.dump(c_params)) # use serialization to ensure whole operation is pure
|
169
|
+
cp_c_remain_param_count = c_remain_param_count
|
170
|
+
arg_idx = 0
|
171
|
+
_kwargs = { **kwargs }
|
172
|
+
|
173
|
+
(0...cp_c_params.length).each { |i|
|
174
|
+
param = cp_c_params[i]
|
175
|
+
filled = param[:value] != Special::PH && param[:value] != Special::OPT
|
176
|
+
|
177
|
+
if (param[:type] & (req | opt)) != 0 && !filled
|
178
|
+
param[:value] = args[arg_idx]
|
179
|
+
arg_idx += 1
|
180
|
+
cp_c_remain_param_count -= 1 if param[:type] == req
|
181
|
+
end
|
182
|
+
|
183
|
+
if (param[:type] & (kreq | kopt) != 0) && !filled && _kwargs[param[:name]] != nil
|
184
|
+
param[:value] = _kwargs.delete(param[:name])
|
185
|
+
cp_c_remain_param_count -= 1 if param[:type] == kreq
|
186
|
+
end
|
187
|
+
|
188
|
+
if param[:type] == block && !filled && proc
|
189
|
+
param[:value] = proc
|
190
|
+
cp_c_remain_param_count -= 1
|
191
|
+
end
|
192
|
+
}
|
193
|
+
|
194
|
+
if args.length >= arg_idx + 1 && cp_c_params.any? { |p| p[:type] == rest }
|
195
|
+
cp_c_params.find { |p| p[:type] == rest }[:value] = args[arg_idx, args.length]
|
196
|
+
end
|
197
|
+
|
198
|
+
if _kwargs.length > 0 && cp_c_params.any? { |p| p[:type] == krest }
|
199
|
+
cp_c_params.find { |p| p[:type] == krest }[:value] = _kwargs
|
200
|
+
end
|
201
|
+
|
202
|
+
if cp_c_remain_param_count == 0
|
203
|
+
_params = []
|
204
|
+
_kparams = {}
|
205
|
+
_proc = nil
|
206
|
+
cp_c_params.each do |param|
|
207
|
+
case param[:type]
|
208
|
+
when req, opt
|
209
|
+
_params << param[:value] if param[:value] != Special::OPT && param[:value] != Special::PH
|
210
|
+
when kreq, kopt
|
211
|
+
_kparams[param[:name]] = param[:value] if param[:value] != Special::OPT && param[:value] != Special::PH
|
212
|
+
when rest
|
213
|
+
_params.push(*param[:value])
|
214
|
+
when krest
|
215
|
+
_kparams.update(param[:value])
|
216
|
+
when proc
|
217
|
+
_proc = param[:value]
|
218
|
+
end
|
219
|
+
end
|
220
|
+
if _proc
|
221
|
+
fn.(*_params, **_kparams, &_proc)
|
222
|
+
else
|
223
|
+
fn.(*_params, **_kparams)
|
224
|
+
end
|
225
|
+
else
|
226
|
+
this.(this, fn, cp_c_params, cp_c_remain_param_count)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
params = []
|
232
|
+
remain_param_count = 0
|
233
|
+
|
234
|
+
# check params
|
235
|
+
fn.parameters.each do |detail|
|
236
|
+
detail => [type, name]
|
237
|
+
case type
|
238
|
+
when :req
|
239
|
+
params << { name: name, value: Special::PH, type: req }
|
240
|
+
remain_param_count += 1
|
241
|
+
when :opt
|
242
|
+
params << { name: name, value: Special::OPT, type: opt }
|
243
|
+
when :rest
|
244
|
+
params << { name: name, type: rest }
|
245
|
+
when :keyreq
|
246
|
+
params << { name: name, value: Special::PH, type: kreq }
|
247
|
+
remain_param_count += 1
|
248
|
+
when :key
|
249
|
+
params << { name: name, value: Special::OPT, type: kopt }
|
250
|
+
when :keyrest
|
251
|
+
params << { name: name, type: krest }
|
252
|
+
when :block
|
253
|
+
params << { name: name, value: Special::PH, type: block }
|
254
|
+
remain_param_count += 1
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
core.(core, fn, params, remain_param_count)
|
259
|
+
end
|
260
|
+
|
261
|
+
def self.dec n
|
262
|
+
n - 1
|
263
|
+
end
|
264
|
+
|
265
|
+
def self.inc n
|
266
|
+
n + 1
|
267
|
+
end
|
268
|
+
|
269
|
+
def self.desc(values, &comparator)
|
270
|
+
if values.class == Hash
|
271
|
+
Hash[values.sort_by { |k, v| comparator.(k, v) }.reverse]
|
272
|
+
elsif values.class == Array
|
273
|
+
values.sort_by { |v| comparator.(v) }.reverse
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def self.asc(values, &comparator)
|
278
|
+
if values.class == Hash
|
279
|
+
Hash[values.sort_by { |k, v| comparator.(k, v) }]
|
280
|
+
elsif values.class == Array
|
281
|
+
values.sort_by { |v| comparator.(v) }
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def self.to_sym s
|
286
|
+
s.to_sym
|
287
|
+
end
|
288
|
+
|
289
|
+
def self.diff(obj1, obj2)
|
290
|
+
get_diff = ->(arr1, arr2) {
|
291
|
+
arr1.size > arr2.size ? arr1 - arr2 : arr2 - arr1
|
292
|
+
}
|
293
|
+
if obj1.class != obj2.class
|
294
|
+
raise ArgumentError.new "obj1 is not same type with obj2"
|
295
|
+
elsif obj1.class == Hash
|
296
|
+
diff = get_diff.(obj1.to_a, obj2.to_a)
|
297
|
+
Hash[*diff.flatten]
|
298
|
+
else
|
299
|
+
get_diff.(obj1, obj2)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def self.intersect(obj1, obj2)
|
304
|
+
get_inte = ->(arr1, arr2) {
|
305
|
+
arr1.size > arr2.size ? arr1 - (arr1 - arr2) : arr2 - (arr2 - arr1)
|
306
|
+
}
|
307
|
+
if obj1.class != obj2.class
|
308
|
+
raise ArgumentError.new "obj1 is not same type with obj2"
|
309
|
+
elsif obj1.class == Hash
|
310
|
+
inte = get_inte.(obj1.to_a, obj2.to_a)
|
311
|
+
Hash[*inte.flatten]
|
312
|
+
else
|
313
|
+
get_inte.(obj1, obj2)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def self.non_intersect(obj1, obj2)
|
318
|
+
if obj1.class != obj2.class
|
319
|
+
raise ArgumentError.new "obj1 is not same type with obj2"
|
320
|
+
elsif obj1.class == Hash
|
321
|
+
left = obj1.to_a - obj2.to_a
|
322
|
+
right = obj2.to_a - obj1.to_a
|
323
|
+
Hash[*left.flatten, *right.flatten]
|
324
|
+
else
|
325
|
+
left = obj1 - obj2
|
326
|
+
right = obj2 - obj1
|
327
|
+
(left + right).uniq
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def self.union(obj1, obj2)
|
332
|
+
if obj1.class != obj2.class
|
333
|
+
raise ArgumentError.new "obj1 is not same type with obj2"
|
334
|
+
elsif obj1.class == Hash
|
335
|
+
obj1.merge(obj2)
|
336
|
+
else
|
337
|
+
(obj1 + obj2).uniq
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def self.empty obj
|
342
|
+
case obj.class.to_s
|
343
|
+
when 'Hash'
|
344
|
+
{}
|
345
|
+
when 'Array'
|
346
|
+
[]
|
347
|
+
when 'String'
|
348
|
+
''
|
349
|
+
else
|
350
|
+
nil
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
def self.mean * ns
|
355
|
+
ns.reduce(:+) / ns.length
|
356
|
+
end
|
357
|
+
|
358
|
+
def self.median * ns
|
359
|
+
ns.sort[(ns.length / 2).floor]
|
360
|
+
end
|
361
|
+
|
362
|
+
def self.memorize_with(get_key, &action)
|
363
|
+
cache = {}
|
364
|
+
->(*args, **kwargs) do
|
365
|
+
key = get_key.(*args, **kwargs).to_sym
|
366
|
+
cache[key] = action.(*args, **kwargs) unless cache[key]
|
367
|
+
cache[key]
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def self.negate n
|
372
|
+
-n
|
373
|
+
end
|
374
|
+
|
375
|
+
def self.xor? a, b
|
376
|
+
(a && !b) || (!a && b)
|
377
|
+
end
|
378
|
+
end
|