What is the best way of chaining multiple custom methods together? I want to put the output of my method directly into the next method in an elegant way. The first one below is what I have now.
verified = search_verified(@providers)
matching = search_matching(verified)
deactivated = search_deactivated(matching)
networks = search_networks(deactivated)
designations = search_designations(networks)
disorders = search_disorders(designations)
age_groups = search_age_groups(disorders)
governing = search_governing(age_groups)
search_availabilities(governing)
maybe something more along the lines of:
search_verified(@providers)
>> search_matching
>> search_deactivated
>> search_networks
>> ....
Method chaining eliminates an extra variable for each intermediate step. The developer is saved from the cognitive burden of naming the variable and keeping the variable in mind.
Method chaining interface allows you to chain method calls, which results in less typed characters when applying multiple operations on the same object. Using method chaining.
You might want to use then
to chain your methods and numbers parameter to simplify the blocks:
search_verified(@providers)
.then { search_matching(_1) }
.then { search_deactivated(_1) }
.then { search_networks(_1) }
.then { search_designations(_1) }
.then { search_disorders(_1) }
.then { search_age_groups(_1) }
.then { search_governing(_1) }
.then { search_availabilities(_1) }
You can do something along those lines. Ruby 2.6.0 introduces then
, and the function composition operators <<
and >>
.
You do have to select your methods with method(:method_name)
because method_name
by itself invokes the method and does not return it.
@providers.then(&
method(:search_verified) >>
method(:search_matching) >>
method(:search_deactivated) >>
method(:search_networks) >>
method(:search_designations) >>
method(:search_disorders) >>
method(:search_age_groups) >>
method(:search_governing) >>
method(:search_availabilities)
)
If you don't like the character "overhead". You could shrink the amount of characters by storing the method
method in a shorter variable first:
fn = method(:method)
@providers.then(&
fn[:search_verified] >>
# ...
)
You could write that as follows.
METHODS = [:verified, :matching, :deactivated, :networks, :designations,
:disorders, :age_groups, :governing, :search_availabilities]
def doit(first_arg)
METHODS.reduce(first_arg) { |arg, meth| send(meth, arg) }
end
This would be called
doit(@providers)
For example:
def a(arg)
arg * 2
end
def b(arg)
arg + 1
end
def c(arg)
arg/5.0
end
METHODS = [:a, :b, :c]
doit(3)
#=> 1.4
One could alternatively write
def doit(first_arg)
METHODS.reduce(first_arg) { |arg, meth| method(meth).call(arg) }
end
doit(3)
#=> 1.4
One advantage of this approach is that if methods are added, removed or renamed is is only necessary to change the constant METHODS
; the method doit
is unaffected.
I've not actually tried this other than a quick attempt in the console, but from looking at: https://andersmurphy.com/2019/12/07/ruby-functional-programming.html it looks like something like the following should be possible:
pipe = -> *fns {fns.reverse.reduce {|f, g| -> x {f.(g.(x))}}}
add_one = -> x {x + 1}
times_two = -> x {x * 2}
add_one_and_times_two = pipe.(add_one, times_two)
add_one_and_times_two.(2)
=> 6
pipe.(add_one, times_two).(3)
=> 8
If you want to use this with methods you can possibly (this seems to work in the console) do something like:
def divide_by_three(x); x / 3.0 end
pipe.(
add_one,
times_two,
method(:divide_by_three)
).(4)
=> 3.3333333333333335
using the method function as shown in @3limin4t0r's answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With