Ruby how to delegate module function of Namespace to Namespace::Base inner class

762 views Asked by At

I was confronted against choosing either #1 :

class Abstract
end
class Abstract::Foo < Abstract
end
class Abstract::Bar < Abstract
end

versus #2 :

module Abstract
  class Base
  end
  class Foo < Base
  end
  class Bar < Base
  end
end

I ended up choosing option #2, as my Abstract felt more like a namespace, and I could eventually add other things like

module Abstract # Instead of class if I had used option #1
  class SomeAbstractService
  end
end

However I feel that calling Abstract::Base.some_class_method is a bit weird. it possible to add a module function delegation ? For example if my Base is an ActiveRecord or Mongoid model (so Foo and Bar are like STI), i'd like to be able to query the collection/table with

Abstract.where(...) instead of Abstract::Base.where(...)

Is it possible to delegate the module function .where to the constant/class Base ?

Something like

module Abstract
  class Base
  end

  delegate_module_function :where, to: :Base
end

Or is there a different/better way to do that ?

1

There are 1 answers

1
Eric Duminil On BEST ANSWER

You can use a standard Ruby library called Forwardable.

require 'forwardable'

module Abstract
  extend SingleForwardable
  class Base
    def self.where(p)
      "where from base : #{p}"
    end
  end

  delegate :where => Base
end

Abstract.where(id: 3)
# => "where from base : {:id=>3}"

For multiple methods, you can write :

delegate [:where, :another_method] => Base