Last active
April 8, 2018 02:17
-
-
Save bkerley/754df43c98e116e82003 to your computer and use it in GitHub Desktop.
elixir-style function chaining that is also awful!
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
require 'pp' | |
class Object | |
def mutate | |
Mutagen.new(self) | |
end | |
end | |
class Mutagen < BasicObject | |
def initialize(collection) | |
@collection = collection | |
end | |
def method_missing(method_name, *args, &block) | |
return const_method_missing(method_name) if probably_constant(method_name) | |
instance_method_missing(method_name, *args, &block) | |
end | |
private | |
def const_method_missing(method_name) | |
const_callee = ::Kernel.const_get method_name | |
::ConstMutation.new const_callee, @collection | |
end | |
def instance_method_missing(method_name, *args, &block) | |
callee = @collection | |
::SelfMutation.new(@collection, method_name, args, block).invoke | |
end | |
def probably_constant(method_name) | |
method_name_start = method_name.to_s.chars.first | |
is_uppercase = method_name_start.upcase == method_name_start | |
end | |
end | |
class SelfMutation < BasicObject | |
def initialize(collection, method_name, args, block) | |
@collection = collection | |
@method_name = method_name | |
@args = args | |
@block = block | |
end | |
def invoke | |
::Mutagen.new @collection.send(@method_name, *@args, &@block) | |
end | |
end | |
class ConstMutation < BasicObject | |
def initialize(callee, collection) | |
@callee = callee | |
@collection = collection | |
end | |
def method_missing(method_name, *args, &block) | |
returned = @callee.send method_name, @collection, *args, &block | |
::Mutagen.new returned | |
end | |
end | |
module Manipulator | |
def self.filter(collection, block) | |
collection.select &block | |
end | |
end | |
module Printer | |
def self.pretty_print(collection) | |
pp collection | |
end | |
end | |
pp @collection = (1..20).to_a | |
@collection.mutate | |
.Manipulator.filter( ->(x) { x.even? } ) | |
.shuffle | |
.take(5) | |
.Printer.pretty_print | |
"steve".mutate | |
.upcase | |
.chars | |
.to_a | |
.Manipulator.filter( ->(x) { x.ord > 'F'.ord}) | |
.join | |
.Printer.pretty_print | |
# visualize: | |
# collection | |
# |> Manipulator.filter(fn(x) -> is_even(x) end) | |
# |> Printer.pretty_print |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@akitaonrails, @bkerley, have you seen this trick with
>->
'operator' https://github.com/txus/kleisli;)
It feels like current solution with
.
is not very friendly to method's likeArray(42), URI("http://foo.com/")
, etc...I wonder if single argument functions (with unnamed arguments) are too simple?
Good DSLs are pretty often chainable out of the box without pipelines -- but 'connecting' others sure sounds very interesting.
Thank you for sharing!