Last active
September 22, 2018 08:32
-
-
Save ffloyd/00871c405b5a18b1e9f856316f1ca090 to your computer and use it in GitHub Desktop.
Elixir-like matching for ruby proposal
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
# example function | |
def f | |
[:ok, 'bla bla'] | |
end | |
# | |
# elixir-like offensive matching (match or exception) | |
# | |
# success case | |
_, data = match(:ok, String) { f() } | |
# => [:ok, 'bla bla'] | |
# failure case | |
_, data = match(:ok, String) { [:error, '=('] } | |
# raises exception | |
# dry-types | |
_, data = match(:ok, Dry::Types::String) { f() } | |
# proc-matchers | |
_, data = match(:ok, ->(x) { x.is_a? String }) { f() } | |
# | |
# elixir-like defensive matching (multimatch and else clause) | |
# | |
# non-DSL variant | |
case_match(f(), | |
[:ok, String] => labmda do |_, str| | |
puts str | |
end, | |
[:error, String] => lambda do |_, err_str| | |
raise err_str | |
end, | |
:else => lambda do |*args| | |
raise "Unexpected result: #{args.inspect}" | |
end) | |
# DSL variant | |
case_dsl(f()) do | |
when_match(:ok, String) do |_, str| | |
puts str | |
end | |
when_match(:error, String) do |_, str_err| | |
puts str_err | |
end | |
else_match do |*args| | |
raise "Unexpected result: #{args.inspect}" | |
end | |
end | |
# works as expression | |
x = case_dsl(f()) do | |
# some matching | |
end | |
# | |
# Do-monad like usage | |
# | |
class MyClass | |
extend ElixirMatching | |
yield_matching_for(:call) | |
def call | |
_, data = yield(:ok, String) { private_method_a() } | |
processed_data = do_something_with(data) | |
yield(:ok) { private_method_b(processed_data) } | |
end | |
private | |
def private_method_a | |
# some code | |
end | |
def private_method_b | |
# some code | |
end | |
end | |
# | |
# partial `with` emulation (do-like stuff in local DSL, without else clause) | |
# | |
result = yield_match do | |
_, data_a = yield(:ok, String) { f_a() } | |
_, data_b = yield(:ok, String) { f_b() } | |
data_a + data_b | |
end | |
# | |
# full `with` emulation with DSL | |
# | |
result = with_match do | |
yield_match do | |
_, data_a = yield(:ok, String) { f_a() } | |
_, data_b = yield(:ok, String) { f_b() } | |
data_a + data_b | |
end | |
else_dsl do | |
when_match(:error, :total_bullshit) do |_, err_str| | |
puts "It's bullshit!" | |
raise TotalBullshitError | |
end | |
when_match(:error, Symbol) do |_, err_sym| | |
raise "Error: #{err_sym}" | |
end | |
else_match do |*args| | |
raise "Unexpected result: #{args.inspect}" | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment