How does scope work in Ruby? - ruby-on-rails

I cannot figure this out as someone who has primarily worked in C.
How is the following code plausible?
if true
hi = "hello"
end
puts hi
I'm used to hi not being in the scope of the puts, so it would error. How does scope in Ruby work. I can't seem to find a clear tutorial explaining it.
And even though that's valid, is it good practice?

In Ruby, there are 5 scopes:
script scope
module scope
class scope
method scope
block scope
Block scopes nest, the other ones don't. Blocks can close over their lexical environment, the other ones can't. (IOW: not only do they nest inside their lexically surrounding environment, i.e. can access variables from their lexically surrounding environment, they can even continue to do so after that surrounding environment ceases to exist.)
Unlike some other languages, Ruby doesn't have a top-level or global scope for local variables. The "biggest" scope is script scope, but that isn't global, it is confined to a single script. (Usually, a script is the same as a file, but there are Ruby implementations that don't use files, so a term like "file scope" would be misleading.)
Local variables are defined from the point on where their definition is parsed, and initialized from the point on that their definition is executed. In between, when they are defined but not initialized, they evaluate to nil.
Consider this slightly modified example:
if false
hi = 'hello'
end
hi
# => nil
# hi is defined here, because its definition was parsed
if true
hi = 'olleh'
end
hi
# => 'olleh'
# hi is initialized here, because its definition was executed

In Ruby we have 4 scopes -
top level scope
def creates a new scope
class creates a new scope
module creates a new scope.
In your case hi is a local variable which has been created in the top level scope. As I said above if doesn't create a new scope, so it is using the default scope, which is top level scope, and hi is created in the top level scope.
Example :
foo = 12
def baz
p foo # undefined local variable or method `foo'
bar = 2
end
bar # undefined local variable or method `bar'
As def creates a completely brand new scope, thus inside baz, that scope has no idea about foo and it objects. Similarly, inside the baz, I have created a new variable bar, but it is not known to the out side the scope of baz, thus top level also objects against bar.

Related

Rails NoMethodError when calling a method from a constant

I'm trying to call a method inside a class constant. It returns a NoMethodError. Here's a sample code:
class TestingA
CONSTANT_HERE = { details: get_details('example.json') }
def get_details(file)
# retrieve details here
end
end
The error that appears is:
NoMethodError (undefined method `get_details' for TestingA:Class)
Any ideas on why?
Generally, dynamic constant assignment is discouraged in Ruby. Why would you want to define a constant that can possibly change within the life-cycle of an object? We don't know exactly what get_details is doing, but what is the use case of creating an instance method that is called from a constant as well as exposing the method? We can only assume return value is dynamic at this stage. Rubocop is also going arrest you for not freezing the constants, which is bad as linters are a good tool to abide by.
Constants can be changed and there is no way to avoid this as variables in Ruby are not containers: they point towards an object. However, it is your duty to make your code readable. If you see a constant that you cannot easily discern the value of, would you think that is readable?
We should talk about how Ruby loads constants and, more generally, files. Every Ruby application has its entry point. The interpreter will need the file to load and execute the commands of the application. The Ruby interpreter will increment over each statement inside your file and execute them following a specific set of rules, until it parses the entire file. What happens when the interpreter iterates to a constant? What other types of constants are there? Hint: CONSTANT_HERE is not the only constant you are defining.
The class keyword is processed first and the interpreter creates a constant 'TestingA' and stores in that constant a class object. The name of the class instance is "TestingA", a string, named after the constant. Yes, classes and modules are constants. Each class has a constant table, which is where "TestingA" will be stored. After this, the body of the class is interpreted and a new entry is created in the constant table for "CONSTANT_HERE" and the value is set and stored. This is happening before your definition of get_details has been defined: the interpreter wants to set the value, to store it, before "get_details" has been interpreted, which is why you are experiencing the error you are.
Now we know this, and wanting to provide an example of how constants are evaluated in code, you would need to mimic the below in order to have a method defined in a constant:
def get_details(file)
"stub_return"
end
class TestingA
CONSTANT_HERE = { details: get_details('example.json') }
end
In my opinion, the above is not good practise as it is an example mis-use of constant assignment. If you want to get details from a file, define a class/method and call the API/method instead. It's neater, assigns role of responsibility and is less ambiguous.

Namespacing module method definition

I accidentally came across this piece of code in Ruby's Postgresql gem:
### Convenience alias for PG::Connection.new.
def self::connect( *args )
return PG::Connection.new( *args )
end
I played around a bit and turns out that this thing is used just like a normal module class method (it's called like this: PG.connect). In fact we could instead say def self.connect ( #args ) ... end and it would work just the same.
Since self::whatever is a first for me I'm wondering what exactly does self namespaces in such a context and what is its true purpose in this case. Can anyone help shed some light on this?
:: is the scope resolution operator. So self::connect resolves connect from self. Which means that its equivalent to self.connect. You can see how it works from this very contrived example:
class Foo; end
class Bar
def Foo::baz
"Hello World"
end
end
puts Foo.baz # "Hello World"
Of course we could also just use def Foo.baz to get the exact same result.
Using double colons for method definition is discouraged by the Ruby Style guide:
Do not use :: to define class methods.
# bad
class Foo
def self::some_method
end
end
# good
class Foo
def self.some_method
end
end
Its also not recommended for anything other than referencing constants and constructors:
Use :: only to reference constants (this includes classes and modules)
and constructors (like Array() or Nokogiri::HTML()). Do not use :: for
regular method invocation.
:: is, in some situations, somewhat equivalent to .. (I will leave out a precise definition in which exact situations it is equivalent and to what degree, because I freely admit I don't fully know it myself, nor is it well-documented.)
Here is an example of where :: and . behave differently:
module Foo
def self.Bar
'method'
end
Bar = 'constant'
def self.Qux; end
end
Foo.Bar
#=> 'method'
Foo::Bar
#=> 'constant'
Foo::Bar()
#=> 'method'
Foo.Qux
Foo::Qux
# NameError (uninitialized constant Foo::Qux)
Foo::Qux()
[Note: this is not a perfect example, since this is about the message sending side of things whereas your example is about the method definition side of things. I believe on the method definition side, they are 100% identical since def never defines a constant and thus there is no ambiguity.]
All Style Guides heavily advocate against this usage, from strongly advising against the message sensing part of it to flat out forbidding both usages of it. The main reason for this is the fact that the two behave differently for message sends, and this may lead to confusion. It is also simpler to explain the conceptual difference between method lookup (dynamic, upwards in the inheritance chain) and constant lookup (first static, lexically outward, then dynamic, upwards in the inheritance chain) when not using the same operator for both.
The typical style used by many Rubyists is:
NEVER use :: for singleton method definition, always use ..
ALWAYS use :: for referencing singleton methods in documentation, never use ..
ALWAYS use . for usage examples of message sends (including singleton methods) in documentation, never use ::.
NEVER use :: for message sends (including singleton methods), always use ..
Those last two are sometimes softened to allow for methods that are supposed to return modules or classes, and to allow for methods that act as factories (e.g. Nokogiri::XML) to be invoked via message sends that "look like" constant lookup, (e.g. Nokogiri::XML('<root/>') instead of Nokogiri.XML('<root/>')).
There was a feature request for removing this usage of ::, but it was rejected mostly because of backwards-compatibility concerns.

Understanding Ruby variables and symbols?

I am having some trouble understanding the syntax of variables and symbols in Ruby. I am reading a book called Agile Web Development with Rails 4. I am trying to learn both Ruby and Rails so that I can build websites.
The books and tutorials I have been reading sometimes have variables with the "#" symbol in front of them, and then some variables do not have the # symbol in front of them. What is the difference between them?
Also, I am getting confused with the colon. Sometimes I see variables where the colon is in the front, such as :order, and then I see variables where the colon is at the end, such as colon:. I do not understand what the colon is doing.
Please help me understand the Ruby syntax.
Variables starting with # are instance variables, "properties" in other languages. Whereas 'classic' variables are local to the scope of their method/block, instance variables are local to a specific instance of an object, for example:
class Foo
def initialize(bar)
#bar = bar
end
def bar
#bar # the variable is specific to this instance
end
def buzz
buzz = 'buzz' # this variable is not accessible outside of this method
end
end
You may also see variables starting with ##, which are class variables, and are accessible by every instance of the class and shared with every instance of the subclass. Usage of those variables is usually discouraged, primarily because subclasses share the variable, which can cause a lot of mess.
In Ruby everything is an object, classes are objects (instances of class Class), so you can also have class instance variables:
class Foo
def self.bar
#bar #we are in class Foo's scope, which is an instance of class Class
end
def self.bar=(bar)
#bar = bar
end
def bar
#bar # Foo.new.bar != Foo.bar
end
end
What you call "variables with a colon" are not variables. They are a particular type of string, called a symbol, that is immutable and optimized for quick identification by the interpreter, in fact, those are stored internally as pointers, so that :this == :this is a very quick operation.
This property makes them good candidates for hash keys because they offer quick retrieval or for "flags" to pass to a method; Think of them as a sort of loose constant that "stands for" what they say. Their immutability is also dangerous: All symbols ever created never get garbage collected; It's easy to create a memory-leak by creating thousands of symbols, so use them wisely.
UPDATE since ruby 2.2 symbols may be garbage-collected in certain cases (when no reference is kept and no comparison is needed)
Variables with an # symbol are instance variables. What this means is that they persist as long as the instance of the class they are declared in persists. So if you have a class called Message and each message has a variable called #subject, when you instantiate a new message it will keep that subject variable in memory as long as the message object itself lives. Now if it did not have the # symbol, once the function it was declared in "went out of scope" aka finished, the variable would be "lost" as the function was complete and the memory was reclaimed by the Ruby VM. There are also "class variables" that are prefaced with two # symbols. This means the variable is shared across all instances of a class.
As for the colon, if it is before a variable that means it is a "symbol", which is usually used as an identifer for hashes and other bits of data in Ruby. If it is at the end of a word that means it is the key portion of a hash identifier in Ruby 1.9+ syntax.
Instance Variables: (#foo = '123') An instance variable is defined and keeps its value throughout the current instance of the request. In the rails mvc paradigm, the most common use of instance variables are used to help communicate data from the controller to the view, and allows you ro define things in one part of the controller and use in another.
class ProjectsController < ApplicationController
before_filter :find_project
def show; end
def update
if #project.update_attributes(params[:project])
...
end
end
private
def find_project
#project = Project.find(params[:id])
end
end
In the above code, you can see that there is a before filter that gets ran before every method. In the above case, we find the current project and save it to an instance variable. And because its an instance method, its able to be access anywhere within this class as well as the views used to render the html.
Local Variables: (foo = '123') Pretty much exactly what the name implies, they are only able to be accessed within the current method (def) of where they are defined.
sometimes have variables with the "#" symbol in front of them, and then some variables do not have the # symbol in front of them.
Variables with the "#" symbol are instance variables,which are not preceded by #,can be constants or local variables or global variables. Read Ruby Programming/Syntax/Variables and Constants.
Sometimes I see variables where the colon is in the front, such as :order
They are called symbols.
and then I see variables where the colon is at the end, such as colon:. I do not understand what the colon is doing.
These probably the Hash syntax(as you give us hints,so I would guess),where keys are symbols. Example : {foo: 1} - this is a Hash.
Also read as you requested :
Normal Variables Vs Instance variable in Ruby, Whats the difference?

How to access an included module's methods from within another included module?

module Foo
attr_accessor :val
end
module Bar
def bar
val = 50
end
end
class FooBar
include Foo
include Bar
end
fb = FooBar.new
puts fb.bar # 50
puts fb.val # nil
I would like to, from within Bar, change Foo's "val" value.
Just so you know, I'm trying to do this because I want to add user authentication through a Facebook Canvas app in Clearance (0.8.2 (old, I know)). The variable that I want to change is https://github.com/thoughtbot/clearance/blob/b8ccca00d91cb336e044b76b5c6ae1d8de9d2d8d/lib/clearance/authentication.rb#L25.
This module gets included into ApplicationController, and I'm including another module afterwards (FacebookAuthenticationHelper) that does something like
def authenticate_facebook
current_user ||= facebook_user if coming_from_facebook?
end
I would love to know if there's a better way to do this as well. I'm not using OAuth, I'm just saving Facebook's user_id sends to my app from signed_request into my DB.
Thanks!
In ruby, any statement of the form varname = value will create a local variable named varname if it doesn't already exist. This is even true within class methods where the class has a setter method of the same name. Furthermore, if a local variable exists, it takes precedence over getters and setters. For example:
class Demo
attr_accessor :foo
def demonstrate!
#foo = 1 #1: Set member variable foo, so we get meaningful output
puts foo #2: Prints 1 (this calls the getter)
puts self.foo #3: Prints 1 (also calls the getter)
foo = 2 #4: Creates a LOCAL variable named foo with the value 2
puts foo #5: Prints 2 (locals take precedence over getters)
puts self.foo #6: Prints 1 (calls the getter - the member variable hasn't changed)
self.foo = 3 #7: Use SELF to ensure you call a getter or setter
puts foo #8: Prints 2 (the local again)
puts self.foo #9: Prints 3 (the member, which is now 3)
end
end
The bad thing about this system is: Look at lines 2 and 5. The same exact code does different things! On line 2, the local variable foo didn't exist yet, so ruby did the "next best" thing and called the getter. But on line 5, the local foo exists, so it takes precedence.
I'd say that this is bad language design: If setters can't be called without self, why should it be okay for getters - especially when it can lead to rickety, context-sensitive code like the above? But it's what we have to work with, and it leads to some general guidelines:
If you can, use #foo. It's obvious what that does.
If you're using a getter or setter, always use self, even when it's not strictly necessary. This makes it obvious what you're calling. It also guarantees your code won't behave differently if you add a local with the same name later.
If you do 1 and 2, you can assume that anything without a # or a self is a local variable (or a function call, but you can probably tell those apart by name).
And that ended up being a bit long-winded, but I was unable to find a good demonstration of the getter/setter/local problem to link to. So maybe this is it - hope it's helpful!

How declare a global variable in ROR3.0 within a function?

hi i m new to ruby on rails please let me know is it possible to declare a variable within the function/method
def fun1
#initialized a global variable
end
def fun2
#access value
end
is it possible get value of a variable declared in fun1 function by fun2 function
To create a truly global variable, use $:
def fun1
$foo = 'bar'
end
def fun2
puts $foo
end
Here $foo is available outside the class instance once fun1 has been called.
As noted in the first comment, this should be used sparingly:
They are dangerous because
they can be written to from anywhere. Overuse of globals can make
isolating bugs difficult; it also tends to indicate that the design of
a program has not been carefully thought out.
What you're probably asking for is an instance variable, which uses #:
def fun1
#foo = 'bar'
end
def fun2
puts #foo
end
Here #foo is available anywhere in the current instance of the class, again once it has been declared by calling fun1.
See for example this on the various variable scopes in ruby.
First of all, it would be better if you could share your actual scenario for what you need to define a global variable from a function. There might be a better, manageable, DRY approach for your solution.
Secondly, apart from the answer from "Thilo", here are few references showing the usage of global variables for rails in different situations. Not just for ruby. You need it for rails right?
https://stackoverflow.com/a/4110947/1160106
https://stackoverflow.com/a/3600860/1160106

Resources