在Ruby中将self作为调用父类的类

时间:2017-07-28 12:41:00

标签: ruby-on-rails ruby ruby-on-rails-4 constants self

我的第一堂课有不变。我想让它以某种方式工作作为动态价值。

class Post < ActiveRecord::Base
  TEST = ["#{self.name}", "test1"]
end


class FakePost < Post
end

rails console我试图通过FakePost访问TEST常量,但仍然显示self为&#34; Post&#34;宾语。有没有办法实现这个目标?

当前

  

IRB(主):004:0&GT; FakePost ::测试

     

=&GT; [&#34;发布&#34;,&#34; test1&#34;]

但是当我通过Post而不是vi FakePost访问Constant时,我想返回这个结果。

预期:

  

IRB(主):004:0&GT; FakePost ::测试

     

=&GT; [&#34; FakePost&#34;,&#34; test1&#34;]

3 个答案:

答案 0 :(得分:3)

问题是代码TEST = ["#{self.name}", "test1"]仅在实例化Post类时被解释一次。之后,它将被修复为["Post", "test1"]

在我的脑海中,我无法想到一种使用常量使其工作的方法,但是如果你用类方法替换它就可以正常工作:

class Post
  def self.TEST
    [self.name, "test1"]
  end
end

class FakePost < Post
end

Post.TEST
#=> ["Post", "test1"]

FakePost.TEST
#=> ["FakePost", "test1"]

这样做的原因是类方法中的代码在运行时被解释(即当你调用方法时),而不是在解释类时。两种情况的时间表如下:

使用TEST常量:

  1. Post类被实例化并逐行解释。
  2. self.name已解释并返回'Post',因为self目前是Post类。
  3. Post::TEST不可撤销地设置为["Post", "test1"]
  4. FakePost类已实例化并从Post继承,包括TEST已经实例化的["Post", "test1"]常量
  5. FakePost::TEST == Post::TEST == ["Post", "test1"] #=> true
  6. 使用TEST类方法:

    1. 对帖子类进行实例化并逐行解释。
    2. 添加了帖子类方法TEST(但尚未解释)。
    3. FakePost类已实例化,并从TEST继承Post类方法。尚未解释。
    4. 当您运行Post.TESTFakePost.TEST时,最终会解释该方法。 self现在可以是PostFakePost,具体取决于称为TEST方法的类。

答案 1 :(得分:1)

不能修改常量,因此当您在后继中引用它时,它将返回已分配的值。使用类方法。

class Post < ActiveRecord::Base
  def self.test
    ["#{self.name}", "test1"] 
  end
end

class FakePost < Post
end

答案 2 :(得分:0)

正如其他人所指出的那样,TEST在解析["Post", "test1"]时被设置为等于Post;它与简单TEST = ["Post", "test1"]的行没有什么不同。

要从常量(TEST)获得所需的结果,一种可能性是将TEST设置为等于proc,然后使用self作为参数调用该proc。这可以通过以下方式完成。

class News
  TEST = ->(slf) { ["#{slf}", "test1"] }
end

class FakeNews < News
end

News.instance_eval { self::TEST[self] }
  #=> ["News", "test1"]
FakeNews.instance_eval { self::TEST[self] }
  #=> ["FakeNews", "test1"]
需要

BasicObject#instance_eval才能使self等于instance_eval的接收者。 Proc#[]Proc#call相同(以及Proc.yieldProc#===和折旧的Proc#() [书面TEST.(self)])。随便挑选!