Skip to content

Instantly share code, notes, and snippets.

@johncarney
Last active July 12, 2020 22:37
Show Gist options
  • Save johncarney/869776930fe43dc3373e2d005f11731e to your computer and use it in GitHub Desktop.
Save johncarney/869776930fe43dc3373e2d005f11731e to your computer and use it in GitHub Desktop.
Module for implementing the service object pattern that allows for custom 'verbs'

A module for implementing the Service Object pattern that allows for custom "verbs".

Usage

Including CallMe in your class adds a call class method that instantiates an object of the class using the provided arguments and invokes its call method. For example:

Thing = Struct.new(:value) do
  include CallMe

  def call
    puts value
  end
end

Thing.call(123)
# => "123"

If you would prefer a verb other than call, then use CallMe.with(:your_verb):

Thing = Struct.new(:value) do
  include CallMe.with(:say)

  def say
    puts value
  end
end

Thing.say(123)
# => "123"

with is aliased to [], so you can use CallMe[:verb] instead of CallMe.with(:verb) if you prefer.

One final note: while the examples all use include, you can also use extend.

module CallMe
class << self
def included(base)
base.include with(:call)
end
def with(verb)
callable_modules[verb.to_sym] ||= Module.new do
define_singleton_method(:included) do |base|
base.define_singleton_method(verb) do |*args|
new(*args).public_send(verb)
end
base.define_singleton_method(:to_proc) do
method(verb).to_proc
end
end
end
end
alias [] with
def callable_modules
@callable_modules ||= {}
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment