As some writing code in a functional style, I really like passing functions as arguments. Whether in Rust or in JavaScript, first-class functions are very useful. Sadly, as naming a function/method in Ruby is the same as calling it with zero parameters, this at first seems impossible to do.

What you can do is pass closures blocks methods. E.g., Array#map really likes being called with a block:

xs = ["lorem", "ipsum", "dolor"]
xs.map { |x| x.size }

Not the passing an actual function… but there is one built-in shortcut: You can call the methods defined for the item’s class (this calls String#size):

xs.map(&:size)

This works quite well for a lot of cases and is very useful in practice. This also probably 95% of what a regular Ruby should ever need. But, you know, it wasn’t enough. I had to dig deeper.

The thing is: I sometimes just want to write simple modules that contain functions.

module Foo
  def self.bar(x)
    if x == "lorem"
      "bar"
    else
      "baz"
    end
  end
end

I’m not saying this is idiomatic Ruby, but it often is exactly what I want. Not a singleton class whose name ends with Service, just a module. Not adding a method to Integer, just a function in a namespace module. Not adding this module as a mixin to a class defined in my application (and not writing a wrapper class if the item’s class is not defined in my application). And not a { |x| Foo::bar(x) }, I just want Foo::bar.

So, is this possible? Yes, kinda:

xs.map(&Foo::method(:bar))

The method method gives you, well, a Method. It’s meta programming at its finest, and, aside from obvious things like arity and name, has some interesting methods, like curry, owner, and source. And the official documentation also abbreviates it with “meth”. Just saying.

But, back to the problem at hand: Is this ugly as hell and should you never ever use it? Most likely, yes.

So, how to make it better? With more weird meta programming, of course! Let’s add a method $m_fn that automatically gives the Method of $m. If you liked my rambling on doing weird things with Rust traits more than my Rust flavored Ruby post, you will love what follows. If you want to keep your sanity innocence, close this tab right now.

module BlackMagic
  def self.included(klass)
    klass.extend(MethodAccessorMacros)
  end
  
  module MethodAccessorMacros
    def method_accessor(method_name)
      self.class.instance_eval do
        Array(method_name).each do
          define_method("#{method_name}_fn".intern) do
            method(method_name.intern)
          end
        end
      end
    end
  end
end

Yeah, that chain of end lines that make even the most experienced LISP programmers blush is a good indicator of how many tries it took me to get this to work. But it does work:

module Foo
  include BlackMagic

  method_accessor :bar

  def self.bar(x)
    if x == "lorem"
      "bar"
    else
      "baz"
    end
  end
end

xs = ["lorem", "ipsum", "dolor"]

xs.map(&Foo::bar_fn)
# => ["bar", "baz", "baz"]

See it in action here.

And finally: Should you ever use this? Let’s just say I hope you don’t need to…

Update: It just occurred to me that people might want to read even more on this weird interesting aspect of Ruby. Here you go: