Calling method within Class
class TestClass
# a class method
def self.test_method
puts "Hello from TestClass"
end
# an instance method
def test_method
puts "Hello from an instance of TestClass"
end
end
# call the class method
TestClass.test_method
# create and instance object of TestClass
instance_of_TestClass = TestClass.new
# call the instance method of the new object
instance_of_TestClass.test_method
Ruby methods called at top of classes
It'll be easier to understand by looking at it in action.
# Step 1
# Run this in IRB
class MyClass
def self.another_method
puts "Executed when class is loaded to memory"
end
end
# Step 2
# Now when you run the following in IRB after that, its going to execute the
# class method which was defined in its parent class (MyClass)
class MyAwesomeClass < MyClass
another_method # Executed ONCE when the class is loaded to memory for the first
def initialize; end
end
# Now if you instantiate MyAwesomeClass though, it will not print the same as of
# Step 2 as class method :another_method already has been executed when class
# was loaded
awesome1 = MyAwesomeClass.new
The body of a class will be interpreted and executed sequentially & behaves much like you'd expect it inside an instance method. Try putting a puts "Hello World"
in the body of your class definition like so:
class MyClass
# Executes when the class is defined in IRB(Loaded to memory)
puts "Hello World"
end
How to test in Ruby/Rails if method has been called in class body?
It's usually recommended to test the behavior, not the implementation. In this case, whatever acts_as_paranoid
provides for this class in terms of behavior, is what you want to test.
However, if you trust that calling acts_as_paranoid
correctly provides all the behavior you need and just want to test that it is added to the class, you can use:
assert User.included_modules.include? ActsAsParanoid::Core
To figure this out I just briefly looked at the source code for acts_as_paranoid here: https://github.com/ActsAsParanoid/acts_as_paranoid/blob/master/lib/acts_as_paranoid.rb#L8
You can see that on line 50, it extends the ActsAsParanoid module to ActiveRecord::Base, which gives the model classes access to the acts_as_paranoid
method. And if you look at the definition of this method, you can see it calls include ActsAsParanoid::Core
Why can't a class method have the same name as a non-class method?
tldr; within the scope of the instance, the puts
resolves to self.puts
(which then resolves to the locally defined method, and not Kernel#puts). This method overriding is a form of shadowing.
Ruby has an 'implicit self' which is the basis for this behavior and is also how the bare puts
is resolved - it comes from Kernel, which is mixed into every object.
The Kernel module is included by class Object, so its methods [like Kernel#puts] are available in every Ruby object. These methods are called without a receiver and thus can be called in functional form [such as
puts
, except when they are overridden].
To call the original same-named method here, the super
keyword can be used. However, this doesn't work in the case where X#another_method calls X#puts with arguments when it expects to be calling Kernel#puts. To address that case, see Calling method in parent class from subclass methods in Ruby (either use an alias or instance_method on the appropriate type).
class X
def puts
super "hello!"
end
end
X.new.puts
P.S. The second example should trivially fail, as my_puts
clearly does not take any parameters, without any confusion of there being another "puts". Also, it's not a syntax error as it occurs at run-time after any language parsing.
Method invocation in class definition?
In Ruby, class declarations are just chunks of code, executed in order.
It's important to remember that inside a class definition, self
points to the class itself. validates
is a class method of ActiveRecord
. As the class is being defined, code in the definition is executed. The validates
method resolves to a class method of ActiveRecord
, so is called during class definition.
In your Person
example, it will only print once, because you only define the class once.
Consider the following:
class Foo
def self.validates_nothing(sym)
(@@syms ||= []) << sym
puts "!!! Here there be logic"
end
def validate
@@syms.each { |s| puts s }
end
end
This defines a class with a class method validates_nothing
, and an instance method, validate
. validates_nothing
just gathers whatever arguments are given it, validate
just dumps them out.
class Bar < Foo
validates_nothing :anything
validates_nothing :at_all
end
This defines a subclass. Note that when the class method validates_nothing
is called, it prints:
Here there be logic
Here there be logic
If we create a new bar and call validate, we get the expected output:
> Bar.new.validate
!!!anything
!!!at_all
Add method to a class which can only be accessed inside specific class
You could use refinements for this:
Due to Ruby's open classes you can redefine or add functionality to existing classes. This is called a “monkey patch”. Unfortunately the scope of such changes is global. All users of the monkey-patched class see the same changes. This can cause unintended side-effects or breakage of programs.
Refinements are designed to reduce the impact of monkey patching on other users of the monkey-patched class. Refinements provide a way to extend a class locally. Refinements can modify both classes and modules.
Something like this:
module HashPatches
refine Hash do
def new_hash_method
# ...
end
end
end
and then:
class YourClass
using HashPatches
def m
{}.new_hash_method
end
end
That would let you call YourClass.new.m
(which would use new_hash_method
) but it wouldn't pollute Hash
globally so outside YourClass
, some_hash.new_hash_method
would be a NoMethodError
.
Reading:
- Official Refinements docs
- Refinements spec
What is the 'self' keyword doing exactly in this Class method?
self
is the class Restaurant
. def self.method
is how you implement a method on the class itself rather than an instance of the class. Restaurant.filter_by_city(...)
rather than Restaurant.new.filter_by_city(...)
.
self
changes in Ruby depending on context. Within a method, self
is the object the method was called on.
Within the class Restaurant
block, and outside of any method, self
is the Restaurant
object which is a Class object. Everything is an object in Ruby. Everything.
You can also do this by declaring a block where the class is the instance.
class << self
def filter_by_city(restaurants, city)
restaurants.select { |restaurant| restaurant.city == city }
end
end
Normally you'd use this syntax if you have a lot of class methods.
See Self in Ruby: A Comprehensive Overview for more.
Related Topics
How to Set Up a Sinatra App Under Apache with Passenger
Extract Links (Urls), with Nokogiri in Ruby, from a Href HTML Tags
Can't Install Ffi -V '1.9.18' on MACos Catalina
Rails 3/Ruby: Activerecord Find Method in Condition Array to Parameters Single Quote Issue
Puppet/Facter "Could Not Retrieve Fact Fqdn": How to Fix or Circumvent
Ruby Loading Config (Yaml) File in Same Dir as Source
Error Loading Rubygems Plugin ,Openssl.Bundle (Loaderror)
Array.Join("\N") Not the Way to Join with a Newline
Aws-Sdk for Ruby Access Folder Within Bucket
Openid Support for Ruby on Rails Application
Best Practice to Mark Deprecated Code in Ruby
How to List the Currently Available Objects in the Current Scope in Ruby
How to Convert Array of Activerecord Models to CSV
Rails Authentication Across Apps/Servers
Rspec: How to Test File Operations and File Content
Guidelines for Where to Put Classes in Rails Apps That Don't Fit Anywhere