为什么我不能在课堂上使用私有方法?如何修复我的代码以防止错误?
module CarRegistration
class Basics < Base
fields_of_model(:car).each do |attr|
delegate attr.to_sym, "#{attr}=".to_sym, to: :car
end
private
car_structure = #array of hashes
def fields_of_model(model)
car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
end
end
NoMethodError(未定义的方法“ fields_of_model”,用于 CarRegistration :: Basics:Class):
答案 0 :(得分:3)
我认为您在这里遇到了许多问题。
首先,您已经将fields_of_model
定义为实例方法,在这里:
def fields_of_model(model)
car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
end
但是您正试图从班级中调用它,
fields_of_model(:car).each do |attr|
delegate attr.to_sym, "#{attr}=".to_sym, to: :car
end
因此,您需要将fields_of_model
设为一个类方法,并在调用它之前对其进行定义。像这样:
module CarRegistration
class Basics < Base
private
car_structure = #array of hashes
class << self
def fields_of_model(model)
car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
end
end
fields_of_model(:car).each do |attr|
delegate attr.to_sym, "#{attr}=".to_sym, to: :car
end
end
我认为您还会遇到该car_structure
变量的问题,因为它将超出类方法的范围。因此,我认为您需要制作一个类级实例变量。因此,尝试一下:
module CarRegistration
class Basics < Base
@car_structure = #array of hashes
class << self
def fields_of_model(model)
@car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
end
private :fields_of_model
end
fields_of_model(:car).each do |attr|
delegate attr.to_sym, "#{attr}=".to_sym, to: :car
end
end
请注意,我使用:fields_of_models
将类方法private :fields_of_model
设为私有。
为演示整个过程,我进行了RSpec测试:
require 'rails_helper'
class Car
attr_accessor *%w(
color
make
year
).freeze
end
module CarRegistration
class Basic
@car_structure = [
{model: :car, name: :color},
{model: :car, name: :make},
{model: :car, name: :year}
]
class << self
def fields_of_model(model)
@car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
end
private :fields_of_model
end
fields_of_model(:car).each do |attr|
delegate attr.to_sym, "#{attr}=".to_sym, to: :car
end
def car
@car ||= Car.new
end
end
end
RSpec.describe CarRegistration::Basic do
it "has :fields_of_model as a private class method" do
expect(CarRegistration::Basic.public_methods).not_to include(:fields_of_model)
expect(CarRegistration::Basic.private_methods).to include(:fields_of_model)
end
it "responds to :color and :color=" do
expect(car_registration).to respond_to(:color)
expect(car_registration).to respond_to(:color=)
end
it "sets and gets attributes on car" do
expect(car_registration.color).to be_nil
expect(car_registration.car.color).to be_nil
car_registration.color = :red
expect(car_registration.car.color).to eq(:red)
expect(car_registration.color).to eq(:red)
expect(car_registration.instance_variable_get(:@color)).to be_nil
end
end
def car_registration
@car_registration ||= described_class.new
end
运行时会产生:
CarRegistration::Basic
has :fields_of_model as a private class method
responds to :color and :color=
sets and gets attributes on car
Finished in 0.733 seconds (files took 27.84 seconds to load)
3 examples, 0 failures
顺便说一句,将这段代码放在def
-end
之外的类中很好,而不是问题的根源。实际上,这很正常。
此外,我会注意到Jörg W Mittag想说:
我是那些想要指出Ruby中没有类方法之类的Ruby Purists的人之一。不过,我很好地使用了 class方法这个术语,只要各方都完全理解这是一个俗语用法。换句话说,如果您知道,就没有类方法之类的东西,并且术语“类方法”只是“作为实例的对象的单例类的实例方法”的简称的
Class
”,那么就没有问题。但是否则,我只会看到它妨碍理解。
让所有各方都完全理解,术语“ <类>类方法” 在上面用的是口语含义。
答案 1 :(得分:-1)
因为您在def
-end
子句中编写了 not 方法;你应该这样写
def my_method
fields_of_model(:car).each do |attr|
delegate attr.to_sym, "#{attr}=".to_sym, to: :car
end
end
这就是为什么错误消息显示CarRegistration::Basics:Class
而不是CarRegistration::Basics
这是一个有效的示例代码。
通常无需在Module
内放一个类,但是如果您由于某种原因必须这样做,这是一种方法。
module CarRegistration
class Basics < Object
def run(model)
fields_of_model(model)
end
private
def fields_of_model(model)
puts model
end
end
end
a = CarRegistration::Basics.new
a.run('xyz') # => 'xyz' is printed.