Proc Composition (>> and <<, with specs)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# See https://bugs.ruby-lang.org/issues/6284 | |
# (It's probably going to happen, but they haven't figured out what they want | |
# to call it. I've chosen << and >> for now.) | |
module Patches | |
module Proc | |
module Composition | |
# (f << g)[x] == f[g[x]] | |
# (f << g).call(x) == f.call(g.call(x)) | |
# "self" is "f" in the above. | |
def <<(g) | |
proc { |*args| | |
self.call(*g.to_proc.call(*args)) | |
} | |
end | |
# The above, except "forwards". | |
# (f >> g)[x] == g[f[x]] | |
# (f >> g).call(x) == g.call(f.call(x)) | |
# "self" is "f" in the above. | |
def >>(g) | |
proc { |*args| | |
g.to_proc.call(*self.call(*args)) | |
} | |
end | |
end | |
end | |
end | |
# Examples of usage: | |
# to_s = proc {|x| x.to_s } | |
# to_upper = proc {|x| x.upcase } | |
# to_a = proc {|x| x.split('') } | |
# | |
# # Pipeline | |
# p (to_a << to_upper << to_s).call("Abc123") # => ['A', 'B', 'C', '1', '2', '3'] | |
# p (to_s >> to_upper >> to_a).call("Abc123") # => ['A', 'B', 'C', '1', '2', '3'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
RSpec.describe Patches::Proc::Composition do | |
let(:reverse) { proc {|x| x.reverse } } | |
let(:uppercase) { proc {|x| x.upcase } } | |
let(:ascii_nums) { proc {|x| x.split('').map(&:ord) } } | |
describe "<<" do | |
it "allows procs to be stuck together in a pipeline" do | |
expect((ascii_nums << uppercase << reverse).call("Hello World")).to eq [68, 76, 82, 79, 87, 32, 79, 76, 76, 69, 72] | |
end | |
it "doesn't matter which bits of the pipeline you stick together first" do # (is associative) | |
expect( | |
((ascii_nums << uppercase) << reverse).call("Hello World") | |
).to eq( | |
(ascii_nums << (uppercase << reverse)).call("Hello World") | |
) | |
end | |
it "matters what order the bits of the pipeline are stuck together" do # (is not commutative) | |
expect((ascii_nums << uppercase << reverse).call("Hello World")).to eq [68, 76, 82, 79, 87, 32, 79, 76, 76, 69, 72] | |
expect{(uppercase << ascii_nums << reverse).call("Hello World")}.to raise_error | |
expect{(uppercase << reverse << ascii_nums).call("Hello World")}.to raise_error | |
end | |
it "duck-types on #to_proc when composing" do | |
# More of an accident than anything. Symbol has to_proc(), which converts ":to_s" to "proc {|x| x.to_s }". | |
expect((reverse << :to_s).call(123)).to eq "321" | |
end | |
end | |
describe ">>" do | |
it "allows procs to be stuck together in a pipeline" do | |
expect((uppercase >> reverse >> ascii_nums).call("Hello World")).to eq [68, 76, 82, 79, 87, 32, 79, 76, 76, 69, 72] | |
end | |
it "doesn't matter which bits of the pipeline you stick together first" do # (is associative) | |
expect( | |
((uppercase >> reverse) >> ascii_nums).call("Hello World") | |
).to eq( | |
(uppercase >> (reverse >> ascii_nums)).call("Hello World") | |
) | |
end | |
it "matters what order the bits of the pipeline are stuck together" do # (is not commutative) | |
expect((uppercase >> reverse >> ascii_nums).call("Hello World")).to eq [68, 76, 82, 79, 87, 32, 79, 76, 76, 69, 72] | |
expect{(uppercase >> ascii_nums >> reverse).call("Hello World")}.to raise_error | |
expect{(ascii_nums >> uppercase >> reverse).call("Hello World")}.to raise_error | |
end | |
it "duck-types on #to_proc when composing" do | |
# More of an accident than anything. Symbol has to_proc(), which converts ":to_i" to "proc {|x| x.to_i }". | |
expect((reverse >> :to_i).call("123")).to eq 321 | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Patches::Proc::Composition | |
<< | |
duck-types on #to_proc when composing | |
allows procs to be stuck together in a pipeline | |
doesn't matter which bits of the pipeline you stick together first | |
matters what order the bits of the pipeline are stuck together | |
>> | |
duck-types on #to_proc when composing | |
allows procs to be stuck together in a pipeline | |
doesn't matter which bits of the pipeline you stick together first | |
matters what order the bits of the pipeline are stuck together | |
Finished in 0.3115 seconds | |
8 examples, 0 failures |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment