pipe_operator 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fc08d5b15937d1418ca864e631eb9f0a6a3fafd04e2c1f7496fbdd925531eec7
4
+ data.tar.gz: 340f185be7fe2f803a0d61603f1b1c89c641f6dfbf21ba691e1c3e48c3c5bdce
5
+ SHA512:
6
+ metadata.gz: 4b2e3096c092d839dde50eadbc196cef82745371c99cb313f845587b0c4908ab6225a261309984d2cdef927605f44308026adf57a7c02970721d84c0e240d958
7
+ data.tar.gz: a873ca59f03c6e50630c9d8b91f5494a5b7bfb06b558b21c574c716065f63fb381d155b66c106c4d12de237fbb8b1506bb40fd2e459f130a278ceea26ee0daa5
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ coverage
2
+ doc
3
+ pkg
4
+ rdoc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format progress
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,116 @@
1
+ AllCops:
2
+ DisplayCopNames: true
3
+ TargetRubyVersion: 2.5
4
+ Exclude:
5
+ - "Rakefile"
6
+ - "tmp/**/*"
7
+
8
+ Gemspec/RequiredRubyVersion:
9
+ Enabled: false
10
+
11
+ Layout/AlignHash:
12
+ Exclude:
13
+ - "spec/**/*"
14
+
15
+ Layout/EmptyLineAfterGuardClause:
16
+ Enabled: false
17
+
18
+ Layout/SpaceBeforeBlockBraces:
19
+ Exclude:
20
+ - "spec/**/*"
21
+
22
+ Layout/SpaceInsideBlockBraces:
23
+ Exclude:
24
+ - "spec/**/*"
25
+
26
+ Metrics/AbcSize:
27
+ Enabled: false
28
+
29
+ Metrics/BlockLength:
30
+ Enabled: false
31
+
32
+ Metrics/CyclomaticComplexity:
33
+ Enabled: false
34
+
35
+ Metrics/LineLength:
36
+ Enabled: false
37
+
38
+ Metrics/MethodLength:
39
+ Enabled: false
40
+
41
+ Metrics/PerceivedComplexity:
42
+ Exclude:
43
+ - "lib/pipe_operator/proxy.rb"
44
+ - "lib/pipe_operator/proxy_resolver.rb"
45
+
46
+ Naming/MemoizedInstanceVariableName:
47
+ Exclude:
48
+ - "lib/pipe_operator/closure.rb"
49
+
50
+ Naming/UncommunicativeMethodParamName:
51
+ Enabled: false
52
+
53
+ Style/BlockDelimiters:
54
+ Exclude:
55
+ - "spec/**/*"
56
+
57
+ Style/CaseEquality:
58
+ Enabled: false
59
+
60
+ Style/Documentation:
61
+ Enabled: false
62
+
63
+ Style/DoubleNegation:
64
+ Enabled: false
65
+
66
+ Style/FormatString:
67
+ Enabled: false
68
+
69
+ Style/FormatStringToken:
70
+ Enabled: false
71
+
72
+ Style/FrozenStringLiteralComment:
73
+ Enabled: false
74
+
75
+ Style/GuardClause:
76
+ Enabled: false
77
+
78
+ Style/LambdaCall:
79
+ Exclude:
80
+ - "spec/**/*"
81
+
82
+ Style/MethodMissingSuper:
83
+ Exclude:
84
+ - "lib/pipe_operator/closure.rb"
85
+ - "lib/pipe_operator/pipe.rb"
86
+
87
+ Style/RedundantBegin:
88
+ Exclude:
89
+ - "lib/pipe_operator/proxy_resolver.rb"
90
+
91
+ Style/RescueModifier:
92
+ Exclude:
93
+ - "lib/pipe_operator/proxy_resolver.rb"
94
+
95
+ Style/MissingRespondToMissing:
96
+ Exclude:
97
+ - "lib/pipe_operator/closure.rb"
98
+ - "lib/pipe_operator/pipe.rb"
99
+
100
+ Style/Semicolon:
101
+ Exclude:
102
+ - "spec/**/*"
103
+
104
+ Style/SingleLineMethods:
105
+ Exclude:
106
+ - "spec/**/*"
107
+
108
+ Style/StringLiterals:
109
+ EnforcedStyle: double_quotes
110
+
111
+ Style/TrailingCommaInHashLiteral:
112
+ Exclude:
113
+ - "spec/**/*"
114
+
115
+ Style/WordArray:
116
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "https://www.rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "codeclimate-test-reporter"
6
+ gem "fasterer"
7
+ gem "pry"
8
+ gem "pry-byebug"
9
+ gem "rake"
10
+ gem "rdoc"
11
+ gem "rspec"
12
+ gem "rubocop"
data/Gemfile.lock ADDED
@@ -0,0 +1,83 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pipe_operator (0.0.1)
5
+
6
+ GEM
7
+ remote: https://www.rubygems.org/
8
+ specs:
9
+ ast (2.4.0)
10
+ byebug (10.0.2)
11
+ codeclimate-test-reporter (1.0.9)
12
+ simplecov (<= 0.13)
13
+ coderay (1.1.2)
14
+ colorize (0.8.1)
15
+ diff-lcs (1.3)
16
+ docile (1.1.5)
17
+ fasterer (0.4.1)
18
+ colorize (~> 0.7)
19
+ ruby_parser (~> 3.11.0)
20
+ jaro_winkler (1.5.1)
21
+ json (2.1.0)
22
+ method_source (0.9.2)
23
+ parallel (1.12.1)
24
+ parser (2.5.3.0)
25
+ ast (~> 2.4.0)
26
+ powerpack (0.1.2)
27
+ pry (0.12.2)
28
+ coderay (~> 1.1.0)
29
+ method_source (~> 0.9.0)
30
+ pry-byebug (3.6.0)
31
+ byebug (~> 10.0)
32
+ pry (~> 0.10)
33
+ rainbow (3.0.0)
34
+ rake (12.3.1)
35
+ rdoc (6.0.4)
36
+ rspec (3.8.0)
37
+ rspec-core (~> 3.8.0)
38
+ rspec-expectations (~> 3.8.0)
39
+ rspec-mocks (~> 3.8.0)
40
+ rspec-core (3.8.0)
41
+ rspec-support (~> 3.8.0)
42
+ rspec-expectations (3.8.2)
43
+ diff-lcs (>= 1.2.0, < 2.0)
44
+ rspec-support (~> 3.8.0)
45
+ rspec-mocks (3.8.0)
46
+ diff-lcs (>= 1.2.0, < 2.0)
47
+ rspec-support (~> 3.8.0)
48
+ rspec-support (3.8.0)
49
+ rubocop (0.60.0)
50
+ jaro_winkler (~> 1.5.1)
51
+ parallel (~> 1.10)
52
+ parser (>= 2.5, != 2.5.1.1)
53
+ powerpack (~> 0.1)
54
+ rainbow (>= 2.2.2, < 4.0)
55
+ ruby-progressbar (~> 1.7)
56
+ unicode-display_width (~> 1.4.0)
57
+ ruby-progressbar (1.10.0)
58
+ ruby_parser (3.11.0)
59
+ sexp_processor (~> 4.9)
60
+ sexp_processor (4.11.0)
61
+ simplecov (0.13.0)
62
+ docile (~> 1.1.0)
63
+ json (>= 1.8, < 3)
64
+ simplecov-html (~> 0.10.0)
65
+ simplecov-html (0.10.2)
66
+ unicode-display_width (1.4.0)
67
+
68
+ PLATFORMS
69
+ ruby
70
+
71
+ DEPENDENCIES
72
+ codeclimate-test-reporter
73
+ fasterer
74
+ pipe_operator!
75
+ pry
76
+ pry-byebug
77
+ rake
78
+ rdoc
79
+ rspec
80
+ rubocop
81
+
82
+ BUNDLED WITH
83
+ 1.17.1
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2018 LendingHome - engineering@lendinghome.com
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,384 @@
1
+ # ![LendingHome](https://avatars0.githubusercontent.com/u/5448482?s=24&v=4) pipe_operator
2
+
3
+ > Elixir/Unix style pipe operations in Ruby - **PROOF OF CONCEPT**
4
+
5
+ ```ruby
6
+ -9.pipe { abs | Math.sqrt | to_i } #=> 3
7
+ ```
8
+
9
+ ```ruby
10
+ [9, 64].map(&Math.|.sqrt.to_i) #=> [3, 8]
11
+ ```
12
+
13
+ ```ruby
14
+ "https://api.github.com/repos/ruby/ruby".| do
15
+ URI.parse
16
+ Net::HTTP.get
17
+ JSON.parse.fetch("stargazers_count")
18
+ yield_self { |n| "Ruby has #{n} stars" }
19
+ Kernel.puts
20
+ end
21
+ #=> Ruby has 15115 stars
22
+ ```
23
+
24
+ ## Why?
25
+
26
+ There's been some recent activity related to `Method` and `Proc` composition in Ruby:
27
+
28
+ * [#6284 - Add composition for procs](https://bugs.ruby-lang.org/issues/6284)
29
+ * [#13581 - Syntax sugar for method reference](https://bugs.ruby-lang.org/issues/13581)
30
+ * [#12125 - Shorthand operator for Object#method](https://bugs.ruby-lang.org/issues/12125)
31
+
32
+ This gem was created to **propose an alternative syntax** for this kind of behavior.
33
+
34
+ ## Concept
35
+
36
+ The general idea is to **pass the result of one expression as an argument to another expression** - similar to [Unix pipelines](https://en.wikipedia.org/wiki/Pipeline_(Unix)):
37
+
38
+ ```ruby
39
+ echo "testing" | sed "s/ing//" | rev
40
+ #=> tset
41
+ ```
42
+
43
+ The [Elixir pipe operator documentation](https://elixirschool.com/en/lessons/basics/pipe-operator/) has some other examples but basically it allows expressions like:
44
+
45
+ ```ruby
46
+ JSON.parse(Net::HTTP.get(URI.parse(url)))
47
+ ```
48
+
49
+ To be **inversed** and rewritten as **left to right** or **top to bottom** which is more **natural to read** in English:
50
+
51
+ ```ruby
52
+ # left to right
53
+ url.pipe { URI.parse | Net::HTTP.get | JSON.parse }
54
+
55
+ # or top to bottom for clarity
56
+ url.pipe do
57
+ URI.parse
58
+ Net::HTTP.get
59
+ JSON.parse
60
+ end
61
+ ```
62
+
63
+ The differences become a bit **clearer when other arguments are involved**:
64
+
65
+ ```ruby
66
+ loans = Loan.preapproved.submitted(Date.current).where(broker: Current.user)
67
+ data = loans.map { |loan| LoanPresenter.new(loan).as_json }
68
+ json = JSON.pretty_generate(data, allow_nan: false)
69
+ ```
70
+
71
+ Using pipes **removes the verbosity of maps and temporary variables**:
72
+
73
+ ```ruby
74
+ json = Loan.pipe do
75
+ preapproved
76
+ submitted(Date.current)
77
+ where(broker: Current.user)
78
+ map(&LoanPresenter.new.as_json)
79
+ JSON.pretty_generate(allow_nan: false)
80
+ end
81
+ ```
82
+
83
+ While the ability to perform a job correctly and efficiently is certainly important - the **true beauty of a program lies in its clarity and conciseness**:
84
+
85
+ ```ruby
86
+ "https://api.github.com/repos/ruby/ruby".| do
87
+ URI.parse
88
+ Net::HTTP.get
89
+ JSON.parse.fetch("stargazers_count")
90
+ yield_self { |n| "Ruby has #{n} stars" }
91
+ Kernel.puts
92
+ end
93
+ #=> Ruby has 15115 stars
94
+ ```
95
+
96
+ There's nothing really special here - it's just a **block of expressions like any other Ruby DSL** and the pipe `|` operator has been [around for decades](https://en.wikipedia.org/wiki/Pipeline_(Unix))!
97
+
98
+ ```ruby
99
+ # we can already do this
100
+ objects.map(&Marshal.method(:dump))
101
+
102
+ # but this is more concise
103
+ objects.map(&Marshal.|.dump)
104
+ ```
105
+
106
+ The **simplicity and elegance of Ruby** is one of the many reasons that people fall in love with the language!
107
+
108
+ ```ruby
109
+ Ruby.is.so(:simple, &elegant).that(you can) do
110
+ pretty_much ANYTHING if it.compiles!
111
+ end
112
+ ```
113
+
114
+ This concept of **pipes could be a great fit** like it has been for many other languages:
115
+
116
+ * [Caml composition operators](http://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html#1_Compositionoperators)
117
+ * [Closure threading macros](https://clojure.org/guides/threading_macros)
118
+ * [Elixir pipe operator](https://elixirschool.com/en/lessons/basics/pipe-operator/)
119
+ * [Elm operators](https://elm-lang.org/docs/syntax#operators)
120
+ * [F# function composition and pipelining](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/index#function-composition-and-pipelining)
121
+ * [Hack pipe operator](https://docs.hhvm.com/hack/operators/pipe-operator)
122
+ * [Haskell pipes](http://hackage.haskell.org/package/pipes-4.3.9/docs/Pipes-Tutorial.html)
123
+ * [JavaScript pipeline operator proposals](https://github.com/tc39/proposal-pipeline-operator/wiki)
124
+ * [LiveScript piping](http://livescript.net/#piping)
125
+ * [Unix pipelines](https://en.wikipedia.org/wiki/Pipeline_(Unix))
126
+
127
+ ## Usage
128
+
129
+ **WARNING - EXPERIMENTAL PROOF OF CONCEPT**
130
+
131
+ This has only been **tested in isolation with RSpec**!
132
+
133
+ ```ruby
134
+ # First `gem install pipe_operator`
135
+ require "pipe_operator"
136
+
137
+ # Then use PipeOperator as a refinement
138
+ using ::PipeOperator
139
+
140
+ # Or include PipeOperator in classes/modules
141
+ class AnyClass
142
+ include ::PipeOperator
143
+ end
144
+
145
+ # Or monkey patch PipeOperator into ALL objects
146
+ require "pipe_operator/autoload"
147
+ ```
148
+
149
+ ## Implementation
150
+
151
+ The [PipeOperator](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator.rb) module has a method named `__pipe__` which is aliased as `pipe` for convenience and `|` for syntactic sugar:
152
+
153
+ ```ruby
154
+ def __pipe__(*args, &block)
155
+ Pipe.new(self, *args, &block)
156
+ end
157
+
158
+ alias | __pipe__
159
+ alias pipe __pipe__
160
+ ```
161
+
162
+ When no arguments are passed to `__pipe__` then a [PipeOperator::Pipe](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/pipe.rb) object is returned:
163
+
164
+ ```ruby
165
+ Math.| #=> #<PipeOperator::Pipe:Math>
166
+ ```
167
+
168
+ Any methods invoked on this object returns a [PipeOperator::Closure](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/closure.rb) which **calls the method on the object later**:
169
+
170
+ ```ruby
171
+ sqrt = Math.|.sqrt #=> #<PipeOperator::Closure:0x00007fc1172ed558@pipe_operator/closure.rb:18>
172
+ sqrt.call(16) #=> 4.0
173
+
174
+ missing = Math.|.missing #=> #<PipeOperator::Closure:0x00007fc11726f0e0@pipe_operator/closure.rb:18>
175
+ missing.call #=> NoMethodError: undefined method 'missing' for Math:Module
176
+
177
+ Math.method(:missing) #=> NameError: undefined method 'missing' for class '#<Class:Math>'
178
+ ```
179
+
180
+ When `__pipe__` is called **with arguments but without a block** then it behaves similar to `__send__`:
181
+
182
+ ```ruby
183
+ sqrt = Math | :sqrt #=> #<PipeOperator::Closure:0x00007fe52e0cdf80@pipe_operator/closure.rb:18>
184
+ sqrt.call(16) #=> 4.0
185
+
186
+ sqrt = Math.pipe(:sqrt, 16) #=> #<PipeOperator::Closure:0x00007fe52fa18fd0@pipe_operator/closure.rb:18>
187
+ sqrt.call #=> 4.0
188
+ sqrt.call(16) #=> ArgumentError: wrong number of arguments (given 2, expected 1)
189
+ ```
190
+
191
+ These [PipeOperator::Closure](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/closure.rb) objects can be [bound as block arguments](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/proxy.rb#L10-L13) just like any other [Proc](https://ruby-doc.org/core-2.5.3/Proc.html):
192
+
193
+ ```ruby
194
+ [16, 256].map(&Math.|.sqrt) #=> [4.0, 16.0]
195
+ ```
196
+
197
+ Simple **closure composition is supported** via [method chaining](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/closure.rb#L56):
198
+
199
+ ```ruby
200
+ [16, 256].map(&Math.|.sqrt.to_i.to_s) #=> ["4", "16"]
201
+ ```
202
+
203
+ The **block** form of `__pipe__` behaves **similar to instance_exec** but can also [call methods on other objects](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/pipe.rb#L81):
204
+
205
+ ```ruby
206
+ "abc".pipe { reverse } #=> "cba"
207
+ "abc".pipe { reverse.upcase } #=> "CBA"
208
+
209
+ "abc".pipe { Marshal.dump } #=> "\x04\bI\"\babc\x06:\x06ET"
210
+ "abc".pipe { Marshal.dump | Base64.encode64 } #=> "BAhJIghhYmMGOgZFVA==\n"
211
+ ```
212
+
213
+ Outside the context of a `__pipe__` block things behave like normal:
214
+
215
+ ```ruby
216
+ Math.sqrt #=> ArgumentError: wrong number of arguments (given 0, expected 1)
217
+ Math.sqrt(16) #=> 4.0
218
+ ```
219
+
220
+ But within a `__pipe__` block the `Math.sqrt` expression returns a [PipeOperator::Closure](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/closure.rb) instead:
221
+
222
+ ```ruby
223
+ 16.pipe { Math.sqrt } #=> 4.0
224
+ 16.pipe { Math.sqrt(16) } #=> ArgumentError: wrong number of arguments (given 2, expected 1)
225
+ ```
226
+
227
+ The **piped object is passed as the first argument by default** but can be customized by specifying `self`:
228
+
229
+ ```ruby
230
+ class String
231
+ def self.join(*args, with: "")
232
+ args.map(&:to_s).join(with)
233
+ end
234
+ end
235
+
236
+ "test".pipe { String.join("123", with: "-") } #=> "test-123"
237
+
238
+ "test".pipe { String.join("123", self, with: "-") } #=> "123-test"
239
+ ```
240
+
241
+ Instance methods like `reverse` below [do not receive the piped object](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/pipe.rb#L79) as [an argument](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/closure.rb#L47) since it's available as `self`:
242
+
243
+ ```ruby
244
+ Base64.encode64(Marshal.dump("abc").reverse) #=> "VEUGOgZjYmEIIkkIBA==\n"
245
+
246
+ "abc".pipe { Marshal.dump | reverse | Base64.encode64 } #=> "VEUGOgZjYmEIIkkIBA==\n"
247
+ ```
248
+
249
+ Pipes also support **multi-line blocks for clarity**:
250
+
251
+ ```ruby
252
+ "abc".pipe do
253
+ Marshal.dump
254
+ reverse
255
+ Base64.encode64
256
+ end
257
+ ```
258
+
259
+ Notice the pipe `|` operator wasn't used to **separate expressions** - it's actually always optional:
260
+
261
+ ```ruby
262
+ # this example from above
263
+ "abc".pipe { Marshal.dump | reverse | Base64.encode64 }
264
+
265
+ # could also be written as
266
+ "abc".pipe { Marshal.dump; reverse; Base64.encode64 }
267
+ ```
268
+
269
+ The closures created by these **pipe expressions are evaluated via reduce**:
270
+
271
+ ```ruby
272
+ pipeline = [
273
+ -> object { Marshal.dump(object) },
274
+ -> object { object.reverse },
275
+ -> object { Base64.encode64(object) },
276
+ ]
277
+
278
+ pipeline.reduce("abc") do |object, pipe|
279
+ pipe.call(object)
280
+ end
281
+ ```
282
+
283
+ [Intercepting methods](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/proxy.rb#L19-L25) within pipes requires [prepending](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/pipe.rb#L38) a [PipeOperator::Proxy](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/proxy.rb) module infront of `::Object` and all [nested constants](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/proxy_resolver.rb#L46):
284
+
285
+ ```ruby
286
+ define_method(method) do |*args, &block|
287
+ if Pipe.open
288
+ Pipe.new(self).__send__(method, *args, &block)
289
+ else
290
+ super(*args, &block)
291
+ end
292
+ end
293
+ ```
294
+
295
+ These proxy modules are prepended everywhere! It's certainly something that **could be way more efficient as a core part of Ruby**.
296
+
297
+ ## Bugs
298
+
299
+ This test case doesn't work yet - seems like the [object is not proxied](https://github.com/lendinghome/pipe_operator/blob/master/lib/pipe_operator/pipe.rb#L39) for some reason:
300
+
301
+ ```ruby
302
+ class Markdown
303
+ def format(string)
304
+ string.upcase
305
+ end
306
+ end
307
+
308
+ "test".pipe(Markdown.new, &:format) # expected "TEST"
309
+ #=> ArgumentError: wrong number of arguments (given 0, expected 1)
310
+ ```
311
+
312
+ ## Caveats
313
+
314
+ * `PIPE_OPERATOR_AUTOLOAD`
315
+ * Constants flagged for autoload are NOT proxied by default (for performance)
316
+ * Set `ENV["PIPE_OPERATOR_AUTOLOAD"] = 1` to enable this behavior
317
+ * `PIPE_OPERATOR_FROZEN`
318
+ * Objects flagged as frozen are NOT proxied by default
319
+ * Set `ENV["PIPE_OPERATOR_FROZEN"] = 1` to enable this behavior (via [Fiddle](http://ruby-doc.org/stdlib-2.5.3/libdoc/fiddle/rdoc/Fiddle.html))
320
+ * `PIPE_OPERATOR_REBIND`
321
+ * `Object` and its recursively nested `constants` are only proxied ONCE by default (for performance)
322
+ * Constants defined after `__pipe__` is called for the first time are NOT proxied
323
+ * Set `ENV["PIPE_OPERATOR_REBIND"] = 1` to enable this behavior
324
+ * `PIPE_OPERATOR_RESERVED`
325
+ * The following methods are reserved on `PipeOperator::Closure` objects:
326
+ * `==`
327
+ * `[]`
328
+ * `__chain__`
329
+ * `__send__`
330
+ * `__shift__`
331
+ * `call`
332
+ * `class`
333
+ * `kind_of?`
334
+ * The following methods are reserved on `PipeOperator::Pipe` objects:
335
+ * `!`
336
+ * `!=`
337
+ * `==`
338
+ * `__call__`
339
+ * `__id__`
340
+ * `__pop__`
341
+ * `__push__`
342
+ * `__send__`
343
+ * `instance_exec`
344
+ * `method_missing`
345
+ * `|`
346
+ * These methods can be piped via `send` as a workaround:
347
+ * `9.pipe { Math.sqrt.to_s.send(:[], 0) }`
348
+ * `example.pipe { send(:__call__, 1, 2, 3) }`
349
+ * `example.pipe { send(:instance_exec) { } }`
350
+
351
+ ## Testing
352
+
353
+ ```bash
354
+ bundle exec rspec
355
+ ```
356
+
357
+ ## Inspiration
358
+
359
+ * https://github.com/hopsoft/pipe_envy
360
+ * https://github.com/akitaonrails/chainable_methods
361
+ * https://github.com/kek/pipelining
362
+ * https://github.com/k-motoyan/shelike-pipe
363
+ * https://github.com/nwtgck/ruby_pipe_chain
364
+ * https://github.com/teamsnap/pipe-ruby
365
+ * https://github.com/danielpclark/elixirize
366
+ * https://github.com/tiagopog/piped_ruby
367
+ * https://github.com/jicksta/methodphitamine
368
+ * https://github.com/jicksta/superators
369
+
370
+ ## Contributing
371
+
372
+ * Fork the project.
373
+ * Make your feature addition or bug fix.
374
+ * Add tests for it. This is important so we don't break it in a future version unintentionally.
375
+ * Commit, do not mess with the version or history.
376
+ * Open a pull request. Bonus points for topic branches.
377
+
378
+ ## Authors
379
+
380
+ * [Sean Huber](https://github.com/shuber)
381
+
382
+ ## License
383
+
384
+ [MIT](https://github.com/lendinghome/pipe_operator/blob/master/LICENSE) - Copyright © 2018 LendingHome