首页 > 解决方案 > 如何在Ruby的模块文件中引用类之外的类变量

问题描述

我正在尝试在模块文件的类中引用类变量:

require 'pry'
require_relative '../lib/concerns/memorable'

class Song
  extend Memorable::ClassMethods
  extend Findable::ClassMethods
  attr_accessor :name
  attr_reader :artist

  @@songs = []

  def initialize
    @@songs << self
  end

  # def self.find_by_name(name)
  #   @@songs.detect{|a| a.name == name}
  # end

  def self.all
    @@songs
  end

  # def self.reset_all
  #   self.all.clear
  # end
  #
  # def self.count
  #   self.all.count
  # end

  def artist=(artist)
    @artist = artist
  end

  def to_param
    name.downcase.gsub(' ', '-')
  end
end
module Findable
  module ClassMethods

    def all
      @@artists
    end

    def all
      @@songs
    end

    def find_by_name(name)
      @@songs.detect{|a| a.name == name}
    end

    def self.find_by_name(name)
      @@artists.detect{|a| a.name == name}
    end

 end

end

标签: ruby

解决方案


实现共享行为的一种常见方法是需要某个接口。例如,核心Enumerable模块需要您实现each大多数方法才能工作。(有些方法sort需要其中的元素来实现<=>运算符。)

将此应用于您尝试做的事情,您可能需要扩展模块的类来实现all方法。你不需要专门检查这个。假设该all方法在那里,如果不是,用户将看到一个异常“NoMethodError:未定义方法'all' for 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">]

推荐阅读