pipey 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pipey.gemspec
4
+ gemspec
5
+ gem 'pry'
@@ -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.
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new :default do |t|
5
+ t.libs << "test"
6
+ t.test_files = FileList['test/**/*_test.rb']
7
+ t.verbose = true
8
+ end
@@ -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__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,11 @@
1
+ require 'pipey/version'
2
+ require 'pipey/line'
3
+ require 'pipey/chain'
4
+ require 'pipey/steps'
5
+ require 'pipey/steps'
6
+ require 'pipey/extensions'
7
+ require 'pipey/extensions'
8
+
9
+ module Pipey
10
+ # Your code goes here...
11
+ end
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Pipey
2
+ VERSION = "0.1.0"
3
+ end
@@ -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: []