Disclaimer: Although I'm asking in context of a Rails application, I'm not talking about Rails helpers (i.e. view helpers)
Let's say I have a helper method/function:
def dispatch_job(job = {})
#Do something
end
Now I want to use this from several different places (mostly controllers, but also a few BackgrounDRb workers)
What's the preferred way to do this?
I can think of two possibilities:
1. Use a class and make the helper a static method:
class MyHelper
def self.dispatch_job(job = {})
end
end
class MyWorker
def run
MyHelper.dispatch_job(...)
end
end
2. Use a module and include the method into whatever class I need this functionality
module MyHelper
def self.dispatch_job(job = {})
end
end
class MyWorker
include MyHelper
def run
dispatch_job(...)
end
end
3. Other possibilities I don't know yet
...
The first one is more Java-like, but I'm not sure if the second one is really an appropriate use of Ruby's modules.
The module approach is the direction I would take. I prefer it because of its flexibility and how nicely it allows you to organize your code. I suppose you could argue that they are just another form of mixin. I always think of mixins as direct extensions of a particular class
class Foo
def hello
'Hello'
end
end
class Foo
def allo
'Allo?'
end
end
f = Foo.new
f.hello => 'Hello'
f.allo => 'Allo?'
That always seems very specific, whereas the module approach can extend any class you include it in.
Peer
If you are going to use that in your controllers and some other code, you can create a mixin and add it to your application controller, from which other controllers derive from, that way you can have it in your controllers, then you can add the module to your other outside classes.
Related
Module#refine method takes a class and a block and returns a refinement module, so I thought I could define:
class Class
def include_refined(klass)
_refinement = Module.new do
include refine(klass) {
yield if block_given?
}
end
self.send :include, _refinement
end
end
and the following test passes
class Base
def foo
"foo"
end
end
class Receiver
include_refined(Base) {
def foo
"refined " + super
end
}
end
describe Receiver do
it { should respond_to(:foo) }
its(:foo) { should eq("refined foo") }
end
So, using refinements, I can turn a class into a module, refine its behaviour on the fly, and include it in other classes.
Is there a simpler way to turn a class into a module in Ruby (say in ruby < 2)?
In the C-implementation of rb_mod_refine
we see
refinement = rb_module_new();
RCLASS_SET_SUPER(refinement, klass);
Is this just setting the superclass of refinement to klass that copies the implementation of the class inside the refinement module?
I am aware that multiple inheritance IS
done via Modules, but what would the community think of the above Class#include_refined?
Would it be reasonable to extract this aspect out of refinements?
"Locally" patching inside a Class instead of using "using" switches to activate refinements?
I am happy indeed with Ruby 2.1 (and later) class-level "private" scope of refinements. My example above can be rephrased as:
# spec/modulify_spec.rb
module Modulify
refine(Class) do
def include_refined(klass)
_refined = Module.new do
include refine(klass) { yield if block_given? }
end
include _refined
end
end
end
class A
def a
"I am an 'a'"
end
end
class B
using Modulify
include_refined(A) do
def a
super + " and not a 'b'"
end
end
def b
"I cannot say: " + a
end
end
RSpec.describe B do
it "can use refined methods from A" do
expect(subject.b).to eq "I cannot say: I am an 'a' and not a 'b'"
end
end
and suits as solution for the original problem.
Andrea, thank you for the info in comment. Excuse my lack of knowledge to understand this is really necessary though it sounds doable as per your research.
I don't think we need to go so low level to do something in Rails.
If I'm going to do similar on Engine, I will try the following ideas, from easy to hard.
In routes.rb, mount the whole engine in right route.
I'm afraid this most common usage can't fit your need
In routes.rb, Customize engine's route for specific controllers in application route.
Devise, as an engine, can do easily. But I know not every engine could do this.
In routes.rb, redirect specific or whole set of routes to engine's routes
In your application's action, redirect to specific engine's action in application's action.
This should be customized enough for specific action
class FoosController < ApplicationController
def foo
redirect_to some_engine_path if params[:foo] == 'bar'
end
Inherit the engine's controller - for a set of actions, and if all above can't fit
*The engine's classes are available in all application, you can inherit a controller from them, instead of normal ApplicationController.
# class FoosController < ApplicationController
class FoosController < BarEngine::BarsController
*Since most engine's controller inherit from ApplicationController, this inheritance still allows you to use your own things from ApplicationController, no bad effect at all.
If all above can't do, I can try to serve a customized locally or from my github repo.
In conclusion, the above should be able to solve most of cases, and I myself prefer #5 when possible and needed.
I have a class in Ruby that holds some stuff, I'll call FooBox:
class FooBox
...
end
I have two possible backing-data stores for FooBox called BoxA and BoxB with different characteristics but the same interface:
class BoxA
include Enumerable
def put_stuff(thing)
...
end
end
class BoxB
include Enumerable
def put_stuff(thing)
...
end
end
How can I instantiate a FooBox, and, based on a parameter, decide whether to back it with a BoxA or BoxB implementation? I do not want to pass in the implementation into the constructor; I only want to pass something to determine which kind to use.
class FooBox
def initialize(implementation_choice)
# ???
end
end
I usually do something like this:
class BoxA
def self.match? options
# figure out if BoxA can be used given options
end
end
# Implement BoxB (and other strategies) similarly to BoxA
class FooBox
STRATEGIES = [BoxA, BoxB]
def initialize options
#options = options
end
def strategy
#strategy ||= STRATEGIES.detect { |strategy| strategy.match? #options }
end
end
This keeps the responsibility of “knowing” if the strategy is able to be used within the strategy itself (rather than making the context class monolithic), and then just picks the first one in the list that says it can work.
I’ve used this pattern (and similar variations for slightly different problems) several times and have found it very clean.
The simple solution is create a mapping for the strategy's type and strategy class, just like #Andrew Marshall's solution
But to be better I would considering two things:
The strategies' holder (here is the FooxBox ) now need to know every box implenentation, and hard-coding their names to itself; this is not a flexiable
approach, considering one day you want to add another strategy, go to the code and add it? With ruby we can do it with a 'self registering' easily.
You don't want to strategies holder will return implementation wildly, I mean both 'BoxA' and 'BoxB' or someday's 'BoxXYZ' should belong to same strategy
concept, in Java, it maybe means all of them should implemente an interface, with ruby we generally do it with include SomeMoudle
In my application I use the following solution(just demo)
module Strategies
def self.strategies
##strategies ||= {}
end
def self.strategy_for(strategy_name)
##strategies[strategy_name]
end
end
module Strategy
def self.included(base)
base.class_eval do
def self.strategy_as(strategy_name)
Strategies.strategies[strategy_name] = self
end
end
end
end
class BoxA
include Strategy
strategy_as :box_a
def do_stuff
puts "do stuff in BoxA"
end
end
class BoxB
include Strategy
strategy_as :box_b
def do_stuff
p "do stuff in BoxB"
end
end
## test
Strategies.strategy_for(:box_a).new.do_stuff
Strategies.strategy_for(:box_b).new.do_stuff
If you want to detect strategy with match block, you can change strategy_as to accept a block. then use Strategies.strategy_for{...}.new.do_stuff
I would like to expand the functionality of some class using class_eval. I would like to force the class to inherit some methods from some other class.
I.e.:
SomeClass.class_eval do
# force inheritence from some other class
end
What's the best way to achieve it?
If overriding existing functionality is a hard requirement here, you need to have those existing methods defined in a module that's also included.
class SomeClass
include DefaultBehaviour
end
module DefaultBehaviour
def run
puts "ran default"
end
end
module AlternateBehaviour
def run
puts "ran alternate"
end
end
SomeClass.class_eval {
include AlternateBehaviour
}
SomeClass.new.run #=> "ran alternate"
The reason for this is because of ruby's method lookup path.
It starts off as SomeClass -> Object.
When you include AlternateBehaviour, it becomes SomeClass -> AlternateBehaviour -> Object. So methods defined directly on SomeClass still take precedence.
However, if those methods are defined on DefaultBehaviour, the lookup path becomes SomeClass -> AlternateBehaviour -> DefaultBehaviour -> Object, so your alternate method takes priority. Whichever module was included most recently is the highest priority.
In the case where you do not have control of the original class, you can do instead:
module AlternateBehaviour
def self.included(base)
base.send(:remove_method, :run)
end
def run
puts "ran alternate"
end
end
Though at this point, one starts to wonder whether you might be better off by just doing
SomeClass.class_eval {
def run
"ran alternate"
end
end
Try using include and extend, both explained here. They only work with modules; you just can't modify/add superclasses of a class in Ruby after it has already been created.
Only one problem: you can't override already existing methods in a class for the explained in the third comment to this post.
Also see this topic for more information.
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.
Can you explain why the developer is using class << self to add a methods to the base class?
base.rb from the GeoPlanet Gem
module GeoPlanet
class Base
class << self
def build_url(resource_path, options = {})
end
end
end
Because he doesn't know that
def GeoPlanet::Base.build_url(resource_path, options = {}) end
would work just as well?
Well, they aren't 100% equivalent: if GeoPlanet doesn't exist, then the original snippet will create the module, but my version will raise a NameError. To work around that, you'd need to do this:
module GeoPlanet
def Base.build_url(resource_path, options = {}) end
end
Which will of course raise a NameError, if Base doesn't exist. To work around that, you'd do:
module GeoPlanet
class Base
def self.build_url(resource_path, options = {}) end
end
end
However you look at it, there's no need to use the singleton class syntax. Some people just simply prefer it.
I think it is simply a matter of style/taste. I like to use the class << self approach when I have a lot of class methods that I want to group together or provide some sort of visual separation from instance methods.
I would also use this approach if all my methods were class methods as the GeoPlanet author did.