RUBY
What is access control?
Access control provide restriction to access sensible parts of your code from other. This feature enables you to hide the implementation details of your code, and specify a preferred way by which that code can be accessed and used.
Object is only thing with which we can make changes in application. The only way to change an object's state in Ruby is calling one of its methods.
Good rule of thumb in access control:
"never to expose methods that could leave an object in an invalid state"
In Ruby, the inheritance hierarchy or the package/module don't really enter into the equation in context of access control like any other language, it is rather all about which object is the receiver of a particular method call.
Ruby gives you three levels of protection:
Public methods : Public methods can be called by everyone - no access control is enforced. Methods are public by default, anyone can call them. Can be accessed with implicit & explicit receiver. But initialize method is always private.
Protected methods : Protected methods can be only called by objects of the defining class and its subclasses. Can be accessed with implicit & explicit receiver. However, usage of protected is limited.
Private methods : Private methods cannot be called with an explicit receiver - the receiver is always self. This means that private methods can be called only in the context of the current object. We cannot call another object's private methods.
So now implicit & explicit receiver comes in picture.
What is implicit & explicit calling ?
In explicit calling we need to provide reference of object, on which method should be call. We provide this using self or using class instance. But in implicit calling we do not need to provide any reference to object, it will automatically take self as referencing object.
Confused confused confused :(
If we take example from real world then it might be easy to understand. If I ask some one to purchase a book then without any specification that person will go to bookshop not to hospital or medical. This we can consider as implicit calling. Now if I ask that person to purchase book from specific vendor (ABC shop). Then he will go to that specific shop to purchase that book. This we call as explicit calling.
Lets see below code to understand what Implicit and Explicit calling is
class Test
def method1
# Implicit calling
method2
end
def method2
end
end
t = Test.new
# Explicit calling
t.method1
def method1
# Implicit calling
method2
end
def method2
end
end
t = Test.new
# Explicit calling
t.method1
We will study further about private and protected access modifier.
How we can define a method private or protected in ruby?
There are two ways to define a method private or protected.
class MyClass
def method1 # this method is public
end
protected
def method2 # this method is protected
end
private
def method3 # this method is private
end
end
def method1 # this method is public
end
protected
def method2 # this method is protected
end
private
def method3 # this method is private
end
end
class MyClass
def method1 # this method is public
end
def method2
end
def method3
end
protected :method2 # this method is protected
private :method3 # this method is private
end
def method1 # this method is public
end
def method2
end
def method3
end
protected :method2 # this method is protected
private :method3 # this method is private
end
Lets run below example.
class MyClass
def method1
self.private1
end
private
def private1
puts "Hello I am Private"
end
end
MyClass.new.method1
def method1
self.private1
end
private
def private1
puts "Hello I am Private"
end
end
MyClass.new.method1
Running this produces the following noMethodError:
in `method1': private method `private1' called for #<XXXX> (NoMethodError)
Oh no! I missed private method receiver concept. Private method can be called only with implicit receiver. So I have changed my class like below.
class MyClass
def method1
private1
end
private
def private1
puts "Hello I am Private"
end
end
MyClass.new.method1
def method1
private1
end
private
def private1
puts "Hello I am Private"
end
end
MyClass.new.method1
Now run again.
Hello I am Private
I get desired output from my code. Now if I call it in subclass then.
class ClassA
def main_method1
method1
end
private
def method1
puts "hello from #{self.class}"
end
end
class ClassB < ClassA
def main_method1
method1
end
end
ClassA.new.main_method1
ClassB.new.main_method1
def main_method1
method1
end
private
def method1
puts "hello from #{self.class}"
end
end
class ClassB < ClassA
def main_method1
method1
end
end
ClassA.new.main_method1
ClassB.new.main_method1
If I run this program.
hello from ClassA
hello from ClassB
hello from ClassB
Get desired result. "This means we can call a private method from within a class it is declared in as well as all subclasses of this class"
We can not call private method with explicit receiver not even with self. So changing previous example accordingly.
class ClassA
def main_method1
method1
end
private
def method1
puts "hello from #{self.class}"
end
end
class ClassB < ClassA
def main_method1
self.method1
end
end
ClassA.new.main_method1
ClassB.new.main_method1
def main_method1
method1
end
private
def method1
puts "hello from #{self.class}"
end
end
class ClassB < ClassA
def main_method1
self.method1
end
end
ClassA.new.main_method1
ClassB.new.main_method1
Output :
hello from classA
`main_method1': private method `method1' called for #<XXXX> (NoMethodError)
`main_method1': private method `method1' called for #<XXXX> (NoMethodError)
Now Moving to protected method.
protected methods can be called by any instance of the defining class or its subclasses.
So changing examples for protected method.
class MyClass
def method1
protected1
end
def method2
self.protected2
end
protected
def protected1
puts "Hello I am Protected1"
end
def protected2
puts "Hello I am Protected2"
end
end
MyClass.new.method1
MyClass.new.method2
def method1
protected1
end
def method2
self.protected2
end
protected
def protected1
puts "Hello I am Protected1"
end
def protected2
puts "Hello I am Protected2"
end
end
MyClass.new.method1
MyClass.new.method2
Output:
Hello I am Protected1
Hello I am Protected2
Hello I am Protected2
Similarly for subclass:
class ClassA
def main_method1
method1
end
protected
def method1
puts "hello from #{self.class}"
end
end
class ClassB < ClassA
def main_method1
self.method1
end
end
ClassA.new.main_method1
ClassB.new.main_method1
def main_method1
method1
end
protected
def method1
puts "hello from #{self.class}"
end
end
class ClassB < ClassA
def main_method1
self.method1
end
end
ClassA.new.main_method1
ClassB.new.main_method1
Output:
hello from ClassA
hello from ClassB
hello from ClassB
So no change in output.
Now I added another class C
class ClassC < ClassA
def main_method1
ClassB.new.method1
end
end
ClassC.new.main_method1
def main_method1
ClassB.new.method1
end
end
ClassC.new.main_method1
Run it and output is :
hello from ClassB
Why we need Protected ??
why we need protected if we can call a method explicitely why we need implicit call to a method.
If private method is so secure why we need one more level of access with protected in ruby.
I found my solution when I try to compaire two objects of same class. This can not achive with explicit reciever(Private Method).
class Person
def initialize(number)
@number = number
end
def number
@number
end
def compare_number(c)
if c.number > number
"The second number is bigger."
else
"The second number is the same or smaller."
end
end
protected :number
end
first = Person.new(25)
second = Person.new(34)
puts first.compare_number(second)
def initialize(number)
@number = number
end
def number
@number
end
def compare_number(c)
if c.number > number
"The second number is bigger."
else
"The second number is the same or smaller."
end
end
protected :number
end
first = Person.new(25)
second = Person.new(34)
puts first.compare_number(second)
Output is:
The second number is bigger.
We cannot accomplish this with private method only and public method are not secure for such methods. So It's clear protected methods are equally important in ruby as private.
No comments:
Post a Comment