'Call Private methods outside class definition

I'm trying to use a Gem that provides me with a DSL i need to apply on some of my classes. But using it directly makes my class definitions not as clean as i want them to be, so i want to move the code that uses the DSL somewhere else, which bring me to this problem, that i will describe in an abstract/general way:

If i have a ruby class that includes methods from another gem as private, and in the docs they tell to call those methods inside class definition.

for example:

class A
  include ModuleB::PrivateMethods
end

class B < A
  do_z :param do
    set_property 'a', :x, :y, false
    set_property 'b', :x, :y, false
    set_property 'only for class B', :x, :y, true
  end

  def whatever
  end
end

# this is from the gem
module ModuleZ
  module PrivateMethods
    def self.included(base)
      base.extend Zmethods
    end
    module Zmethods
      private
      def do_z(param1, &block)
        # this method do something and calls the block
      end
    end
  end
end

Is there a way to DRY up those calls to do_z if, for example any class that inherit from A have to do this:

  do_z :param do
    set_property 'a', :x, :y, false
    set_property 'b', :x, :y, false
  end

and

  do_z :param do
    set_property 'only for class B', :x, :y, true
  end

is only needed for class B and i don't want to write this calls inside the class definition but somewhere else?

Like another module that, when included make those calls even when those methods are private?

So i can write the class definition with something like this?

class B < A
  include TheModuleForAllClases::AndTheOneForBclass

  def whatever
  end
end

I could call #do_z on the base class, and then again for each specialized class to only make the calls needed on each implementation, but they are still many and the blocks are very large, so my class definitions get really long, and the actual method implementation of the class get buried behind those calls.

if wondering, the Gem is swagger-docs look: documenting-a-controller on Rails.

Greetings!



Solution 1:[1]

Something like this should work

module AllClassesMethods
  def self.included(base)
    base.class_eval do
      do_z :param do
        set_property 'a', :x, :y, false
        set_property 'b', :x, :y, false
      end
    end
  end
end

module OnlyBMethods
  def self.included(base)
    base.class_eval do
      do_z :param do
        set_property 'only for class B', :x, :y, true
      end
    end
  end
end

class A
  include ModuleB::PrivateMethods
  include AllClassesMethods

  def self.inherited(klass)
    klass.include AllClassesMethods
  end
end

class B < A
  include OnlyBMethods
end

A and any class that inherits from A will include AllClassesMethods, running the code in its included method. It has to be explicitly included on each inherited class, or else the included method will only get called for the parent A. The class_eval block executes within the including class's context, so it's just like opening up the class in your class definition. Only B is including OnlyBMethods, and therefore is the only one triggerring the included implementation of both Modules.

There's another approach you could use. If you define a class method macro in an extended module, the class method will be executed within the class context, also giving you easy access to it's private methods (I say "easy" access because in Ruby you can always access an object's private methods from any context by using send)

module AllClassesMethods
  def does_z
    do_z :param do
      set_property 'a', :x, :y, false
      set_property 'b', :x, :y, false
    end
  end

  def does_z_for_b
    do_z :param do
      set_property 'only for class B', :x, :y, true
    end
  end
end

class A
  include ModuleB::PrivateMethods
  extend AllClassesMethods

  does_z

  def self.inherited(klass)
    klass.does_z
  end
end

class B < A
  does_z_for_b
end 

Solution 2:[2]

using send method

obj = SomeClass.new
obj.send(:private_method)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 deepak raghuwanshi