ramda-ruby 0.12.0 → 0.14.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +69 -2
- data/ROADMAP.md +0 -9
- data/docs/FUNCTIONS.md +9 -0
- data/docs/FUNCTORS.md +39 -0
- data/lib/ramda/function.rb +22 -3
- data/lib/ramda/internal/class_which_respond_to.rb +17 -0
- data/lib/ramda/internal/dispatchable.rb +30 -2
- data/lib/ramda/internal/functors.rb +72 -1
- data/lib/ramda/internal/integrations.rb +48 -0
- data/lib/ramda/internal/transducers.rb +1 -30
- data/lib/ramda/internal/transducers/drop_repeats_transducer.rb +19 -0
- data/lib/ramda/internal/transducers/drop_repeats_with_transducer.rb +19 -0
- data/lib/ramda/internal/transducers/filter_transdurer.rb +19 -0
- data/lib/ramda/internal/transducers/map_transducer.rb +15 -0
- data/lib/ramda/internal/transducers/take_transducer.rb +21 -0
- data/lib/ramda/list.rb +78 -27
- data/lib/ramda/logic.rb +17 -5
- data/lib/ramda/math.rb +32 -1
- data/lib/ramda/object.rb +14 -1
- data/lib/ramda/string.rb +23 -4
- data/lib/ramda/version.rb +1 -1
- data/spec/ramda/function_spec.rb +20 -7
- data/spec/ramda/list_spec.rb +86 -20
- data/spec/ramda/logic_spec.rb +30 -0
- data/spec/ramda/math_spec.rb +29 -0
- data/spec/ramda/object_spec.rb +11 -0
- data/spec/ramda/string_spec.rb +43 -0
- data/spec/ramda_spec.rb +8 -0
- data/spec/spec_helper.rb +9 -1
- metadata +11 -2
@@ -0,0 +1,48 @@
|
|
1
|
+
# module Ramda
|
2
|
+
# module Internal
|
3
|
+
# module Integrations
|
4
|
+
# module Comparable
|
5
|
+
# def ===(other)
|
6
|
+
# specifications.find(&other.method(:respond_to?))
|
7
|
+
# end
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# class DryMonadsType
|
11
|
+
# extend Comparable
|
12
|
+
#
|
13
|
+
# def self.specifications
|
14
|
+
# @specifications ||= [
|
15
|
+
# :bind,
|
16
|
+
# :fmap,
|
17
|
+
# :pure,
|
18
|
+
# ]
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# class RamdaFantasyRubyType
|
23
|
+
# extend Comparable
|
24
|
+
#
|
25
|
+
# def self.specifications
|
26
|
+
# @specifications ||= [
|
27
|
+
# :ap,
|
28
|
+
# :chain,
|
29
|
+
# :map,
|
30
|
+
# :of
|
31
|
+
# ]
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# class KleisliType
|
36
|
+
# extend Comparable
|
37
|
+
#
|
38
|
+
# def self.specifications
|
39
|
+
# @specifications ||= [
|
40
|
+
# :'>->',
|
41
|
+
# :*,
|
42
|
+
# :fmap
|
43
|
+
# ]
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
# end
|
@@ -5,36 +5,7 @@ module Ramda
|
|
5
5
|
# Signature: (*, reducing_fn) -> Proc((acc, input) -> acc)
|
6
6
|
#
|
7
7
|
module Transducers
|
8
|
-
#
|
9
|
-
def self.filter(predicate, reducer)
|
10
|
-
lambda do |acc, x|
|
11
|
-
if predicate.call(x)
|
12
|
-
reducer.call(acc, x)
|
13
|
-
else
|
14
|
-
acc
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
# transformer - fn with 1 arity
|
20
|
-
def self.map(transformer, reducer)
|
21
|
-
lambda do |acc, x|
|
22
|
-
reducer.call(acc, transformer.call(x))
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# limit - number
|
27
|
-
def self.take(limit, reducer)
|
28
|
-
count = 0
|
29
|
-
lambda do |acc, x|
|
30
|
-
count += 1
|
31
|
-
if limit >= count
|
32
|
-
reducer.call(acc, x)
|
33
|
-
else
|
34
|
-
acc
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
8
|
+
Dir["#{File.dirname(__FILE__)}/transducers/*"].each { |file| require file }
|
38
9
|
end
|
39
10
|
end
|
40
11
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Ramda
|
2
|
+
module Internal
|
3
|
+
module Transducers
|
4
|
+
# Removes repeats from list
|
5
|
+
class DropRepeatsTransducer
|
6
|
+
# No arguments
|
7
|
+
def call(reducer)
|
8
|
+
lambda do |acc, x|
|
9
|
+
if acc.any? && acc.last == x
|
10
|
+
acc
|
11
|
+
else
|
12
|
+
reducer.call(acc, x)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Ramda
|
2
|
+
module Internal
|
3
|
+
module Transducers
|
4
|
+
# Remove repeats with based on predicate which receives a, b
|
5
|
+
class DropRepeatsWithTransducer
|
6
|
+
# predicate - fn with 2 arity
|
7
|
+
def call(predicate, reducer)
|
8
|
+
lambda do |acc, x|
|
9
|
+
if acc.any? && predicate.call(acc.last, x)
|
10
|
+
acc
|
11
|
+
else
|
12
|
+
reducer.call(acc, x)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Ramda
|
2
|
+
module Internal
|
3
|
+
module Transducers
|
4
|
+
# Filter list based on predicate which receives x
|
5
|
+
class FilterTransducer
|
6
|
+
# predicate - fn with 1 arity
|
7
|
+
def call(predicate, reducer)
|
8
|
+
lambda do |acc, x|
|
9
|
+
if predicate.call(x)
|
10
|
+
reducer.call(acc, x)
|
11
|
+
else
|
12
|
+
acc
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Ramda
|
2
|
+
module Internal
|
3
|
+
module Transducers
|
4
|
+
# Transform collection based on transformer
|
5
|
+
class MapTransducer
|
6
|
+
# transformer - fn with 1 arity
|
7
|
+
def call(transformer, reducer)
|
8
|
+
lambda do |acc, x|
|
9
|
+
reducer.call(acc, transformer.call(x))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Ramda
|
2
|
+
module Internal
|
3
|
+
module Transducers
|
4
|
+
# Returns a head of collection
|
5
|
+
class TakeTransducer
|
6
|
+
# limit - number
|
7
|
+
def call(limit, reducer)
|
8
|
+
count = 0
|
9
|
+
lambda do |acc, x|
|
10
|
+
count += 1
|
11
|
+
if limit >= count
|
12
|
+
reducer.call(acc, x)
|
13
|
+
else
|
14
|
+
acc
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/ramda/list.rb
CHANGED
@@ -6,11 +6,21 @@ module Ramda
|
|
6
6
|
# List functions
|
7
7
|
# rubocop:disable Metrics/ModuleLength
|
8
8
|
module List
|
9
|
-
Transducer = ->(method) { ::Ramda::Internal::Transducers.method(method) }
|
10
|
-
|
11
9
|
extend ::Ramda::Internal::CurriedMethod
|
12
10
|
extend ::Ramda::Internal::Dispatchable
|
13
11
|
|
12
|
+
Trans = ::Ramda::Internal::Transducers
|
13
|
+
|
14
|
+
# Applies a function to the value at the given index of an array,
|
15
|
+
# returning a new copy of the array with the element at the given
|
16
|
+
# index replaced with the result of the function application.
|
17
|
+
#
|
18
|
+
# (a -> a) -> Number -> [a] -> [a]
|
19
|
+
#
|
20
|
+
curried_method(:adjust) do |f, idx, xs|
|
21
|
+
xs.dup.tap { |a| a[idx] = f.call(a[idx]) }
|
22
|
+
end
|
23
|
+
|
14
24
|
# Returns true if all elements of the list match the predicate,
|
15
25
|
# false if there are any that don't.
|
16
26
|
#
|
@@ -65,7 +75,7 @@ module Ramda
|
|
65
75
|
#
|
66
76
|
# Chain m => (a -> m b) -> m a -> m b
|
67
77
|
#
|
68
|
-
curried(:chain, &dispatchable([:chain, :bind], ::Array) do |f, xs|
|
78
|
+
curried(:chain, &dispatchable([:chain, :bind, :'>'], ::Array) do |f, xs|
|
69
79
|
xs.flat_map(&f)
|
70
80
|
end)
|
71
81
|
|
@@ -105,6 +115,34 @@ module Ramda
|
|
105
115
|
xs[num..-1] || xs.class.new
|
106
116
|
end)
|
107
117
|
|
118
|
+
# Returns a new list without any consecutively repeating elements.
|
119
|
+
# R.equals is used to determine equality.
|
120
|
+
#
|
121
|
+
# Acts as a transducer if a transformer is given in list position.
|
122
|
+
#
|
123
|
+
# [a] -> [a]
|
124
|
+
#
|
125
|
+
curried_method(:drop_repeats,
|
126
|
+
&dispatchable1([], ::Array, Trans::DropRepeatsTransducer.new) do |xs|
|
127
|
+
xs.chunk { |n| n }.map(&:first)
|
128
|
+
end)
|
129
|
+
|
130
|
+
# Returns a new list without any consecutively repeating elements.
|
131
|
+
# Equality is determined by applying the supplied predicate to each
|
132
|
+
# pair of consecutive elements.
|
133
|
+
# The first element in a series of equal elements will be preserved.
|
134
|
+
#
|
135
|
+
# Acts as a transducer if a transformer is given in list position.
|
136
|
+
#
|
137
|
+
# (a, a -> Boolean) -> [a] -> [a]
|
138
|
+
#
|
139
|
+
curried_method(:drop_repeats_with,
|
140
|
+
&dispatchable([], [::Array], Trans::DropRepeatsWithTransducer.new) do |f, xs|
|
141
|
+
xs.each_with_object([]) do |a, acc|
|
142
|
+
acc.push(a) unless acc.any? && f.call(acc.last, a)
|
143
|
+
end
|
144
|
+
end)
|
145
|
+
|
108
146
|
# Returns a new list excluding the leading elements of a given list which
|
109
147
|
# satisfy the supplied predicate function. It passes each value to the
|
110
148
|
# supplied predicate function, skipping elements while the predicate
|
@@ -130,13 +168,14 @@ module Ramda
|
|
130
168
|
#
|
131
169
|
# Filterable f => (a -> Boolean) -> f a -> f a
|
132
170
|
#
|
133
|
-
curried(:filter,
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
171
|
+
curried(:filter,
|
172
|
+
&dispatchable(:filter, [::Array, ::Hash], Trans::FilterTransducer.new) do |f, xs|
|
173
|
+
if xs.is_a?(Hash)
|
174
|
+
xs.select { |_, value| f.call(value) }
|
175
|
+
else
|
176
|
+
xs.select(&f)
|
177
|
+
end
|
178
|
+
end)
|
140
179
|
|
141
180
|
# Creates a new object from a list key-value pairs. If a key appears in
|
142
181
|
# multiple pairs, the rightmost pair is included in the object.
|
@@ -270,6 +309,19 @@ module Ramda
|
|
270
309
|
xs.dup.insert(index, *elts)
|
271
310
|
end
|
272
311
|
|
312
|
+
# Creates a new list with the separator interposed between elements.
|
313
|
+
#
|
314
|
+
# Dispatches to the intersperse method of the second argument, if present.
|
315
|
+
#
|
316
|
+
# a -> [a] -> [a]
|
317
|
+
#
|
318
|
+
curried_method(:intersperse, &dispatchable([:intersperse], ::Array) do |sep, xs|
|
319
|
+
xs.reduce([]) do |acc, a|
|
320
|
+
acc << sep if acc.any?
|
321
|
+
acc << a
|
322
|
+
end
|
323
|
+
end)
|
324
|
+
|
273
325
|
# Transforms the items of the list with the transducer and appends
|
274
326
|
# the transformed items to the accumulator using an appropriate iterator
|
275
327
|
# function based on the accumulator type.
|
@@ -293,16 +345,13 @@ module Ramda
|
|
293
345
|
curried_method(:into) do |acc, xf, xs|
|
294
346
|
rx = case acc
|
295
347
|
when ::Array
|
296
|
-
|
297
|
-
arr.push(x)
|
298
|
-
arr
|
299
|
-
}
|
348
|
+
->(arr, x) { arr << x }
|
300
349
|
when ::String
|
301
350
|
->(str, x) { "#{str}#{x}" }
|
302
351
|
when ::Object
|
303
352
|
->(obj, x) { obj.merge(x) }
|
304
353
|
else
|
305
|
-
raise ArgumetError, "Cannot create transformer for #{acc}"
|
354
|
+
raise ArgumetError, "Cannot create default transformer for #{acc}"
|
306
355
|
end
|
307
356
|
xs.reduce(acc, &xf.call(rx))
|
308
357
|
end
|
@@ -349,14 +398,15 @@ module Ramda
|
|
349
398
|
#
|
350
399
|
# Functor f => (a -> b) -> f a -> f b
|
351
400
|
#
|
352
|
-
curried(:map,
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
401
|
+
curried(:map,
|
402
|
+
&dispatchable([:map, :fmap], [::Hash, ::Array], Trans::MapTransducer.new) do |f, xs|
|
403
|
+
case xs
|
404
|
+
when ::Hash
|
405
|
+
Hash[xs.map { |k, v| [k, f.call(v)] }]
|
406
|
+
when ::Array
|
407
|
+
xs.map(&f)
|
408
|
+
end
|
409
|
+
end)
|
360
410
|
|
361
411
|
# The mapAccum function behaves like a combination of map and reduce;
|
362
412
|
# it applies a function to each element of a list, passing
|
@@ -426,7 +476,7 @@ module Ramda
|
|
426
476
|
# Functor f => k -> f {k: v} -> f v
|
427
477
|
#
|
428
478
|
curried_method(:pluck) do |key, xs|
|
429
|
-
|
479
|
+
Ramda.map(->(x) { x[key] }, xs)
|
430
480
|
end
|
431
481
|
|
432
482
|
# Returns a new list with the given element at the front, followed by the
|
@@ -557,9 +607,10 @@ module Ramda
|
|
557
607
|
# Number -> [a] -> [a]
|
558
608
|
# Number -> String -> String
|
559
609
|
#
|
560
|
-
curried(:take,
|
561
|
-
|
562
|
-
|
610
|
+
curried(:take,
|
611
|
+
&dispatchable(:take, [::Array, ::String], Trans::TakeTransducer.new) do |num, xs|
|
612
|
+
xs[0, num]
|
613
|
+
end)
|
563
614
|
|
564
615
|
# Returns a new list containing the first n elements of a given list,
|
565
616
|
# passing each value to the supplied predicate function, and terminating
|
data/lib/ramda/logic.rb
CHANGED
@@ -51,7 +51,11 @@ module Ramda
|
|
51
51
|
# (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
|
52
52
|
#
|
53
53
|
curried_method(:both) do |fa, fb|
|
54
|
-
|
54
|
+
if fa.is_a?(Proc)
|
55
|
+
->(*args) { fa.call(*args) && fb.call(*args) }
|
56
|
+
else
|
57
|
+
Ramda.lift(Ramda.and, fa, fb)
|
58
|
+
end
|
55
59
|
end
|
56
60
|
|
57
61
|
# Takes a function f and returns a function g such that if called with
|
@@ -63,9 +67,13 @@ module Ramda
|
|
63
67
|
# (*... -> *) -> (*... -> Boolean)
|
64
68
|
#
|
65
69
|
curried_method(:complement) do |fn|
|
66
|
-
|
67
|
-
|
68
|
-
|
70
|
+
if fn.is_a?(Proc)
|
71
|
+
::Ramda::Internal::FunctionWithArity.call(fn.arity) do |*args|
|
72
|
+
!fn.call(*args)
|
73
|
+
end.curry
|
74
|
+
else
|
75
|
+
Ramda.lift(Ramda.not, fn)
|
76
|
+
end
|
69
77
|
end
|
70
78
|
|
71
79
|
# Returns a function, fn, which encapsulates if/else, if/else, ...
|
@@ -105,7 +113,11 @@ module Ramda
|
|
105
113
|
# (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean))
|
106
114
|
#
|
107
115
|
curried_method(:either) do |fa, fb|
|
108
|
-
|
116
|
+
if fa.is_a?(Proc)
|
117
|
+
->(*args) { fa.call(*args) || fb.call(*args) }
|
118
|
+
else
|
119
|
+
::Ramda.lift(Ramda.or, fa, fb)
|
120
|
+
end
|
109
121
|
end
|
110
122
|
|
111
123
|
# Creates a function that will process either the onTrue or the onFalse
|
data/lib/ramda/math.rb
CHANGED
@@ -26,7 +26,7 @@ module Ramda
|
|
26
26
|
# Number -> Number -> Number
|
27
27
|
#
|
28
28
|
curried_method(:divide) do |a, b|
|
29
|
-
a.
|
29
|
+
a.fdiv(b)
|
30
30
|
end
|
31
31
|
|
32
32
|
# Increments its argument.
|
@@ -43,6 +43,37 @@ module Ramda
|
|
43
43
|
# return ((m % p) + p) % p;
|
44
44
|
end
|
45
45
|
|
46
|
+
# Returns the mean of the given list of numbers.
|
47
|
+
#
|
48
|
+
# [Number] -> Number
|
49
|
+
#
|
50
|
+
curried_method(:mean) do |xs|
|
51
|
+
size = xs.size
|
52
|
+
|
53
|
+
if size.zero?
|
54
|
+
Float::NAN
|
55
|
+
else
|
56
|
+
xs.reduce(&:+).fdiv(size)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the median of the given list of numbers.
|
61
|
+
#
|
62
|
+
# [Number] -> Number
|
63
|
+
#
|
64
|
+
curried_method(:median) do |xs|
|
65
|
+
sorted = xs.sort
|
66
|
+
size = sorted.size
|
67
|
+
|
68
|
+
if size.zero?
|
69
|
+
Float::NAN
|
70
|
+
elsif size.odd?
|
71
|
+
sorted[size / 2]
|
72
|
+
else
|
73
|
+
sorted[size / 2 - 1, 2].reduce(&:+).fdiv(2)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
46
77
|
# Divides the first parameter by the second and returns the remainder.
|
47
78
|
#
|
48
79
|
# Number -> Number -> Number
|