Skip to content

Instantly share code, notes, and snippets.

@JAMSUPREME
Last active October 27, 2017 22:00
Show Gist options
  • Save JAMSUPREME/a131da3ff48ed4805709c599d6ec0118 to your computer and use it in GitHub Desktop.
Save JAMSUPREME/a131da3ff48ed4805709c599d6ec0118 to your computer and use it in GitHub Desktop.
pipey
module Pipey
def <<(next_pipey)
if self.result.is_a?(EmptyPipe)
next_pipey.call
else
next_pipey.call(self.result)
end
end
# For self.execute
def execute(*args)
self.new.execute(*args)
end
# For self.pipe
def pipe(*args)
self.new.pipe(*args)
end
def self.included(klass)
klass.class_eval do
# Create result attribute
attr_accessor :result
# When including Pipey, also extend it (to give Pluggy syntax)
extend Pipey
# Immediate execution
# def execute(*args)
define_method('execute') do |*args|
@result = self.run(*args)
return self
end
# Deferred execution
# def pipe(*args)
define_method('pipe') do |*args|
# Create a proc that takes splat args
# Must merge the args it received with the args it will get passed during evaluation
->(*proc_args) {
proc_args += args
@result = self.run(*proc_args)
return self
}
end
end
end
end
# Empty pipe helper to avoid forcing use of execute
class EmptyPipe
include Pipey
def execute
@result = self
self
end
end
# Value pipe helper to make the base of a chain simpler
class ValuePipe
include Pipey
def execute(value)
@result = value
self
end
end
class IncrementNumber
include Pipey
def run(*args)
base_number = args.empty? ? 0 : args[0]
base_number + 1
end
end
class MultiplyBy
include Pipey
def run(*args)
raise 'Need 2 args to multiply' if args.length != 2
base_number = args[0]
multiplier = args[1]
base_number * multiplier
end
end
# First item in a chain must be an execute
# because we cannot "<<" on a Proc
# puts (IncrementNumber.pipe(1) <<
# IncrementNumber.pipe <<
# MultiplyBy.pipe(5)).result
# But we can mitigate with EmptyPipe
puts (EmptyPipe.execute <<
IncrementNumber.pipe(1) <<
IncrementNumber.pipe <<
MultiplyBy.pipe(5)).result
# Or a ValuePipe
puts (ValuePipe.execute(1) <<
IncrementNumber.pipe <<
MultiplyBy.pipe(5)).result
module Pipey
def <<(next_pipey)
next_pipey.call(self.result)
end
# For self.execute
def execute(*args)
self.new.execute(*args)
end
# When including Pipey, also extend it (to give Pluggy syntax)
def self.included(klass)
klass.class_eval do
attr_accessor :result
extend Pipey # TODO
define_method('execute') do |*args|
unless args.empty?
@result = self.run(*args)
return self
end
->(*args) {
@result = self.run(*args)
return self
}
end
end
end
end
class IncrementNumber
include Pipey
# Might later call this "call" or "execute"
def run(*args)
base_number = args.empty? ? 0 : args[0]
base_number + 1
end
end
puts (IncrementNumber.execute(1) <<
IncrementNumber.execute <<
IncrementNumber.execute).result
module Pipey
# a pipey has a custom "into"
def >>(next_pipey)
puts "Result is #{@result} and next pipey is #{next_pipey}"
# next_pipey.execute(@result)
end
def execute
raise StandardError 'A pipey must implement execute'
end
end
class Incrementer
include Pipey
def execute(input)
puts input + 1
@result = input + 1
end
class << self
def execute(input)
puts input + 1
@result = input + 1
end
end
end
p1 = Incrementer.new
p2 = Incrementer.new
p1 >> p2
# p1.execute(1)
# p1.execute(1) >> p2
# Later TODO
# https://www.rubypigeon.com/posts/a-review-of-immutability-in-ruby/
# make things immutable
module Pipey
def <<(next_pipey)
puts "piped"
next_pipey.call(self.result)
end
end
class Incrementer
attr_accessor :result
include Pipey
def execute(*args)
unless args.empty?
@result = args[0] + 1
puts @result
return self
end
->(input) {
puts input + 1
@result = input + 1
return self
}
end
end
p1 = Incrementer.new
p2 = Incrementer.new
p1.execute(1) << p2.execute << p2.execute << p2.execute
module Pipey
def <<(next_pipey)
next_pipey.call(self.result)
end
end
class Incrementer
attr_accessor :result
include Pipey
extend Pipey
def execute(*args)
unless args.empty?
@result = args[0] + 1
return self
end
->(input) {
@result = input + 1
return self
}
end
class << self
def execute(*args)
Incrementer.new.execute(*args)
end
end
end
puts (Incrementer.execute(1) <<
Incrementer.execute <<
Incrementer.execute <<
Incrementer.execute).result
module Pipey
def <<(next_pipey)
puts 'piped'
next_pipey.call(self.result)
end
# For self.execute
def execute(*args)
self.new.execute(*args)
end
# For self.pipe
def pipe(*args)
self.new.pipe(*args)
end
def self.included(klass)
klass.class_eval do
# Create result attribute
attr_accessor :result
# When including Pipey, also extend it (to give Pluggy syntax)
extend Pipey
# Immediate execution
# def execute(*args)
define_method('execute') do |*args|
@result = self.run(*args)
return self
end
# Deferred execution
# def pipe(*args)
define_method('pipe') do |*args|
# Create a proc that takes splat args
# Must merge the args it received with the args it will get passed during evaluation
->(*proc_args) {
proc_args += args
@result = self.run(*proc_args)
return self
}
end
end
end
end
class IncrementNumber
include Pipey
def run(*args)
puts 'incremented'
base_number = args.empty? ? 0 : args[0]
base_number + 1
end
end
class MultiplyBy
include Pipey
def run(*args)
raise 'Need 2 args to multiply' if args.length != 2
puts 'multiplied'
base_number = args[0]
multiplier = args[1]
base_number * multiplier
end
end
puts (IncrementNumber.execute(1) <<
IncrementNumber.pipe <<
MultiplyBy.pipe(5)).result
# First item in a chain must be an execute
# because we cannot "<<" on a Proc
# puts (IncrementNumber.pipe(1) <<
# IncrementNumber.pipe <<
# MultiplyBy.pipe(5)).result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment