pipey 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 +9 -0
- data/Gemfile +5 -0
- data/README.md +155 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/pipey.rb +11 -0
- data/lib/pipey/chain.rb +23 -0
- data/lib/pipey/core.rb +23 -0
- data/lib/pipey/extensions.rb +31 -0
- data/lib/pipey/line.rb +23 -0
- data/lib/pipey/steps.rb +33 -0
- data/lib/pipey/version.rb +3 -0
- data/pipey.gemspec +26 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d5af6b9a3c74fce3126319deb94789a55cbe9e80
|
4
|
+
data.tar.gz: a5fd97c3205c86a00cb2e303093d41a9a203093a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8f54f83712ed5d9c3f5a9d91f28cb3ccc3f3b2034327a04932c74d6b5817095c0b0cb1ff31509a29c3918a483d6b07dfc8a7ea1959c4733a592b1d84657c9ae5
|
7
|
+
data.tar.gz: e1e51361b41741ec6cd2fc4923e1eb7a5a205400fe250fe1c92db8ac05c04e3c4294d6d4cf51ee87e22e0af71589ee5dc23e1b4e114ff9cd4a0c9317933fffac
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
# Pipey
|
2
|
+
|
3
|
+
A utility for pipeline operations.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'pipey'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install pipey
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### `Pipey::Line`
|
24
|
+
|
25
|
+
`Pipey::Line` can be used to work with any object in a pipe-line manner.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
class MyPipe < Pipey::Line
|
29
|
+
extend Pipey::Steps::Scanner[/^run_/]
|
30
|
+
|
31
|
+
def run_foo(num, multiply:, **)
|
32
|
+
num * multiply
|
33
|
+
end
|
34
|
+
|
35
|
+
def run_bar(num, add:, **)
|
36
|
+
num + add
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
MyPipe.call(1, multiply: 10, add: 5) #=> 15
|
41
|
+
```
|
42
|
+
|
43
|
+
### `Pipey::Chain`
|
44
|
+
|
45
|
+
`Pipey::Chain` is a slightly fancier way to work with chainable objects like `Array`s or `ActiveRecord::Relation`s.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class MyPipe < Pipey::Chain
|
49
|
+
extend Pipey::Steps::Scanner[/^run_/]
|
50
|
+
|
51
|
+
def run_foo(multiply:, **)
|
52
|
+
map { |v| v * a }
|
53
|
+
end
|
54
|
+
|
55
|
+
def run_bar(minimum:, **)
|
56
|
+
select { |v| v > minimum }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
MyPipe.call([1, 2, 3], multiply: 5, minimum: 6) #=> [10, 15]
|
61
|
+
```
|
62
|
+
|
63
|
+
### `Pipey::Steps::Scanner`
|
64
|
+
|
65
|
+
`Pipey::Steps::Scanner` takes a `Regexp` as an argument, and it will run the methods that match the regexp.
|
66
|
+
|
67
|
+
**NOTE:** This does not guarantee the order in which steps will run.
|
68
|
+
|
69
|
+
### `Pipey::Steps::DSL`
|
70
|
+
|
71
|
+
If you don't like the automatic behavior provided by `Pipey::Steps::Scanner`, you can use `Pipey::Steps::DSL` instead. With it, you can list out your steps.
|
72
|
+
|
73
|
+
**NOTE:** This does guarantee the order in which steps will run.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
class MyPipe < Pipey::Line
|
77
|
+
extend Pipey::Steps::DSL
|
78
|
+
|
79
|
+
step :foo
|
80
|
+
step :bar
|
81
|
+
|
82
|
+
def foo(num, multiply:, **)
|
83
|
+
num * multiply
|
84
|
+
end
|
85
|
+
|
86
|
+
def bar(num, add:, **)
|
87
|
+
num + add
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
MyPipe.call(1, multiply: 10, add: 5) #=> 15
|
92
|
+
```
|
93
|
+
|
94
|
+
### `Pipey::Extensions::RequiredKeys`
|
95
|
+
|
96
|
+
This extension won't call a step if it requires a key that is falsy.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
class MyPipe < Pipey::Line
|
100
|
+
extend Pipey::Steps::Scanner[/^run_/]
|
101
|
+
extend Pipey::Extensions::RequiredKeys
|
102
|
+
|
103
|
+
def run_foo(num, multiply:, **)
|
104
|
+
num * multiply
|
105
|
+
end
|
106
|
+
|
107
|
+
def run_bar(num, add:, **)
|
108
|
+
num + add
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
MyPipe.call(1, multiply: 10, add: 5) #=> 15
|
113
|
+
MyPipe.call(1, multiply: 10) #=> 10
|
114
|
+
MyPipe.call(1, add: 5) #=> 6
|
115
|
+
```
|
116
|
+
|
117
|
+
### `Pipey::Extensions::IgnoreNil`
|
118
|
+
|
119
|
+
By using this extension, any step that returns nil will be ignored.
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
class MyPipe < Pipey::Line
|
123
|
+
extend Pipey::Steps::Scanner[/^run_/]
|
124
|
+
extend Pipey::Extensions::IgnoreNil
|
125
|
+
|
126
|
+
def run_foo(num, add:, **)
|
127
|
+
num * add if add > 5
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
MyPipe.call(1, add: 5) #=> 1
|
132
|
+
MyPipe.call(1, add: 6) #=> 6
|
133
|
+
```
|
134
|
+
|
135
|
+
### `Pipey::Extensions::Ignore`
|
136
|
+
|
137
|
+
This can be used to create more complicated ignores.
|
138
|
+
|
139
|
+
For example, the implementation of `IgnoreNil` looks like this:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
Pipey::Extensions::Ignore.new(&:nil?)
|
143
|
+
```
|
144
|
+
|
145
|
+
If you wanted to ignore any value equal to 5, you could do this:
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
class MyPipe < Pipey::Line
|
149
|
+
extend Pipey::Extensions::Ignore.new { |v| v == 5 }
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
## Contributing
|
154
|
+
|
155
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rzane/pipey.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "pipey"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/pipey.rb
ADDED
data/lib/pipey/chain.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'pipey/core'
|
2
|
+
|
3
|
+
module Pipey
|
4
|
+
class Chain < SimpleDelegator
|
5
|
+
include Core
|
6
|
+
|
7
|
+
def self.call(initial, params = {})
|
8
|
+
new(initial).call(params)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call!(params = {}) # :nodoc:
|
12
|
+
self.class.steps_for(params).each do |name|
|
13
|
+
result = send(name, params)
|
14
|
+
|
15
|
+
if self.class.valid_pipe_result?(result)
|
16
|
+
__setobj__(result)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
__getobj__
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/pipey/core.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Pipey
|
2
|
+
module Core # :nodoc:
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def valid_pipe_result?(_)
|
9
|
+
true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def stop!(*args)
|
14
|
+
throw(:__pipey_stop, *args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(*args)
|
18
|
+
catch :__pipey_stop do
|
19
|
+
clone.call!(*args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Pipey
|
2
|
+
module Extensions
|
3
|
+
module RequiredKeys
|
4
|
+
# @override Pipey::DSL.steps_for
|
5
|
+
# @override Pipey::Scanner.steps_for
|
6
|
+
def steps_for(params)
|
7
|
+
super.reject do |step|
|
8
|
+
instance_method(step).parameters.any? do |type, name|
|
9
|
+
type == :keyreq && params[name].nil?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Ignore < Module
|
16
|
+
class << self
|
17
|
+
alias [] new
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(&comparator)
|
21
|
+
# @override Pipey::Chain#valid_pipe_result?
|
22
|
+
# @override Pipey::Line#valid_pipe_result?
|
23
|
+
define_method :valid_pipe_result? do |result|
|
24
|
+
super(result) && !comparator.call(result)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
IgnoreNil = Ignore.new(&:nil?)
|
30
|
+
end
|
31
|
+
end
|
data/lib/pipey/line.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'pipey/core'
|
2
|
+
|
3
|
+
module Pipey
|
4
|
+
class Line
|
5
|
+
include Core
|
6
|
+
|
7
|
+
def self.call(*args)
|
8
|
+
new.call(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call!(initial, opts = {})
|
12
|
+
self.class.steps_for(opts).reduce(initial) do |value, name|
|
13
|
+
result = send(name, value, opts)
|
14
|
+
|
15
|
+
if self.class.valid_pipe_result?(result)
|
16
|
+
result
|
17
|
+
else
|
18
|
+
value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/pipey/steps.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Pipey
|
2
|
+
module Steps
|
3
|
+
module DSL
|
4
|
+
def steps
|
5
|
+
@steps ||= []
|
6
|
+
end
|
7
|
+
|
8
|
+
def steps_for(_)
|
9
|
+
steps
|
10
|
+
end
|
11
|
+
|
12
|
+
def step(key)
|
13
|
+
steps << key
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Scanner < Module
|
18
|
+
class << self
|
19
|
+
alias [] new
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(pattern)
|
23
|
+
define_method :steps do
|
24
|
+
instance_methods.grep(pattern)
|
25
|
+
end
|
26
|
+
|
27
|
+
define_method :steps_for do |_|
|
28
|
+
steps
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/pipey.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pipey/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "pipey"
|
8
|
+
spec.version = Pipey::VERSION
|
9
|
+
spec.authors = ["Ray Zane"]
|
10
|
+
spec.email = ["raymondzane@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Utilities for building data pipelines.}
|
13
|
+
spec.homepage = "https://github.com/rzane/pipey"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
16
|
+
f.match(%r{^(test|spec|features)/})
|
17
|
+
end
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "minitest"
|
25
|
+
spec.add_development_dependency "m"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pipey
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ray Zane
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-11 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.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
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: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: m
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- raymondzane@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- Gemfile
|
78
|
+
- README.md
|
79
|
+
- Rakefile
|
80
|
+
- bin/console
|
81
|
+
- bin/setup
|
82
|
+
- lib/pipey.rb
|
83
|
+
- lib/pipey/chain.rb
|
84
|
+
- lib/pipey/core.rb
|
85
|
+
- lib/pipey/extensions.rb
|
86
|
+
- lib/pipey/line.rb
|
87
|
+
- lib/pipey/steps.rb
|
88
|
+
- lib/pipey/version.rb
|
89
|
+
- pipey.gemspec
|
90
|
+
homepage: https://github.com/rzane/pipey
|
91
|
+
licenses: []
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 2.6.10
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
112
|
+
summary: Utilities for building data pipelines.
|
113
|
+
test_files: []
|