Preferred Ruby-ist way of declaring access controls - ruby

This is a simple style question. What is the preferred means for declaring access controls in Ruby code?
Example A:
#!/usr/bin/env ruby
class MyClass
def method1 # this is public by default
#...
end
protected # subsequent methods will be protected
def method2
#...
end
private # subsequent methods will be private
def method3
#...
end
public # subsequent methods will be public
def method4
#...
end
end
or Example B:
#!/usr/bin/env ruby
class MyClass
def method1
#...
end
def method2
#...
end
def method3
#...
end
def method4
#...
end
public :method1, :method4
protected :method2
private :method3
end
Syntactically, I like Example B. A introduces ambiguity between public methods declared after protected/private methods, although I see no reason why you shouldn't just call method1 after specifying it as being public.
This isn't however about what I like. What is the industry defined norm for this?

The only place I've ever seen the second method used is in Ruby books, and only as a "You can also do this" example.
And you very rarely see the use of "public" like in the first method, as it's the default and people just define all their public methods before any protected/private declarations.

I think it really depends on your coding style. If you read "Clean Code" by Uncle Bob, you (which I personally loved), you're encouraged to write methods or functions that are called by each other closely together. In this case, using the visibility of a method as in example B would make sense:
class Foo
def method1
method2
end
def method2
..
end
private :method2
end
Uncle Bob actually makes a good case for having methods close together, since this prevents scrolling in your code.

Related

Public method with methods defined inside vs. private

Suppose I have
class SomeClass
def some_public_method
method_1
method_2
end
where method_1 and method_2 won't be used by anything except some_public_method.
They can be defined inside that method:
class SomeClass
def some_public_method
def method_1
p 'hi'
end
def method_2
p 'there'
end
method_1
method_2
end
end
or defined separately as private ones in the class. I was wondering which approach will be easier to maintain in the future and why (should these methods "belong" to some_public_method and not created unless some_public_method is created or they should belong to the class). I think this question isn't opinion-based because of the why part. Please provide examples of how some other code might conflict with either of these two approaches to prove your point on why either approach is better for more maintainable code.
There are no such a thing as nested methods in ruby, but you can write methods which define new methods. By doing this:
class SomeClass
def some_public_method
def method_1
p 'hi'
end
def method_2
p 'there'
end
method_1
method_2
end
end
Methods method_1 and method2 are not defined just after class is declared, because their definitions has not been executed. As soon as you execute some_public_method, those definitions are executed and both methods are added to the class. Whether they are public or private depends on whether methods private, protected or public (Yep, those are methods) has been executed against the class or not. If none of those methods has been executed, they are public.
s = SomeClass.new
t = SomeClass.new
s.method_1 #=> undefined method error
t.some_public_method
s.method_1 #=> hi
If you run some_public_method again, those methods will be redefined which may result in a warning.
In short, do not nest method definitions, unless you are going for some nice metaprograming feature. Even then it is probably better to use define_method method.

Are all methods public by default?

If I have this in my main program:
def hi
puts 'hi'
end
self.hi
it won't work because hi is private.
I've learned that all methods in Ruby are public by default, but this doesn't seem to be the case, why?
It is tricky to define a method in the main environment. A method is private by default when you define it in main. So you either have to use it as private:
def hi
puts 'hi'
end
hi
or explicitly make it public:
def hi
puts 'hi'
end
public :hi
self.hi
Methods are public by default, except for "top-level procedures". If you define something which looks like a top-level procedure, it will actually be defined as a private instance method of Object.
def main_method
p "This is from main_method"
end
public :main_method
class Klass
def initialize
Object.main_method # Or we can simply say main_method as we do in the second exaple
end
end
puts Klass.new
It is the way to create Object 'class methods' as shown. If it were private, then we could not specify the receiver.
When it is private, as it is by default, then we would call it like this:
def main_method
p "This is from main_method"
end
class Klass
def initialize
main_method # With it being private, implicit self only
end
end
puts Klass.new
So is there any advantage to either way? I guess if you make it private, you send some kind of communication to the developer that you have a preference and this should be used as a private method, rather than a public method.
In practice, I don't see an advantage.

Ruby Access Control - Specify with method or listed at ACL function?

I see there are two ways to specify access control in Ruby. One with access modifier specified with the method and the other as a list to the ACL function.
E.g. with the access modifier specified with the method
class MyClass
public
def method1
#...
end
private
def method2
#...
end
end
and another way where you specify the access as a list to the ACL function
class MyClass
def method1
#...
end
def method2
#...
end
public :method1
private :method2
end
Is there any reason to use one over the other?
Normally, you use the first method you described. You would first have all public methods grouped together (without public specified, since it is the default at the beginning), followed by all protected methods grouped together, finally followed by all private methods grouped together. An example:
class C
def first_public_method
#...
end
def second_public_method
#...
end
protected
def protected_method_1
#...
end
def protected_method_2
#...
end
private
def one_private_method
#...
end
def another_private_method
#...
end
end
The second method you described in your question is rarely used, mostly for doing some tricks. It allows you to do the following things for example that are impossible with the first method:
Dynamically build a list of methods that should have a certain visibility and then set that visibility by calling the appropriate method with the dynamic list, e.g. public(*an_array_containing_names_of_all_methods_that_should_be_public)
Change the visibility of a method after a class has been defined
An example for the second point above:
class C
#...
private
def a_private_method
#...
end
end
instance = C.new
instance.a_private_method # raises NoMethodError
C.send(:public, :a_private_method) # changes the visibility of the method dynamically to public
instance.a_private_method # executes the formerly private method without error
If specify the modifier with the method, it's right there with the method definition, not hidden away somewhere. Conventionally you might groupall the private methods at the bottom of the file with one private modifier as these modifiers like private, public, module_function (others?) work as "everything below this line until you meet a contradictory one".
Alternately, you could use the method form but then I'd place them as near to the top as possible so it's obvious. Hang on, would that lead into a "this method isn't defined, so what the hell am I private-ing???" exception? In that case I'd group them at the bottom. The point being to not scatter them in the middle.

Ruby : Invoke overridden method of parent class, in child class

Say I have class B derived from class A
Is it possible to invoke overrided method of A like this?
class A
def method1
end
def method2
end
end
class B < A
def method1
### invoke method2 of class A is what I want to do here
end
def method2
end
end
# not exactly duplicate to How do I call an overridden parent class method from a child class? , but we seem want to do the same thing.
I'm assuming here that B is supposed to inherit from A and you simply made a typo in your example code. If this is not the case, there is no way to do what you want.
Otherwise you can do what you want using reflection by binding A's method2 instance method to your current B object and calling it like this:
class A
def method1
end
def method2
end
end
class B < A
def method1
A.instance_method(:method2).bind(self).call
end
def method2
end
end
Note though that you shouldn't pull out the big black-magic-guns like this unless you really need to. In most cases redesigning your class hierarchy so that you don't need to do this is the better alternative.
You can create a synonym for parent method using alias statement and call it from the overriden method:
class A
def method1
puts '1'
end
def method2
puts '2'
end
end
class B < A
alias parent_method1 method1
alias parent_method2 method2
def method1
parent_method2
end
def method2
end
end
b = B.new
b.method1 # => 2
The answer of #sepp2k is technically correct, however I would like to explain why this technique is not appropriate in my opinion (so the question is technically interesting, but leads to the wrong goal):
Ruby does not allow to call super.method2 in the context of method1called in an instance of B, because it is just wrong to do it. Class inheritance should be used when your instances are specializations of the superclass. That includes that you normally only expand behavior, by calling super and doing something additionally before or after that call.
There are languages like Java and others, that allow to call super for another method, and that leads to something similar to spaghetti code, but the object-oriented way. No one understands when which methods are called, so try to avoid it.
So try to find the reason why you want to change the call, and fix that. If your method1 in A is wrong implemented in B, then you should not subclass is.

How does one access protected class methods from instance methods in Ruby?

I must be missing something about how people do this in Ruby.
If '#protected' is uncommented we get:
in 'what': protected method 'zoop' called for Foo:Class (NoMethodError)
Is there a better way to approach protected class methods?
class Foo
class << self
#protected
def zoop
"zoop"
end
end
public
def what
"it is '#{self.class.zoop}'"
end
protected
end
a = Foo.new
p a.what # => "it is 'zoop'"
I would like zoop to be protected or private (no calling 'Foo.zoop'), but so far, I can't seem to find an elegant way.
It barely matters to make methods private or protected in Ruby, since you can just call send() to get around them.
If you want zoop to stay protected, use send() like this:
def what
"it is '#{self.class.send(:zoop)}'"
end
Upon further discussions with rue: and drbrain: in ruby-lang, it turns out that my impulse to save memory by placing utility functions at the class level was misplaced.
In Ruby, the instance methods hang off the class anyway, and the answer is to go ahead and place the utility functions at the instance level as private.
In summary, a utility function that is accessed only by instance methods:
class Foo
def what
"it is '#{zoop}'"
end
private
def zoop
"zoop"
end
end
p Foo.new.what # => "it is 'zoop'"
For a utility function that needs to be called from instance and class methods, a nested module seemed to be a popular approach:
class Foo
module Util
def self.zoop
"zoop"
end
end
def what
"it is '#{Util.zoop}'"
end
class << self
def class_what
"for all time it is '#{Util.zoop}'"
end
end
end
p Foo.new.what # => "it is 'zoop'"
p Foo.class_what # => "for all time it is 'zoop'"
p Foo::Util.zoop # visible, alas

Resources