Skip to content

Instantly share code, notes, and snippets.

@henrik
Last active December 4, 2020 05:41
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save henrik/00e3712d97c79325e25a to your computer and use it in GitHub Desktop.
Save henrik/00e3712d97c79325e25a to your computer and use it in GitHub Desktop.
Silly #elixir-lang macro experiment for Ruby-like method chaining. Don't use this for serious purposes :)
defmodule Chain do
defmacro chain(ex) do
parse(ex)
end
defp parse({:., _, [first_arg, function_name]}, more_args) do
args = [first_arg|more_args] |> Enum.map(&parse/1)
apply(String, function_name, args)
end
defp parse({ex, _, args}) do
parse(ex, args)
end
defp parse(anything), do: anything
end
ExUnit.start
defmodule ChainTest do
use ExUnit.Case
import Chain
test "one function" do
assert (chain " hello ".strip) == "hello"
end
test "multiple functions" do
assert (chain " hello ".strip.reverse.upcase) == "OLLEH"
end
test "argument" do
assert (chain "XXhelloXX".strip(?X)) == "hello"
end
test "multiple arguments" do
assert (chain "hello".ljust(10, ?Y)) == "helloYYYYY"
end
test "chained arguments" do
assert (chain "XXhelloXX".strip(?X).ljust(10, ?Y)) == "helloYYYYY"
end
test "nested arguments" do
assert (chain "hello".replace("xEx".downcase.strip(?x), "x".upcase)) == "hXllo"
end
end
@henrik
Copy link
Author

henrik commented Jul 20, 2015

Note that this is very much a toy. It doesn't handle all input sensibly. It e.g. doesn't handle arguments being variables or non-string-chain expressions like :random.uniform. Which is good, because it also executes the string functions at compile time, so any changing arguments would be stuck at one value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment