Refinements and namespaces - ruby

Trying to patch net/http and have it only apply to one service class. Refinements seem to be the way to go. The monkey patch below works but the refinement doesn't. Is this a namespace issue? The project is on ruby 2.3.0 but have tried with 2.4.1 as well and only the monkey patch seems to get applied.
With a monkey patch:
module Net
class HTTPGenericRequest
def write_header(sock, ver, path)
puts "monkey patched!"
# patch stuff...
end
end
end
Service.new.make_request
# monkey patched!
With a refinement:
module NetHttpPatch
refine Net::HTTPGenericRequest do
def write_header(sock, ver, path)
puts "refined!"
# patch stuff...
end
end
end
class Service
using NetHttpPatch
end
Service.new.make_request
# :(
UPDATE:
This seems to be similar scope wise? Obviously more complex things are happening when net/http makes a request does it lose scope then?
module TimeExtension
refine Fixnum do
def hours
self * 60
end
end
end
class Service
using TimeExtension
def one_hour
puts 1.hours
end
end
puts Service.new.one_hour
# 60
UPDATE UPDATE:
nvm, I see what's happening now :) have to keep your brain from mixing using up with how mixins work.
module TimeExtension
refine Fixnum do
def hours
self * 60
end
end
end
class Foo
def one_hour
puts 1.hours
end
end
class Service
using TimeExtension
def one_hour
puts 1.hours
end
def another_hour
Foo.new.one_hour
end
end
puts Service.new.one_hour
# 60
puts Service.new.another_hour
# undefined method `hours' for 1:Fixnum (NoMethodError)

Is this a namespace issue?
It is a scope issue. Refinements are lexically scoped:
class Service
using NetHttpPatch
# Refinement is in scope here
end
# different lexical scope, Refinement is not in scope here
class Service
# another different lexical scope, Refinement is *not* in scope here!
end
Originally, there was only main::using, which was script-scoped, i.e. the Refinement was in scope for the entire remainder of the script. Module#using came later, it scopes the Refinement to the lexical class definition body.

Related

Ruby prepend doesn't work for class method

I'm trying to use prepend method in ruby to overwrite methods of a class, here is how my code works:
module PrependedModule
def self.klass_method
puts 'PrependedModule klass_method'
end
def instance_method_a
puts 'PrepenedModule instance method'
end
end
class SomeClass
prepend PrependedModule
def self.klass_method
puts 'SomeClass klass_method'
end
def instance_method_a
puts 'SomeClass instance_method'
end
end
SomeClass.klass_method
SomeClass.new.instance_method_a
#output:
#SomeClass klass_method
#PrependedModule instance method
#expected:
#PrependedModule klass_method
#PrependedModule instance method
The output of this script is shown above, as we can see, the instance method instance_method_a was overwritten by module PrependedModule, but not the class method klass_method, when I called klass_method on SomeClass, it still executes it's origin method, instead of the one defined in PrependedModule.
I'm confused about this and don't know what happend with class methods when using prepend. It would be a great help if anyone can solve this question for me.
Singleton classes do not work that way. You need to explicitly prepend the methods to the eigenclass of SomeClass:
module PrependedModule
module ClassMethods
def klass_method
puts 'PrependedModule klass_method'
end
end
def instance_method_a
puts 'PrepenedModule instance method'
end
end
class SomeClass
# prepending to the class
prepend PrependedModule
class << self
# prepending to the eigenclass
prepend PrependedModule::ClassMethods
end
def self.klass_method
puts 'SomeClass klass_method'
end
def instance_method_a
puts 'SomeClass instance_method'
end
end
With include or prepend you can only gain access to a module's instance methods1. You therefore might ask if there is any reason to define module methods on a module. The answer is a resounding "yes". There are two reasons you might want to do that.
The first has nothing to do with including or prepending the module. You need only look at the module Math to understand why you might want to do that. All methods defined on Math are module methods. These constitute a library of useful functions. They are of course methods, but since all have Math as their receiver, they behave like functions in non-OOP languages.
The second reason is that you might want to define a callback method (aka hook method) on a module that is to be included or prepended by another module. The main ones are Module#included, Module#prepended, Module#extended, Class#inherited and BasicObject#method_missing. The last of these is an instance method; the others are module methods. An example of Module#prepended is given below.
#mudasoba has shown how to confine instance methods to a sub-module Sub of Mod so that Mod::Sub can be prepended (or included) to a class's (or module's) singleton class. A commonly-used pattern for doing that employs the callback Module#prepended. It follows.
module PrependedModule
module ClassMethods
def klass_method
puts 'PrependedModule klass_method'
end
end
def instance_method_a
puts 'PrepenedModule instance method'
end
def self.prepended(mod)
mod.singleton_class.prepend(ClassMethods)
end
end
class SomeClass
def self.klass_method
puts 'SomeClass klass_method'
end
def instance_method_a
puts 'SomeClass instance_method'
end
prepend PrependedModule
end
SomeClass.klass_method
# PrependedModule klass_method
SomeClass.new.instance_method_a
# PrepenedModule instance method
1 I've always found it curious that instance methods can be defined on modules (that are not classes), considering that such modules cannot have instances. True, these methods become instance methods in classes that include or prepend the module, but keep in mind that those modules can be included or prepended by other modules (that are not classes) as well. One might therefore expect such methods to have some name other than "instance method". Finding a suitable alternative would be a challenge, however, which is perhaps one reason why that nomenclature has persisted.
Someone can comment on when this was introduced, but my personal experience and also suggested by https://stackoverflow.com/users/256970/cary-swoveland in comments section of the selected answer, you can always do
class Source
def self.hello
puts "hello"
end
end
module Extension
def hello
# you're also allowed to call super from here
puts "world"
end
end
Source.singleton_class.prepend Extension
Now if you call Source.hello, the method from the Extension module will be called.
This is also valid for overriding Module's static/class methods But I've mentioned the code explicitly because I've rarely come accross this solution on S/O.
module Source
def self.hello
puts "hello"
end
end
module Extension
def hello
# you're also allowed to call super from here
puts "world"
end
end
Source.singleton_class.prepend Extension
class Foo
singleton_class.prepend ClassMethods
def self.hello
puts "hi"
end
end
module ClassMethods
def hello
puts "ho"
end
end

How to use refinements dynamically

Trying to make sense of this 'refinements' business.
I'm making a module which refines a core class:
module StringPatch
refine String do
def foo
true
end
end
end
Then a class to use the refinement
class PatchedClass
end
PatchedClass.send :using, StringPatch
I get this error:
RuntimeError: Module#using is not permitted in methods
How can I make this work?
I am trying to dynamically patch core classes in a certain scope only. I want to make the patches available in the class and instance scope.
As far as I know, the refinement is active until the end of the script when using is in main, and until the end of the current Class/Module definition when using is in a Class or Module.
module StringPatch
refine String do
def foo
true
end
end
end
class PatchedClass
using StringPatch
puts "test".foo
end
class PatchedClass
puts "test".foo #=> undefined method `foo' for "test":String (NoMethodError)
end
This would mean that if you manage to dynamically call using on a Class or Module, its effect will be directly removed.
You cannot use refine in methods, but you can define methods in a Class that has been refined :
class PatchedClass
using StringPatch
def foo
"test".foo #=> true
end
end
class PatchedClass
def bar
"test".foo
end
end
patched = PatchedClass.new
puts patched.foo #=> true
puts patched.bar #=> undefined method `foo' for "test":String (NoMethodError)
For your questions, this discussion could be interesting. It looks like refinements are restricted on purpose, but I don't know why :
Because refinement activation should be as static as possible.
Refinements are strictly scoped and can't be used dynamically as it stands. I get around this by structuring modules such that I can use them a refinement or as a monkey patch when needed. There are still limitations to this approach, and with refinements in general, but still handy.
module StringPatch
def foo
true
end
refine String do
include StringPatch
end
end
Used as a refinement
class PatchedClass
using StringPatch
end
Used as a single instance patch
obj = PatchedClass.new
obj.extend(StringPatch)
You can of course also extend the whole class as a monkey patch but then you pollute the class forever and for all eternity.
PatchedClass.prepend(StringPatch)
I appreciate the other answers but I think I have to add my own.
It seems there's very little leeway with using - the error that it can't be used in methods is serious. The best wiggle room I found is to iteratively call it, passing a variable as argument.
So if I have two patch classes, I can make a constant Patches, a list that includes both. Then in the class/module I want to load the patches, I can run the iterative using.
module StringPatch
refine String do
def patch; :string_patch; end
end
end
module HashPatch
refine Hash do
def patch; :hash_patch; end
end
end
Patches = [StringPatch, HashPatch]
class C
Patches.each { |x| using x }
def self.test
[''.patch, {}.patch]
new.test
end
def test
[''.patch, {}.patch]
end
end
C.test
The using does make the patches available in both instance and class scope.
The limitation is that there is no way to abstract away the using call.
I can't say Patches.each &method(:using)
or move Patches.each { |x| using x } to a method,
or use eval "Patches.each { |x| using x}"

Dynamically extend existing method or override send method in ruby

Let say we have classes A,B,C.
A
def self.inherited(sub)
# meta programming goes here
# take class that has just inherited class A
# and for foo classes inject prepare_foo() as
# first line of method then run rest of the code
end
def prepare_foo
# => prepare_foo() needed here
# some code
end
end
B < A
def foo
# some code
end
end
C < A
def foo
# => prepare_foo() needed here
# some code
end
end
As you can see I am trying to inject foo_prepare() call to each one of foo() methods.
How can that be done?
Also I have been thinking about overriding send class in class A that way I would run foo_prepare and than just let send (super) to do rest of the method.
What do you guys think, what is the best way to approach this problem?
Here's a solution for you. Although it's based on module inclusion and not inheriting from a class, I hope you will still find it useful.
module Parent
def self.included(child)
child.class_eval do
def prepare_for_work
puts "preparing to do some work"
end
# back up method's name
alias_method :old_work, :work
# replace the old method with a new version, which has 'prepare' injected
def work
prepare_for_work
old_work
end
end
end
end
class FirstChild
def work
puts "doing some work"
end
include Parent # include in the end of class, so that work method is already defined.
end
fc = FirstChild.new
fc.work
# >> preparing to do some work
# >> doing some work
I recommend Sergio's solution (as accepted). Here is what I did which fit my needs.
class A
def send(symbol,*args)
# use array in case you want to extend method covrage
prepare_foo() if [:foo].include? symbol
__send__(symbol,*args)
end
end
or
class A
alias_method :super_send, :send
def send(symbol,*args)
prepare_foo() if [:foo].include? symbol
super_send(symbol,*args)
end
end
As of Ruby 2.0 you can use 'prepend' to simplify Sergio's solution:
module Parent
def work
puts "preparing to do some work"
super
end
end
class FirstChild
prepend Parent
def work
puts "doing some work"
end
end
fc = FirstChild.new
fc.work
This allows a module to override a class's method without the need for alias_method.

Best way to add methods to a Class in execution time

I have to add methods to Class in execution time.
class ExtendableClass
end
The methods to add are declared in independent Classes.
module ExtensionClassOne
def method_one
end
end
module ExtensionClassTwo
def method_two
end
end
I'm looking for an (elegant) mechanism to add all the extension class methods into the ExtendableClass.
Approach 1
I'm thinking in explicily include the extension classes like:
ExtendableClass.send( :include, ExtensionClassOne )
ExtendableClass.send( :include, ExtensionClassTwo )
but it looks a little forced to have to call this private method every time I define a new extension class.
Approach 2
So I was looking for an automatic way to include this methods into my ExtendableClass class.
I'm thinking in declare an specific ancestor for this extension classes:
class ExtensionClassOne < Extension
def method_one
end
end
and then I'd need a mechanism to know all the childs of a class... something like the oposite of ancestors.
Once I have this list I can easily ExtendableClass.include all the list of classes. Even if I have to call to the private method here.
Approach 3
Also inheriting from the Extension class and detect in declaration time when this class is used as ancestor. In the way that the ActiveSupport.included method works, like an event binding. Then make the include there.
Any solution for implement approach 2 or approach 3? Do you recommend approach 1? New approachs?
#fguillen, you are right that the "explicit way is the cleanest approach". Since that is so, why don't you use the most "explicit" code which could be imagined:
class Extendable
end
class Extendable
def method_one
puts "method one"
end
end
class Extendable
def method_two
puts "method two"
end
end
...In other words, if you are defining a module which will be automatically included in a class as soon as it is defined, why bother with the module at all? Just add your "extension" methods directly to the class!
Approach 4 would be to define a macro on class level in Object
class Object
def self.enable_extension
include InstanceExtension
extend ClassExtension
end
end
and calling this macro in all your classes you want to be extended.
class Bacon
enable_extension
end
Car.enable_extension
This way,
you don't have to use #send to circumvent encapsulation (Approach 1)
you can inherit from any Class you want, because everything inherits from Object anyway (except 1.9's BasicObject)
the usage of your extension is declarative and not hidden in some hook
Downside: you monkeypatch build-in Classes and may break the world. Choose long and decriptive names.
Edit: Given your answer to my comment on the question I suppose this is not what you wanted. I see no problem with your "Approach 1" in this case; it's what I'd do. Alternatively, instead of using send to bypass the private method, just re-open the class:
class ExtendableClass
include ExtensionOne
end
Assuming I understand what you want, I'd do this:
module DelayedExtension
def later_include( *modules )
(#later_include||=[]).concat( modules )
end
def later_extend( *modules )
(#later_extend||=[]).concat( modules )
end
def realize_extensions # better name needed
include *#later_include unless !#later_include || #later_include.empty?
extend *#later_extend unless !#later_extend || #later_extend.empty?
end
end
module ExtensionOne
end
module ExtensionTwo
def self.included(klass)
klass.extend ClassMethods
end
module ClassMethods
def class_can_do_it!; end
end
end
class ExtendableClass
extend DelayedExtension
later_include ExtensionOne, ExtensionTwo
end
original_methods = ExtendableClass.methods
p ExtendableClass.ancestors
#=> [ExtendableClass, Object, Kernel, BasicObject]
ExtendableClass.realize_extensions
p ExtendableClass.ancestors
#=> [ExtendableClass, ExtensionOne, ExtensionTwo, Object, Kernel, BasicObject]
p ExtendableClass.methods - original_methods
#=> [:class_can_do_it!]
The included method is actually a hook. It is called whenever you are inherited from:
module Extensions
def someFunctionality()
puts "Doing work..."
end
end
class Foo
def self.inherited(klass)
klass.send(:include, Extensions) #Replace self with a different module if you want
end
end
class Bar < Foo
end
Bar.new.someFunctionality #=> "Doing work..."
There is also the included hook, which is called when you are included:
module Baz
def self.included(klass)
puts "Baz was included into #{klass}"
end
end
class Bork
include Baz
end
Output:
Baz was included into Bork
A very tricky solution, I think too much over-engineering, would be to take the inherited hook that #Linux_iOS.rb.cpp.c.lisp.m.sh has commented and keep all and every child class in a Set and combined it with the #Mikey Hogarth proposition of method_missing to look for all this child class methods every time I call a method in the Extendable class. Something like this:
# code simplified and no tested
# extendable.rb
class Extendable
##delegators = []
def self.inherited( klass )
##delegators << klass
end
def self.method_missing
# ... searching in all ##delegators methods
end
end
# extensions/extension_one.rb
class ExtensionOne < Extendable
def method_one
end
end
But the logic of the method_missing (and respond_to?) is gonna be very complicate and dirty.
I don't like this solution, just let it here to study it like a possibility.
After a very interesting propositions you have done I have realized that the explicit way is the cleanest approach. If we add a few recommendations taking from your answers I think I'm gonna go for this:
# extendable.rb
class Extendable
def self.plug( _module )
include( _module )
end
end
# extensions/extension_one.rb
module ExtensionOne
def method_one
puts "method one"
end
end
Extendable.plug( ExtensionOne )
# extensions/extension_two.rb
module ExtensionTwo
def method_two
puts "method two"
end
end
Extendable.plug( ExtensionTwo )
# result
Extendable.new.method_one # => "method one"
Extendable.new.method_two # => "method two"

Can I invoke an instance method on a Ruby module without including it?

Background:
I have a module which declares a number of instance methods
module UsefulThings
def get_file; ...
def delete_file; ...
def format_text(x); ...
end
And I want to call some of these methods from within a class. How you normally do this in ruby is like this:
class UsefulWorker
include UsefulThings
def do_work
format_text("abc")
...
end
end
Problem
include UsefulThings brings in all of the methods from UsefulThings. In this case I only want format_text and explicitly do not want get_file and delete_file.
I can see several possible solutions to this:
Somehow invoke the method directly on the module without including it anywhere
I don't know how/if this can be done. (Hence this question)
Somehow include Usefulthings and only bring in some of it's methods
I also don't know how/if this can be done
Create a proxy class, include UsefulThings in that, then delegate format_text to that proxy instance
This would work, but anonymous proxy classes are a hack. Yuck.
Split up the module into 2 or more smaller modules
This would also work, and is probably the best solution I can think of, but I'd prefer to avoid it as I'd end up with a proliferation of dozens and dozens of modules - managing this would be burdensome
Why are there lots of unrelated functions in a single module? It's ApplicationHelper from a rails app, which our team has de-facto decided on as the dumping ground for anything not specific enough to belong anywhere else. Mostly standalone utility methods that get used everywhere. I could break it up into seperate helpers, but there'd be 30 of them, all with 1 method each... this seems unproductive
I think the shortest way to do just throw-away single call (without altering existing modules or creating new ones) would be as follows:
Class.new.extend(UsefulThings).get_file
If a method on a module is turned into a module function you can simply call it off of Mods as if it had been declared as
module Mods
def self.foo
puts "Mods.foo(self)"
end
end
The module_function approach below will avoid breaking any classes which include all of Mods.
module Mods
def foo
puts "Mods.foo"
end
end
class Includer
include Mods
end
Includer.new.foo
Mods.module_eval do
module_function(:foo)
public :foo
end
Includer.new.foo # this would break without public :foo above
class Thing
def bar
Mods.foo
end
end
Thing.new.bar
However, I'm curious why a set of unrelated functions are all contained within the same module in the first place?
Edited to show that includes still work if public :foo is called after module_function :foo
Another way to do it if you "own" the module is to use module_function.
module UsefulThings
def a
puts "aaay"
end
module_function :a
def b
puts "beee"
end
end
def test
UsefulThings.a
UsefulThings.b # Fails! Not a module method
end
test
If you want to call these methods without including module in another class then you need to define them as module methods:
module UsefulThings
def self.get_file; ...
def self.delete_file; ...
def self.format_text(x); ...
end
and then you can call them with
UsefulThings.format_text("xxx")
or
UsefulThings::format_text("xxx")
But anyway I would recommend that you put just related methods in one module or in one class. If you have problem that you want to include just one method from module then it sounds like a bad code smell and it is not good Ruby style to put unrelated methods together.
To invoke a module instance method without including the module (and without creating intermediary objects):
class UsefulWorker
def do_work
UsefulThings.instance_method(:format_text).bind(self).call("abc")
...
end
end
Not sure if someone still needs it after 10 years but I solved it using eigenclass.
module UsefulThings
def useful_thing_1
"thing_1"
end
class << self
include UsefulThings
end
end
class A
include UsefulThings
end
class B
extend UsefulThings
end
UsefulThings.useful_thing_1 # => "thing_1"
A.new.useful_thing_1 # => "thing_1"
B.useful_thing_1 # => "thing_1"
Firstly, I'd recommend breaking the module up into the useful things you need. But you can always create a class extending that for your invocation:
module UsefulThings
def a
puts "aaay"
end
def b
puts "beee"
end
end
def test
ob = Class.new.send(:include, UsefulThings).new
ob.a
end
test
A. In case you, always want to call them in a "qualified", standalone way (UsefulThings.get_file), then just make them static as others pointed out,
module UsefulThings
def self.get_file; ...
def self.delete_file; ...
def self.format_text(x); ...
# Or.. make all of the "static"
class << self
def write_file; ...
def commit_file; ...
end
end
B. If you still want to keep the mixin approach in same cases, as well the one-off standalone invocation, you can have a one-liner module that extends itself with the mixin:
module UsefulThingsMixin
def get_file; ...
def delete_file; ...
def format_text(x); ...
end
module UsefulThings
extend UsefulThingsMixin
end
So both works then:
UsefulThings.get_file() # one off
class MyUser
include UsefulThingsMixin
def f
format_text # all useful things available directly
end
end
IMHO it's cleaner than module_function for every single method - in case want all of them.
As I understand the question, you want to mix some of a module's instance methods into a class.
Let's begin by considering how Module#include works. Suppose we have a module UsefulThings that contains two instance methods:
module UsefulThings
def add1
self + 1
end
def add3
self + 3
end
end
UsefulThings.instance_methods
#=> [:add1, :add3]
and Fixnum includes that module:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
include UsefulThings
end
We see that:
Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
#=> [:add2, :add3, :add1]
1.add1
2
1.add2
cat
1.add3
dog
Were you expecting UsefulThings#add3 to override Fixnum#add3, so that 1.add3 would return 4? Consider this:
Fixnum.ancestors
#=> [Fixnum, UsefulThings, Integer, Numeric, Comparable,
# Object, Kernel, BasicObject]
When the class includes the module, the module becomes the class' superclass. So, because of how inheritance works, sending add3 to an instance of Fixnum will cause Fixnum#add3 to be invoked, returning dog.
Now let's add a method :add2 to UsefulThings:
module UsefulThings
def add1
self + 1
end
def add2
self + 2
end
def add3
self + 3
end
end
We now wish Fixnum to include only the methods add1 and add3. Is so doing, we expect to get the same results as above.
Suppose, as above, we execute:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
include UsefulThings
end
What is the result? The unwanted method :add2 is added to Fixnum, :add1 is added and, for reasons I explained above, :add3 is not added. So all we have to do is undef :add2. We can do that with a simple helper method:
module Helpers
def self.include_some(mod, klass, *args)
klass.send(:include, mod)
(mod.instance_methods - args - klass.instance_methods).each do |m|
klass.send(:undef_method, m)
end
end
end
which we invoke like this:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
Helpers.include_some(UsefulThings, self, :add1, :add3)
end
Then:
Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
#=> [:add2, :add3, :add1]
1.add1
2
1.add2
cat
1.add3
dog
which is the result we want.
After almost 9 years here's a generic solution:
module CreateModuleFunctions
def self.included(base)
base.instance_methods.each do |method|
base.module_eval do
module_function(method)
public(method)
end
end
end
end
RSpec.describe CreateModuleFunctions do
context "when included into a Module" do
it "makes the Module's methods invokable via the Module" do
module ModuleIncluded
def instance_method_1;end
def instance_method_2;end
include CreateModuleFunctions
end
expect { ModuleIncluded.instance_method_1 }.to_not raise_error
end
end
end
The unfortunate trick you need to apply is to include the module after the methods have been defined. Alternatively you may also include it after the context is defined as ModuleIncluded.send(:include, CreateModuleFunctions).
Or you can use it via the reflection_utils gem.
spec.add_dependency "reflection_utils", ">= 0.3.0"
require 'reflection_utils'
include ReflectionUtils::CreateModuleFunctions
This old question comes to me today when I am studing Ruby and found interesting so I want to answer with my new knowlege.
Assume that you have the module
module MyModule
def say
'I say'
end
def cheer
'I cheer'
end
end
then with the class so call Animal I can take cheer method from MyModule as following
class Animal
define_method(:happy, MyModule.method(:cheer))
end
This is so called unbound method, so you can take a callable object and bind it to another place(s).
From this point, you can use the method as usual, such as
my_dog = Animal.new
my_dog.happy # => "I cheer"
Hope this help as I also learned something new today.
To learn further, you can use irb and take a look at Method object.

Resources