ruby-on-railsrubystructselfpresenter

In Ruby, how does one verify the identity of a Struct?


I've been trying to make sense of the class of self in the present method that Ryan Bates used in his Presenters RailsCast (#287 Presenters from Scratch (pro) - RailsCasts). In the video, Ryan says, 'Self is the template object which has all the helper methods we want to access', but I wanted to know the class for this object. After reading a range of blog posts, SO threads, and Ruby docs, I'm starting to think that self is a kind of Struct, but I don't know how to confirm this notion.

My questions are: 1) In the present method below, is self a Struct?, and 2) How does one verify that something is a 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

I'm asking this because I don't have much experience working with Struct classes and when I stick binding.pry in the middle of the method above and try to get the name of the class for self, I end up with more questions.

This post was helpful in explaining how a Struct works, but doesn't explain how one can confirm that they have a Struct.

Initially, when I started dissecting the present method, I found this answer to be helpful. However, I was thrown off by the comment, saying that the "ModelPresenter is initialized by passing the model, and the ApplicationHelper class", since ApplicationHelper is a module.


Solution

  • Summary

    Use is_a?(Struct)

    Explanation

    A struct is a constructor for an anonymous class:

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

    You can check that an instance of the anonymous class is a struct like so:

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

    However Object#is_a? checks the parent class as well as superclasses:

    inst.is_a?(Struct)
    # => true
    

    You can see the same behavior in the following arbitrary example:

    # inherits from String
    anon_class = Class.new(String) 
    
    inst = anon_class.new
    # => ""
    
    inst.class == String
    # => false
    
    inst.is_a?(String)
    # => true