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.
Related
I'm playing with some of the very basics of ruby mixins, and for some reason can't access behavior from my module.
Running this on Ruby Fiddle:
module Cats
MEOW = "meow meow meow"
def Cats.meow?
return Cats::MEOW
end
end
class Example
include Cats
def sample
return "it's a sample"
end
end
e = Example.new
puts e.sample
puts e.meow?
This keeps returning NoMethodError: undefined method 'meow?' for #
My understanding of how mixins should work from tutorialspoint makes me feel like I should be able to validly call e.meow?, and get back the same result I would get from calling Cats.meow?.
Here's the code in RubyFiddle.
Incredibly basic, but any ideas where I'm falling down here?
As it turns out, I was being overly specific when defining Cats.meow?. If you want to use a module as a mixin you'll want to define your methods more generally, not with respect to their specific module namespace.
So instead of
def Cats.meow?
...
end
it should have been
def meow?
...
end
This lets you call e.meow?, since the method definition no longer limits it just to the Cats namespace.
Whoops.
As a general rule to using include and extend in Ruby:
If you want to use your module as a namespace
module Outer
module Inner
def self.my_method
"namespaced method!"
end
end
end
You use it like this Outer::Inner::my_method or Outer::Inner.my_method.
And if you want to use the module as a mixin:
# In some cases it makes sense to use names ending in -able, since it expreses
# what kind of messages you can send to an instance or class that mixes
# this module in.
# Like Devise's Recoverable module: https://github.com/plataformatec/devise/blob/f39c6fd92774cb66f96f546d8d5e8281542b4e78/lib/devise/models/recoverable.rb#L24
module Fooable
def foo
"#{self} has been foo'ed!"
end
end
Then you can include it (instances of Something obtain #foo):
class Something
include Fooable # Now Something.new can receive the #foo message.
end
Something.new.foo
=> "#<Something:0x0055c2dc104650> has been foo'ed!"
Or you can extend it (Something itself obtains #foo as a class message):
class Something
extend Fooable # Now Something can receive the #foo message.
end
Something.foo
=> "Something has been foo'ed!"
I'm trying to make a DSL like configuration for classes that include a module but to have the configured variable available to both class and instance methods seems to require littering the module with access methods. Is there a more elegant way to do this?
module DogMixin
class << self
def included(base)
base.extend ClassMethods
end
end
module ClassMethods
def breed(value)
#dog_breed = value
end
def dog_breed
#dog_breed
end
end
end
class Foo
include DogMixin
breed :havanese
end
puts Foo.dog_breed
# not implemented but should be able to do this as well
f = Foo.new
f.dog_breed
Your example is a bit weird I think :)
Anyway, one way to avoid writing the accessors (the assignment - accessor is problematic in my eyes - especially in the given example) is to define constants, as in the example below. If however you need runtime-assignments, please edit your question (and thus render this answer invalid :) except you want to mess with runtime constant assignment, which is possible but messy).
module DogMixin
# **include** DogMixin to get `Class.dog_breed`
class << self
def included(base)
def base.dog_breed
self::DOG_BREED || "pug"
end
end
end
# **extend** DogMixin to get `instance.dog_breed`
def dog_breed
self.class.const_get(:DOG_BREED) || "pug"
end
end
class Foomer
DOG_BREED = 'foomer'
extend DogMixin
include DogMixin
end
f = Foomer.new
puts Foomer.dog_breed
puts f.dog_breed
# If I understand you correctly, this is the most important (?):
f.dog_breed == Foomer.dog_breed #=> true
It took some reading of (In Ruby) allowing mixed-in class methods access to class constants to get the Instance-And-Class Constant lookup from a module, but it works. I am not sure if I really like the solution though. Good question, although you could add a little detail.
I have an app that includes modules into core Classes for adding client customizations.
I'm finding that class_eval is a good way to override methods in the core Class, but sometimes I would like to avoid re-writing the entire method, and just defer to the original method.
For example, if I have a method called account_balance, it would be nice to do something like this in my module (i.e. the module that gets included into the Class):
module CustomClient
def self.included base
base.class_eval do
def account_balance
send_alert_email if balance < min
super # Then this would just defer the rest of the logic defined in the original class
end
end
end
end
But using class_eval seems to take the super method out of the lookup path.
Does anyone know how to work around this?
Thanks!
I think there are several ways to do what you're wanting to do. One is to open the class and alias the old implementation:
class MyClass
def method1
1
end
end
class MyClass
alias_method :old_method1, :method1
def method1
old_method1 + 1
end
end
MyClass.new.method1
=> 2
This is a form of monkey patching, so probably best to make use of the idiom in moderation. Also, sometimes what is wanted is a separate helper method that holds the common functionality.
EDIT: See Jörg W Mittag's answer for a more comprehensive set of options.
I'm finding that instance_eval is a good way to override methods in the core Class,
You are not overriding. You are overwriting aka monkeypatching.
but sometimes I would like to avoid re-writing the entire method, and just defer to the original method.
You can't defer to the original method. There is no original method. You overwrote it.
But using instance_eval seems to take the super method out of the lookup path.
There is no inheritance in your example. super doesn't even come into play.
See this answer for possible solutions and alternatives: When monkey patching a method, can you call the overridden method from the new implementation?
As you say, alias_method must be used carefully. Given this contrived example :
module CustomClient
...
host.class_eval do
alias :old_account_balance :account_balance
def account_balance ...
old_account_balance
end
...
class CoreClass
def old_account_balance ... defined here or in a superclass or
in another included module
def account_balance
# some new stuff ...
old_account_balance # some old stuff ...
end
include CustomClient
end
you end up with an infinite loop because, after alias, old_account_balance is a copy of account_balance, which now calls itself :
$ ruby -w t4.rb
t4.rb:21: warning: method redefined; discarding old old_account_balance
t4.rb:2: warning: previous definition of old_account_balance was here
[ output of puts removed ]
t4.rb:6: stack level too deep (SystemStackError)
[from the Pickaxe] The problem with this technique [alias_method] is that you’re relying on there not being an existing method called old_xxx. A better alternative is to make use of method objects, which are effectively anonymous.
Having said that, if you own the source code, a simple alias is good enough. But for a more general case, i'll use Jörg's Method Wrapping technique.
class CoreClass
def account_balance
puts 'CoreClass#account_balance, stuff deferred to the original method.'
end
end
module CustomClient
def self.included host
#is_defined_account_balance = host.new.respond_to? :account_balance
puts "is_defined_account_balance=#{#is_defined_account_balance}"
# pass this flag from CustomClient to host :
host.instance_variable_set(:#is_defined_account_balance,
#is_defined_account_balance)
host.class_eval do
old_account_balance = instance_method(:account_balance) if
#is_defined_account_balance
define_method(:account_balance) do |*args|
puts 'CustomClient#account_balance, additional stuff'
# like super :
old_account_balance.bind(self).call(*args) if
self.class.instance_variable_get(:#is_defined_account_balance)
end
end
end
end
class CoreClass
include CustomClient
end
print 'CoreClass.new.account_balance : '
CoreClass.new.account_balance
Output :
$ ruby -w t5.rb
is_defined_account_balance=true
CoreClass.new.account_balance : CustomClient#account_balance, additional stuff
CoreClass#account_balance, stuff deferred to the original method.
Why not a class variable ##is_defined_account_balance ? [from the Pickaxe] The module or class definition containing the include gains access to the constants, class variables, and instance methods of the module it includes.
It would avoid passing it from CustomClient to host and simplify the test :
old_account_balance if ##is_defined_account_balance # = super
But some dislike class variables as much as global variables.
[from the Pickaxe] The method Object#instance_eval lets you set self to be some arbitrary object, evaluates the code in a block with, and then resets self.
module CustomClient
def self.included base
base.instance_eval do
puts "about to def account_balance in #{self}"
def account_balance
super
end
end
end
end
class Client
include CustomClient #=> about to def account_balance in Client
end
As you can see, def account_balance is evaluated in the context of class Client, the host class which includes the module, hence account_balance becomes a singleton method (aka class method) of Client :
print 'Client.singleton_methods : '
p Client.singleton_methods #=> Client.singleton_methods : [:account_balance]
Client.new.account_balance won't work because it's not an instance method.
"I have an app that includes modules into core Classes"
As you don't give much details, I have imagined the following infrastructure :
class SuperClient
def account_balance
puts 'SuperClient#account_balance'
end
end
class Client < SuperClient
include CustomClient
end
Now replace instance_eval by class_eval. [from the Pickaxe] class_eval sets things up as if you were in the body of a class definition, so method definitions will define instance methods.
module CustomClient
...
base.class_eval do
...
print 'Client.new.account_balance : '
Client.new.account_balance
Output :
#=> from include CustomClient :
about to def account_balance in Client #=> as class Client, in the body of Client
Client.singleton_methods : []
Client.new.account_balance : SuperClient#account_balance #=> from super
"But using instance_eval seems to take the super method out of the lookup path."
super has worked. The problem was instance_eval.
Please help me out.
I need to use the same bunch of attributes in many classes. I would suggest to create module with predefined attributes and extend this module in every class
module Basic
#a=10
end
class Use
extend Basic
def self.sh
#a
end
end
puts Use.sh
but the output is empty. It seems like I missed something.
Maybe there is a better way to do that?
Your thoughts?
It's all about the self:
module Basic
#a=10
end
has self evaluating to Basic. You want it to evaluate to Use when the latter is extended:
module Basic
# self = Basic, but methods defined for instances
class << self
# self = Basic's eigenclass
def extended(base)
base.class_eval do
# self = base due to class_eval
#a=10
end
end
end
end
class Use
# self = Use, but methods defined for instances
extend Basic # base = Use in the above
class << self
# self = Use's eigenclass
def sh
#a
end
end
end
Use.sh # 10
What you're describing is the Flyweight design pattern. While some view this as rarely used in ruby ( http://designpatternsinruby.com/section02/flyweight.html ), others provide an implementation ( http://www.scribd.com/doc/396559/gof-patterns-in-ruby page 14 )
Personally, what I would do is to put all these attributes into a yaml file, and parse them either into a global variable:
ATTRIBUTES = YAML.load_file(File.expand_path('attributes.yml', File.dirname(FILE))
or a class method (with caching here, assuming you won't change the yml file while the app is running and need the new values). I'd suggest using ActiveSupport::Concern here as it's easier to read than the traditional way of mixing in class methods:
module Basic
extend ActiveSupport::Concern
module ClassMethods
def attributes_file
File.expand_path('attributes.yml', File.dirname(__FILE__))
def attributes
#attributes ||= YAML.load_file(attributes_file)
#attributes
end
end
module InstanceMethods
# define any here that you need, like:
def attributes
self.class.attributes
end
end
end
You can define methods for each of the attributes, or rely on indexing into the attributes hash. You could also get fancy and define method_missing to check if an attribute exists with that name, so that you don't have to keep adding methods as you want to add more attributes to the shared configs.
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.