I got a few Classes that include the same module, I want to override one of the methods of the module in one place in my code.
How to do this?
I tried
module [Module_name]
def [method_to_override]
and add it to the autoload path of rails but no success
If you are using the module as a mixin, you can redefine the method in your class. The method defined at the class level will take precedence when called. The module as a mixin simply behaves as a superclass in this case.
If you are using the module as a namespace, I am not sure that there's a way to dynamically redefine the code as you are attempting to do. Perhaps opening the namespaced module in-place and including the new code for the method will work. I haven't tried this before.
Some reference material
Related
I have a logger method that I would like to make accessible to all classes within a module. Is there a way of doing that without just putting the method in a module and including it in every single class? I'd also prefer not to have to call the method with the module (e.g. Module.logger)
From what I can tell, the class does not inherit at all from the module it is in, so I can't figure out anyway of doing this, but I thought I'd ask to be sure.
Ruby doesn't have nested classes. The classes aren't in the module. There is no relationship whatsoever between the classes and the module.
The constants which reference the classes are namespaced inside the module, but that has nothing to do with the relationship between the classes and the module.
So, no, what you want is not possible, for the simple reason that there is no relationship between the classes and the module that could be exploited to somehow make the method available. You will have to go for good old (mixin) inheritance.
I have a Ruby module in a file called my_module.rb:
module My_module
def my_module_method
puts 'inside my method'
end
end
In a file my_class.rb in the same folder, I have a class contained within the module.
module My_module
class My_class
def my_object_method
My_module.my_module_method
end
end
end
My_module::My_class.new.my_object_method => 'undefined method 'my_module_method''
I was not expecting this error. I assumed that Ruby would run into the line 'My_module.my_module_method' and search for a module called 'My_module' and a method within it called 'my_module_method.' This is what Java does, for example. However, Ruby does not do this. In order to get my_object_method to work, I have to write in my_class.rb:
require 'my_module.rb'
Why doesn't Ruby search for My_module when I call my_object_method? It seems obvious what it should search for and therefore redundant to require the programmer to explicitly write 'yes, Ruby, please allow me to make calls to module-wide methods.' What am I missing?
Ruby doesn't automatically load files. If you need a code from some file, you have to load it (by calling require) explicitly.
Thus, when you run "ruby my_class.rb" it loads only this file and you have to define dependencies between files by yourself.
You seem to have a misunderstanding of how to define a class method. In order to make your method call work, you could define it as def self.my_method_name.
In both classes and modules, methods work the same when you define them as class methods using self. or alternatively the class << self syntax. However instance methods (methods without the self.) work differently in these 2 cases. In classes, as you seem to understand, they're accessible once you instantiate the class using .new. In modules, they're only accessible if you include or extend.
See also:
difference between class method , instance method , instance variable , class variable?
http://www.rortuts.com/ruby/ruby-include-vs-extend/
Oh any by the way. Ruby doesn't enforce any convention where you have 1 file per class (named identically). You need to manually require files wherever you need them. Although there are some frameworks such as Rails which auto-require files, and enforce naming conventions.
I have a class defined in a gem to which I am adding some methods via refinements (in Ruby 2.3.0). This class turns up in some Sinatra views (haml).
When I refer to these extra methods in a helper, there is not a problem. But in the view, I get an Undefined Method error.
Am I missing a trick, or is it that the using ... statement would need to go somewhere I just can't get to?
(Workaround: I can define helper methods to return the method on the object. But if I wanted to do that then I wouldn't have used refinements...)
The scope of refinement is determined lexically. Unless you rewrite the method inside haml that calls that method so that it becomes within the scope of the using command, you cannot use refinements. But I guess haml is internally using eval or something like that to evaluate the code you write in a haml file. In that case, it is impossible.
Is there a difference between the following two examples? Is it possible to get method conflicts in the second example because of method names? Aren't methods within a module automatically "encapsulated" within this module?
Example 1
module ImageUtils
def self.preview(image)
#do something
end
end
Example 2
module ImageUtils
def preview(image)
#do something
end
end
If I would put everything into a class Foo within the module ImageUtils, how would this differ?
The difference is that first example defines module method called preview, and second example defines mixin method preview.
So that if you include first module into a class, you'll be able to call this method on the class (whereas calling the method on the class instance would cause the error), while including the second module into the class will allow you to call the method on class' instances, but calling the method on the class itself will cause
NoMethodError: undefined method preview for Foo:Class
Regarding conflicts basing on the same method name in class and module included to it. Answer to this question lays in Ruby method lookup, which is following:
Methods from the object's singleton/meta/eigen class
Methods from prepended modules (Ruby 2.0+ feature)
Methods from the object's class
Methods from included modules
Methods from the class hierarchy (superclass and its ancestors)
Method lookup stops, when the method is found.
With prepend the mixin method will have precedence in method lookup;
With include method defined in class has the precedence in method lookup.
So no conflicts are possible.
I'm writing a small gem, and I want to define a DSL-like method, pretty much the same as the desc and task methods in Rake.
Rake defines them as private methods in the Rake::DSL module and then
self.extend Rake::DSL
to mix the module into the main object? (I'm a newbie and go ahead laugh if I'm wrong)
what are the benefits by doing so? is it because making these methods private can prevent any other objects to use them (that is, to prevent something like some_obj.desc) ?
what if I define the methods in Kernel
module Kernel
private
include Rake::DSL
end
Is there any difference?
If you define private method in Kernel module it will be available in the whole project. You will also rewrite desc method that project use to define rake task. But if you write your methods in your submodule and then extend it in superclass or some module - you can easily write any kind of DSL lang like you might saw in Rake or RSpec.
P.S. Making methods private prevents other moludes or classes (but not subclasses) to use them (but not owerwrite) - I mean module nesting hierarchy.
Just to extend the answer given by bor1s, about the private methods:
In ruby you have "private" and "protected" methods. What bor1s says, is correct when talking about "protected" methods. Declaring a method "private" additionally prevents other instances of the same class from using the method.
When you call a "private" method, you cannot use a dot in front of it - you cannot even use self., even though using or omitting self has usually the same effect.
class Xyzzy
private
def foo
puts "Foo called"
end
public
def do_it
foo # <= Is OK
self.foo # <= raises NoMethodError
end
end
Xyzzy.new.do_it
If you change 'private' to 'protected' in the code above, no error will be raised.
And about modules:
The final result of defining a method in Kernel and extending Kernel with the method defined in some module is the same: in both cases the method is global.
Using a module is just a little more elegant, as it groups your changes in one place, but I would say it's a matter of personal taste.
Usually you do not include methods in Kernel or Object (as it may be a little dangerous), but you include (or extend) a specific class or object which needs these methods, and in this case you need your methods grouped in a module.
Even Rake in version 0.9.0 stopped including the DSL commands in Object:
== Version 0.9.0
Incompatible *change*: Rake DSL commands ('task', 'file', etc.) are
no longer private methods in Object. If you need to call 'task :xzy' inside
your class, include Rake::DSL into the class. The DSL is still available at
the top level scope (via the top level object which extends Rake::DSL).