ramda-ruby 0.11.0 → 0.12.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d5757dd75ba41c1a2d00617b9ac764d96f378a1
4
- data.tar.gz: 379e4d2156f99f92bb273d3b85e53f3ecab52ae4
3
+ metadata.gz: b89810eb9aeb97f4360a2ef5cdfff495a46d2495
4
+ data.tar.gz: 0ef2de2a457e9b889311f4af94a1b7f52c122abf
5
5
  SHA512:
6
- metadata.gz: b469dce9a379ee2b6abeb701eb8fe23aff6189a3b2075cfd7c39addda944ad205fe86fb46e6066718cb3bd819fae37efe086743b438c9b437899860ca98a5dd4
7
- data.tar.gz: 3f8d3a0c7d2853db5c8be295651827f792774566791d2cc43880b4927e4001c4d0780a8e4dba1c49736e5f63e95f0df186119bd68cd5b6ded3c7a80af8c1efa3
6
+ metadata.gz: e7b826795f824e977f6f9c0b8d8d87bb482bc96b861f3c2ce4e0aa9d81c4c4f15efe3b5f5f0d32ee9abbb8f45342c9d0c548b0fdd9f579453508f8906edb7e12
7
+ data.tar.gz: cd22adad8b7b4ce649844de486c1a0f6f67daebdd9901a5a9cf9ed8f2d50fab7895b5d903ff39990fd3f1723ebb9a1ef92cc5f7f9a2544ba7615c8074d821317
@@ -1,6 +1,25 @@
1
1
  Not Released
2
2
  ---------------
3
3
 
4
+ Release 0.12.0
5
+ ---------------
6
+
7
+ Added:
8
+
9
+ * [aperture](http://ramdajs.com/docs/#aperture)
10
+ * [both](http://ramdajs.com/docs/#both)
11
+ * [either](http://ramdajs.com/docs/#either)
12
+ * [into](http://ramdajs.com/docs/#into)
13
+ * [none](http://ramdajs.com/docs/#none)
14
+ * [test](http://ramdajs.com/docs/#test)
15
+ * [transduce](http://ramdajs.com/docs/#transduce)
16
+
17
+ Transducers for:
18
+
19
+ * filter
20
+ * map
21
+ * take
22
+
4
23
  Release 0.11.0
5
24
  ---------------
6
25
 
data/README.md CHANGED
@@ -4,7 +4,7 @@ Ramda Ruby
4
4
  This is a ruby version of [Ramda Js](http://ramdajs.com) library.
5
5
 
6
6
  [![Gem Version](https://badge.fury.io/rb/ramda-ruby.svg)](http://badge.fury.io/rb/ramda-ruby)
7
- [![Functions](https://img.shields.io/badge/Functions-171-green.svg)](docs/FUNCTIONS.md)
7
+ [![Functions](https://img.shields.io/badge/Functions-178-green.svg)](docs/FUNCTIONS.md)
8
8
  [![Travis badge](https://travis-ci.org/lazebny/ramda-ruby.svg?branch=master)](https://travis-ci.org/lazebny/ramda-ruby)
9
9
  [![AppVeyor status](https://ci.appveyor.com/api/projects/status/ponccdax7aj4ufw2?svg=true)](https://ci.appveyor.com/project/lazebny/ramda-ruby)
10
10
  [![Coverage Status](https://coveralls.io/repos/lazebny/ramda-ruby/badge.png)](https://coveralls.io/r/lazebny/ramda-ruby)
@@ -47,15 +47,17 @@ require 'ramda'
47
47
  Documentation
48
48
  -------------
49
49
 
50
- Currently the gem doesn't have own documentation but it tries to follow specification from [Ramda Js](http://ramdajs.com/docs/)
51
-
52
- * each release includes [functions](docs/FUNCTIONS.md) from the relevant [Ramda Js](http://ramdajs.com) release
53
- * each release includes more functions which i found pretty useful but they are from upcoming releases
54
-
55
- You could use [Ramda Js](http://ramdajs.com/docs/) as a source of documentation.
56
-
57
- Ruby scpecific examples can be found in [tests](spec/ramda).
50
+ * [Function](docs/FUNCTIONS.md#function)
51
+ * [List](docs/FUNCTIONS.md#list)
52
+ * [Logic](docs/FUNCTIONS.md#logic)
53
+ * [Math](docs/FUNCTIONS.md#math)
54
+ * [Object](docs/FUNCTIONS.md#object)
55
+ * [Relation](docs/FUNCTIONS.md#relation)
56
+ * [String](docs/FUNCTIONS.md#string)
57
+ * [Type](docs/FUNCTIONS.md#type)
58
58
 
59
+ You can use Ramda [docs](http://ramdajs.com/docs/) as a documentation
60
+ or to check Ruby [examples](spec/ramda).
59
61
 
60
62
  Usage
61
63
  -------------
@@ -87,6 +89,29 @@ Placeholder:
87
89
 
88
90
  ```
89
91
 
92
+ Transducers:
93
+
94
+ ```ruby
95
+
96
+ appender = R.flip(R.append)
97
+
98
+ xform = R.map(R.add(10))
99
+ R.transduce(xform, appender, [], [1, 2, 3, 4]) # [11, 12, 13, 14]
100
+
101
+ xform = R.filter(:odd?.to_proc)
102
+ R.transduce(xform, appender, [], [1, 2, 3, 4]) # [1, 3]
103
+
104
+ xform = R.compose(R.map(R.add(10)), R.take(2))
105
+ R.transduce(xform, appender, [], [1, 2, 3, 4]) # [11, 12]
106
+
107
+ xform = R.compose(R.filter(:odd?.to_proc), R.take(2))
108
+ R.transduce(xform, R.add, 100, [1, 2, 3, 4, 5]) # 104)
109
+ R.transduce(xform, appender, [], [1, 2, 3, 4, 5]) # [1, 3])
110
+ R.into([], xform, [1, 2, 3, 4, 5]) # [1, 3])
111
+
112
+
113
+ ```
114
+
90
115
  Change exceptions handler:
91
116
 
92
117
  ```ruby
data/ROADMAP.md CHANGED
@@ -1,13 +1,3 @@
1
- Release 0.12.0
2
- ---------------
3
- * apperture
4
- * both
5
- * either
6
- * into
7
- * none
8
- * test
9
- * transduce
10
-
11
1
  Release 0.13.0
12
2
  ---------------
13
3
 
@@ -51,13 +51,14 @@ List
51
51
 
52
52
  * [all](http://ramdajs.com/docs/#all)
53
53
  * [any](http://ramdajs.com/docs/#any)
54
+ * [aperture](http://ramdajs.com/docs/#aperture)
54
55
  * [append](http://ramdajs.com/docs/#append)
55
56
  * [chain](http://ramdajs.com/docs/#chain)
56
57
  * [concat](http://ramdajs.com/docs/#concat)
57
58
  * [contains](http://ramdajs.com/docs/#contains)
58
59
  * [drop](http://ramdajs.com/docs/#drop)
59
60
  * [drop_while](http://ramdajs.com/docs/#dropWhile)
60
- * [filter](http://ramdajs.com/docs/#filter)
61
+ * [filter](http://ramdajs.com/docs/#filter) - transducer
61
62
  * [find](http://ramdajs.com/docs/#find)
62
63
  * [find_index](http://ramdajs.com/docs/#findIndex) - returns nil if index doesn't exist
63
64
  * [find_last](http://ramdajs.com/docs/#findLast)
@@ -71,13 +72,15 @@ List
71
72
  * [init](http://ramdajs.com/docs/#init)
72
73
  * [insert](http://ramdajs.com/docs/#insert)
73
74
  * [insert_all](http://ramdajs.com/docs/#insertAll)
75
+ * [into](http://ramdajs.com/docs/#into)
74
76
  * [join](http://ramdajs.com/docs/#join)
75
77
  * [last](http://ramdajs.com/docs/#last)
76
78
  * [last_index_of](http://ramdajs.com/docs/#lastIndexOf) - returns nil if index doesn't exist
77
79
  * [length](http://ramdajs.com/docs/#length)
78
- * [map](http://ramdajs.com/docs/#map)
80
+ * [map](http://ramdajs.com/docs/#map) - transducer
79
81
  * [map_obj_indexed](http://ramdajs.com/docs/#mapObjIndexed)
80
82
  * [merge_all](http://ramdajs.com/docs/#mergeAll)
83
+ * [none](http://ramdajs.com/docs/#none)
81
84
  * [nth](http://ramdajs.com/docs/#nth)
82
85
  * [partition](http://ramdajs.com/docs/#partition)
83
86
  * [pluck](http://ramdajs.com/docs/#pluck)
@@ -94,9 +97,10 @@ List
94
97
  * [sort](http://ramdajs.com/docs/#sort)
95
98
  * [sort_by](http://ramdajs.com/docs/#sortBy)
96
99
  * [tail](http://ramdajs.com/docs/#tail)
97
- * [take](http://ramdajs.com/docs/#take)
100
+ * [take](http://ramdajs.com/docs/#take)- transducer
98
101
  * [take_while](http://ramdajs.com/docs/#takeWhile)
99
102
  * [times](http://ramdajs.com/docs/#times)
103
+ * [transduce](http://ramdajs.com/docs/#transduce)
100
104
  * [unfold](http://ramdajs.com/docs/#unfold)
101
105
  * [uniq](http://ramdajs.com/docs/#uniq)
102
106
  * [uniq_with](http://ramdajs.com/docs/#uniqWith) - first argument is a function with 1 arity which transforms each list element and applies uniq function to results
@@ -113,9 +117,11 @@ Logic
113
117
  * [all_pass](http://ramdajs.com/docs/#allPass)
114
118
  * [and](http://ramdajs.com/docs/#and)
115
119
  * [any_pass](http://ramdajs.com/docs/#anyPass)
120
+ * [both](http://ramdajs.com/docs/#both)
116
121
  * [complement](http://ramdajs.com/docs/#complement)
117
122
  * [cond](http://ramdajs.com/docs/#cond)
118
123
  * [default_to](http://ramdajs.com/docs/#defaultTo)
124
+ * [either](http://ramdajs.com/docs/#either)
119
125
  * [if_else](http://ramdajs.com/docs/#ifElse)
120
126
  * [is_empty](http://ramdajs.com/docs/#isEmpty)
121
127
  * [not](http://ramdajs.com/docs/#not)
@@ -201,6 +207,7 @@ String
201
207
  * [match](http://ramdajs.com/docs/#math)
202
208
  * [replace](http://ramdajs.com/docs/#replace) - it uses a gsub method and global replacement
203
209
  * [split](http://ramdajs.com/docs/#split)
210
+ * [test](http://ramdajs.com/docs/#test)
204
211
  * [to_lower](http://ramdajs.com/docs/#toLower)
205
212
  * [to_upper](http://ramdajs.com/docs/#toUpper)
206
213
  * [trim](http://ramdajs.com/docs/#trim)
@@ -1,4 +1,5 @@
1
1
  require_relative 'internal/curried_method'
2
+ require_relative 'internal/dispatchable'
2
3
  require_relative 'internal/function_with_arity'
3
4
 
4
5
  module Ramda
@@ -6,6 +7,7 @@ module Ramda
6
7
  # rubocop:disable Metrics/ModuleLength
7
8
  module Function
8
9
  extend ::Ramda::Internal::CurriedMethod
10
+ extend ::Ramda::Internal::Dispatchable
9
11
 
10
12
  # Returns a function that always returns the given value. Note that
11
13
  # for non-primitives the value returned is a reference to the original
@@ -26,13 +28,9 @@ module Ramda
26
28
  # [a -> b] -> [a] -> [b]
27
29
  # Apply f => f (a -> b) -> f a -> f b
28
30
  #
29
- curried_method(:ap) do |apply_f, apply_x|
30
- if apply_x.is_a?(Array)
31
- apply_f.flat_map { |fn| apply_x.map(&fn) }
32
- else
33
- Internal::Dispatchable.call([:ap], nil, apply_f, apply_x)
34
- end
35
- end
31
+ curried(:ap, &dispatchable(:ap, ::Array) do |apply_f, apply_x|
32
+ apply_f.flat_map { |fn| apply_x.map(&fn) }
33
+ end)
36
34
 
37
35
  # Applies function fn to the argument list args. This is useful
38
36
  # for creating a fixed-arity function from a variadic function.
@@ -4,10 +4,12 @@ module Ramda
4
4
  module Internal
5
5
  # Curried Method
6
6
  module CurriedMethod
7
- def curried_method(name, &block)
7
+ def curried(name, &block)
8
8
  define_method(name, &curried_method_body(name, block.arity, &block))
9
9
  end
10
10
 
11
+ alias curried_method curried
12
+
11
13
  # rubocop:disable Metrics/MethodLength
12
14
  def curried_method_body(name, arity, &block)
13
15
  Ramda::Internal::FunctionWithArity.call(arity) do |*args|
@@ -1,8 +1,10 @@
1
1
  module Ramda
2
2
  module Internal
3
3
  # Dispatchable
4
+ # rubocop:disable Performance/CaseWhenSplat
5
+ # rubocop:disable Metrics/MethodLength
6
+ # rubocop:disable Style/GuardClause
4
7
  module Dispatchable
5
- #
6
8
  # Returns a function that dispatches with different strategies based on the
7
9
  # object in list position (last argument). If it is an array, executes [fn].
8
10
  # Otherwise, if it has a function with [methodname], it will execute that
@@ -11,17 +13,33 @@ module Ramda
11
13
  # default to executing [fn].
12
14
  #
13
15
  # @private
14
- # - @param {String} methodname property to check for a custom implementation
16
+ # - @param {Array[Symbol]|Symbol} method_names property to check for a custom implementation
17
+ # - @param {Array[Class]|Class} described_types a list of type with default behaviour
15
18
  # - @param {Function} xf transducer to initialize if object is transformer
16
19
  # - @param {Function} fn default ramda implementation
17
20
  # - @return {Function} A function that dispatches on object in list position
18
21
  #
19
- def self.call(method_names, _xf, *args, xs)
20
- method_name = method_names.find { |name| xs.respond_to?(name) }
22
+ def dispatchable(method_names, described_types, xf = nil, &fn)
23
+ method_names = Array(method_names)
24
+
25
+ FunctionWithArity.call(fn.arity) do |*args, xs|
26
+ case xs
27
+ when *described_types # default behaviour
28
+ yield(*args, xs)
29
+
30
+ when Proc # transducer behaviour
31
+ xf.call(*args, xs)
21
32
 
22
- return xs.public_send(method_name, *args) if method_name
33
+ else # method dispatch behaviour
34
+ method_name = method_names.find { |name| xs.respond_to?(name) }
23
35
 
24
- raise ArgumentError, "Unexpected type #{xs.class} in method: #{method_name}"
36
+ if method_name
37
+ xs.public_send(method_name, *args)
38
+ else
39
+ raise ArgumentError, "Unexpected type #{xs.class} in method: #{method_name}"
40
+ end
41
+ end
42
+ end
25
43
  end
26
44
  end
27
45
  end
@@ -0,0 +1,40 @@
1
+ module Ramda
2
+ module Internal
3
+ # Transducers
4
+ #
5
+ # Signature: (*, reducing_fn) -> Proc((acc, input) -> acc)
6
+ #
7
+ module Transducers
8
+ # predicate - fn with 1 arity
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
38
+ end
39
+ end
40
+ end
@@ -1,11 +1,15 @@
1
1
  require_relative 'internal/curried_method'
2
2
  require_relative 'internal/dispatchable'
3
+ require_relative 'internal/transducers'
3
4
 
4
5
  module Ramda
5
6
  # List functions
6
7
  # rubocop:disable Metrics/ModuleLength
7
8
  module List
9
+ Transducer = ->(method) { ::Ramda::Internal::Transducers.method(method) }
10
+
8
11
  extend ::Ramda::Internal::CurriedMethod
12
+ extend ::Ramda::Internal::Dispatchable
9
13
 
10
14
  # Returns true if all elements of the list match the predicate,
11
15
  # false if there are any that don't.
@@ -16,13 +20,9 @@ module Ramda
16
20
  #
17
21
  # (a -> Boolean) -> [a] -> Boolean
18
22
  #
19
- curried_method(:all) do |f, xs|
20
- if xs.is_a?(::Array)
21
- xs.all?(&f)
22
- else
23
- Internal::Dispatchable.call([:any], nil, f, xs)
24
- end
25
- end
23
+ curried(:all, &dispatchable(:all, ::Array) do |f, xs|
24
+ xs.all?(&f)
25
+ end)
26
26
 
27
27
  # Returns true if at least one of elements of the list match the predicate,
28
28
  # false otherwise.
@@ -33,12 +33,19 @@ module Ramda
33
33
  #
34
34
  # (a -> Boolean) -> [a] -> Boolean
35
35
  #
36
- curried_method(:any) do |f, xs|
37
- if xs.is_a?(::Array)
38
- xs.any?(&f)
39
- else
40
- Internal::Dispatchable.call([:any], nil, f, xs)
41
- end
36
+ curried(:any, &dispatchable(:any, ::Array) do |f, xs|
37
+ xs.any?(&f)
38
+ end)
39
+
40
+ # Returns a new list, composed of n-tuples of consecutive elements.
41
+ # If n is greater than the length of the list, an empty list is returned.
42
+ #
43
+ # Acts as a transducer if a transformer is given in list position.
44
+ #
45
+ # Number -> [a] -> [[a]]
46
+ #
47
+ curried_method(:aperture) do |n, xs|
48
+ xs.each_cons(n).to_a
42
49
  end
43
50
 
44
51
  # Returns a new list containing the contents of the given list,
@@ -58,35 +65,28 @@ module Ramda
58
65
  #
59
66
  # Chain m => (a -> m b) -> m a -> m b
60
67
  #
61
- curried_method(:chain) do |f, xs|
62
- if xs.is_a?(::Array)
63
- xs.flat_map(&f)
64
- else
65
- Internal::Dispatchable.call([:chain, :bind], nil, f, xs)
66
- end
67
- end
68
+ curried(:chain, &dispatchable([:chain, :bind], ::Array) do |f, xs|
69
+ xs.flat_map(&f)
70
+ end)
68
71
 
69
72
  # Returns the result of concatenating the given lists or strings.
70
- # String -> String -> String
71
73
  #
74
+ # Dispatches to the concat method of the first argument, if present.
75
+ #
76
+ # String -> String -> String
72
77
  # List -> List -> List
73
78
  #
74
- curried_method(:concat) do |list_a, list_b|
75
- case list_b
76
- when ::String, ::Symbol
77
- [list_a, list_b].join('')
78
- when ::Array
79
- list_a.dup + list_b
79
+ curried(:concat, &dispatchable(:concat, [::Array, ::String, ::Symbol]) do |list_a, list_b|
80
+ if list_b.is_a?(::Array)
81
+ list_a + list_b
80
82
  else
81
- Internal::Dispatchable.call([:concat], nil, list_a, list_b)
83
+ [list_a, list_b].join('')
82
84
  end
83
- end
85
+ end)
84
86
 
85
87
  # Returns true if the specified value is equal, in R.equals terms,
86
88
  # to at least one element of the given list; false otherwise.
87
89
  #
88
- # Dispatches to the concat method of the first argument, if present.
89
- #
90
90
  # a -> [a] -> Boolean
91
91
  #
92
92
  curried_method(:contains) do |x, xs|
@@ -101,16 +101,9 @@ module Ramda
101
101
  # Number -> [a] -> [a]
102
102
  # Number -> String -> String
103
103
  #
104
- curried_method(:drop) do |num, xs|
105
- case xs
106
- when ::String
107
- xs[num..-1] || ''
108
- when ::Array
109
- xs[num..-1] || []
110
- else
111
- Internal::Dispatchable.call([:drop], nil, num, xs)
112
- end
113
- end
104
+ curried(:drop, &dispatchable(:drop, [::Array, ::String]) do |num, xs|
105
+ xs[num..-1] || xs.class.new
106
+ end)
114
107
 
115
108
  # Returns a new list excluding the leading elements of a given list which
116
109
  # satisfy the supplied predicate function. It passes each value to the
@@ -124,13 +117,9 @@ module Ramda
124
117
  #
125
118
  # (a -> Boolean) -> [a] -> [a]
126
119
  #
127
- curried_method(:drop_while) do |f, xs|
128
- if xs.is_a?(::Array)
129
- xs.drop_while(&f)
130
- else
131
- Internal::Dispatchable.call([:drop_while], nil, f, xs)
132
- end
133
- end
120
+ curried(:drop_while, &dispatchable(:drop_while, ::Array) do |f, xs|
121
+ xs.drop_while(&f)
122
+ end)
134
123
 
135
124
  # Takes a predicate and a Filterable, and returns a new filterable of the same
136
125
  # type containing the members of the given filterable which satisfy the given
@@ -141,16 +130,13 @@ module Ramda
141
130
  #
142
131
  # Filterable f => (a -> Boolean) -> f a -> f a
143
132
  #
144
- curried_method(:filter) do |f, xs|
145
- case xs
146
- when ::Hash
133
+ curried(:filter, &dispatchable(:filter, [::Array, ::Hash], Transducer[:filter]) do |f, xs|
134
+ if xs.is_a?(Hash)
147
135
  xs.select { |_, value| f.call(value) }
148
- when ::Array
149
- xs.select(&f)
150
136
  else
151
- Internal::Dispatchable.call([:filter], nil, f, xs)
137
+ xs.select(&f)
152
138
  end
153
- end
139
+ end)
154
140
 
155
141
  # Creates a new object from a list key-value pairs. If a key appears in
156
142
  # multiple pairs, the rightmost pair is included in the object.
@@ -168,13 +154,9 @@ module Ramda
168
154
  #
169
155
  # (a -> Boolean) -> [a] -> a | NilClass
170
156
  #
171
- curried_method(:find) do |f, xs|
172
- if xs.is_a?(::Array)
173
- xs.find(&f)
174
- else
175
- Internal::Dispatchable.call([:find], nil, f, xs)
176
- end
177
- end
157
+ curried(:find, &dispatchable(:find, ::Array) do |f, xs|
158
+ xs.find(&f)
159
+ end)
178
160
 
179
161
  # Returns the index of the first element of the list which matches the predicate,
180
162
  # or nil if no element matches.
@@ -218,13 +200,9 @@ module Ramda
218
200
  #
219
201
  # (a -> *) -> [a] -> [a]
220
202
  #
221
- curried_method(:for_each) do |f, xs|
222
- if xs.is_a?(::Array)
223
- xs.each(&f)
224
- else
225
- Internal::Dispatchable.call([:for_each], nil, f, xs)
226
- end
227
- end
203
+ curried(:for_each, &dispatchable(:for_each, ::Array) do |f, xs|
204
+ xs.each(&f)
205
+ end)
228
206
 
229
207
  # Splits a list into sub-lists stored in an object, based on the result of
230
208
  # calling a String-returning function on each element, and grouping the
@@ -235,13 +213,9 @@ module Ramda
235
213
  #
236
214
  # (a -> String) -> [a] -> {String: [a]}
237
215
  #
238
- curried_method(:group_by) do |f, xs|
239
- if xs.is_a?(::Array)
240
- xs.group_by(&f)
241
- else
242
- Internal::Dispatchable.call([:group_by], nil, f, xs)
243
- end
244
- end
216
+ curried(:group_by, &dispatchable(:group_by, ::Array) do |f, xs|
217
+ xs.group_by(&f)
218
+ end)
245
219
 
246
220
  # Returns the first element of the given list or string. In some libraries
247
221
  # this function is named first.
@@ -296,6 +270,43 @@ module Ramda
296
270
  xs.dup.insert(index, *elts)
297
271
  end
298
272
 
273
+ # Transforms the items of the list with the transducer and appends
274
+ # the transformed items to the accumulator using an appropriate iterator
275
+ # function based on the accumulator type.
276
+ #
277
+ # The accumulator can be an array, string, object or a transformer.
278
+ # Iterated items will be appended to arrays and concatenated to strings.
279
+ # Objects will be merged directly.
280
+ #
281
+ # The accumulator can also be a transformer object that provides a 2-arity
282
+ # reducing iterator function, step, 0-arity initial value function,
283
+ # init, and 1-arity result extraction function result.
284
+ # The step function is used as the iterator function in reduce. The result
285
+ # function is used to convert the final accumulator into the return type
286
+ # and in most cases is R.identity. The init function is used to provide
287
+ # the initial accumulator.
288
+ #
289
+ # The iteration is performed with R.reduce after initializing the transducer.
290
+ #
291
+ # a -> (b -> b) -> [c] -> a
292
+ #
293
+ curried_method(:into) do |acc, xf, xs|
294
+ rx = case acc
295
+ when ::Array
296
+ lambda { |arr, x|
297
+ arr.push(x)
298
+ arr
299
+ }
300
+ when ::String
301
+ ->(str, x) { "#{str}#{x}" }
302
+ when ::Object
303
+ ->(obj, x) { obj.merge(x) }
304
+ else
305
+ raise ArgumetError, "Cannot create transformer for #{acc}"
306
+ end
307
+ xs.reduce(acc, &xf.call(rx))
308
+ end
309
+
299
310
  # Returns a string made by inserting the separator between each element and
300
311
  # concatenating all the elements into a single string.
301
312
  #
@@ -338,16 +349,14 @@ module Ramda
338
349
  #
339
350
  # Functor f => (a -> b) -> f a -> f b
340
351
  #
341
- curried_method(:map) do |f, xs|
352
+ curried(:map, &dispatchable(:map, [::Hash, ::Array], Transducer[:map]) do |f, xs|
342
353
  case xs
343
354
  when ::Hash
344
355
  Hash[xs.map { |k, v| [k, f.call(v)] }]
345
356
  when ::Array
346
357
  xs.map(&f)
347
- else
348
- Internal::Dispatchable.call([:map], nil, f, xs)
349
358
  end
350
- end
359
+ end)
351
360
 
352
361
  # The mapAccum function behaves like a combination of map and reduce;
353
362
  # it applies a function to each element of a list, passing
@@ -371,6 +380,16 @@ module Ramda
371
380
  xs.reduce(&:merge)
372
381
  end
373
382
 
383
+ # Returns true if no elements of the list match the predicate, false otherwise.
384
+ #
385
+ # Dispatches to the none? method of the second argument, if present.
386
+ #
387
+ # (a -> Boolean) -> [a] -> Boolean
388
+ #
389
+ curried_method(:none) do |f, xs|
390
+ xs.none?(&f)
391
+ end
392
+
374
393
  # Returns the nth element of the given list or string. If n is negative
375
394
  # the element at index length + n is returned.
376
395
  #
@@ -507,14 +526,9 @@ module Ramda
507
526
  # Number -> Number -> [a] -> [a]
508
527
  # Number -> Number -> String -> String
509
528
  #
510
- curried_method(:slice) do |from, to, xs|
511
- case xs
512
- when ::Array, ::String
513
- xs[from...to]
514
- else
515
- Internal::Dispatchable.call([:slice], nil, from, to, xs)
516
- end
517
- end
529
+ curried(:slice, &dispatchable(:slice, [::Array, ::String]) do |from, to, xs|
530
+ xs[from...to]
531
+ end)
518
532
 
519
533
  # Returns a copy of the list, sorted according to the comparator function,
520
534
  # which should accept two values at a time and return a negative number
@@ -543,14 +557,9 @@ module Ramda
543
557
  # Number -> [a] -> [a]
544
558
  # Number -> String -> String
545
559
  #
546
- curried_method(:take) do |num, xs|
547
- case xs
548
- when ::Array, ::String
549
- xs[0, num]
550
- else
551
- Internal::Dispatchable.call([:take], nil, num, xs)
552
- end
553
- end
560
+ curried(:take, &dispatchable(:take, [::Array, ::String], Transducer[:take]) do |num, xs|
561
+ xs[0, num]
562
+ end)
554
563
 
555
564
  # Returns a new list containing the first n elements of a given list,
556
565
  # passing each value to the supplied predicate function, and terminating
@@ -560,13 +569,9 @@ module Ramda
560
569
  #
561
570
  # (a -> Boolean) -> [a] -> [a]
562
571
  #
563
- curried_method(:take_while) do |f, xs|
564
- if xs.is_a?(::Array)
565
- xs[0, xs.index { |x| !f.call(x) } || xs.size]
566
- else
567
- Internal::Dispatchable.call([:take_while], nil, f, xs)
568
- end
569
- end
572
+ curried(:take_while, &dispatchable(:take_while, ::Array) do |f, xs|
573
+ xs[0, xs.index { |x| !f.call(x) } || xs.size]
574
+ end)
570
575
 
571
576
  # Calls an input function n times, returning an array containing the results
572
577
  # of those function calls.
@@ -579,6 +584,26 @@ module Ramda
579
584
  n.times.to_a.map(&f)
580
585
  end
581
586
 
587
+ # Returns a single item by iterating through the list, successively
588
+ # calling the iterator function and passing it an accumulator value
589
+ # and the current value from the array, and then passing the result
590
+ # to the next call.
591
+ #
592
+ # The iterator function receives two values: (acc, value).
593
+ # It may use R.reduced to shortcut the iteration.
594
+ #
595
+ # The arguments' order of reduceRight's iterator function is (value, acc).
596
+ #
597
+ # Dispatches to the reduce method of the third argument, if present.
598
+ # When doing so, it is up to the user to handle the R.reduced shortcuting,
599
+ # as this is not implemented by reduce.
600
+ #
601
+ # ((a, b) -> a) -> a -> [b] -> a
602
+ #
603
+ curried_method(:transduce) do |xf, rx, acc, xs|
604
+ xs.reduce(acc, &xf.call(rx))
605
+ end
606
+
582
607
  # Builds a list from a seed value. Accepts an iterator function, which
583
608
  # returns either false to stop iteration or an array of length 2
584
609
  # containing the value to add to the resulting list and the seed
@@ -5,18 +5,55 @@ module Ramda
5
5
  module Logic
6
6
  extend ::Ramda::Internal::CurriedMethod
7
7
 
8
+ # Takes a list of predicates and returns a predicate that returns
9
+ # true for a given list of arguments if every one of the provided
10
+ # predicates is satisfied by those arguments.
11
+ #
12
+ # The function returned is a curried function whose arity matches
13
+ # that of the highest-arity predicate.
14
+ #
15
+ # [(*... -> Boolean)] -> (*... -> Boolean)
16
+ #
8
17
  curried_method(:all_pass) do |predicates, obj|
9
18
  predicates.all? { |predicate| predicate.call(obj) }
10
19
  end
11
20
 
21
+ # Returns true if both arguments are true; false otherwise.
22
+ #
23
+ # a -> b -> a | b
24
+ #
12
25
  curried_method(:and) do |a, b|
13
26
  a && b
14
27
  end
15
28
 
29
+ # Takes a list of predicates and returns a predicate that returns
30
+ # true for a given list of arguments if at least one of the
31
+ # provided predicates is satisfied by those arguments.
32
+ #
33
+ # The function returned is a curried function whose arity matches
34
+ # that of the highest-arity predicate.
35
+ #
36
+ # [(*... -> Boolean)] -> (*... -> Boolean)
37
+ #
16
38
  curried_method(:any_pass) do |predicates, obj|
17
39
  predicates.any? { |predicate| predicate.call(obj) }
18
40
  end
19
41
 
42
+ # A function which calls the two provided functions and returns
43
+ # the && of the results. It returns the result of the first function
44
+ # if it is false-y and the result of the second function otherwise.
45
+ # Note that this is short-circuited, meaning that the second function
46
+ # will not be invoked if the first returns a false-y value.
47
+ #
48
+ # In addition to functions, R.both also accepts any fantasy-land
49
+ # compatible applicative functor.
50
+ #
51
+ # (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
52
+ #
53
+ curried_method(:both) do |fa, fb|
54
+ ->(*args) { fa.call(*args) && fb.call(*args) }
55
+ end
56
+
20
57
  # Takes a function f and returns a function g such that if called with
21
58
  # the same arguments when f returns a "truthy" value, g returns false
22
59
  # and when f returns a "falsy" value g returns true.
@@ -56,6 +93,21 @@ module Ramda
56
93
  b || a
57
94
  end
58
95
 
96
+ # A function wrapping calls to the two functions in an || operation,
97
+ # returning the result of the first function if it is truth-y and
98
+ # the result of the second function otherwise.
99
+ # Note that this is short-circuited, meaning that the second
100
+ # function will not be invoked if the first returns a truth-y value.
101
+ #
102
+ # In addition to functions, R.either also accepts any fantasy-land
103
+ # compatible applicative functor.
104
+ #
105
+ # (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean))
106
+ #
107
+ curried_method(:either) do |fa, fb|
108
+ ->(*args) { fa.call(*args) || fb.call(*args) }
109
+ end
110
+
59
111
  # Creates a function that will process either the onTrue or the onFalse
60
112
  # function depending upon the result of the condition predicate.
61
113
  #
@@ -37,6 +37,14 @@ module Ramda
37
37
  x.split(sep)
38
38
  end
39
39
 
40
+ # Determines whether a given string matches a given regular expression.
41
+ #
42
+ # RegExp -> String -> Boolean
43
+ #
44
+ curried_method(:test) do |rx, str|
45
+ !str.match(rx).nil?
46
+ end
47
+
40
48
  # The upper case version of a string.
41
49
  #
42
50
  # String -> String
@@ -1,3 +1,3 @@
1
1
  module Ramda
2
- VERSION = '0.11.0'.freeze
2
+ VERSION = '0.12.0'.freeze
3
3
  end
@@ -32,6 +32,14 @@ describe Ramda::List do
32
32
  end
33
33
  end
34
34
 
35
+ context '#aperture' do
36
+ it 'from docs' do
37
+ expect(R.aperture(2, [1, 2, 3, 4, 5])).to eq([[1, 2], [2, 3], [3, 4], [4, 5]])
38
+ expect(R.aperture(3, [1, 2, 3, 4, 5])).to eq([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
39
+ expect(R.aperture(7, [1, 2, 3, 4, 5])).to eq([])
40
+ end
41
+ end
42
+
35
43
  context '#append' do
36
44
  it 'from docs' do
37
45
  expect(r.append('tests', ['write', 'more'])).to eq(['write', 'more', 'tests'])
@@ -300,6 +308,32 @@ describe Ramda::List do
300
308
  end
301
309
  end
302
310
 
311
+ context '#into' do
312
+ it 'transduces into arrays' do
313
+ expect(R.into([], R.map(R.add(1)), [1, 2, 3, 4])).to eq([2, 3, 4, 5])
314
+ expect(R.into([], R.filter(:odd?.to_proc), [1, 2, 3, 4])).to eq([1, 3])
315
+ expect(R.into([], R.compose(R.map(R.add(1)), R.take(2)), [1, 2, 3, 4])).to eq([2, 3])
316
+ end
317
+
318
+ it 'transduces into strings' do
319
+ expect(R.into('', R.map(R.add(1)), [1, 2, 3, 4])).to eq('2345')
320
+ expect(R.into('', R.filter(:odd?.to_proc), [1, 2, 3, 4])).to eq('13')
321
+ expect(R.into('', R.compose(R.map(R.add(1)), R.take(2)), [1, 2, 3, 4])).to eq('23')
322
+ end
323
+
324
+ it 'transduces into objects' do
325
+ # expect(R.into({}, R.identity, [[:a, 1], [:b, 2]])).to eq(a: 1, b: 2)
326
+ expect(R.into({}, R.identity, [{ a: 1 }, { b: 2, c: 3 }])).to eq(a: 1, b: 2, c: 3)
327
+ end
328
+
329
+ it 'is curried' do
330
+ into_array = R.into([])
331
+ add2 = R.map(R.add(2))
332
+ result = into_array.call(add2)
333
+ expect(result.call([1, 2, 3, 4])).to eq([3, 4, 5, 6])
334
+ end
335
+ end
336
+
303
337
  context '#join' do
304
338
  it 'from docs' do
305
339
  expect(r.join('|', [1, 2, 3])).to eq('1|2|3')
@@ -370,6 +404,16 @@ describe Ramda::List do
370
404
  end
371
405
  end
372
406
 
407
+ context '#none' do
408
+ it 'from docs' do
409
+ is_even = :even?.to_proc
410
+ is_odd = :odd?.to_proc
411
+
412
+ expect(R.none(is_even, [1, 3, 5, 7, 9, 11])).to be_truthy
413
+ expect(R.none(is_odd, [1, 3, 5, 7, 9, 11])).to be_falsey
414
+ end
415
+ end
416
+
373
417
  context '#nth' do
374
418
  it 'with array' do
375
419
  list = ['foo', 'bar', 'baz', 'quux']
@@ -594,6 +638,58 @@ describe Ramda::List do
594
638
  end
595
639
  end
596
640
 
641
+ context '#transduce' do
642
+ context 'transduces into arrays' do
643
+ let(:append) { R.flip(R.append) }
644
+
645
+ it 'different cases' do
646
+ xform = R.map(R.add(10))
647
+ expect(R.transduce(xform, append, [], [1, 2, 3, 4])).to eq([11, 12, 13, 14])
648
+
649
+ xform = R.filter(:odd?.to_proc)
650
+ expect(R.transduce(xform, append, [], [1, 2, 3, 4])).to eq([1, 3])
651
+
652
+ xform = R.compose(R.map(R.add(10)), R.take(2))
653
+ expect(R.transduce(xform, append, [], [1, 2, 3, 4])).to eq([11, 12])
654
+
655
+ xform = R.compose(R.filter(:odd?.to_proc), R.take(2))
656
+ expect(R.transduce(xform, append, [], [1, 2, 3, 4, 5])).to eq([1, 3])
657
+ expect(R.transduce(xform, R.add, 100, [1, 2, 3, 4, 5])).to eq(104)
658
+ end
659
+ end
660
+
661
+ context '#transducers into strings' do
662
+ let(:add) { ->(acc, x) { [acc, x].join } }
663
+
664
+ it 'different cases' do
665
+ xform = R.map(R.inc)
666
+ expect(R.transduce(xform, add, '', [1, 2, 3, 4])).to eq('2345')
667
+
668
+ xform = R.filter(:odd?.to_proc)
669
+ expect(R.transduce(xform, add, '', [1, 2, 3, 4])).to eq('13')
670
+
671
+ xform = R.compose(R.map(R.add(1)), R.take(2))
672
+ expect(R.transduce(xform, add, '', [1, 2, 3, 4])).to eq('23')
673
+ end
674
+ end
675
+
676
+ context 'transduces into objects' do
677
+ it 'different cases' do
678
+ xform = R.map(R.identity)
679
+ expect(R.transduce(xform, R.merge, {}, [{ a: 1 }, { b: 2, c: 3 }])).to eq(a: 1, b: 2, c: 3)
680
+ end
681
+ end
682
+
683
+ it 'returns the accumulator for an empty collection' do
684
+ reducer = ->(acc, x) { acc + x }
685
+
686
+ xform = R.map(R.identity)
687
+ expect(R.transduce(xform, reducer, 0, [])).to be(0)
688
+ expect(R.transduce(xform, reducer, 1, [])).to be(1)
689
+ expect(R.transduce(xform, reducer, [], [])).to eql([])
690
+ end
691
+ end
692
+
597
693
  context '#unfold' do
598
694
  it 'from docs' do
599
695
  f = ->(n) { n > 50 ? false : [-n, n + 10] }
@@ -3,31 +3,47 @@ require 'spec_helper'
3
3
  describe Ramda::Logic do
4
4
  let(:r) { Ramda }
5
5
 
6
- it '#all_pass' do
7
- is_queen = R.prop_eq(:rank, 'Queen')
8
- is_spade = R.prop_eq(:suit, 'Spade')
6
+ context '#all_pass' do
7
+ it 'from docs' do
8
+ is_queen = R.prop_eq(:rank, 'Queen')
9
+ is_spade = R.prop_eq(:suit, 'Spade')
9
10
 
10
- is_queen_of_spades = r.all_pass([is_queen, is_spade])
11
+ is_queen_of_spades = r.all_pass([is_queen, is_spade])
11
12
 
12
- expect(is_queen_of_spades.call(rank: 'King', suit: 'Spade')).to be_falsey
13
- expect(is_queen_of_spades.call(rank: 'Queen', suit: 'Spade')).to be_truthy
13
+ expect(is_queen_of_spades.call(rank: 'King', suit: 'Spade')).to be_falsey
14
+ expect(is_queen_of_spades.call(rank: 'Queen', suit: 'Spade')).to be_truthy
15
+ end
14
16
  end
15
17
 
16
- it '#and' do
17
- expect(r.and(true, true)).to be_truthy
18
- expect(r.and(true, false)).to be_falsey
19
- expect(r.and(false, true)).to be_falsey
20
- expect(r.and(false, false)).to be_falsey
18
+ context '#and' do
19
+ it 'from docs' do
20
+ expect(r.and(true, true)).to be_truthy
21
+ expect(r.and(true, false)).to be_falsey
22
+ expect(r.and(false, true)).to be_falsey
23
+ expect(r.and(false, false)).to be_falsey
24
+ end
21
25
  end
22
26
 
23
- it '#any_pass' do
24
- is_club = R.prop_eq(:suit, 'club')
25
- is_spade = R.prop_eq(:suit, 'spade')
26
- is_black_card = r.any_pass([is_club, is_spade])
27
+ context '#any_pass' do
28
+ it 'from docs' do
29
+ is_club = R.prop_eq(:suit, 'club')
30
+ is_spade = R.prop_eq(:suit, 'spade')
31
+ is_black_card = r.any_pass([is_club, is_spade])
32
+
33
+ expect(is_black_card.call(rank: '10', suit: 'club')).to be_truthy
34
+ expect(is_black_card.call(rank: 'Q', suit: 'spade')).to be_truthy
35
+ expect(is_black_card.call(rank: 'Q', suit: 'diamond')).to be_falsey
36
+ end
37
+ end
27
38
 
28
- expect(is_black_card.call(rank: '10', suit: 'club')).to be_truthy
29
- expect(is_black_card.call(rank: 'Q', suit: 'spade')).to be_truthy
30
- expect(is_black_card.call(rank: 'Q', suit: 'diamond')).to be_falsey
39
+ context '#both' do
40
+ it 'from docs' do
41
+ gt10 = R.gt(R.__, 10)
42
+ lt20 = R.lt(R.__, 20)
43
+ f = R.both(gt10, lt20)
44
+ expect(f.call(15)).to be_truthy
45
+ expect(f.call(30)).to be_falsey
46
+ end
31
47
  end
32
48
 
33
49
  context '#complement' do
@@ -62,6 +78,16 @@ describe Ramda::Logic do
62
78
  end
63
79
  end
64
80
 
81
+ context '#either' do
82
+ it 'from docs' do
83
+ gt10 = ->(x) { x > 10 }
84
+ even = :even?.to_proc
85
+ f = R.either(gt10, even)
86
+ expect(f.call(101)).to be_truthy
87
+ expect(f.call(8)).to be_truthy
88
+ end
89
+ end
90
+
65
91
  context '#if_else' do
66
92
  it 'from docs' do
67
93
  inc_count = R.if_else(
@@ -29,6 +29,13 @@ describe Ramda::String do
29
29
  end
30
30
  end
31
31
 
32
+ context '#test' do
33
+ it 'from docs' do
34
+ expect(R.test(/^x/, 'xyz')).to be_truthy
35
+ expect(R.test(/^y/, 'xyz')).to be_falsey
36
+ end
37
+ end
38
+
32
39
  context '#to_upper' do
33
40
  it 'from docs' do
34
41
  expect(r.to_upper('abc')).to eq('ABC')
@@ -24,12 +24,14 @@ describe Ramda do
24
24
  r(:any)
25
25
  r(:any_pass)
26
26
  r(:ap)
27
+ r(:aperture)
27
28
  r(:append)
28
29
  r(:apply)
29
30
  r(:assoc)
30
31
  r(:assoc_path)
31
32
  r(:binary)
32
33
  r(:bind)
34
+ r(:both)
33
35
  r(:call)
34
36
  r(:chain)
35
37
  r(:clone)
@@ -55,6 +57,7 @@ describe Ramda do
55
57
  r(:drop)
56
58
  r(:drop_while)
57
59
  r(:empty)
60
+ r(:either)
58
61
  r(:eq_by)
59
62
  r(:eq_props)
60
63
  r(:equals)
@@ -82,6 +85,7 @@ describe Ramda do
82
85
  r(:insert)
83
86
  r(:insert_all)
84
87
  r(:intersection)
88
+ r(:into)
85
89
  r(:invert)
86
90
  r(:invert_obj)
87
91
  r(:invoker)
@@ -116,6 +120,7 @@ describe Ramda do
116
120
  r(:multiply)
117
121
  r(:n_ary)
118
122
  r(:negate)
123
+ r(:none)
119
124
  r(:not)
120
125
  r(:nth)
121
126
  r(:nth_arg)
@@ -161,10 +166,12 @@ describe Ramda do
161
166
  r(:take)
162
167
  r(:take_while)
163
168
  r(:tap)
169
+ r(:test)
164
170
  r(:times)
165
171
  r(:to_lower)
166
172
  r(:to_pairs)
167
173
  r(:to_upper)
174
+ r(:transduce)
168
175
  r(:trim)
169
176
  r(:type)
170
177
  r(:unapply)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ramda-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vadim Lazebny
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-06 00:00:00.000000000 Z
11
+ date: 2017-07-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby version of Ramda Js library.
14
14
  email:
@@ -37,6 +37,7 @@ files:
37
37
  - lib/ramda/internal/function_with_arity.rb
38
38
  - lib/ramda/internal/functors.rb
39
39
  - lib/ramda/internal/java/__make_curry_proc__.rb
40
+ - lib/ramda/internal/transducers.rb
40
41
  - lib/ramda/list.rb
41
42
  - lib/ramda/logic.rb
42
43
  - lib/ramda/math.rb