[英]NoMethodError (undefined method) from Private method in class
Why can't I use a private method from within my class? 为什么我不能在课堂上使用私有方法? How do I fix my code to prevent the error?
如何修复我的代码以防止错误?
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 (undefined method `fields_of_model' for CarRegistration::Basics:Class):
NoMethodError(CarRegistration :: Basics:Class的未定义方法`fields_of_model'):
I think you have a number of problems going on here. 我认为您在这里遇到了许多问题。
First, you've defined fields_of_model
as an instance method, here: 首先,您已经将
fields_of_model
定义为实例方法,在这里:
def fields_of_model(model)
car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
end
but you're trying to call it from the class, here: 但您正在尝试从班级中调用它:
fields_of_model(:car).each do |attr|
delegate attr.to_sym, "#{attr}=".to_sym, to: :car
end
So, you'll want to make fields_of_model
a class method, and define it before you call it. 因此,您需要将
fields_of_model
一个类方法,并在调用它之前对其进行定义。 Something like: 就像是:
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
You'll also have problems with that car_structure
variable, I think, because it'll be out of scope for the class method. 我认为,您还会遇到那个
car_structure
变量问题,因为它将超出类方法的范围。 So, I think you need to make a class-level instance variable. 因此,我认为您需要制作一个类级实例变量。 So, give this a try:
因此,尝试一下:
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
Note that I made the class method, :fields_of_models
private using private :fields_of_model
. 请注意,我使用
private :fields_of_model
将类方法:fields_of_models
私有。
To demonstrate the whole thing, I ginned up this RSpec test: 为了演示整个过程,我进行了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
Which, when run, yields: 运行时产生以下结果:
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
BTW, having this code in your class outside of a def
- end
is just fine and not the root of your problem. 顺便说一句,有外部你们班这个代码
def
- end
是蛮好的,而不是你的问题的根源。 In fact, it's quite normal. 实际上,这很正常。
Also, I will note that Jörg W Mittag wishes to say: 另外,我会注意到JörgW Mittag希望说:
I am one of those Ruby Purists who likes to point out that there is no such thing as a class method in Ruby.
我是那些喜欢指出Ruby中没有类方法之类的Ruby Purists的人之一。 I am perfectly fine, though, with using the term class method colloquially, as long as it is fully understood by all parties that it is a colloquial usage .
不过, 只要各方都充分理解这是一种口语用法,那么以口语方式使用术语类方法 就可以了 。 In other words, if you know that there is no such thing as a class method and that the term "class method" is just short for "instance method of the singleton class of an object that is an instance of
Class
", then there is no problem.换句话说,如果你知道有没有这样的事,作为一个类的方法和术语“类方法”只是短期的“单身类的对象,它是实例的实例方法
Class
”,再有就是没问题。 But otherwise, I have only seen it obstruct understanding.但是否则,我只能看到它妨碍理解。
Let it be fully understood by all parties that the term class method is used above in its colloquial sense. 各方应完全理解,术语“ 类方法”是在其通俗意义上使用的。
Because you wrote the method not in def
- end
clause; 因为您未在
def
- end
子句中编写该方法; you should write it like 你应该这样写
def my_method
fields_of_model(:car).each do |attr|
delegate attr.to_sym, "#{attr}=".to_sym, to: :car
end
end
That is why the error message says CarRegistration::Basics:Class
as opposed to CarRegistration::Basics
这就是为什么错误消息显示
CarRegistration::Basics:Class
而不是CarRegistration::Basics
Here is a sample code that works. 这是一个有效的示例代码。 Usually there is no need to put a class inside
Module
, but if you must for some reason, this is a way. 通常不需要在
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.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.