Skip to content

Instantly share code, notes, and snippets.

@akitaonrails
Last active May 30, 2016 20:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akitaonrails/83990ad43843da6a1dfaab57aac8e8e6 to your computer and use it in GitHub Desktop.
Save akitaonrails/83990ad43843da6a1dfaab57aac8e8e6 to your computer and use it in GitHub Desktop.
Attempt to implement a Pipe operator-like behavior in Crystal
# this was copied from https://carc.in/#/r/fg2
# thanks to @waterlink from this issue thread https://github.com/crystal-lang/crystal/issues/1388
module CrChainableMethods
module Pipe
macro pipe(ast)
{% uast = ast.stringify.gsub(/ >>/, ".pipe").id %}
{% pp uast %}
{% if uast.stringify != ast.stringify %}
pipe {{uast}}
{% else %}
{% if ast.name.id == "pipe".id %}
{% if ast.args.first.receiver.is_a?(Nop) %}
{% pp ast.args.first %}
{{ast.args.first.name}}({{ast.receiver}}, {{ast.args.first.args.argify}})
{% else %}
pipe {{ast.args.first.receiver.name}}({{ast.receiver}}, {{ast.args.first.receiver.args.argify}}).pipe {{ast.args.first.args.argify}}
{% end %}
{% else %}
{{ast}}
{% end %}
{% end %}
end
macro included
#FIXME this should be used as the last call in the chain if the previous call explicitly calls from a module such as:
# .>> Foo.method .>> unwrap
# Still don't know why the ast parsing works ok for just .>> method but fails for .>> Foo.method
def self.unwrap(foo)
foo
end
end
end
end
module Foo
include CrChainableMethods::Pipe
def self.split_words(phrase)
phrase.split(" ")
end
def self.append_message(words, message)
words + [message]
end
def self.join(words)
words.join(" - ")
end
end
module Bar
def self.add_something(words)
words + ["something"]
end
end
module Foo
# for some reason I am unable to make the chain from outside the context of the module
# I can't even create another module and include Foo, for example
# this example explicitly name the Module (Foo.split_words) but it's not necessary, but if I do so
# I need to add the #unwrap method as the last in the chain
# I'd like to see if I can mix and match methods from different modules
def self.workflow
pipe "Hello World"
.>> Foo.split_words
.>> Foo.append_message("Bar")
.>> Bar.add_something # mixing this in doesn't work
.>> Foo.join
.>> unwrap
end
end
puts Foo.workflow
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment