4

I have the following class:

class Library < Array
  attr_accessor :authors
end

And I would like to initilize the authors attribute inside the constructor of the class, and still use the Array#new behaviour. I tried this:

class Library < Array
  attr_accessor :authors

  def initialize(**args)
     @authors = {key1: 'val1', key2: 'val2'}
     super(args)
  end

end

But that yields an error.

How can I achieve this ?

1
  • One way is to alias Array::new to Array::old_new and then create a new Array::new method that does what you want before or after (depending on your needs) calling Array::old_new. Commented Sep 25, 2016 at 22:12

1 Answer 1

3

So the #initialize override is failing because you're using object splat (**) instead of array splat (*).

But you shouldn't do this. Subclassing Ruby's core classes will lead to all sorts of counter-intuitive behavior because they have many methods that create new instances of that class -- that won't be updated to create new instances of your class. For example, Library.new.reverse and Library.new + Library.new will both return new arrays, not libraries.

Instead you can get the behavior you want by creating an array instance variable in your class and delegating to it. You can define #each and get all the Ruby enumerable methods. You can also define any array methods you want.

class Library
  include Enumerable
  attr_accessor :authors

  def initialize(*args)
    @authors = {key1: 'val1', key2: 'val2'}
    @array = args
  end

  def each(&block)
    @array.each(&block)
  end

  def [](index)
    @array[index]
  end
end
Sign up to request clarification or add additional context in comments.

3 Comments

If you're subclassing from Array then why do you have to include Enumerable?
@jack-noble probably meant to remove the < Array from the class definition. Thanks for the warning about not subclassing Array, that's a good landmine to know!
@gmcnaughton Yep, I meant to remove the subclassing. Sorry about that, editing.

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.