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}"
I'm doing some metaprogramming in Ruby, and I need to dynamically generate a sibling class inside of a module. In doing so, I want to call const_set on the module, but I don't know which Module constant to call that on until runtime. An example:
Given classes
Foo::Bar::Baz
Foo::Quox::Quack
I want to be able to call a function like this (oversimplified here):
def generate_from klass
mod = klass.enclosing_module # <- THIS LINE is the one I need to figure out
mod.const_set("GeneratedClassName", Class.new)
end
and what I want to end up with, when calling with Baz, is a new class defined as
Foo::Bar::GeneratedClassName
and with a Quack, I want
Foo::Quox::GeneratedClassName
The only way I know of is to split up klass.name, then repeatedly call const_get on those strings, constantized. Does anyone know of a more elegant way?
This should get you on track:
module Foo
module Bar
class Baz
def initialize
#nesting = Module.nesting
end
def enclosing_module
#nesting.last
end
end
end
end
puts Foo::Bar::Baz.new.enclosing_module #=> Foo
Relevant documentation:
http://ruby-doc.org/core/classes/Module.html#M000441
Got it.
ActiveSupport has this Ruby extension, Module#parent. It's good enough for my use.
In Rails you can use a combination of deconstantize and constantize.
'Foo::Bar::Baz'.deconstantize.constantize # => Foo::Bar
so in a method of the class it can be used like this:
self.class.name.deconstantize.constantize
In case anyone is looking for a pure ruby version:
def get_parent_type
#Note: This will break for base types (lacking '::' in the name)
parent_type=self.class.name.split('::')[0...-1]
begin
Object.const_get(parent_type.join('::'))
rescue NameError => e
nil
end
end
In what sort of situation is the code:
module M
extend self
def greet
puts "hello"
end
end
more beneficial to use over say something like:
module M
def self.greet
puts "hello"
end
end
In the top, one is an instance method being extended, and the latter is just a class method, but when calling either method, you'd have to M.greet , right? I was just curious if anyone could shed some light on when to use one code over the other. Thanks!
The first example is typically a way people achieve the functionality of module_function (when they do not know the existence of this method).
A module_function is both an instance method and a class method. In your second code example the method is just a class method.
It would be possible to do this with your first example, but not your second:
include M
greet
A module can be used as a namespace by writing module methods, and a module's instance methods can be mixed into another object.
The self-extending module concept allows a module to be used in both ways; either as a stand-alone namespace or as a mixin. Consider this module:
module M
def bar
puts "bar"
end
end
class C
include M
end
It has an instance method and can be mixed in to another object. It does not have a module method and cannot, therefore be used as a namespace:
puts M::bar # => undefined method `bar' for M:Module
puts C.bar # => this is bar
But, a module is an just an object of class Module, as we can demonstrate
puts M.class # => Module
This means that we can do something crazy. We can mix a module into itself so that its methods become both instance and module methods.
module M
extend self
def bar
puts "bar"
end
end
puts M::bar # => this is bar
puts C.bar # => this is bar
I a writing a DSL to generate parsers for bioinformatics flat files. I would like to let the user define helper functions in block and then include the function in the parsing context object. I would like to use a syntax like:
rules = Rules.new do
helpers do
def foo()
#...
end
def bar( baz )
#...
end
end
# Here come the parsing rules which can access both helper methods
end
I would like to add the helper methods to a module definition and the include the module in a instance (just the instance not the class).
Do you have an idea how I can reach that goal ? Answers with a slightly different syntax are appreciated too.
Something like this, perhaps?
class Rules
def initialize(&block)
instance_eval &block
end
def helpers
yield
end
end
Rules.new do
helpers do
def hi_world
puts "Hello World!"
end
end
hi_world
end
Note though that here the helpers method does nothing special, it just relies on the fact that the Rules block is already the current scope.
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.