I have the following class:
class Alphabet
attr_reader :letter_freqs, :statistic_letter
def initialize(lang)
@lang = lang
case lang
when :en
@alphabet = ('A'..'Z').to_a
@letter_freqs = { ... }
when :ru
@alphabet = ('А'..'Я').to_a.insert(6, 'Ё')
@letter_freqs = { ... }
...
end
@statistic_letter = @letter_freqs.max_by { |k, v| v }[0]
end
end
foo = Alphabet.new(:en)
The central member here is @alphabet.
I'd like to make it some sort of a container class to invoke Array methods directly like
foo[i]
foo.include?
instead of explicitly accessing @alphabet:
foo.alphabet[i]
foo.alphabet.include?
I know I could define a lot of methods like
def [](i)
@alphabet[i]
end
but I'm looking for a proper way of "inheriting" them.
You can use Forwardable (it is included in the Ruby standard library):
require 'forwardable'
class Alphabet
extend Forwardable
def_delegators :@alphabet, :[], :include?
def initialize
@alphabet = ('A'..'Z').to_a
end
end
foo = Alphabet.new
p foo[0] #=> "A"
p foo.include? 'ç' #=> false
If you wish to delegate all the methods not defined by your class you can use SimpleDelegator (also in the standard library); it lets you delegate all the methods that are not responded by the instance to an object specified by __setobj__:
require 'delegate'
class Alphabet < SimpleDelegator
def initialize
@alphabet = ('A'..'Z').to_a
__setobj__(@alphabet)
end
def index
'This is not @alphabet.index'
end
end
foo = Alphabet.new
p foo[0] #=> "A"
p foo.include? 'ç' #=> false
p foo.index #=> "This is not @alphabet.index"
When the delegate doesn't need to be dynamic you can arrange the master class to be a subclass of DelegateClass, passing the name of the class to be delegated as argument and calling super passing the object to be delegated in the #initialize method of the master class:
class Alphabet < DelegateClass(Array)
def initialize
@alphabet = ('A'..'Z').to_a
super(@alphabet)
end
More info about the delegation design pattern in Ruby here
You could extend the Forwardable module:
class Alphabet
require 'forwardable'
extend Forwardable
attr_accessor :alphabet
def initialize
@alphabet = [1,2,3]
end
def_delegator :@alphabet, :[], :include?
end
Then you can do:
alpha = Alphabet.new
alpha[1]==hey.alphabet[1]
=> true
Warning:
Don't try to delegate all methods (don't know if that's even possible) since they probably share some of the same method names such as class, which would probably make chaos.
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