I'm trying to create a component system in Ruby using the observer pattern. Components must be defined as modules because they exist only to be mixed in to a ComponentContainer. But there are certain methods that Components have, which I'd ideally like to define in some kind of base class, but I can't do that since they're modules.
Here's what I'd like to do:
module Component
def self.on(event, &block)
#definition..
end
def self.fire(event)
#pass event to subscribers
end
end
module FooComponent < Component
on :foo_event do |param1, param2|
#...
end
end
The different types of Components use the on and fire methods, but they can't inherit them, because modules can't have parents. What should I do? Is this not ruby-like?
I could get this to work by making Component and FooComponent classes, but then I can't mix them into a ComponentContainer using extend or include.
A clean way to do this is to abstract away the use of extend using the Module#included hook method. This method is called on a module with a reference to the base that is including it. What this code does is creates a Component module that automatically extends the base with the desired methods:
module Component
def self.included(base)
base.extend Methods
end
module Methods
def on(event, &block)
# ...
end
def fire(event)
# ...
end
end
end
module FooComponent
include Component
on :foo_event do |param1, param2|
# ...
end
end
What if you created a separate module called BaseComponent that defined the basic methods all component modules should have, and then in your custom components, include that BaseComponent.
Then, you should still be able to mixin those custom components into your ComponentContainer class.
You can extend the Component's methods into your "child"-module:
module Component
extend self # (only if you also want to allow calling via Component.on like in the original example)
def on(event, &block)
#definition..
end
def fire(event)
#pass event to subscribers
end
end
module FooComponent
extend Component
on :foo_event do |param1, param2|
#...
end
end
Related
module Add
def addition
sum=1+2
puts sum
end
a=Add.addition
Can anyone tell me what I'm missing and why I am getting this error->
undefined method `addition' for Add:Module (NoMethodError)
You are confusing class methods and instance methods. Your definition:
module Add
def addition
...
end
end
defines methods on instances of Add whereas you called a method on the module Add. If you want to define a class/module method, you need to define like:
module Add
def self.addition
...
end
end
If you want to be able to call it directly, define it as a directly accessible method:
def self.addition
# ...
end
Or you can always rework this using:
module Add
# ...(methods)...
extend self
end
Where that will automatically promote all mixin-type methods as being directly accessible.
You can also tag them more selectively like this:
module Add
def addition
# ...
end
module_method :addition
end
That method is then available either as Add.addition or if some other module or class calls include Add.
I'm using a Ruby Component inside an Audio Application Environment. This Ruby Component is represented by an instance of a RubyEdit class. This provide the interface between my Ruby code and the Environment.
For example if I write self it outputs the instance of the RubyEdit class that represents that component:
the nice things is that I can/must "implement/extend" some methods that RubyEdit will call when it get some events. I can define my custom method event for that instance:
def event
# my own event code
end
and it will be called when the Environment get some events outside this Ruby Component. Or I can call a class method called redraw, and it will call my custom method draw:
def draw
# my own draw code (this will called after invoking redraw from Ruby Component)
end
I need to understand some hierarchy of this process, so I'm making a simulation of that RubyEdit class in Ruby.
How it will looks? I mean: how can I provide methods that will be defined "later"?
This is how RubyEdit will look I think:
class RubyEdit
def self.redraw
# calling this class method should invoke my extended draw method
end
def draw
end
def event
end
end
but I don't understand how to place event and draw methods extendible. Interfaces?
module ExtendRubyEdit
def self.included(base)
base.extend(ClassMethods)
end
def draw
end
def event
end
module ClassMethods
def redraw
end
end
end
class RubyEdit
include ExtendRubyEdit
end
This should be an easy one for a ruby dev. I'm playing around with a gem and I need help with inheriting module variables. Code should speak better than me:
module SomeModule
extend ActiveSupport::Concern
attr_accessor :bbonified
class Railtie < Rails::Railtie
initializer "some_module.study" do
Rails.application.eager_load!
# => I WANT TO ACCESS HERE
puts #bbonified
end
end
module ClassMethods
def bbonify(*columns)
# => WHAT I DEFINE HERE
#bbonified = columns
end
end
end
ActiveRecord::Base.send(:include, SomeModule)
You're not going to be able to access #bbonified directly, that's a local variable in the class that imports this module.
You need to define a separate accessor method to retrieve it:
module ClassMethods
def bbonified
#bbonified
end
end
Then later you need to refer to this somehow, but as you're just talking about a module it will depend on what class has been extended.
Rails.application.eager_load!
SomeClass.bbonified
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.
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.