1

I am trying to write a class which acts as an Array (i.e inherits the methods from the Array class) and as a Hash (i.e inherits the methods from the Hash class), based on the object passed to it.

class MyClass

end

class_a = MyClass[1,2,3,4,5,6,7,8,9,10]  # => Acts like an Array
class_a[1] # =>  2


class_h = MyClass[:a => 1, :b => 2]      # => Acts like a Hash
class_h.key(1) #=> :a

I know Ruby doe not really support multiple inheritance. How can I accomplish this? Help appreciated.

Edit

Use case:

Lets say I have a class which performs some 'special' functions on a hash (transforms the hash based on criteria, does a hash lookup of some sort sort, etc)

I would write the class like this:

class MyClass < Hash
   def some_function
      code
   end
end

and use it like so

hash = MyClass[:a => 1, :b => 2, :c => 3].some_function

But a small problem arises, when I do something like this

hash = MyClass[[
  {:a => 1, :b => 2},
  {:a => 2, :b => 3},
  {:a => 3, :b => 3}
 ]].some_function

In the case above, I would need to iterate over the array, and call some_function and each hash.

3
  • 1
    This seems like somewhat of a bad idea. What's your use case? Commented Feb 14, 2015 at 6:59
  • @bitops I made an edit Commented Feb 14, 2015 at 7:11
  • 2
    It still seems like a bad idea. Whatever you are trying to do can probably be expressed as just a method that takes hashes or arrays for input, and gives hashes or arrays as output. Hashes and Arrays are complicated objects and it will be really hard for you to implement all the methods of each class in some reasonable way. Commented Feb 14, 2015 at 7:16

1 Answer 1

2

You want to implement Proxy pattern. The simplest implementation, which takes no care about details, looks like:

class MyClass
  def initialize o
    @o = o 
  end 
  def method_missing meth, *args, &cb 
    @o.respond_to?(meth) ? @o.send(meth, *args, &cb) : super
  end 
end

class_a = MyClass.new [1,2,3,4,5,6,7,8,9,10]
class_a.[] 1
#⇒ 2

class_h = MyClass.new({ :a => 1, :b => 2 })
class_h.key(1)
#⇒ :a

In general, this is all about creating an instance variable of your class and pass methods called on the instance of your MyClass to it.

Later on you might want to add explicit checks for the variable type, like:

throw 'NOT AN ARRAY' unless Array === @o

Please be aware that calling method_missing is resulting in performance penalties compared against native method calls.

Hope it helps.

Sign up to request clarification or add additional context in comments.

4 Comments

If only it were this simple. There's a problem in that none of the methods that MyClass inherits will be caught by method_missing, so some of those can't be used. For example, consider the method ===, which MyClass inherits from Module: Array === [1,2] #=> true, but Array === class_a #=> false. I don't know what you might do about those, or even which they are. You might be able to delete them from MyClass, but I fear that could break Ruby.
Another example: [1,2] <=> [2,1] #=> -1, whereas a1 = MyClass.new [1,2]; a2 = MyClass.new [2,1]; a1 <=> a2 #=> nil.
@CarySwoveland Yes, you are definitely right, that’s why I forestalled the answer with “The simplest implementation, which takes no care about details.”
@CarySwoveland I would go with undef everything significant on MyClass.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.