Stepping into Ruby Meta-Programming: Generating proxy methods for multiple internal methods

Posted by mstksg on Stack Overflow See other posts from Stack Overflow or by mstksg
Published on 2010-06-14T19:27:35Z Indexed on 2010/06/14 21:42 UTC
Read the original article Hit count: 254

Filed under:
|

Hi all; I've multiply heard Ruby touted for its super spectacular meta-programming capabilities, and I was wondering if anyone could help me get started with this problem.

I have a class that works as an "archive" of sorts, with internal methods that process and output data based on an input. However, the items in the archive in the class itself are represented and processed with integers, for performance purposes. The actual items outside of the archive are known by their string representation, which is simply number_representation.to_s(36).

Because of this, I have hooked up each internal method with a "proxy method" that converts the input into the integer form that the archive recognizes, runs the internal method, and converts the output (either a single other item, or a collection of them) back into strings.

The naming convention is this: internal methods are represented by _method_name; their corresponding proxy method is represented by method_name, with no leading underscore.

For example:

class Archive

  ## PROXY METHODS ##
  ## input: string representation of id's
  ## output: string representation of id's

  def do_something_with id
    result = _do_something_with id.to_i(36)
    return nil if result == nil
    return result.to_s(36)
  end

  def do_something_with_pair id_1,id_2
    result = _do_something_with_pair id_1.to_i(36), id_2.to_i(36)
    return nil if result == nil
    return result.to_s(36)
  end

  def do_something_with_these ids
    result = _do_something_with_these ids.map { |n| n.to_i(36) }
    return nil if result == nil
    return result.to_s(36)
  end

  def get_many_from id
    result = _get_many_from id
    return nil if result == nil         # no sparse arrays returned
    return result.map { |n| n.to_s(36) }
  end

  ## INTERNAL METHODS ##
  ## input: integer representation of id's
  ## output: integer representation of id's

  def _do_something_with id
    # does something with one integer-represented id,
    # returning an id represented as an integer
  end

  def do_something_with_pair id_1,id_2
    # does something with two integer-represented id's,
    # returning an id represented as an integer
  end

  def _do_something_with_these ids
    # does something with multiple integer ids,
    # returning an id represented as an integer
  end

  def _get_many_from id
    # does something with one integer-represented id,
    # returns a collection of id's represented as integers
  end
end

There are a couple of reasons why I can't just convert them if id.class == String at the beginning of the internal methods:

  1. These internal methods are somewhat computationally-intensive recursive functions, and I don't want the overhead of checking multiple times at every step
  2. There is no way, without adding an extra parameter, to tell whether or not to re-convert at the end
  3. I want to think of this as an exercise in understanding ruby meta-programming

Does anyone have any ideas?


edit

The solution I'd like would preferably be able to take an array of method names

@@PROXY_METHODS = [:do_something_with, :do_something_with_pair,
                   :do_something_with_these, :get_many_from]

iterate through them, and in each iteration, put out the proxy method. I'm not sure what would be done with the arguments, but is there a way to test for arguments of a method? If not, then simple duck typing/analogous concept would do as well.

© Stack Overflow or respective owner

Related posts about ruby

Related posts about metaprogramming