fl-web fl-web - 4 months ago 16
Ruby Question

Move block to lib

I have code like this:

MyClass.foo do
some code
end


I need to do refactoring: move block (or code from block) to gem (or to lib folder) some like this:

MyClass.foo ...


In
lib/Lib.rb


...
some code
...


What I need to write instead of
...

Answer

The answer highly depends on how some code is stored in Lib.rb. I assume that it is not free standing code like in a script, but rather contained in a Proc, function or (class/module) method. What you can do then is just change the some code in your original block to a call to the respective object like this:

For Procs of any kind

In Lib.rb

some_code = proc { some code }  # or
some_code = Proc.new { some code }  # or
some_code = lambda { some code }  # or
some_code = -> { some code }

The call:

MyClass.foo do
  some_code.call  # or
  some_code[]  # or
  some_code.()
end

For instance methods

In Lib.rb:

def SomeClass
  def some_code
    some code
  end
end

The call:

# Somewhere else
some_instance = SomeClass.new

MyClass.foo do
  some_instance.some_code
end

For class (or module) methods

In Lib.rb:

class SomeClass
  def self.some_code
    some code
  end
end

The call:

MyClass.foo do
  SomeClass::some_code
end

The alternative: passing blocks explicitly

An interesting alternative is to pass things as an explicit parameter that Ruby then interprets as blocks. Every function f accepting a block can be called like this:

f(other, parameters, &something)

The & in front of the something instructs Ruby to call to_proc (if it is not already a Proc) on something and pass the result as the block that f expects.

How something has to look again depends on Lib.rb:

For Procs

MyClass.foo(&some_code)

For instance methods

MyClass.foo(&some_instance.method(:some_code))

using Object#method.

For class/module methods

This one is tricky since these are actually basically instance methods of the metaclass, which you can get like this:

SomeMetaClass = class << SomeClass; self; end

Then you can proceed as above:

MyClass.foo(SomeMetaClass.method(:some_code))