Why are global methods allowed to be defined outside of a class in Ruby?
When you define a function in Ruby at the global scope in this way, it technically becomes a private
method of the Object
class, which is the base class that everything inherits from in Ruby. Everything in Ruby is an object, so it is indeed true that you have defined a method.
def say_goodnight(name)
result = "Goodnight, " + name
return result
end
Object.private_methods.include? :say_goodnight
=> true
Because it is defined as a method with private
visibility on Object
, it can only be called inside objects of the class on which it's defined or subclasses. So why does it appear to be available globally?Basically, the Ruby program itself defines an instance of Object
called main
, which serves as the top-level scope where your method was defined. So if you think of your program as running inside main
(which is an Object
) its private methods are available for use.
# In irb:
self
=> main
self.class
=> Object
self.private_methods.include? :say_goodnight
=> true
Addendum:This answer which further explains how
main
is defined and implemented.Update for Ruby >= 2.3
Noted in the comment thread, later versions of Ruby would define the methodObject#say_goodnight
in this example with public
visibility rather than private
. This behavior appears to have changed between Ruby 2.2.x and 2.3.x, but does not affect method exposure. Why can some classes and/or methods be called without instances of their parent class?
First of all, your intuition is correct.
Every methods must be an instance method of some receiver.
Global methods are defined as private instance methods on Object
class and hence seem to be globally available. Why? From any context Object
is always in the class hierarchy of self
and hence private methods on Object
are always callable without receiver.
def fuuuuuuuuuuun
end
Object.private_methods.include?(:fuuuuuuuuuuun)
# => true
Class methods are defined as instance methods on the "singleton class" of their class instance. Every object in Ruby has two classes, a "singleton class" with instance methods just for that one single object and a "normal class" with method for all objects of that class. Classes are no different, they are objects of the Class
class and may have singleton methods.class A
class << self # the singleton class
def example
end
end
end
A.singleton_class.instance_methods.include?(:example)
# => true
Alternative ways of defining class methods areclass A
def self.example
end
end
# or
def A.example
end
Fun fact, you can define singleton methods on any object (not just on class objects) using the same syntax def (receiver).(method name)
as followsstr = "hello"
def str.square_size
size * size
end
str.square_size
# => 25
"any other string".square_size
# => raises NoMethodError
Some programming language history — Singleton classes are taken from the Smalltalk language where they are called "metaclasses". Basically all object-oriented features in Ruby (as well as the functional-style enumerators on
Enumerable
) are taken from the Smalltalk language. Smalltalk was an early class-based object-oriented language created in the 70ies. It was also the language that invented graphical user interfaces like overlapping windows and menus et cetera. If you love Ruby maybe also take a look at Smalltalk, you might fall in love yet again. Using define_method to define global methods outside of a module
I don't know your whole situation, but you probably don't really want to be defining global methods. If you don't want to type the HTML::
then add an include HTML
statement at the beginning of your code.
Is a Ruby global variable equivalent to a class variable on Class Object?
This depends on what exactly you mean by "variables". Variables declared with1) JS: My understanding is that variables set outside the "outer" function's scope are global in context
const
or let
are lexically scoped.Variables declared with var
in the top-level context aren't actually variables at all, they become properties of the top-level object (e.g. window
, document
, global
, … depending on your environment).
That is true of all variables in both Ruby and ECMAScript, as well as properties in ECMAScript.and store a location to the assigned value.
This really depends on what exactly you mean by "everything". There are lots of "objects" (in the sense of "things we can talk about") in Ruby that aren't "objects" (in the sense of "things we can assign to variables, pass around, manipulate in Ruby code"). For example, variables aren't objects in Ruby.3) "Everything" in Ruby is an object (except blocks and individual index items within an array), including classes, primitives, etc.
I have no idea what this has to do with global variables.A) Is the Rails.application object actually an instance of the Application Class?
Yes, there is the pretty obvious difference that objects and classes which don't haveIs there any difference between a Ruby global variable:
$var = "A Ruby global variable"
and
Class Object
@@var = "A class variable set on the Class Object"
end
Object
in their ancestors chain won't have access to Object
's class variables:class BasicObject
@@var
end
# NameError: uninitialized class variable @@var in BasicObject
TheIs Class Object, as the Class from which all other Classes/Objects ultimately inherit, therefore, Ruby's "global" context (or not, and I missed something huge)?
Object
class acts as a sort-of global context for some stuff, but that is not because it is global, but rather because it is the parent of most classes (basically anything that doesn't extend directly from BasicObject
).Anything that uses inheritance (class variables, methods, and constants) and is defined in Object
will also be available in everything that descends from Object
. But that has nothing to do with "global". That's just how inheritance works. Note that Object
itself inherits from Kernel
and BasicObject
, so this is true for anything defined in those two as well.
No, it is not. A global variable is neither an instance variable nor a class variable. It is a global variable.C) (added as an edit) Because a global variable needs to be initiated and is available in a global scope, it is a class variable and not an instance variable. Is that reasoning sound?
Variables aren't objects in Ruby.If a global variable is an object, it has to inherit from Class Object, right? This would mean the "global" context is still wrapped within Class Object.
If I define a method in Ruby, does it belong to any class?
If you define a method outside of any class, it will become a private method of the Object
class.
Create a global Rails method inside a module?
TLDR
You need to "extend" theKernel
module by including your methods into it with include
.Global methods
Generally a "global" method in Ruby means creating a method inKernel
or Object
. The method is then available to all (most) classes because they inherit from Object
(which includes Kernel
). Your method can be called without a prefix from most places because the implicit self
in any given context will be an object that inherits from Object
and therefore contains the method you defined.One way to define such a method is just to place its definition in a file outside of any class or module:
def my_method
# do fancy stuff
end
Of course, you have to make sure that file gets loaded (i.e. required) somewhere.Global methods from a module
If you want your method to be organized within a module (which is a good idea), you need to include that module intoKernel
like this:module MySpecialMethods
def my_method
# do fancy stuff
end
end
module Kernel
private
include MySpecialMethods # This is where the method gets added to Kernel
end
In Rails, I would put the MySpecialMethods
module in lib/
, add put the Kernel
part inside an initializer file like config/initializers/extend_kernel.rb
. You also need to help Rails "find" your module in lib/
by adding config.autoload_paths += %W(#{config.root}/lib)
to application.rbConsider avoiding global methods
It's worth nothing that there are very few situations where it's a good idea to extendKernel
in this way. It's possible (likely?) that for your situation it is better to put your methods in a module and explicitly call them with the module name like MyModule.my_method
.module MyModule
def self.my_method
# do fancy stuff here
end
end
There are many places you could place this code. In Rails, I'd recommend putting it in the lib/
folder as above and then making sure Rails can find it by adding config.autoload_paths += %W(#{config.root}/lib)
to application.rbFrom a Gem
Creating a gem is beyond the scope of this question, but supposing you created a gem, typically the modules within that gem are available in your Rails app as long as you specify the gem in your Gemfile. This is because Rails apps by default callBundler.require
. As long as the gem follows proper naming conventions, the main gem file is required automatically, and the main gem file requires any other necessary files.If you want to extend Kernel
from a gem, just put the Kernel
extension code (from above) inside a file that is required (directly or indirectly) when your gem is required.
Notes
Rails initializers only run once when you boot the Rails server, so changes to them are not autoloaded like many other pieces of Rails in development.
If you're tweaking Rails'
autoload_paths
, you might also want to tweakeager_load_paths
(see this blog post)There are some objects in Ruby that do not inherit from
Object
(e.g. BasicObject), so technically these "global" methods will not be available everywhere. That's not likely to cause problems for you.Using
Bundler.require
in a Rails app is perhaps controversial (see this blog post for more information on that)
Can't access array defined outside my ruby function
Ruby is an object oriented language. Even more, Ruby appeared on the scene with a motto “everything is an object.” Even numbers and (sic!) nil
in Ruby are objects:
▶ 42.class
#⇒ Fixnum < Integer
▶ nil.__id__
#⇒ 8
So, you are supposed to use objects for anything that is slightly more complicated than a one-liner. Objects have a lot of goodness out of the box: instance variables, lifecycle, etc.class Game
def initialize
@coins = []
end
def add_coin(value)
@coins << value
end
def coins
@coins
end
def amount
@coins.size
end
end
Now you might create in instance of this class and while it’s alive, it will hold the value of @coins
:game = Game.new
game.add_coin("1")
puts game.coins
#⇒ ["1"]
puts game.amount
#⇒ 1
game.add_coin("1")
game.add_coin("2")
puts game.coins
#⇒ ["1", "1", "2"]
puts game.amount
#⇒ 3
Ruby - create a global variable from within a method
You can create a global variable from everywhere if you prefix it with a "$" sign, like: $var
If you declare it in a method, make sure you run that method before calling your variable.
For example:
def global_test
$name = "Josh"
end
$name # => nil
global_test() # Your method should run at least once to initialize the variable
$name # => "Josh"
So, in your example, if you would like to use s_name
from outside of your method, you can do it by adding a '$' sign before it like this: $s_name
Here is a good description about ruby variable types:
http://www.techotopia.com/index.php/Ruby_Variable_Scope
But as you can read in it (and mostly everywhere in "ruby best practices" and styleguides) it is better to avoid global variables.
Module vs methods outside module
Modules allow you group your methods and you can include them in other modules and classes. You can include module methods into the module/class itself or its eigenclass. So, with modules you have more flexibility. Not to mention that you are not cluttering up the "global" namespace.
Also, when you define method in a file, you are defining it in the current context. Since, everything in Ruby is an object, you are actually defining it within a main
object (an instance of Object
class).
2.3.0 :001 > self
=> main
2.3.0 :002 > self.class
=> Object
2.3.0 :003 > self.object_id
=> 70123533022000
2.3.0 :004 > def test; end;
2.3.0 :005 > self.public_methods.include? :test
=> true
Related Topics
Skipping: Touch Associations When Saving an Activerecord Object
Does The Rails Orm Limit The Ability to Perform Aggregations
Gem Ransack Doesn't Return Any Results When Searched with Full Name
Script Executes Successfully in Commandline But Not as a Cronjob
Watir Changing Mozilla Firefox Preferences
Seed Images in Heroku with Paperclip
Cucumber Embed for Screenshots Not Linking to Screenshot
How to Create Line Breaks in Ruby
How to Validate Overlapping Times in Rails with Postgresql
Error Generating Source Map - Grunt and SASS Configuration
Completely Random Identifier of a Given Length
Unit Testing Code Which Gets Current Time
Strong Parameters with Nested Hash
How to Pick The Method to Call When There Is Mixin Method Name Conflict
Asynchronously Iterating Over The Response of a Request Using Thin and Sinatra