在Ruby中,如何验证Struct的身份?

4
我一直在试图理解Ryan Bates在他的Presenters RailsCast (#287 Presenters from Scratch (pro) - RailsCasts)中使用的present方法中的self类。在视频中,Ryan说,“Self是模板对象,具有我们想要访问的所有帮助器方法”,但我想知道这个对象的类。阅读了一系列博客文章、SO线程和Ruby文档后,我开始认为self是一种Struct,但我不知道如何确认这个概念。
我的问题是:1) 在下面的present方法中,self是一个Struct吗?2) 如何验证某个东西是否是Struct?
module ApplicationHelper
  def present(object, klass = nil)
    klass ||= "#{object.class}Presenter".constantize
    presenter = klass.new(object, self)
    yield presenter if block_given?
    presenter
  end
end

我之所以问这个问题,是因为我没有很多使用Struct类的经验。当我在上述方法中插入binding.pry并尝试获取self的类名时,我会遇到更多问题。

  • When I enter self.class, I get, #<Class:0x007fb64f696268> I wondered if getting Class here might indicate that I have a Struct, but I couldn't find any documentation that confirmed this
  • When I enter self.class.class, I get Class
  • When I enter self, I get an extensive object that starts with the lines of code of code listed below

    @ line 16 ApplicationHelper#present:
    
    14: def present(object, klass = nil)
    15:   klass ||= "#{object.class}Presenter".constantize
    16:   binding.pry
    17:   presenter = klass.new(object, self)
    18:   yield presenter if block_given?
    19: end
    
    [1] pry(#<#<Class:0x007fb64f696268>>)> self
    => #<#<Class:0x007fb64f696268>:0x007fb64f6948f0
    @_assigns={"marked_for_same_origin_verification"=>true},
    @_config={},
    @_controller=
      #<PostsController:0x007fb64f6762d8
       @_action_has_layout=true,
       @_action_name="show",
       @_config={},
       @_db_runtime=0,
       @_lookup_context=
        #<ActionView::LookupContext:0x007fb64f6760d0
          @cache=true,
          @details=
            {:locale=>[:en],
            :formats=>[:html],
            :variants=>[],
            :handlers=>[:raw, :erb, :html, :builder, :ruby]},
          @details_key=#<Concurrent::Map:0x007fb64f697938 entries=0 default_proc=nil>,
          @prefixes=["posts", "application"],
          @rendered_format=:html,
          @view_paths=
            #<ActionView::PathSet:0x007fb64f675fe0
    

这篇文章在解释Struct的工作原理方面非常有帮助,但没有解释如何确认自己是否有一个Struct。

起初,当我开始分析present方法时,发现这个答案很有帮助。然而,我被评论中说“ModelPresenter是通过传递模型和ApplicationHelper类来初始化”的说法所困扰,因为ApplicationHelper是一个模块。


请记住,您正在涉及Rails内部,并且Rails内部并不是简单、直接或者有很好的文档记录的。这非常令人困惑,需要花费很长时间才能理解其中的奥秘。 - mu is too short
1
确实!我不想陷入细节中,但我也想花一些时间挑战自己的错误假设,以便最终能够理解其中的奥秘。 - Ginnie Hench
1个回答

2

摘要

使用is_a?(Struct)

解释

结构体是一个匿名类的构造函数:

struct_class = Struct.new(:foo)
# => #<Class:0x007fa7e006ea98>

您可以通过以下方式检查匿名类的实例是否为结构体:

inst = struct_class.new
inst.class.superclass
# => Struct

然而,Object#is_a? 检查父类和超类:

inst.is_a?(Struct)
# => true

您可以在以下任意示例中看到相同的行为:
# inherits from String
anon_class = Class.new(String) 

inst = anon_class.new
# => ""

inst.class == String
# => false

inst.is_a?(String)
# => true

1
问题是,当我提交self.is_a?(Struct)时,会得到false - Ginnie Hench
但是,self.class.superclass 返回 ActionView::Base... 最后,这让我更接近我所寻找的东西。谢谢,@max-pleaner。 - Ginnie Hench
1
@GinnieHench 这意味着使用 Class.new(ActionView::Base) do ... end 动态创建了一个 ActionView::Base 的子类,其中包含一些特定于所讨论的视图的额外方法和其他内容。 - mu is too short
1
嗯,我在我的应用程序中没有调用过那样的方法,但是我在视图中的erb中调用了present方法。通过在pry中运行self.class.ancestors,我看到了一堆列出的ActionView::Helpers,以及其他Rails模块,所以我可以看到self“具有我们想要访问的所有帮助器方法”,这就是Bates提到的,但我仍然不确定该如何称呼self...鉴于self.is_a?(Object)返回true和self.class.is_a?(Class)返回true,我必须接受self是来自Class类的对象。 - Ginnie Hench
1
Rails在需要一个隔离容器来存放一些东西(比如视图)时,通常会创建匿名类。这不是你在做,而是Rails在做。然后Rails会将一堆模块(比如视图助手)混合到匿名类中,并将控制器的实例变量复制到视图实例中。 - mu is too short
1
小提示:使用case objectwhen Struct也可以起作用。 - Joshua Pinter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接