Распространенным способом реализации общего поведения является требование определенного интерфейса. Например, модуль Enumerable
требует, чтобы вы внедрили each
для работы большинства методов. (Некоторым методам, таким как sort
, необходимы элементы внутри для реализации оператора <=>
.)
Чтобы применить это к тому, что вы пытаетесь сделать, вам могут потребоваться классы, расширяющие модуль для реализации all
метод. Вам не нужно проверять это специально. Просто предположим, что есть метод all
, если пользователь не увидит исключение "NoMethodError: неопределенный метод" all "для Song: Class" , что довольно ясно.
module Findable
##
# The class extending Findable::ClassMethods must provide a method
# `all` which returns an Enumerable collection.
module ClassMethods
def find_by_name(name)
all.select { |instance| instance.name == name }
end
end
end
class Song
extend Findable::ClassMethods
attr_accessor :name, :artist
@@songs = []
def initialize
@@songs << self
end
def self.all
@@songs
end
end
foo = Song.new
foo.name = "foo"
bar = Song.new
bar.name = "bar"
Song.all
#=> [#<Song:0x0055828c8ca3e8 @name="foo">, #<Song:0x0055828c8cc9e0 @name="bar">]
Song.find_by_name("foo")
#=> [#<Song:0x0055828c8ca3e8 @name="foo">]