Skip to content

Instantly share code, notes, and snippets.

@ffloyd
Last active September 22, 2018 08:32
Show Gist options
  • Save ffloyd/00871c405b5a18b1e9f856316f1ca090 to your computer and use it in GitHub Desktop.
Save ffloyd/00871c405b5a18b1e9f856316f1ca090 to your computer and use it in GitHub Desktop.
Elixir-like matching for ruby proposal
# 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