Public method with methods defined inside vs. private - ruby

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.

Related

How to override the metaclass constructor in Ruby

I want a piece of code to run before any other static methods run, is it possible to do something in the spirit of the following?
class MyClass
def self.initialize
#stuff = 1
end
def self.print_stuff
puts #stuff
end
end
My Ruby version of interest is 2.3.
Every chunk of code in Ruby is an expression. Even a class definition is a series of expressions: method definitions are expressions that have the side-effect of adding the method to the class.
This is how meta-programming methods work. attr_reader is a private method call where the implicit self is the class. So, long story short, you aren't restricted inside a class body, you can put whatever code you want to run in the context of the class:
class MyClass
#stuff = 1
def self.print_stuff
puts #stuff
end
end
There's no such thing as an explicit metaclass initializer. The class itself is "initialized" as it's defined, so it's perfectly valid to do this:
class MyClass
# Code here will be executed as the class itself is defined.
#stuff = 1
def self.print_stuff
puts #stuff
end
end
MyClass.print_stuff
Remember that def itself is a form of method call and defining a class in Ruby involves sending a bunch of messages (method calls) around to the proper context objects, such as the class itself as it's being defined.

Accessing the name of an anonymous class in superclass' self.inherited

I would like to access a class' name in its superclass MySuperclass' self.inherited method. It works fine for concrete classes as defined by class Foo < MySuperclass; end but it fails when using anonymous classes. I tend to avoid creating (class-)constants in tests; I would like it to work with anonymous classes.
Given the following code:
class MySuperclass
def self.inherited(subclass)
super
# work with subclass' name
end
end
klass = Class.new(MySuperclass) do
def self.name
'FooBar'
end
end
klass#name will still be nil when MySuperclass.inherited is called as that will be before Class.new yields to its block and defines its methods.
I understand a class gets its name when it's assigned to a constant, but is there a way to set Class#name "early" without creating a constant?
I prepared a more verbose code example with failing tests to illustrate what's expected.
Probably #yield has taken place after the ::inherited is called, I saw the similar behaviour with class definition. However, you can avoid it by using ::klass singleton method instead of ::inherited callback.
def self.klass
#klass ||= (self.name || self.to_s).gsub(/Builder\z/, '')
end
I am trying to understand the benefit of being able to refer to an anonymous class by a name you have assigned to it after it has been created. I thought I might be able to move the conversation along by providing some code that you could look at and then tell us what you'd like to do differently:
class MySuperclass
def self.inherited(subclass)
# Create a class method for the subclass
subclass.instance_eval do
def sub_class() puts "sub_class here" end
end
# Create an instance method for the subclass
subclass.class_eval do
def sub_instance() puts "sub_instance here" end
end
end
end
klass = Class.new(MySuperclass) do
def self.name=(name)
#name = Object.const_set(name, self)
end
def self.name
#name
end
end
klass.sub_class #=> "sub_class here"
klass.new.sub_instance #=> "sub_instance here"
klass.name = 'Fido' #=> "Fido"
kn = klass.name #=> Fido
kn.sub_class #=> "sub_class here"
kn.new.sub_instance #=> "sub_instance here"
klass.name = 'Woof' #=> "Woof"
kn = klass.name #=> Fido (cannot change)
There is no way in pure Ruby to set a class name without assigning it to a constant.
If you're using MRI and want to write yourself a very small C extension, it would look something like this:
VALUE
force_class_name (VALUE klass, VALUE symbol_name)
{
rb_name_class(klass, SYM2ID(symbol_name));
return klass;
}
void
Init_my_extension ()
{
rb_define_method(rb_cClass, "force_class_name", force_class_name, 1);
}
This is a very heavy approach to the problem. Even if it works it won't be guaranteed to work across various versions of ruby, since it relies on the non-API C function rb_name_class. I'm also not sure what the behavior will be once Ruby gets around to running its own class-naming hooks afterward.
The code snippet for your use case would look like this:
require 'my_extension'
class MySuperclass
def self.inherited(subclass)
super
subclass.force_class_name(:FooBar)
# work with subclass' name
end
end

Abstract Method in Ruby

How can I force a subclass to implement a method in Ruby. There doesn't seem to be an abstract keyword in Ruby, which is the approach I would take in Java. Is there another more Ruby-like way to enforce abstract?
Abstract methods are supposed to be less useful in Ruby because it's not strongly statically typed.
However, this is what I do:
class AbstractThing
MESS = "SYSTEM ERROR: method missing"
def method_one; raise MESS; end
def method_two; raise MESS; end
end
class ConcreteThing < AbstractThing
def method_one
puts "hi"
end
end
a = ConcreteThing.new
a.method_two # -> raises error.
It rarely seems to be necessary, however.
I like the answer by pvandenberk, but I would improve it as follows:
module Canine # in Ruby, abstract classes are known as modules
def bark
fail NotImplementedError, "A canine class must be able to #bark!"
end
end
Now if you make a class belonging to Canine "abstract class" (ie. a class that has Canine module in its ancestors), it will complain if it is found that #bark method is not implemented:
class Dog
include Canine # make dog belong to Canine "abstract class"
end
Dog.new.bark # complains about #bark not being implemented
class Dog
def bark; "Bow wow!" end
end
# Now it's OK:
Dog.new.bark #=> "Bow wow!"
Note that since Ruby classes are not static, but always open to changes, Dog class itself cannot enforce existence of #bark methods, since it doesn't know when is it supposed to be finished. If you as a programmer do, it is up to you to test it at such time.
My preferred approach is similar but slightly different... I prefer it as follows, because it makes the code self-documenting, giving you something very similar to Smalltalk:
class AbstractThing
def method_one; raise "SubclassResponsibility" ; end
def method_two; raise "SubclassResponsibility" ; end
def non_abstract_method; method_one || method_two ; end
end
Some people will complain that this is less DRY, and insist on creating an exception subclass and/or put the "SubclassResponsibility" string in a constant, but IMHO you can dry things up to the point of being chafed, and that is not usually a good thing. E.g. if you have multiple abstract classes across your code base, where would you define the MESS string constant?!?
I like the use of a gem like abstract_method which gives a dsl rails style syntax abstract methods:
class AbstractClass
abstract_method :foo
end
class AbstractModule
abstract_method :bar
end
class ConcreteClass < AbstractClass
def foo
42
end
end
This code will not let you load the class if the methods 'foo', 'bar' and 'mate' are not defined in the inherited class.
It does not account for classes being defined across many files, but lets get honest do many of us actually define class methods across many files? I mean if you don't count mix-ins. (which this does account for)
def self.abstract(*methods_array)
##must_abstract ||= []
##must_abstract = Array(methods_array)
end
def self.inherited(child)
trace = TracePoint.new(:end) do |tp|
if tp.self == child #modules also trace end we only care about the class end
trace.disable
missing = ( Array(##must_abstract) - child.instance_methods(false) )
raise NotImplementedError, "#{child} must implement the following method(s) #{missing}" if missing.present?
end
end
trace.enable
end
abstract :foo
abstract :bar, :mate
If you want to have an error thrown when you create an instance of the class you could do the following
class AbstractClass
def self.new(args)
instance = allocate # make memory space for a new object
instance.send(:default_initialize, args)
instance.send(:initialize, args)
instance
end
#This is called whenever object created, regardless of whether 'initialize' is overridden
def default_initialize(args)
self.abstract_method #This will raise error upon object creation
end
private :default_initialize
def initialize(args)
# This can be overridden by new class
end
end
class NewClass < AbstractClass
end
NewClass.new #Throw error
Because the question is (focus on) "How can I force a subclass to implement a method in Ruby", so i think we can use TDD :D, for example: rspec shared example
shared_examples "MUST implement abstract method" do |method_sym|
it { is_expected.to respond_to(method_sym) }
end
describe Stack do
it_behaves_like "MUST implement abstract method", :push
it_behaves_like "MUST implement abstract method", :pop
end
Maybe Tests are better than Abstract :D , reference: http://morningcoffee.io/interfaces-in-ruby.html

Whats the difference between class_eval and class << className?

I am a Ruby starter. I found both of these are quite similar (in output), but i couldn't understand the difference in the below context. For example, I have a class
class Say
def self.hello
puts "hello"
end
end
and can be extended like this
class << Say
def hi
puts "hi"
end
end
and also like this
Say.class_eval do
def self.bye
puts "bye"
end
end
When should I use << and when class_eval?
class_eval doesn't really have anything to do with class << className.
A.class_eval do
...
end
is equivalent to
class A
...
end
with a few differences. class_eval uses a block (or a string, but ignoring that for the moment) which means it closes over the containing lexical scope. In other words you can use local variables from the surrounding scope. The common class block introduces a brand new scope. Likewise you can create the block and pass it to many different class_eval's, and the body of the block will be executed in the context of the class you are calling class_eval on.
class << className opens the singleton class of className, allowing you to define class methods.
class << A
def foo
...
end
end
Is the same as
def A.foo
...
end
Note that they are oly class methods if A happens to be a class (almost) all objects in ruby have singleton classes and you can define methods for them using either of those two syntaxes. The advantage of class << obj is mainly if you're defining many singleton methods in one go.
As already said class_eval has really not much to do with
class <<self
even if they seem to do the same thing in your example (while the effect is similar it does not do the same, there are subtle differences).
Here is another example where the usage of the second form is far more clearer:
class A
end
a = A.new
b = A.new
class <<b
def say_hi
puts "Hi !"
end
end
b.say_hi # will print "Hi !"
a.say_hi # will raise an undefined method
a and b are both objects of the same class A but we added a method to the metaclass of b so the method say_hi is only available to the b object.

Preferred Ruby-ist way of declaring access controls

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.

Resources