rize 1.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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rubocop.yml +52 -0
- data/.travis.yml +11 -0
- data/.yardopts +1 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +100 -0
- data/Rakefile +11 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/lib/rize.rb +18 -0
- data/lib/rize/functional.rb +226 -0
- data/lib/rize/iteration.rb +218 -0
- data/lib/rize/version.rb +3 -0
- data/rize.gemspec +28 -0
- metadata +131 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 8db91982bf1a6ec94bd2b535aad16c487979a0b3
|
|
4
|
+
data.tar.gz: 3f33d42668c3d92d78a180fd708b97adb7537cfa
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: f3b7a05514ec46cd1e0b3fb0635906c35c96fe55427cf67b6df602696bebce7a507ac33f14e6dc64de74af5531ed5b287ff54b74accfaca1d13e9b5e2c956f48
|
|
7
|
+
data.tar.gz: 4e1ac5fc93e5cdb5ecc23c62a88a460cf5f7bbb4c46816faacec71363c3af2e3347a420744ae73014bacfae06983fae879c1c281f1f5f1d12a81055869ac65a2
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 2.2
|
|
3
|
+
Exclude:
|
|
4
|
+
- 'lib/rize/version.rb'
|
|
5
|
+
|
|
6
|
+
Style/SpaceInsideHashLiteralBraces:
|
|
7
|
+
Enabled: false
|
|
8
|
+
|
|
9
|
+
Style/StringLiterals:
|
|
10
|
+
Enabled: false
|
|
11
|
+
|
|
12
|
+
Style/NumericLiterals:
|
|
13
|
+
Enabled: false
|
|
14
|
+
|
|
15
|
+
Metrics/AbcSize:
|
|
16
|
+
Enabled: false
|
|
17
|
+
|
|
18
|
+
Metrics/LineLength:
|
|
19
|
+
Max: 120
|
|
20
|
+
|
|
21
|
+
Style/HashSyntax:
|
|
22
|
+
Enabled: false
|
|
23
|
+
|
|
24
|
+
Style/PercentLiteralDelimiters:
|
|
25
|
+
Enabled: false
|
|
26
|
+
|
|
27
|
+
Style/Documentation:
|
|
28
|
+
Enabled: false
|
|
29
|
+
|
|
30
|
+
Style/UnneededPercentQ:
|
|
31
|
+
Enabled: false
|
|
32
|
+
|
|
33
|
+
Style/BracesAroundHashParameters:
|
|
34
|
+
Enabled: false
|
|
35
|
+
|
|
36
|
+
Metrics/MethodLength:
|
|
37
|
+
Enabled: false
|
|
38
|
+
|
|
39
|
+
Style/Lambda:
|
|
40
|
+
Enabled: false
|
|
41
|
+
|
|
42
|
+
Style/WordArray:
|
|
43
|
+
Enabled: false
|
|
44
|
+
|
|
45
|
+
Style/SymbolProc:
|
|
46
|
+
Enabled: false
|
|
47
|
+
|
|
48
|
+
Metrics/ClassLength:
|
|
49
|
+
Enabled: false
|
|
50
|
+
|
|
51
|
+
Style/GuardClause:
|
|
52
|
+
Enabled: false
|
data/.travis.yml
ADDED
data/.yardopts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--exclude lib/rize.rb
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Contributor Code of Conduct
|
|
2
|
+
|
|
3
|
+
As contributors and maintainers of this project, and in the interest of
|
|
4
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
|
5
|
+
contribute through reporting issues, posting feature requests, updating
|
|
6
|
+
documentation, submitting pull requests or patches, and other activities.
|
|
7
|
+
|
|
8
|
+
We are committed to making participation in this project a harassment-free
|
|
9
|
+
experience for everyone, regardless of level of experience, gender, gender
|
|
10
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
|
11
|
+
body size, race, ethnicity, age, religion, or nationality.
|
|
12
|
+
|
|
13
|
+
Examples of unacceptable behavior by participants include:
|
|
14
|
+
|
|
15
|
+
* The use of sexualized language or imagery
|
|
16
|
+
* Personal attacks
|
|
17
|
+
* Trolling or insulting/derogatory comments
|
|
18
|
+
* Public or private harassment
|
|
19
|
+
* Publishing other's private information, such as physical or electronic
|
|
20
|
+
addresses, without explicit permission
|
|
21
|
+
* Other unethical or unprofessional conduct
|
|
22
|
+
|
|
23
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
|
24
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
25
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
26
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
|
27
|
+
threatening, offensive, or harmful.
|
|
28
|
+
|
|
29
|
+
By adopting this Code of Conduct, project maintainers commit themselves to
|
|
30
|
+
fairly and consistently applying these principles to every aspect of managing
|
|
31
|
+
this project. Project maintainers who do not follow or enforce the Code of
|
|
32
|
+
Conduct may be permanently removed from the project team.
|
|
33
|
+
|
|
34
|
+
This code of conduct applies both within project spaces and in public spaces
|
|
35
|
+
when an individual is representing the project or its community.
|
|
36
|
+
|
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
38
|
+
reported by contacting a project maintainer at abhijeetkalyan@gmail.com. All
|
|
39
|
+
complaints will be reviewed and investigated and will result in a response that
|
|
40
|
+
is deemed necessary and appropriate to the circumstances. Maintainers are
|
|
41
|
+
obligated to maintain confidentiality with regard to the reporter of an
|
|
42
|
+
incident.
|
|
43
|
+
|
|
44
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
45
|
+
version 1.3.0, available at
|
|
46
|
+
[http://contributor-covenant.org/version/1/3/0/][version]
|
|
47
|
+
|
|
48
|
+
[homepage]: http://contributor-covenant.org
|
|
49
|
+
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 Abhijeet Kalyan.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
[](https://travis-ci.org/abhijeetkalyan/rize)
|
|
2
|
+
|
|
3
|
+
# Rize
|
|
4
|
+
|
|
5
|
+
### A functional toolkit for Ruby.
|
|
6
|
+
|
|
7
|
+
(Inspired by Javascript's [Underscore](http://underscorejs.org/), Python's [toolz](https://github.com/pytoolz/toolz) and Ocaml's [List module](http://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html)).
|
|
8
|
+
|
|
9
|
+
Rize is a collection of useful methods that can make it easier to work with functions, arrays and hashes in Ruby. Some of the interesting things you can do include:
|
|
10
|
+
|
|
11
|
+
- Compose, memoize and partially supply arguments to your functions
|
|
12
|
+
- Control the behaviour of your functions based on how many times they're called - for example, you could create a function that stops executing on the third try.
|
|
13
|
+
- Map or iterate over multiple arrays at once
|
|
14
|
+
- Elegantly map over just the keys, or just the values of a hash.
|
|
15
|
+
|
|
16
|
+
See the [Usage](https://github.com/abhijeetkalyan/rize#usage) section for more on what rize can do.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
Add this line to your application's Gemfile:
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
gem 'rize'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
And then execute:
|
|
27
|
+
|
|
28
|
+
$ bundle
|
|
29
|
+
|
|
30
|
+
Or install it yourself as:
|
|
31
|
+
|
|
32
|
+
$ gem install rize
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
Rize has two primary uses: working with [functions](https://github.com/abhijeetkalyan/rize/blob/master/lib/rize/functional.rb) and working with [iterables](https://github.com/abhijeetkalyan/rize/blob/master/lib/rize/iteration.rb). More on each follows:
|
|
37
|
+
|
|
38
|
+
### Functions
|
|
39
|
+
|
|
40
|
+
- `memoize` - Creates a new function that caches its results. Useful for expensive computations, which you may not want to re-run multiple times.
|
|
41
|
+
- `compose` - Takes in a list of functions, and creates a new function that composes them together. Useful if you have a bunch of smaller functions, and want to mix them up in various different ways.
|
|
42
|
+
- `partial` - Partially supply arguments to a function. Useful if you have some of the arguments now, but won't get the rest until later. Unlike the stdlib's `Proc#curry`, there are no restrictions on the positions of the arguments - you can have arguments 1 and 3 now, and tell `partial` to supply the second argument when it gets it.
|
|
43
|
+
- `at_most` - Allow a function to be called only a certain number of times. Useful for behaviours you don't want to retry endlessly, like attempting to connect to a database.
|
|
44
|
+
- `at_least` - Allow a function to work only *after* it's been called a certain number of times.
|
|
45
|
+
|
|
46
|
+
### Iterables
|
|
47
|
+
|
|
48
|
+
- `hmap` - A more concise way of mapping over the keys and values of a hash in one go.
|
|
49
|
+
- `hkeymap` - Map over just the keys of a hash, and leave the values as they are.
|
|
50
|
+
- `hvalmap` - Map over just the values of a hash, and leave the keys as they are.
|
|
51
|
+
- `hd` - Get the first element of an array.
|
|
52
|
+
- `tl` - Everything *but* the first element of an array. Useful in recursive functions.
|
|
53
|
+
- `frequencies` - Count the occurrences of each element in an array, or the occurrences of even numbers, or the occurrences of anything else, depending on the block you pass in.
|
|
54
|
+
- `map_n` - Map over multiple arrays at once. Useful when dealing with matrix operations and the like.
|
|
55
|
+
- `each_n` - Iterate over multiple arrays at once. Useful when dealing with matrix operations and the like.
|
|
56
|
+
- `repeat` - Repeat the passed in block a certain number of times. Useful when repeating repetitive(meta!) operations, like mass-assigning a bunch of random numbers or mass-creating a bunch of test factories.
|
|
57
|
+
- `lazy_repeat` - Lazy version of repeat.
|
|
58
|
+
- `flatter_map` - Map over the underlying elements of an array, regardless of how deeply the array is nested.
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## Development
|
|
62
|
+
|
|
63
|
+
For initial setup:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
bundle install
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Run the tests:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
rake test
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
To work with Rize in an interactive console:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
bundle console
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
## Contributing
|
|
84
|
+
|
|
85
|
+
Bug reports and pull requests are welcome on [GitHub] (https://github.com/abhijeetkalyan/rize). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
86
|
+
|
|
87
|
+
Some interesting TODOs might include:
|
|
88
|
+
|
|
89
|
+
- Support timing-related functions such as `throttle` or `debounce` a la [Underscore](http://underscorejs.org/).
|
|
90
|
+
- Lazy versions of the iteration methods
|
|
91
|
+
- C/Java/other extensions for performance
|
|
92
|
+
- Support for passing methods as symbols instead of as method objects, such as `compose(:foo, :bar)` instead of `compose(method(:foo), method(:bar)`
|
|
93
|
+
- More methods available for iteration over multiple arrays at once, in addition to the already-existing `each_n` and `map_n`
|
|
94
|
+
- Integration with a cache such as Redis, to be
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/setup
ADDED
data/lib/rize.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require "rize/version"
|
|
2
|
+
require "rize/iteration"
|
|
3
|
+
require "rize/functional"
|
|
4
|
+
|
|
5
|
+
module Rize
|
|
6
|
+
# A class used when partially supplying positional
|
|
7
|
+
# arguments for a function.
|
|
8
|
+
class DontCare
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
DC = DontCare.new
|
|
12
|
+
|
|
13
|
+
# Error when the function from `after` hasn't been called enough times.
|
|
14
|
+
class TooFewCallsError < StandardError; end
|
|
15
|
+
|
|
16
|
+
# Error when the function from `before` has been called too many times.
|
|
17
|
+
class TooManyCallsError < StandardError; end
|
|
18
|
+
end
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
module Rize
|
|
2
|
+
module_function
|
|
3
|
+
|
|
4
|
+
# Returns a memoized version of a given proc, lambda, or method.
|
|
5
|
+
#
|
|
6
|
+
# @param func [Proc, Lambda, Method] The proc, lambda, or method to memoize.
|
|
7
|
+
#
|
|
8
|
+
# @return [Lambda] A lambda that is the memoized version of the input function.
|
|
9
|
+
# @example Memoize an expensive function.
|
|
10
|
+
# expensive_lambda = lambda do |arg|
|
|
11
|
+
# puts "very expensive computation"
|
|
12
|
+
# arg
|
|
13
|
+
# end
|
|
14
|
+
# memoized = Rize.memoize(expensive_lambda)
|
|
15
|
+
#
|
|
16
|
+
# memoized.call(1)
|
|
17
|
+
# "very expensive computation"
|
|
18
|
+
# 1
|
|
19
|
+
# memoized.call(1)
|
|
20
|
+
# 1
|
|
21
|
+
# memoized.call(2)
|
|
22
|
+
# "very expensive computation"
|
|
23
|
+
# 2
|
|
24
|
+
# memoized.call(2)
|
|
25
|
+
# 2
|
|
26
|
+
def memoize(func)
|
|
27
|
+
memo = {}
|
|
28
|
+
call_count = Hash.new(0)
|
|
29
|
+
lambda do |*args|
|
|
30
|
+
return memo[args] if call_count[args] == 1
|
|
31
|
+
memo[args] = func.call(*args)
|
|
32
|
+
call_count[args] += 1
|
|
33
|
+
memo[args]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Compose multiple procs, lambdas or methods.
|
|
38
|
+
#
|
|
39
|
+
# @param *funcs [Proc, Lambda, Method] A variable-length number of procs, lambdas or methods to compose.
|
|
40
|
+
#
|
|
41
|
+
# @return [Lambda] A lambda that is the composition of the inputs.
|
|
42
|
+
# compose(f, g, h).call(arg) is the same as f(g(h.call(arg)))
|
|
43
|
+
# @example Compose various mathematical operations together to compute (2(a + b))^2.
|
|
44
|
+
# f = lambda { |x| x**2 }
|
|
45
|
+
# g = lambda { |x| 2 * x }
|
|
46
|
+
# h = lambda { |x, y| x + y }
|
|
47
|
+
# composed = Rize.compose(f, g, h)
|
|
48
|
+
# composed.call(2, 3)
|
|
49
|
+
# 100
|
|
50
|
+
def compose(*funcs)
|
|
51
|
+
-> (*args) { call_all(funcs, *args) }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Returns a negated version of a proc, lambda, or method.
|
|
55
|
+
# The input function should return a boolean.
|
|
56
|
+
# @param func [Proc, Lambda, Method] A proc, lambda, or method to negate.
|
|
57
|
+
#
|
|
58
|
+
# @return [Lambda] A lambda that is the negation of func.
|
|
59
|
+
#
|
|
60
|
+
# @example Given a function that checks evenness, create a function that checks oddness.
|
|
61
|
+
# even = lambda { |x| x.even? }
|
|
62
|
+
# odd = Rize.negate(even)
|
|
63
|
+
def negate(func)
|
|
64
|
+
-> (*args) { !func.call(*args) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# TODO: Pull out shared logic between at_least, at_most, and memoize
|
|
68
|
+
|
|
69
|
+
# Raises an error until after a function is called a certain number of times, following which the function is
|
|
70
|
+
# executed.
|
|
71
|
+
# Raises instead of returning nil to provide better transparency to callers.
|
|
72
|
+
#
|
|
73
|
+
# @param func [Proc, Lambda, or Method] A proc, lambda or method.
|
|
74
|
+
# @param allowed_call_count [Fixnum] The minimum number of times this function needs to be called to start executing.
|
|
75
|
+
# @raise TooFewCallsError [StandardError] Exception raised when the function hasn't been called enough times.
|
|
76
|
+
#
|
|
77
|
+
# @return [Lambda] A lambda that places the appropriate call restrictions on func.
|
|
78
|
+
#
|
|
79
|
+
# @example Execute a function only on the 3rd attempt.
|
|
80
|
+
# succeed = lambda { |*args| "success!" }
|
|
81
|
+
# persevere = Rize.at_least(succeed, 3)
|
|
82
|
+
# 3.times do
|
|
83
|
+
# begin
|
|
84
|
+
# persevere.call
|
|
85
|
+
# rescue Rize::TooFewCallsError
|
|
86
|
+
# puts "keep trying"
|
|
87
|
+
# end
|
|
88
|
+
# end
|
|
89
|
+
# "keep trying"
|
|
90
|
+
# "keep trying"
|
|
91
|
+
# "success!"
|
|
92
|
+
def at_least(func, allowed_call_count)
|
|
93
|
+
call_count = 0
|
|
94
|
+
lambda do |*args|
|
|
95
|
+
call_count += 1
|
|
96
|
+
raise TooFewCallsError, "Minimum call count is #{allowed_call_count}." if call_count < allowed_call_count
|
|
97
|
+
func.call(*args)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Executes a function upto a certain number of times, following which an error is raised.
|
|
102
|
+
# Raises instead of returning nil to provide better transparency to callers.
|
|
103
|
+
#
|
|
104
|
+
# @param func [Proc, Lambda, or Method] A proc, lambda or method.
|
|
105
|
+
# @param allowed_call_count [Fixnum] The maximum number of times the function can execute.
|
|
106
|
+
# @raise TooManyCallsError [StandardError] Exception raised when the function has been called too many times.
|
|
107
|
+
#
|
|
108
|
+
# @return [Lambda] A lambda that places the appropriate call restrictions on func.
|
|
109
|
+
#
|
|
110
|
+
# @example Execute a function 2 times, then fail on attempt 3 onwards.
|
|
111
|
+
# are_we_there_yet = lambda { |*args| "Are we there yet?" }
|
|
112
|
+
# but_are_we_really_there_yet = Rize.at_most(are_we_there_yet, 2)
|
|
113
|
+
# 2.times do
|
|
114
|
+
# begin
|
|
115
|
+
# but_are_we_really_there_yet.call
|
|
116
|
+
# rescue Rize::TooManyCallsError
|
|
117
|
+
# puts "That's it, I'm turning this car around"
|
|
118
|
+
# end
|
|
119
|
+
# end
|
|
120
|
+
# "Are we there yet?"
|
|
121
|
+
# "Are we there yet?"
|
|
122
|
+
# "That's it, I'm turning this car around"
|
|
123
|
+
#
|
|
124
|
+
# @example Try connecting to a database 3 times. Give up on attempt 4.
|
|
125
|
+
# MAX_RETRIES = 3
|
|
126
|
+
# try_connect = Rize.at_most( lambda { |db| db.connect }, MAX_RETRIES )
|
|
127
|
+
# loop do
|
|
128
|
+
# begin
|
|
129
|
+
# try_connect.call(db)
|
|
130
|
+
# rescue TooManyCallsError
|
|
131
|
+
# # If we've tried too many times, give up
|
|
132
|
+
# break
|
|
133
|
+
# rescue ConnectionError
|
|
134
|
+
# # If we can't connect, try again
|
|
135
|
+
# try_connect.call(db)
|
|
136
|
+
# end
|
|
137
|
+
# end
|
|
138
|
+
def at_most(func, allowed_call_count)
|
|
139
|
+
call_count = 0
|
|
140
|
+
lambda do |*args|
|
|
141
|
+
call_count += 1
|
|
142
|
+
raise TooManyCallsError, "Maximum call count is #{allowed_call_count}." if call_count > allowed_call_count
|
|
143
|
+
func.call(*args)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Partially supply the arguments to a proc, lambda, or method.
|
|
148
|
+
#
|
|
149
|
+
# @param func [Proc, Lambda, Method] The proc, lambda, or method to partially supply arguments to.
|
|
150
|
+
# @param *args [Object] A variable-length number of positional arguments.
|
|
151
|
+
# Use Rize::DC as a 'don't care' variable to signify that we'd like to supply this argument later.
|
|
152
|
+
# This is useful, for example, if we have arguments 1 and 3, but are waiting on argument 2.
|
|
153
|
+
# @param **kwargs [Object] A variable-length number of keyword arguments.
|
|
154
|
+
#
|
|
155
|
+
# @return [Lambda] A lambda that is the partially filled version of the input function.
|
|
156
|
+
# @example Supply the second and third positional arguments, but not the first.
|
|
157
|
+
# final_lambda = lambda do |a, b, c|
|
|
158
|
+
# (a - b) * c
|
|
159
|
+
# end
|
|
160
|
+
# # Supply b and c.
|
|
161
|
+
# partial_lambda = Rize.partial(final_lambda, Rize::DC, 2, 3)
|
|
162
|
+
# # Supply a.
|
|
163
|
+
# partial_lambda.call(1)
|
|
164
|
+
# -3 # (1 - 2) * 3
|
|
165
|
+
# @example Partial with keyword arguments.
|
|
166
|
+
# final_lambda = lambda do |a:, b:, c:|
|
|
167
|
+
# (a - b) * c
|
|
168
|
+
# end
|
|
169
|
+
# Supply a: and c:.
|
|
170
|
+
# partial_lambda = Rize.partial(final_lambda, a:1, c: 3)
|
|
171
|
+
# Supply b:.
|
|
172
|
+
# partial_lambda.call(b: 2)
|
|
173
|
+
# -3 # (1 - 2) * 3
|
|
174
|
+
# @example Partial with positional and keyword arguments.
|
|
175
|
+
# final_lambda = lambda do |a, b, c:|
|
|
176
|
+
# (a - b) * c
|
|
177
|
+
# end
|
|
178
|
+
# Supply a and c:.
|
|
179
|
+
# partial_lambda = Rize.partial(final_lambda, 1, c: 3)
|
|
180
|
+
# Supply b.
|
|
181
|
+
# partial_lambda.call(2)
|
|
182
|
+
# -3 # (1 - 2) * 3
|
|
183
|
+
def partial(func, *args, **kwargs)
|
|
184
|
+
lambda do |*new_args, **new_kwargs|
|
|
185
|
+
func.call(*(merge_positional(args, new_args) + merge_keyword(kwargs, new_kwargs)))
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Internal method used by partial to handle positional arguments.
|
|
190
|
+
# Given arrays [1, Rize::DC, 3] and [2], returns [1, 2, 3].
|
|
191
|
+
# @param prefilled_args [Array] Prefilled args supplied to Rize.partial.
|
|
192
|
+
# @param new_args [Array] Args supplied at call-time of the function.
|
|
193
|
+
#
|
|
194
|
+
# @return [Array] the merged arguments in the manner described above.
|
|
195
|
+
def merge_positional(prefilled_args, new_args)
|
|
196
|
+
tmp_new_args = new_args.dup
|
|
197
|
+
prefilled_args.map do |elem|
|
|
198
|
+
if elem == DC
|
|
199
|
+
tmp_new_args.shift
|
|
200
|
+
else
|
|
201
|
+
elem
|
|
202
|
+
end
|
|
203
|
+
end + tmp_new_args
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Internal method used by partial to handle keyword arguments.
|
|
207
|
+
# Returns [] if passed in empty hashes.
|
|
208
|
+
# @param prefilled_kwargs [Hash] Prefilled kwargs supplied to Rize.partial.
|
|
209
|
+
# @param new_kwargs [Hash] kwargs supplied at call-time of the function.
|
|
210
|
+
#
|
|
211
|
+
# @return [Array] An array holding the merged keyword arguments.
|
|
212
|
+
def merge_keyword(prefilled_kwargs, new_kwargs)
|
|
213
|
+
return [] if prefilled_kwargs.empty? && new_kwargs.empty?
|
|
214
|
+
[prefilled_kwargs.merge(new_kwargs)]
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Internal helper used by compose to actually call functions.
|
|
218
|
+
#
|
|
219
|
+
# @param funcs [Array] An array of procs, lambdas or methods.
|
|
220
|
+
# @param *args [Object] A variable-length number of arguments to call the actual functions with.
|
|
221
|
+
def call_all(funcs, *args)
|
|
222
|
+
return funcs[0].call(*args) if funcs.length == 1
|
|
223
|
+
|
|
224
|
+
funcs[0].call(call_all(funcs.drop(1), *args))
|
|
225
|
+
end
|
|
226
|
+
end
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
module Rize
|
|
2
|
+
module_function
|
|
3
|
+
|
|
4
|
+
# Map over the keys and values of a hash.
|
|
5
|
+
#
|
|
6
|
+
# @param hsh [Hash] The hash to be mapped over.
|
|
7
|
+
# @yield [key, value] A block which returns in the form [key, value].
|
|
8
|
+
#
|
|
9
|
+
# @return [Hash] Returns a new hash with the results of running the block over it.
|
|
10
|
+
# @example Map over a hash
|
|
11
|
+
# Rize.hmap({a: 1, b: 2}) { |k,v| [k.to_s, v + 1] }
|
|
12
|
+
# { "a" => 2, "b" => 3 }
|
|
13
|
+
def hmap(hsh)
|
|
14
|
+
Hash[hsh.map { |k, v| yield(k, v) }]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Map over the keys of a hash.
|
|
18
|
+
#
|
|
19
|
+
# @param hsh [Hash] The hash to be mapped over.
|
|
20
|
+
# @yield [key] A block that acts upon the hash keys.
|
|
21
|
+
#
|
|
22
|
+
# @return [Hash] Returns a new hash with updated keys, and unchanged values.
|
|
23
|
+
# @example Map over a hash's keys.
|
|
24
|
+
# Rize.hkeymap({a: 1, b: 2}, &:to_s)
|
|
25
|
+
# { "a" => 1, "b" => 2 }
|
|
26
|
+
def hkeymap(hsh)
|
|
27
|
+
Hash[hsh.map { |k, v| [yield(k), v] }]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Map over the values of a hash.
|
|
31
|
+
#
|
|
32
|
+
# @param hsh [Hash] The hash to be mapped over.
|
|
33
|
+
# @yield [value] A block that acts upon the hash values
|
|
34
|
+
#
|
|
35
|
+
# @return [Hash] Returns a new hash with updated values, and unchanged keys.
|
|
36
|
+
# @example Map over a hash's values.
|
|
37
|
+
# Rize.hvalmap({a: 1, b: 2}, &:to_s)
|
|
38
|
+
# { a: "1", b: "2" }
|
|
39
|
+
def hvalmap(hsh)
|
|
40
|
+
Hash[hsh.map { |k, v| [k, yield(v)] }]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns the first element of an array, or nil if the array is empty.
|
|
44
|
+
#
|
|
45
|
+
# @param arr [Array] The array from which we want the head.
|
|
46
|
+
#
|
|
47
|
+
# @return [Object] The first element of the array.
|
|
48
|
+
# @example Get the first element of an array.
|
|
49
|
+
# Rize.hd [1, 2, 3]
|
|
50
|
+
# 1
|
|
51
|
+
# @example
|
|
52
|
+
# Rize.hd []
|
|
53
|
+
# nil
|
|
54
|
+
def hd(arr)
|
|
55
|
+
arr[0]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Returns all but the first element of the array.
|
|
59
|
+
#
|
|
60
|
+
# @param arr [Array] The array from which we want the tail.
|
|
61
|
+
#
|
|
62
|
+
# @return [Array] An array containing all but the first element of the input.
|
|
63
|
+
# @example Get all but the first element of the array.
|
|
64
|
+
# Rize.tl [1, 2, 3]
|
|
65
|
+
# [2, 3]
|
|
66
|
+
# @example
|
|
67
|
+
# Rize.tl []
|
|
68
|
+
# []
|
|
69
|
+
def tl(arr)
|
|
70
|
+
arr.drop(1)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Find how many times a block evaluates to a particular result in an array.
|
|
74
|
+
#
|
|
75
|
+
# @param arr [Array] The array over which we're counting frequencies.
|
|
76
|
+
# @yield [elem] A block whose results we use to calculate frequencies.
|
|
77
|
+
#
|
|
78
|
+
# @return [Hash] A hash containing the count of each of block's output values from the array.
|
|
79
|
+
# The keys are the various outputs, and the values are the number of times said outputs occurred.
|
|
80
|
+
# @example Count the elements in an array.
|
|
81
|
+
# Rize.frequencies([1, 2, 3, 1]) { |el| el }
|
|
82
|
+
# { 1 => 2, 2 => 1, 3 => 1 }
|
|
83
|
+
# @example Count the even numbers in an array.
|
|
84
|
+
# Rize.frequencies([1, 2, 3, 1]) { |el| el.even? }
|
|
85
|
+
# { true => 1, false => 3 }
|
|
86
|
+
def frequencies(arr)
|
|
87
|
+
hvalmap(arr.group_by { |el| yield(el) }, &:length)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Map over multiple arrays together.
|
|
91
|
+
#
|
|
92
|
+
# The same as doing [block(a1, b1, c1), block(a2, b2, c2)]
|
|
93
|
+
# for arrays [a1, b1, c1] and [a2, b2, c2].
|
|
94
|
+
#
|
|
95
|
+
# Raises an ArgumentError if arrays are of unequal length.
|
|
96
|
+
#
|
|
97
|
+
# @param args [Array] A variable-length number of arrays.
|
|
98
|
+
# @yield [*args] A block that acts upon elements at a particular index in the array.
|
|
99
|
+
#
|
|
100
|
+
# @return [Array] The result of calling the block over the matching array elements.
|
|
101
|
+
# @example Sum all the elements at the same position across multiple arrays.
|
|
102
|
+
# Rize.map_n([1, 2, 3], [4, 5, 6], [7, 8, 9]) { |*args| args.reduce(:+) }
|
|
103
|
+
# [12, 15, 18]
|
|
104
|
+
# @example Subtract the second array's element from the first, and multiply by the third.
|
|
105
|
+
# Rize.map_n([1, 2, 3], [4, 5, 6], [7, 8, 9]) { |a, b, c| (a - b) * c }
|
|
106
|
+
# [-21, -24, -27]
|
|
107
|
+
# @example Try with arrays of unequal length.
|
|
108
|
+
# Rize.map_n([1, 2], [1, 2, 3]) { |*args| args.reduce(:+) }
|
|
109
|
+
# ArgumentError: Expected all inputs to be of length 2
|
|
110
|
+
def map_n(*args)
|
|
111
|
+
expected_length = args[0].length
|
|
112
|
+
if args.any? { |arr| arr.length != expected_length }
|
|
113
|
+
raise ArgumentError, "Expected all inputs to be of length #{expected_length}"
|
|
114
|
+
end
|
|
115
|
+
hd(args).zip(*tl(args)).map do |elems|
|
|
116
|
+
yield(*elems)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Iterate over multiple arrays together.
|
|
121
|
+
#
|
|
122
|
+
# The same as doing [block(a1, b1, c1), block(a2, b2, c2)]
|
|
123
|
+
# for arrays [a1, b1, c1] and [a2, b2, c2].
|
|
124
|
+
#
|
|
125
|
+
# Raises an ArgumentError if arrays are of unequal length.
|
|
126
|
+
#
|
|
127
|
+
# @param args [Array] A variable-length number of arrays.
|
|
128
|
+
# @yield [*args] A block that acts upon elements at a particular index in the array.
|
|
129
|
+
#
|
|
130
|
+
# @return [Array] The input arrays.
|
|
131
|
+
# @example Print the transposed version of an array of arrays.
|
|
132
|
+
# Rize.each_n([1, 2, 3], [4, 5, 6], [7, 8, 9]) { |a, b, c| puts "#{a} #{b} #{c}" }
|
|
133
|
+
# 1 4 7
|
|
134
|
+
# 2 5 8
|
|
135
|
+
# 3 6 9
|
|
136
|
+
def each_n(*args)
|
|
137
|
+
expected_length = args[0].length
|
|
138
|
+
if args.any? { |arr| arr.length != expected_length }
|
|
139
|
+
raise ArgumentError, "Expected all inputs to be of length #{expected_length}"
|
|
140
|
+
end
|
|
141
|
+
hd(args).zip(*tl(args)).each do |elems|
|
|
142
|
+
yield(*elems)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Repeat a block N times, and return an array of the results.
|
|
147
|
+
#
|
|
148
|
+
# @param count [Fixnum] The number of times to repeat a block.
|
|
149
|
+
# @yield The block to be called.
|
|
150
|
+
#
|
|
151
|
+
# @return [Array] The result of running block, `count` times.
|
|
152
|
+
# @example Mass-assign several variables to different random numbers.
|
|
153
|
+
# a, b, c = Rize.repeat { Random.new.rand(50) }
|
|
154
|
+
# a
|
|
155
|
+
# 24
|
|
156
|
+
# b
|
|
157
|
+
# 10
|
|
158
|
+
# c
|
|
159
|
+
# 18
|
|
160
|
+
# @example Initialize multiple FactoryGirl objects in one go.
|
|
161
|
+
# u1, u2, u3 = Rize.repeat { FactoryGirl.create(:user) }
|
|
162
|
+
# u1
|
|
163
|
+
# <User Object 1>
|
|
164
|
+
# u2
|
|
165
|
+
# <User Object 2>
|
|
166
|
+
# u3
|
|
167
|
+
# <User Object 3>
|
|
168
|
+
def repeat(count)
|
|
169
|
+
result = []
|
|
170
|
+
count.times { result << yield }
|
|
171
|
+
result
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Lazy version of repeat.
|
|
175
|
+
# Repeat a block N times, and return a lazy enumerator which can be forced for results.
|
|
176
|
+
#
|
|
177
|
+
# @yield The block to be called.
|
|
178
|
+
#
|
|
179
|
+
# @return [Enumerator::Lazy] A lazy enumerator that can be evaluated for the desired number of results.
|
|
180
|
+
# @example Mass-assign several variables to different random numbers.
|
|
181
|
+
# a, b, c = Rize.repeat { Random.new.rand(50) }.first(3)
|
|
182
|
+
# a
|
|
183
|
+
# 24
|
|
184
|
+
# b
|
|
185
|
+
# 10
|
|
186
|
+
# c
|
|
187
|
+
# 18
|
|
188
|
+
# @example Initialize multiple FactoryGirl objects in one go.
|
|
189
|
+
# u1, u2, u3 = Rize.repeat { FactoryGirl.create(:user) }.first(3)
|
|
190
|
+
# u1
|
|
191
|
+
# <User Object 1>
|
|
192
|
+
# u2
|
|
193
|
+
# <User Object 2>
|
|
194
|
+
# u3
|
|
195
|
+
# <User Object 3>
|
|
196
|
+
def lazy_repeat
|
|
197
|
+
(1..Float::INFINITY).lazy.map { yield }
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Variation on Enumerable#flat_map that flattens the array before running the block.
|
|
201
|
+
# Useful when dealing with an array of arrays, where we really want to operate on the underlying elements.
|
|
202
|
+
#
|
|
203
|
+
# @param arr [Array] The array to be operated on.
|
|
204
|
+
#
|
|
205
|
+
# @yield [elem] The block to be called.
|
|
206
|
+
#
|
|
207
|
+
# @return [Array] The result of calling flat_map on the flattened array.
|
|
208
|
+
#
|
|
209
|
+
# @example Capitalize each letter in an array of arrays.
|
|
210
|
+
# Rize.flatter_map([["a", "b"], [["c"], ["d"]]], &:capitalize)
|
|
211
|
+
# ["A", "B", "C", "D"]
|
|
212
|
+
# @example Capitalize each letter in an array of arrays, and also return the non-capitalized version.
|
|
213
|
+
# Rize.flatter_map([["a", "b"], [["c"], ["d"]]]) { |el| [el, el.capitalize] }
|
|
214
|
+
# ["a", "A", "b", "B", "c", "C", "d", "D"]
|
|
215
|
+
def flatter_map(arr, &block)
|
|
216
|
+
arr.flatten.flat_map(&block)
|
|
217
|
+
end
|
|
218
|
+
end
|
data/lib/rize/version.rb
ADDED
data/rize.gemspec
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'rize/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "rize"
|
|
8
|
+
spec.version = Rize::VERSION
|
|
9
|
+
spec.authors = ["abhijeetkalyan"]
|
|
10
|
+
spec.email = ["abhijeetkalyan@gmail.com"]
|
|
11
|
+
|
|
12
|
+
spec.summary = %q{Write a short summary, because Rubygems requires one.}
|
|
13
|
+
spec.description = %q{Write a longer description or delete this line.}
|
|
14
|
+
spec.homepage = "https://github.com/abhijeetkalyan/rize"
|
|
15
|
+
spec.license = "MIT"
|
|
16
|
+
spec.required_ruby_version = '>= 2.0.0'
|
|
17
|
+
|
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
19
|
+
spec.bindir = "exe"
|
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
21
|
+
spec.require_paths = ["lib"]
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
26
|
+
spec.add_development_dependency "byebug", "~> 8.2"
|
|
27
|
+
spec.add_development_dependency "pry", "~> 0.10.3"
|
|
28
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rize
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- abhijeetkalyan
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-05-15 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.12'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.12'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: minitest
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '5.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '5.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: byebug
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '8.2'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '8.2'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: pry
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 0.10.3
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 0.10.3
|
|
83
|
+
description: Write a longer description or delete this line.
|
|
84
|
+
email:
|
|
85
|
+
- abhijeetkalyan@gmail.com
|
|
86
|
+
executables: []
|
|
87
|
+
extensions: []
|
|
88
|
+
extra_rdoc_files: []
|
|
89
|
+
files:
|
|
90
|
+
- ".gitignore"
|
|
91
|
+
- ".rubocop.yml"
|
|
92
|
+
- ".travis.yml"
|
|
93
|
+
- ".yardopts"
|
|
94
|
+
- CODE_OF_CONDUCT.md
|
|
95
|
+
- Gemfile
|
|
96
|
+
- LICENSE.txt
|
|
97
|
+
- README.md
|
|
98
|
+
- Rakefile
|
|
99
|
+
- bin/console
|
|
100
|
+
- bin/setup
|
|
101
|
+
- lib/rize.rb
|
|
102
|
+
- lib/rize/functional.rb
|
|
103
|
+
- lib/rize/iteration.rb
|
|
104
|
+
- lib/rize/version.rb
|
|
105
|
+
- rize.gemspec
|
|
106
|
+
homepage: https://github.com/abhijeetkalyan/rize
|
|
107
|
+
licenses:
|
|
108
|
+
- MIT
|
|
109
|
+
metadata: {}
|
|
110
|
+
post_install_message:
|
|
111
|
+
rdoc_options: []
|
|
112
|
+
require_paths:
|
|
113
|
+
- lib
|
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - ">="
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: 2.0.0
|
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
124
|
+
requirements: []
|
|
125
|
+
rubyforge_project:
|
|
126
|
+
rubygems_version: 2.4.8
|
|
127
|
+
signing_key:
|
|
128
|
+
specification_version: 4
|
|
129
|
+
summary: Write a short summary, because Rubygems requires one.
|
|
130
|
+
test_files: []
|
|
131
|
+
has_rdoc:
|