Jwan622 Jwan622 - 1 month ago 11
Ruby Question

Stripe API opening up the metaclass? Or just defining a class method?

I am reading the Stripe API and I see this:

module Stripe

...

class << self
attr_accessor :stripe_account, :api_key, :api_base, :verify_ssl_certs, :api_version, :connect_base, :uploads_base,
:open_timeout, :read_timeout

attr_reader :max_network_retry_delay, :initial_network_retry_delay
end


What is going on there? I tried reading Yehuda Katz's blog on this, but parts of it are kind of unclear, like this:

What is going on in the two examples he provides?


It turns out that all of these weird rules collapse down into a single
concept: control over the self in a given part of the code. Let's go
back and take a look at some of the snippets we looked at earlier:


class Person
def name
"Matz"
end

self.name #=> "Person"
end



Here, we are adding the name method to
the Person class. Once we say
class Person
, the self until the end of
the block is the
Person
class itself.


Person.class_eval do
def name
"Matz"
end

self.name #=> "Person"
end



Here, we're doing exactly the same
thing: adding the name method to instances of the
Person
class. In
this case,
class_eval
is setting the self to Person until the end of
the block. This is all perfectly straight forward when dealing with
classes, but it's equally straight forward when dealing with
metaclasses:


Why does Yehuda keep writing:

self.name #=> "Person"

Answer

There is no such thing as "class method" in Ruby. All methods are instance methods. Thing is just that instances are different.

Stripe is an instance of class Module, and Person is an instance of class Class.

So in your first example (Stripe) there is a definition of attr_accessors available to object Stripe.

So you will be able to read and write Stripes attributes:

Stripe.api_key = :some_key
Stripe.api_key
#=> :some_key

While the following defines a method available to instances of class Person

Person.class_eval do
  def name
    "Matz"
  end
end

You could have defined instance method available to Person class by using instance_eval, which evaluated the code within the context of the receiver:

Person.instance_eval do
  def name
    "Matz"
  end
end
Person.name # this is what they sometimes called  "a class method", which I don't like personally
#=> 'Matz'

It is always just a matter of a context. Once you understand what self is and where self points at any moment - things will become so much clearer.