I have the need to use a Stack-like data structure for a program that I am writing and I know that Ruby doesn't have an explicit Stack data-structure, but that the Array class has all of the properties that make a Stack: push, pop, size, clear, isEmpty, inspect, to_s.
In searching online I found various posts using this syntax to extract features of the Array class into a subclass:
Stack = Array.extract([
  :push,
  :pop,
  :size,
  :clear,
  :inspect,
  :to_s
])
s = Stack.new
s.push 1
s.push 2
s.push 3
s       # => [1, 2, 3]
s.pop   # => 3
s       # => [1, 2]
I would like to do something similar to this so my subclass of Array is restricted in what calls it can make, but it appears that the extract method is no longer in the Array class API.
Questions:
Take this code, for example:
class Stack
  def initialize
    @array = []
  end
  def push val
    @array.push val
  end
  def pop 
    @array.pop
  end
end
Here you have private instance var to which you delegate selected methods. Other methods cannot be called directly. The syntax can be sweetened and made more "rubesque" with some metaprogramming, but basic idea is as shown above.
Of course, one can always get to that private var via instance_variable_get and there's nothing you can do about it. This is Ruby!
Make clean safe public interface. And if someone tries to meddle with inner parts and breaks something, it's his problem.
If you're using ActiveSupport (which comes with Rails), then there's a simpler way of doing this.
# load ActiveSupport if not in Rails env
require 'active_support/core_ext'
class Stack
  def initialize
    @impl = []
  end
  # the "extract" part :)
  delegate :count, :push, :pop, to: :@impl
end
s = Stack.new
s.push(3).push(4)
s.count # => 2
Or look at similar answer by @AndrewGrimm.
If you're going to be doing a lot of delegating, then you may want to use the delegation methods Ruby provides.
require "forwardable"
class Stack
  extend Forwardable
  def_delegators :@array, :push, :pop
  def initialize
    @array = []
  end
end
Not only does it mean less typing, but if you're familiar with Forwardable, it's easier to read. You know that your class is merely delegating, without having to read the code for Stack#push or Stack#pop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With