What is the difference between instance&class method include&extend (Ruby, Rails) - ruby-on-rails

What's the difference between class method and instance method.
I need to use some functions in a helper "RemoteFocusHelper" (under app/helpers/)
Then include the helper "RemoteFocusHelper" in the Worker module
But when I tried to call 'check_environment' (defined in RemoteFocusHelper),
It raised ""no method error"".
Instead of using "include", I used the "extend" and works.
I wonder know if it is correct that we can only use a class method when in a class method.
Is it possible to call a instance method in a class method ?
By the way,how does the rake resque:work QUEUE='*' know where to search the RemoteFocusHelper I didn't give it the file path.Is the rake command will trace all files under the Rails app?
automation_worker.rb
class AutomationWorker
#queue = :automation
def self.perform(task=false)
include RemoteFocusHelper
if task
ap task
binding.pry
check_environment
else
ap "there is no task to do"
end
end
end

The difference is the context where you're executing. Pretty much every tutorial will have include or extend under the class:
class Foo
include Thingy
end
class Bar
extend Thingy
end
This will get executed at the time the class is defined: self is Foo (or Bar) (of type Class). extend will thus dump the module contents into self - which creates class methods.
When you do it inside a method definition, self is the instance object (of type Foo or Bar). Thus the place where the module gets dumped into changes. Now if you extend (the module contents), it dumps them into what is now self - resulting in instance methods.
EDIT: It is also worth noting that because extend works on any instance object, it is defined on Object. However, since only modules and classes are supposed to be able to include stuff, include is an instance method of Module class (and, by inheritance, Class as well). As a consequence of this, if you try putting include inside a definition of an instance method, it will fail hard, since most things (including your AutomationWorker) are not descended from Module, and thus do not have access to the include method.

Related

Ruby/Rails - force subclasses to override specific methods?

I'm wondering if there is a way to force a subclass to override a method from its parent method in either Ruby or Rails (in Java you would do this with an abstract class/method).
Let's say I have the following classes:
class Pet
end
class Dog < Pet
def collar_color
"red"
end
end
class Cat < Pet
end
dog = Dog.new
dog.collar_color
==> red
cat = Cat.new
cat.collar_color
==> NoMethodError
In this example I would never instantiate a Pet object, but it exists to serve as a way to collect common methods to common classes. But let's say I want to ensure that all subclasses of Pet override the collar_color method. Is there a way to do that? Could I achieve it through testing in some way? Assume I don't want a default defined in the parent class.
My real-life use case is a collection of classes that all have polymorphic ownership of another class. If I have a display page of the owned class, then one of the owner classes not having a method could leave me with a NoMethodError problem.
No, there is no way to enforce this.
I can guarantee you, whatever idea you can come up with, it will break in some way.
First off: doing this statically is out of the question. Determining whether a method is overridden or not is known to be equivalent to solving the Halting Problem.
So, you have to do it dynamically. But even that is going to be problematic.
For example: you could implement the inherited hook and check whether every class that inherits from Pet implements the method. But, that will prevent someone from inheriting their own abstract class. (Also, there is no guarantee when the inherited hook will run – it could run when the class is opened, i.e. before the methods are defined.)
Also, even if you can check that the method exists at the point where a class inherits Pet, the method can still be removed again later, so you don't get any guarantees. And, of course, they can just provide a dummy method, in order to get around your protection.
You could create default implementations of the methods that just raise an Exception, but there is no need to do that: if you don't create a default implementation, that will already raise a NoMethodError exception anyway. (If you do go down this route, do not use NotImplementedError. Instead, use a custom exception that inherits from RuntimeError.)
There are examples of this in the core library: for example, the Enumerable mixin depends on an abstract method each that must be implemented by subclasses. And the way this is handled is by simply documenting that fact:
Usage
To use module Enumerable in a collection class:
Include it:
include Enumerable
Implement method #each which must yield successive elements of the collection. The method will be called by almost any Enumerable method.
That is actually the way any type-related issues have been dealt with in Ruby since the beginning. Since Ruby does not have types, typing only happens in the programmer's head and type information is only written down in documentation.
There always were informal third-party type annotation languages that were used by various IDEs. More recently, two type annotation languages have been introduced: RBI, a third-party type annotation language used by the Sorbet type checker, and RBS, a type annotation language that is part of Ruby proper.
As far as I know, RBS has no way of expressing abstract methods, but RBI does:
class Pet
extend T::Sig
extend T::Helpers
interface!
sig {abstract.returns(String)}
def collar_color; end
end
This will give you a type error if there is object instantiated from a subclass that does not at some point in the inheritance chain define the method. But, of course, only if the user of the code actually type-checks the code using a type-checker like Sorbet. If the user of the code does not type-check it, they will not get a type error.
Ruby has relatively few keywords but it provides the basic building blocks to implement something that vaguely resembles abstract classes or methods.
In its simplest form you just raise an error in the parent "abstract" method:
class AbstractMethodError < StandardError
def initialize(klass, m)
super("Expected #{klass} to implement #{m}")
end
end
class Pet
def collar_color
raise AbstractMethodError.new(self.class, __method__)
end
end
class Cat < Pet
end
Cat.new.collar_color # Expected Cat to implement collar_color (AbstractMethodError)
__method__ is a magic variable that contains the name of the current method.
You can make this a bit more elegant by creating a class method that defines the "abstract method":
module Abstractions
def abstract_method(name)
define_method(name) do
raise AbstractMethodError.new(self.class, __method__)
end
end
end
class Pet
extend Abstractions
abstract_method :collar_color
end
However Ruby is a dynamic langauge and you don't have a compile time check so this will only give a slightly more obvious error message when the method is called. It doesn't actually give any guarentees that subclasses implement the method.
That is down to testing or using type checkers like Sorbet or RBS. In general it might be helpful when learning to forget everything you think you know about Object Oriented Programming and learn the Ruby way. It has a very different design philophy compared to Java - instead of abstract methods and interfaces you use duck typing to see if the object responds to that method.
Just define the default method implementation in the abstract class by raising Not implemented error or something. By doing that you also clarifies in your class design that when others / you want to inherit the Pet class they need to override collar_color method. Clarity is a good think and there is no benefit in not defining a default method in the abstract class.
Or if you want to achieve that by testing you can create a test case for Pet class that check if its descendants is defining their own collar_color method or not. I think Rails / Ruby 3.1 have .descendants methods defined or you can just google them.
# Pet_spec.rb
describe "descendants must implement collar_color" do
it "should not throw error" do
descendants = Pet.descendants
descendants.each do |descendant|
expect { descendant.new.collar_color }.to.not raise_error
end
end
end

What's the difference between sending :include to class and directly defining method in second class definition?

Recently I had to add a method to Redmine's core class. I was unable to use inheritance, so I've done something like this:
require_dependency 'time_entry_query'
class TimeEntryQuery < Query
def my_new_method(foo, bar)
end
end
and it works perfectly - my method is added to all new objects. However, I've seen someone declaring the new method in their own module instead and then sending :include to class, so it become a mixin. Here's an example:
module Patches
module SomeClassPatch
def my_new_method
end
end
and somewhere in app's initialization:
SomeClass.send(:include, Patches::SomeClassPatch) unless SomeClass.include? (Patches::SomeClassPatch)
What's difference between these two methods and which one should I use?
There are two differences:
When you use a mixin, there is a clear place where your "patch" methods can live. If I wonder "Hmm, where's this my_new_method" coming from, and I look at, say, TimeEntryQuery.ancestors or TimeEntryQuery.instance_method(:my_new_method).owner, that will return Patches::SomeClassPatch. So I know I have to look for a file named lib/patches/some_class_patch.rb somewhere to find where it is probably defined. (I could try source_location as well, but that is not always reliable.)
Mixing in a module into a class makes the module the superclass of the class it is being mixed into. So, if there already is a my_new_method defined in TimeEntryQuery, your first option will overwrite it, whereas in your second option, your method will become the super method of that method. IOW: with your second option, your new method won't be called unless the already existing method calls super.

initializing a class with config (yaml), and setting a variable that should be a single instance

I am getting confused as to how to properly set variables in a initializer, I want these to be class level variables, not instance.
And I also want to then create a single instance of another object (it is a connection object, which already has connection pooling built in, so I just need a single reference to it).
My initializer /initializers/my_class.rb
yml = YAML.load_file("#{Rails.root}/config/my_class.yml")
MYMODULE::MyClass.init(yml)
And here is my my_class.rb:
module MYMODULE
class MyClass
def self.init(yml)
#post_url = yml["defaults"]["post_url"]
end
def self.post_url
#post_url
end
# this should be a single instance
def connection_pool
# ???
end
end
end
These class level variables, how can I access them from both class methods and instance methods?
I'm getting wierd behaviour, and I'm confused as to how to reference the post_url from inside of either class methods and instance methods.
I have seen the following ways, unsure which is correct:
self.class.post_url
MyClass.post_url
#post_url
post_url
self.post_url
self.class.post_url or MyClass.post_url will work. The difference is how they work for subclasses (in the former case, subclasses will use their own version of this variable automatically, in the latter, they would share the variable in MyClass).
There is no way to directly access class instance variables from an instance: you have to call a class method which returns (or sets) them. See also: cattr_accessor.
That said, if this is really a singleton, it seems a little strange to me that you would configure part of it on the class, and then reference that info in the (single) instance. Wouldn't it make more sense just to configure this stuff on the instance? Or use a module as a singleton and not create an instance at all?

Sample Ruby code, How is this abstracting things out?

Watching this video by Yehuda, and he gave this snippet about how Ruby helps you build better abstractions.
class FOWA
def self.is_fun
def fun?
true
end
end
is_fun
end
He was talking about, in ruby, how if you are repeating code in your class over and over again, you can abstract it out without having to think about things in terms of methods etc. And he said this was using a metaprogramming technique.
Can someone explain what this is?
It is a class method on FOWA (so its like a static method, you don't need an instance to call it), and this class method is really just wrapping another method that returns true.
And this is_fun class method is now being executed or what? not sure what the last line "is_fun" is doing?
http://vimeo.com/11679138
The is_fun call at the end of the class calls the static method. The static method then defines the fun? method inside of the FOWA class. Then, you can do this:
f = FOWA.new
f.fun?
If you take out the is_fun call at the end of the class, the fun? method doesn't get defined.
He mentioned that you wouldn't use it in this way, but the point is how easy it is to dynamically add a method to a class. You might use it like this if you wanted the method to be available in subclasses and you wouldn't call is_fun in FOWA, but you might in a subclass. It gets a little more interesting if you have a parameter for is_fun and the definition of fun? changes depending on that parameter.
This also leads right into modules because you can define a module with the same is_fun method and then just have your class extend the module and the methods in the module are available in the class. You would use this technique if you want your method to be available to more than just subclasses of FOWA.

Rails: when to use self

I am developing a Rails application and would like to understand when to use self.for.
Here is the code of a method that I would like to fully understand. If it is possible I would like to have an alternative to this code so it would make things more clear.
def self.for(facebook_id)
User.create_by_facebook_id(facebook_id)
end
self refers to the current object.
Within a class, self is used to define a class-level method.
class Foo
def self.for(facebook_id)
User.create_by_facebook_id(facebook_id)
end
end
defines a class method for in class Foo. It is invoked:
Foo.for(facebook_id)
You can google for class methods to learn more.
It could be that a part of Rails or a plugin/gem is expecting that some classes will have a class method "for" More context would be helpful in this regard.
What the method is doing
As is common for class methods, it is creating an instance of a class. For example, the ActiveRecord class has a class method "create" which attempts to create an instance of the model class that has been stored in the database. Thus User.create will return an instance of the User class that has been stored in the database.
In your example code, it is calling a class method "create_by_facebook_id" that is provided by the User class in the application.
Looks like the "for" method is being used for information hiding since all it's doing is making another method call (to User.create_by_facebook)
Added:
By the way, the default return value from Ruby methods is the value of the last statement. So your example method will return the user instance newly created from the supplied facebook_id.
It looks to me like self.for is just an alias for creating a user for a facebook id. I think self.for should actually be:
def self.for(facebook_id)
User.find_or_create_by_facebook_id(facebook_id)
end
That way it searches for the user with that facebook id, and if one isn't found, creates that record and returns it. Then, self.for means "return the user for this facebook id."
Short answer: self always refers to the current object. So within an instance method, self is the instance, within a class method, self is the class and within a class definition (like in your example), self is the class...
For more information on class methods and the code snippet you posted, see the answer by Larry K.
If that code is inside of a class named Foo, then the alternative could be:
def Foo.for(facebook_id)
User.create_by_facebook_id(facebook_id)
end
self in this context is necessary if you have some generic class level methods that you want to be able to use across multiple classes. You add them to a Module using self. to scope them (as you don't know the name of the actual class that they are going to a part of), then include that module as part of your class.

Resources