waterslide 0.1.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/.gitignore +35 -0
- data/LICENSE +22 -0
- data/README.md +170 -0
- data/lib/waterslide.rb +65 -0
- data/test.rb +178 -0
- data/waterslide.gemspec +18 -0
- metadata +50 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 301ba4b66544ec9a3c9291e2f0ca8b993881a009
|
|
4
|
+
data.tar.gz: 3267b0740f98719e6f791dccbc5b177eb0862813
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2529d565230da7c62d34593935581180b2e1c0499ee851660ac1fe66461e33d5b1fc3fd91a136131a85d617307fcaf9939934160159bddbdcadb5c42225e2a4e
|
|
7
|
+
data.tar.gz: c2c0a1baad887e297c0d8ba90680e016e0fa116209b559d760cef3a99167d7a9f6e8f47f68b39c170359b7154e6d670eea6c647ecb903deb5966406c4abc1c5a
|
data/.gitignore
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/test/tmp/
|
|
9
|
+
/test/version_tmp/
|
|
10
|
+
/tmp/
|
|
11
|
+
|
|
12
|
+
## Specific to RubyMotion:
|
|
13
|
+
.dat*
|
|
14
|
+
.repl_history
|
|
15
|
+
build/
|
|
16
|
+
|
|
17
|
+
## Documentation cache and generated files:
|
|
18
|
+
/.yardoc/
|
|
19
|
+
/_yardoc/
|
|
20
|
+
/doc/
|
|
21
|
+
/rdoc/
|
|
22
|
+
|
|
23
|
+
## Environment normalisation:
|
|
24
|
+
/.bundle/
|
|
25
|
+
/vendor/bundle
|
|
26
|
+
/lib/bundler/man/
|
|
27
|
+
|
|
28
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
29
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
30
|
+
# Gemfile.lock
|
|
31
|
+
# .ruby-version
|
|
32
|
+
# .ruby-gemset
|
|
33
|
+
|
|
34
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
35
|
+
.rvmrc
|
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Ben Christel
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# waterslide
|
|
2
|
+
|
|
3
|
+
Unix-style pipes for Ruby programs
|
|
4
|
+
|
|
5
|
+
## TL;DR
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
class FacebookFriendsController < ApplicationController
|
|
9
|
+
def index
|
|
10
|
+
render json:
|
|
11
|
+
FacebookFriends.new(current_user) >>
|
|
12
|
+
DeserializeFacebookUsers >>
|
|
13
|
+
MergeWithAttributesFromDatabase >>
|
|
14
|
+
RemoveRecordsNotInDatabase >>
|
|
15
|
+
Serialize
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Wat
|
|
21
|
+
|
|
22
|
+
A common problem in programming is the need to perform a series of transformations on data. Ruby enumerables have lots of nice functional-style methods (`map`, `reduce`) to make this easy, but in some cases this approach breaks down.
|
|
23
|
+
|
|
24
|
+
Let's say you're building a social app where users log in with Facebook. You want to have a page where users can see which of their Facebook friends are using your site.
|
|
25
|
+
|
|
26
|
+
Doing this requires calling the Facebook API to get the current user's friends, merging the data from Facebook with the user data in your own database, filtering out the Facebook users who don't have accounts on your site, and serializing the remaining users to HTML or JSON so you can render them on your page.
|
|
27
|
+
|
|
28
|
+
The usual solution might look something like this:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
Facebook.friends_of(current_user)
|
|
32
|
+
.map { |friend_datum| FacebookUserDeserializer.deserialize(friend_datum) }
|
|
33
|
+
.map { |user| user.merge_attributes User.find_by_facebook_id(user.facebook_id) }
|
|
34
|
+
.reject { |user| user.id.nil? }
|
|
35
|
+
.map { |user| UserSerializer.serialize(user) }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Later, you find that the page takes a long time to load for users with many facebook friends, and you isolate the problem to the O(n) `User.find_by_facebook_id` calls, most of which don't actually find a user. Fortunately, that's not hard to fix.
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
facebook_friends = Facebook.friends_of(current_user).map do |friend_datum|
|
|
42
|
+
FacebookUserDeserializer.deserialize(friend_datum)
|
|
43
|
+
end
|
|
44
|
+
facebook_ids = facebook_friends.map(&:facebook_id)
|
|
45
|
+
facebook_friends_from_database = User.where(facebook_id: facebook_ids)
|
|
46
|
+
facebook_friends.map! do |friend|
|
|
47
|
+
db_record = facebook_friends_from_database.find do |db_record|
|
|
48
|
+
db_record.facebook_id == friend.facebook_id
|
|
49
|
+
end
|
|
50
|
+
friend.merge_attributes db_record
|
|
51
|
+
end
|
|
52
|
+
facebook_friends.map do |user|
|
|
53
|
+
UserSerializer.serialize(user)
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
In making the code more efficient, its elegance has been destroyed. Now one of the `map` blocks is dependent on an invariant - the users pulled from the database - and that dependency makes the code harder to read and harder to refactor.
|
|
58
|
+
|
|
59
|
+
With Waterslide, the various data transformations can easily be broken into their own classes.
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
class FacebookFriends
|
|
63
|
+
include Waterslide::Pipe
|
|
64
|
+
|
|
65
|
+
def initialize(current_user)
|
|
66
|
+
@current_user = current_user
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def each(&block)
|
|
70
|
+
@friends ||= Facebook.friends_of(@current_user)
|
|
71
|
+
@friends.each(&block)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class DeserializeFacebookUsers
|
|
76
|
+
include Waterslide::Pipe
|
|
77
|
+
|
|
78
|
+
def pipe_one(user_json)
|
|
79
|
+
yield User.new#( ... )
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
class MergeWithAttributesFromDatabase
|
|
84
|
+
include Waterslide::Pipe
|
|
85
|
+
|
|
86
|
+
def pipe_one(user)
|
|
87
|
+
record = database_records.find do |record|
|
|
88
|
+
record.facebook_id == user.facebook_id
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
yield user.merge_attributes record
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def database_records
|
|
95
|
+
@records ||= User.where(facebook_id: incoming.map(&:facebook_id)).to_a
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class RemoveRecordsNotInDatabase
|
|
100
|
+
include Waterslide::Pipe
|
|
101
|
+
|
|
102
|
+
def pipe_one(record)
|
|
103
|
+
yield record if record.id
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
class Serialize
|
|
108
|
+
include Waterslide::Pipe
|
|
109
|
+
|
|
110
|
+
def as_json
|
|
111
|
+
map(&:as_json)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# ...
|
|
116
|
+
|
|
117
|
+
FacebookFriends.new(current_user) >>
|
|
118
|
+
DeserializeFacebookUsers >>
|
|
119
|
+
MergeWithAttributesFromDatabase >>
|
|
120
|
+
RemoveRecordsNotInDatabase >>
|
|
121
|
+
SerializeUsers
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
There's obviously a lot more lines of code in the new version, but the sequence of transformations reads naturally, and, perhaps more importantly, every step can now be unit-tested individually.
|
|
125
|
+
|
|
126
|
+
## Installation
|
|
127
|
+
|
|
128
|
+
Add this line to your application's Gemfile:
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
gem 'waterslide'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
And then execute:
|
|
135
|
+
|
|
136
|
+
$ bundle
|
|
137
|
+
|
|
138
|
+
Or install it yourself as:
|
|
139
|
+
|
|
140
|
+
$ gem install waterslide
|
|
141
|
+
|
|
142
|
+
## Usage
|
|
143
|
+
|
|
144
|
+
TODO: Write usage instructions here
|
|
145
|
+
|
|
146
|
+
## Serving Suggestions
|
|
147
|
+
|
|
148
|
+
If you like syntactic sugar on your cerealizables, you may want to monkey-patch Array with the Waterslide right-shift operator override. That will let you do stuff like this:
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
[1, 2, 3] >> MultiplyByTwo # => [2, 4, 6]
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Here's how to do the monkey-patch:
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
class Array
|
|
158
|
+
include Waterslide::RightShiftOverride
|
|
159
|
+
end
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
You should probably only do this if everyone on your team is on board with Waterslide and knows how to use it; otherwise, they'll have a hell of time deciphering your code.
|
|
163
|
+
|
|
164
|
+
## Contributing
|
|
165
|
+
|
|
166
|
+
1. Fork it ( https://github.com/benchristel/waterslide/fork )
|
|
167
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
168
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
169
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
170
|
+
5. Create a new Pull Request
|
data/lib/waterslide.rb
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Waterslide
|
|
2
|
+
module RightShiftOverride
|
|
3
|
+
def >> (pipe)
|
|
4
|
+
instantiated(pipe).receive_from(self)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
private
|
|
8
|
+
def instantiated(pipe)
|
|
9
|
+
pipe.is_a?(Class) ? pipe.new : pipe
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module Pipe
|
|
14
|
+
def self.included(base)
|
|
15
|
+
base.class_eval do
|
|
16
|
+
include Enumerable
|
|
17
|
+
include RightShiftOverride
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.[] (things)
|
|
22
|
+
things = [things] unless things.respond_to? :each
|
|
23
|
+
NoOp.new.receive_from(things)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def receive_from(enumerable)
|
|
27
|
+
@incoming = enumerable
|
|
28
|
+
self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def each
|
|
32
|
+
incoming.each do |one|
|
|
33
|
+
pipe_one(one) { |out| yield out }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def take
|
|
38
|
+
each { |one| return one }
|
|
39
|
+
return nil # if nothing was yielded
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def all
|
|
43
|
+
all = []
|
|
44
|
+
each { |one| all << one }
|
|
45
|
+
all
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def incoming
|
|
51
|
+
# including classes may override this to do processing on the incoming
|
|
52
|
+
# enumerable as as whole - for instance, to sort it.
|
|
53
|
+
@incoming
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def pipe_one(thing)
|
|
57
|
+
# identity function by default; including classes should override this
|
|
58
|
+
yield thing
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class NoOp
|
|
63
|
+
include Pipe
|
|
64
|
+
end
|
|
65
|
+
end
|
data/test.rb
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
gem 'minitest'
|
|
2
|
+
require 'minitest/autorun'
|
|
3
|
+
require_relative 'lib/waterslide'
|
|
4
|
+
|
|
5
|
+
include Waterslide
|
|
6
|
+
|
|
7
|
+
class AddOne
|
|
8
|
+
include Pipe
|
|
9
|
+
|
|
10
|
+
def pipe_one(thing)
|
|
11
|
+
yield thing + 1
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Add
|
|
16
|
+
include Pipe
|
|
17
|
+
|
|
18
|
+
def initialize(n)
|
|
19
|
+
@increment = n
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def pipe_one(thing)
|
|
23
|
+
yield thing + @increment
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def Add(*args)
|
|
28
|
+
Add.new(*args)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class TestWaterslide < MiniTest::Test
|
|
32
|
+
def test_piping_a_scalar_through_no_op
|
|
33
|
+
assert_equal 1, (Pipe[1] >> NoOp).first
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_piping_a_scalar_through_multiple_no_ops
|
|
37
|
+
assert_equal 1, (Pipe[1] >> NoOp >> NoOp).first
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_piping_a_scalar_through_add_one
|
|
41
|
+
assert_equal 2, (Pipe[1] >> AddOne).first
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_piping_a_scalar_through_multiple_add_ones
|
|
45
|
+
assert_equal 3, (Pipe[1] >> AddOne >> AddOne).first
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_piping_an_array_through_no_op
|
|
49
|
+
assert_equal [1,2,3], (Pipe[[1,2,3]] >> NoOp).all
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_piping_an_array_through_add_one
|
|
53
|
+
assert_equal [2,3,4], (Pipe[[1,2,3]] >> AddOne).all
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_piping_an_array_through_multiple_add_ones
|
|
57
|
+
assert_equal [3,4,5], (Pipe[[1,2,3]] >> AddOne >> AddOne).all
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_piping_an_array_through_add
|
|
61
|
+
assert_equal [4,5,6], (Pipe[[1,2,3]] >> Add(3)).all
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_that_pipes_are_enumerables
|
|
65
|
+
assert (Pipe[[1,2,3]] >> Add(3)).include? 4
|
|
66
|
+
assert_equal 3, (Pipe[[1,2,3]] >> Add(3)).count
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Duplicate
|
|
72
|
+
include Pipe
|
|
73
|
+
|
|
74
|
+
def pipe_one(thing)
|
|
75
|
+
yield thing
|
|
76
|
+
yield thing
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def test_duplicate
|
|
81
|
+
assert_equal [1,1,2,2,3,3], (Pipe[[1,2,3]] >> Duplicate).all
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class OnlyEvens
|
|
87
|
+
include Pipe
|
|
88
|
+
|
|
89
|
+
def pipe_one(n)
|
|
90
|
+
yield n if n % 2 == 0
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def test_piping_an_array_through_a_filter
|
|
95
|
+
assert_equal [2,4,6], (Pipe[[1,2,3,4,5,6]] >> OnlyEvens).all
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class Sort
|
|
101
|
+
include Pipe
|
|
102
|
+
|
|
103
|
+
def incoming
|
|
104
|
+
super.sort
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def test_sorting_with_overridden_incoming
|
|
109
|
+
assert_equal [1,2,3,4,5], (Pipe[[4,1,5,3,2]] >> Sort).all
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class Sort::Descending < Sort
|
|
115
|
+
def incoming
|
|
116
|
+
super.reverse
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def test_subclasses_of_pipes
|
|
121
|
+
assert_equal [5,4,3,2,1], (Pipe[[4,1,5,3,2]] >> Sort::Descending).all
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class AboveAverage
|
|
127
|
+
include Pipe
|
|
128
|
+
|
|
129
|
+
def pipe_one(thing)
|
|
130
|
+
yield thing if thing > average
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def average
|
|
134
|
+
@average ||= incoming.reduce(:+) / incoming.count
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def test_incoming_with_above_average
|
|
139
|
+
assert_equal [4,5], (Pipe[[1,2,3,4,5]] >> AboveAverage).all
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class InfiniteJest
|
|
145
|
+
include Pipe
|
|
146
|
+
|
|
147
|
+
def each
|
|
148
|
+
n = 0
|
|
149
|
+
while(n < 6)
|
|
150
|
+
yield 'ha'
|
|
151
|
+
n += 1
|
|
152
|
+
end
|
|
153
|
+
raise 'oh no you are dead'
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def test_that_enumeration_is_lazy_when_possible
|
|
158
|
+
haha = (InfiniteJest.new >> NoOp).first(5)
|
|
159
|
+
assert_equal ["ha"]*5, haha
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def test_that_enumeration_is_not_lazy_when_impossible
|
|
163
|
+
haha = (InfiniteJest.new >> Sort).first(5) rescue 'got to infinity'
|
|
164
|
+
assert_equal 'got to infinity', haha
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class MagicArray < Array
|
|
170
|
+
include Waterslide::RightShiftOverride
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def test_right_shift_operator_override
|
|
174
|
+
array = MagicArray.new
|
|
175
|
+
array << 1 << 2 << 3
|
|
176
|
+
assert (array >> Add(2)).map(&:to_i) == [3, 4, 5]
|
|
177
|
+
end
|
|
178
|
+
end
|
data/waterslide.gemspec
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
version = "0.1.0"
|
|
6
|
+
|
|
7
|
+
s.name = "waterslide"
|
|
8
|
+
s.version = version
|
|
9
|
+
s.platform = Gem::Platform::RUBY
|
|
10
|
+
s.license = "MIT"
|
|
11
|
+
s.authors = ["Ben Christel"]
|
|
12
|
+
s.homepage = "http://github.com/benchristel/waterslide"
|
|
13
|
+
s.summary = "waterslide-#{version}"
|
|
14
|
+
s.description = "Unix-style pipes in Ruby"
|
|
15
|
+
s.files = `git ls-files`.split("\n")
|
|
16
|
+
s.test_files = s.files.grep(/^test/)
|
|
17
|
+
s.require_paths = ["lib"]
|
|
18
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: waterslide
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ben Christel
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-04-19 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Unix-style pipes in Ruby
|
|
14
|
+
email:
|
|
15
|
+
executables: []
|
|
16
|
+
extensions: []
|
|
17
|
+
extra_rdoc_files: []
|
|
18
|
+
files:
|
|
19
|
+
- ".gitignore"
|
|
20
|
+
- LICENSE
|
|
21
|
+
- README.md
|
|
22
|
+
- lib/waterslide.rb
|
|
23
|
+
- test.rb
|
|
24
|
+
- waterslide.gemspec
|
|
25
|
+
homepage: http://github.com/benchristel/waterslide
|
|
26
|
+
licenses:
|
|
27
|
+
- MIT
|
|
28
|
+
metadata: {}
|
|
29
|
+
post_install_message:
|
|
30
|
+
rdoc_options: []
|
|
31
|
+
require_paths:
|
|
32
|
+
- lib
|
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
34
|
+
requirements:
|
|
35
|
+
- - ">="
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '0'
|
|
43
|
+
requirements: []
|
|
44
|
+
rubyforge_project:
|
|
45
|
+
rubygems_version: 2.4.6
|
|
46
|
+
signing_key:
|
|
47
|
+
specification_version: 4
|
|
48
|
+
summary: waterslide-0.1.0
|
|
49
|
+
test_files:
|
|
50
|
+
- test.rb
|