Created
October 4, 2018 22:21
-
-
Save baweaver/7f8cdc8cebed93799a2c64da088447c1 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
def destructure(method_name) | |
# Intercept the original class | |
meta_klass = class << self; self end | |
# Save the original method as a proc | |
method_proc = method(method_name) | |
# We only want to do this for keyword argument type | |
# methods | |
unless method_proc.parameters.all? { |t, _| t == :key } | |
raise "Only works with keyword arguments" | |
end | |
# Extract the names from the arguments | |
arguments = method_proc.parameters.map(&:last) | |
# Wrap the original method call in a proc to intercept | |
# potential destructuring | |
destructure_proc = -> object { | |
# If the values are a hash, pass it through like | |
# normal keyword arguments | |
values = if object.is_a?(Hash) | |
object | |
# Otherwise, use the names of those keywords to extract | |
# (or rather destructure) values from the object passed | |
# in. Map this to a hash so we can pass it as such to | |
# the original method | |
else | |
arguments.map { |a| [a, object.public_send(a)] }.to_h | |
end | |
# Call that original method with either a plain hash | |
# or values extracted from an object by key name | |
method_proc.call(values) | |
} | |
# Then redefine the method where it lives | |
meta_klass.send(:define_method, method_name, destructure_proc) | |
end | |
require 'ostruct' | |
# Just prefix a method definition with `destructure` | |
destructure def adds(a: 1, b: 2) | |
a + b | |
end | |
=> :adds | |
# And we can now call it with an object: | |
adds(OpenStruct.new(a: 1, b: 3)) | |
=> 4 | |
# Or keywords: | |
adds(a: 1, b: 2) | |
=> 3 | |
# Or a plain old hash: (though that's the same as above) | |
adds({a: 1, b: 2}) | |
=> 3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment