crack_pipe 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b90ccb391cbc78b10497f1978236cac94de4f715
4
+ data.tar.gz: 12f9809281e638984c9d59ac340f5cef7e5c6592
5
+ SHA512:
6
+ metadata.gz: 8e53e038a829b08417c47ab9a961dc76169be2d6ca6393f70ab0bb2e4f1c249a17b2f58851354f1500e55515ab07d0f07060ac14822bb0e440a1c60665dc4168
7
+ data.tar.gz: 3d4f43c12cc6d2c9af68c2b28395d7fdf4da17bc81afbac25bdd9e07ee34b3051097f54044e330e277d2c03107f3a2e50fd3e5ce48892aed8ce2c18db522aa71
data/LICENSE.txt ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2019 Joshua Hansen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # CrackPipe
2
+
3
+ ## Introduction
4
+
5
+ A little over a year ago, I discovered [Trailblazer](http://trailblazer.to) and used its concept of "operations" in a few projects. While I came to enjoy their concept of pipelines and result objects, I felt the entire project was entirely too complex for my use cases. I wanted much simpler pipelines and nesting.
6
+
7
+ ### What's with the name?
8
+
9
+ Gem names are hard to come by these days. I'd considered something slightly more mature like `half_pipe`, but in the age of appending a codes of conduct to projects, I lean offensive in naming wherever possible. I'm kinda wishing I had named [my factory gem](https://github.com/binarypaladin/toil) `meth_lab` instead.
10
+
11
+ ## Installation
12
+
13
+ Pretty standard gem stuff.
14
+
15
+ ```
16
+ $ gem install crack_pipe
17
+ ```
18
+
19
+ If you're using [Bundler](https://bundler.io) (and who isn't?) it's likely you'll add this to your `Gemfile` like so:
20
+
21
+ ```
22
+ gem 'crack_pipe'
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ One day I'll write some actual documentation. (Yeah, right.) In the meantime, [the action spec](spec/action_spec.rb) has a pretty good example of steps, always passing, fail tracks, short circuiting, and nesting actions.
28
+
29
+ ## Contributing
30
+
31
+ ### Issue Guidelines
32
+
33
+ GitHub issues are for bugs, not support. As of right now, there is no official support for this gem. You can try reaching out to the author, [Joshua Hansen](mailto:joshua@epicbanality.com?subject=CrackPipe+sucks) if you're really stuck, but there's a pretty high chance that won't go anywhere at the moment or you'll get a response like this:
34
+
35
+ > Hi. I'm super busy. It's nothing personal. Check the README first if you haven't already. If you don't find your answer there, it's time to start reading the source. Have fun! Let me know if I screwed something up.
36
+
37
+ ### Pull Request Guidelines
38
+
39
+ * Include tests with your PRs.
40
+
41
+ ### Code of Conduct
42
+
43
+ Don't smoke crack.
44
+
45
+ ## License
46
+
47
+ See [`LICENSE.txt`](LICENSE.txt).
48
+
49
+ ## What if I stop maintaining this?
50
+
51
+ The codebase is pretty small. That was one of the main design goals. If you can figure out how to use it, I'm sure you can maintain it.
@@ -0,0 +1,27 @@
1
+ # frozen-string-literal: true
2
+
3
+ module CrackPipe
4
+ class Action
5
+ class Result
6
+ attr_reader :context, :output
7
+
8
+ def initialize(context: {}, output: nil, success:, **)
9
+ @context = context
10
+ @output = output
11
+ @success = success
12
+ end
13
+
14
+ def [](key)
15
+ @context[key]
16
+ end
17
+
18
+ def failure?
19
+ !@success
20
+ end
21
+
22
+ def success?
23
+ @success
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ # frozen-string-literal: true
2
+
3
+ module CrackPipe
4
+ class Action
5
+ class ShortCircuit
6
+ attr_reader :success, :value
7
+
8
+ def initialize(value, success = nil)
9
+ @value = value
10
+ @success = success
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ # frozen-string-literal: true
2
+
3
+ module CrackPipe
4
+ class Action
5
+ class Step
6
+ attr_reader :exec, :context_override, :desc, :output_override, :track
7
+
8
+ def initialize(
9
+ track,
10
+ exec,
11
+ output_override = nil,
12
+ **context_override
13
+ )
14
+ @context_override = context_override.dup
15
+ @exec = exec
16
+ @output_override = output_override
17
+ @track = track
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,166 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'crack_pipe/action/result'
4
+ require 'crack_pipe/action/short_circuit'
5
+ require 'crack_pipe/action/step'
6
+
7
+ module CrackPipe
8
+ class Action
9
+ @steps = []
10
+
11
+ class << self
12
+ attr_reader :steps
13
+
14
+ def call(context, &blk)
15
+ new(context, steps, &blk).result
16
+ end
17
+
18
+ def inherited(subclass)
19
+ subclass.instance_variable_set(:@steps, @steps.dup)
20
+ super
21
+ end
22
+
23
+ private
24
+
25
+ def fail(exec = nil, **kwargs, &blk)
26
+ step(exec, kwargs.merge(track: :fail), &blk)
27
+ end
28
+
29
+ def pass(exec = nil, **kwargs, &blk)
30
+ step(exec, kwargs.merge(output_override: true), &blk)
31
+ end
32
+
33
+ def step(
34
+ exec = nil,
35
+ output_override: nil,
36
+ track: :default,
37
+ **opts,
38
+ &blk
39
+ )
40
+ if block_given?
41
+ raise ArgumentError, '`exec` must be `nil` with a block' unless
42
+ exec.nil?
43
+ exec = blk
44
+ end
45
+ @steps += [Step.new(track, exec, output_override, opts)]
46
+ end
47
+ end
48
+
49
+ attr_reader :history, :result
50
+
51
+ def initialize(context, steps = self.class.steps, &blk)
52
+ @history = []
53
+ _result!(context.dup, steps.dup, &blk)
54
+ end
55
+
56
+ # NOTE: While this hook does nothing by default, it is here with the
57
+ # intention of dealing with potential default values being generated either
58
+ # for output or adding values to the context. A common example would be
59
+ # returning some kind of default failure object in place of a literal `nil`
60
+ # or `false`.
61
+ def after_step(output, _context, _step)
62
+ output
63
+ end
64
+
65
+ def fail!(value)
66
+ ShortCircuit.new(value, false)
67
+ end
68
+
69
+ def pass!(value)
70
+ ShortCircuit.new(value, true)
71
+ end
72
+
73
+ def step_failure?(output)
74
+ case output
75
+ when Result
76
+ output.failure?
77
+ else
78
+ !output
79
+ end
80
+ end
81
+
82
+ def to_a
83
+ history.dup
84
+ end
85
+
86
+ private
87
+
88
+ def _action?(obj)
89
+ obj.is_a?(Class) && obj < Action
90
+ end
91
+
92
+ def _exec_nested!(context, action)
93
+ @history += action.new(context).history
94
+ @history.last.tap { |h| context.merge!(h[:context]) }
95
+ end
96
+
97
+ def _exec_step!(context, step)
98
+ e = step.exec
99
+ return _exec_nested!(context, e) if _action?(e)
100
+
101
+ output =
102
+ case e
103
+ when Symbol
104
+ public_send(e, context, **context)
105
+ when Proc
106
+ instance_exec(context, **context, &e)
107
+ else
108
+ e.call(context, **context)
109
+ end
110
+
111
+ _wrap_output(after_step(output, context, step), context.dup, step)
112
+ .tap { |wo| @history << wo }
113
+ end
114
+
115
+ def _exec_steps!(context, steps)
116
+ next_track = :default
117
+ steps.map do |s|
118
+ next unless next_track == s.track
119
+ _exec_step!(context, s).tap do |wrapped_output|
120
+ next_track =
121
+ wrapped_output[:short_circuit] ? nil : wrapped_output[:next_track]
122
+ end
123
+ end.compact.last
124
+ end
125
+
126
+ def _output_hash(output, step)
127
+ output = step.output_override unless step.output_override.nil?
128
+ success = step.track != :fail && !step_failure?(output)
129
+ case output
130
+ when ShortCircuit
131
+ {
132
+ output: output.value,
133
+ short_circuit: true,
134
+ success: output.success.nil? ? success : output.success
135
+ }
136
+ else
137
+ {
138
+ output: output,
139
+ short_circuit: false,
140
+ success: success
141
+ }
142
+ end
143
+ end
144
+
145
+ # NOTE: The optional block here allows you to wrap the the execution in
146
+ # external functionality, such as a default `rescue` or something like a
147
+ # database transaction if it's necessary to span multiple steps.
148
+ def _result!(context, steps)
149
+ if block_given?
150
+ yield(@result = Result.new(_exec_steps!(context, steps)))
151
+ else
152
+ @result = Result.new(_exec_steps!(context, steps))
153
+ end
154
+ @result
155
+ end
156
+
157
+ def _wrap_output(output, context, step)
158
+ wrapped_output = _output_hash(after_step(output, context, step), step)
159
+ {
160
+ exec: step.exec,
161
+ next_track: wrapped_output[:success] ? :default : :fail,
162
+ context: context
163
+ }.merge(wrapped_output)
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,12 @@
1
+ # frozen-string-literal: true
2
+
3
+ module CrackPipe
4
+ MAJOR = 0
5
+ MINOR = 1
6
+ TINY = 0
7
+ VERSION = [MAJOR, MINOR, TINY].join('.').freeze
8
+
9
+ def self.version
10
+ VERSION
11
+ end
12
+ end
data/lib/crack_pipe.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'crack_pipe/action'
4
+ require 'crack_pipe/version'
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crack_pipe
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Joshua
8
+ - Hansen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-07-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.16'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.16'
28
+ - !ruby/object:Gem::Dependency
29
+ name: minitest
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '5.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '5.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '10.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '10.0'
56
+ description: Pipelines... on crack I guess.
57
+ email:
58
+ - joshua@epicbanality.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - LICENSE.txt
64
+ - README.md
65
+ - lib/crack_pipe.rb
66
+ - lib/crack_pipe/action.rb
67
+ - lib/crack_pipe/action/result.rb
68
+ - lib/crack_pipe/action/short_circuit.rb
69
+ - lib/crack_pipe/action/step.rb
70
+ - lib/crack_pipe/version.rb
71
+ homepage: https://github.com/binarypaladin/crack_pipe
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 2.2.0
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.4.5.4
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Pipelines... on crack I guess.
95
+ test_files: []