Ruby delegation for an object without overriding constructor - ruby

One example of Ruby delegation is to use a SimpleDelegator:
class FooDecorator < SimpleDelegator
include ActiveModel::Model
# ...
end
That's very convenient, since anything not responded to by FooDecorator is passed to the underlying object.
But this overwrites the constructor's signature, which makes it incompatible with things like ActiveModel::Model that expect to see a particular signature.
Another example of Ruby delegation is to use Forwardable:
class Decorator
include ActiveModel::Model
extend Forwardable
attr_accessor :members
def_delegator :#members, :bar, :baz
def_delegators :#members, :a, :b, :c
end
But now you have to be explicit about which methods you want to delegate, which is brittle.
Is there a way to get the best of both worlds, where I...
don't tamper with the constructor
get pass-through delegation for any equivalently named method on the delegated object

Have you looked at the Delegator docs? You could basically re-implement your own Delegator subclass with the __getobj__ and __setobj__ methods. Or, you could just subclass SimpleDelegator and specify your own constructor that calls super(obj_to_delegate_to), no?
You could always just implement method_missing on your decorator and pass through any not-found method to the underlying object, too.
Edit: Here we go. The use of an intermediate inherited class breaks the super() chaining, allowing you to wrap the class as desired:
require 'active_model'
require 'delegate'
class Foo
include ActiveModel::Model
attr_accessor :bar
end
class FooDelegator < Delegator
def initialize
# Explicitly don't call super
end
def wrap(obj)
#obj = obj
self
end
def __getobj__
#obj
end
end
class FooDecorator < FooDelegator
include ActiveModel::Model
def name
self.class.name
end
end
decorator = FooDecorator.new.wrap(Foo.new bar: "baz")
puts decorator.name #=> "decorator"
puts decorator.bar #=> "bar"

Why do you want ActiveModel::Model? Do you truly need all of the features?
Could you merely do the same thing?
extend ActiveModel::Naming
extend ActiveModel::Translation
include ActiveModel::Validations
include ActiveModel::Conversion
I'm aware that changes to ActiveModel::Model could break your decorator in terms of the expected behavior, but you're coupling pretty tightly to it anyway.
Allowing modules to control constructors is a code smell. Might be ok, but you should second guess it and be well aware of why it does so.
ActiveModel::Model defines initialize to expect a hash. I'm not sure how you expect to get the particular object that you want to wrap.
SimpleDelegator uses __setobj__ inside of it's constructor, so you can use that after including a module that overrides your constructor.
If you want automatic forwarding you can just define the methods you need on your decorator when you set the object. If you can control how your object is created, make a build method (or something like that) which calls the initialize that needs to be used for ActiveModel::Model and __setobj__ that's used for SimpleDelegator:
require 'delegate'
require 'forwardable'
class FooCollection < SimpleDelegator
extend Forwardable
include ActiveModel::Model
def self.build(hash, obj)
instance = new(hash)
instance.send(:set_object, obj)
instance
end
private
def set_object(obj)
important_methods = obj.methods(false) - self.class.instance_methods
self.class.delegate [*important_methods] => :__getobj__
__setobj__(obj)
end
end
This allows you to used the ActiveModel interface but adds the SingleForwardable module to the singleton class of the decorator which gives you the delegate method. All you need to do then is pass it a collection of method names and a method to use to get the object for forwarding.
If you need to include or exclude particular methods, just change the way important_methods is created. I didn't think much about that, so double-check what's actually being used there before grabbing this code. For example, once the set_object method is called once, you can skip calling it later, but this is built to expect that all wrapped objects have the same interface.
As you pointed out on twitter, the draper gem uses the delegate method (from ActiveSupport) inside of method_missing. With that approach, each missed hit will incur the cost of opening the class and defining the method for forwarding. The upside is that it's lazy and you don't need to calculate which methods need to be forwarded and that hit is only incurred on the first miss; subsequent method calls won't be missed because you're defining that method.
The code I made above will get all those methods and define them at once.
If you need more flexibility and expect your decorator to not be the same type of object you can use SingleForwardable for the same effect but it will define methods for each wrapped instance instead of affecting the decorator class:
require 'delegate'
require 'forwardable'
class FooCollection < SimpleDelegator
include ActiveModel::Model
def self.build(hash, obj)
instance = new(hash)
instance.set_object(obj)
instance
end
def set_object(obj)
important_methods = obj.methods(false) - self.class.instance_methods
singleton_class.extend SingleForwardable
singleton_class.delegate [*important_methods] => :__getobj__
__setobj__(obj)
end
end
But all of this is using SimpleDelegator and if you're not actually using method_missing, you can cut that out (assuming you've calculated the important_methods part correctly:
require 'forwardable'
class FooCollection
include ActiveModel::Model
def self.build(hash, obj)
instance = new(hash)
instance.set_object(obj)
instance
end
def set_object(obj)
important_methods = obj.methods(false)# - self.class.instance_methods
singleton_class.extend SingleForwardable
singleton_class.delegate [*important_methods] => :__getobj__
__setobj__(obj)
end
def __getobj__
#obj
end
def __setobj__(obj)
__raise__ ::ArgumentError, "cannot forward to self" if self.equal?(obj)
#obj = obj
end
end
If you do that, however, it kills the use of super so you can't override a method defined on your wrapped object and call super to get the original value like you can with method_missing used in SimpleDelegator.
I wrote casting to add behavior to objects without worrying about wrappers. You can't override methods with it, but if all you're doing is adding new behaviors and new methods, then it will be much simpler to use by just adding a bucket of methods to an existing object. It's worth checking it out. I gave a presentation about the delegate and forwardable libraries at RubyConf 2013

Related

"class<<self" vs "extend ClassMethods"

2 main techniques for creating class methods (without the obvious "def self.method") are:
Defining them in "class << self" block
Defining ClassMethod module and extending it later
I personally prefer second way, seems cleaner. Does anyone has any reason to prefer one technique over the other?
There's also "class_method" method, but I never used it, it has quite complex implementation and seem to do a lot more than previous 2.
self.method is the simplest option when you just need to create one method without dependencies or related logic.
class << self allows you to do far more than define methods on the metaclass. This is useful when you're defining methods which need to work with other parts of the metaclass (eg. aliasing existing method names).
For instance:
class Logger
class << self
attr_reader :payload
def log(message)
#payload = message
end
end
end
The module extension method comes in handy for method reuse and to group multiple coherent methods.
For instance:
module QueryMethods
def find
end
def where
end
end
module FactoryMethods
def build
end
def create
end
end
class BusinessModel
extend QueryMethods
extend FactoryMethods
end
First, the class << foo syntax opens up foo's singleton class (eigenclass). This allows you to specialise the behaviour of methods called on that specific object.
a = 'foo'
class << a
def inspect
'"bar"'
end
end
a.inspect # => "bar"
a = 'foo' # new object, new singleton class
a.inspect # => "foo"
class << self opens up self's singleton class, so that methods can be redefined for the current self object (which inside a class or module body is the class or module itself). Usually, this is used to define class/module ("static") methods
class << self is good at keeping all of your class methods in the same block. If methods are being added in def self.method from then there's no guarantee (other than convention and wishful thinking) that there won't be an extra class method tucked away later in the file.
def self.method is good at explicitly stating that a method is a class method, whereas with class << self you have to go and find the container yourself.
Which of these is more important to you is a subjective decision, and also depends on things like how many other people are working on the code and what their preferences are.
Pros of “class << self” style

Why can some classes and/or methods be called without instances of their parent class?

I'm near the finish of the Ruby track in Code Academy, and I'm curious about a peculiar thing: I was under the impression that a class is a repository of constants, methods, etc... and that in order to access most of them, you would first need to create an instance of that class or in some cases the methods of themselves can be invoked (as in they are all technically part of the global object). And then I saw something like this:
#Worked
Time.now
I understood as this as the method [now] of instance of class [Time] being invoked. I then tried to invoke the method on its own:
#Failed
now
and that failed, and I assumed that while a method can be created in the general scope [as part of the global object], if it relies on initialized variables of "parent" class, it cannot be called on its own, because it would not know which object to search for those initialized variables. Following that I created a test class:
class Clock
def initialize
#hours = 1
#minutes = 30
end
def showTime
puts "The time is: #{#hours}:#{#minutes}"
end
end
#this worked
watch = Clock.new
watch.showTime
#this failed
showTime
I then just created a basic method (assuming it's in the global level)
def mymethod
puts "The mighty METHOD!"
end
#Works
mymethod
and calling this method the way I did, without referencing the global object worked. So... the questions I have are as follows:
How can [Time.now] be called in this fashion? Shouldn't there be an instance of Time first created?
Why can't I call the method [now] on its own? Am I right that it relies on resources that it cannot find when called this way?
Why could I not call the method showTime on its own? But if I define any method on the "global" level I can access it without referencing the global object
First of all, your intuition is correct.
Every methods must be an instance method of some receiver.
Global methods are defined as private instance methods on Object class and hence seem to be globally available. Why? From any context Object is always in the class hierarchy of self and hence private methods on Object are always callable without receiver.
def fuuuuuuuuuuun
end
Object.private_methods.include?(:fuuuuuuuuuuun)
# => true
Class methods are defined as instance methods on the "singleton class" of their class instance. Every object in Ruby has two classes, a "singleton class" with instance methods just for that one single object and a "normal class" with method for all objects of that class. Classes are no different, they are objects of the Class class and may have singleton methods.
class A
class << self # the singleton class
def example
end
end
end
A.singleton_class.instance_methods.include?(:example)
# => true
Alternative ways of defining class methods are
class A
def self.example
end
end
# or
def A.example
end
Fun fact, you can define singleton methods on any object (not just on class objects) using the same syntax def (receiver).(method name) as follows
str = "hello"
def str.square_size
size * size
end
str.square_size
# => 25
"any other string".square_size
# => raises NoMethodError
Some programming language history — Singleton classes are taken from the Smalltalk language where they are called "metaclasses". Basically all object-oriented features in Ruby (as well as the functional-style enumerators on Enumerable) are taken from the Smalltalk language. Smalltalk was an early class-based object-oriented language created in the 70ies. It was also the language that invented graphical user interfaces like overlapping windows and menus et cetera. If you love Ruby maybe also take a look at Smalltalk, you might fall in love yet again.
This is known as a class method. If CodeAcademy didn't cover it, that's a shame. Here's some examples:
# basic way
class Foo
def self.bar; :ok; end
end
Foo.bar # => :ok
# alternate syntax
class Foo
class << self
def bar; :ok; end
end
end
# alternate syntax, if Foo class already exists
def Foo.bar; :ok; end
# alternate approach if Foo class already exists
Foo.class_exec do
def bar; :ok; end
end
# to define a class method on an anonymous 'class' for a single instance
# you won't need to use this often
Foo.new.singleton_class.class_exec do
def bar; :ok; end
end
# to define a class method on an instance's actual class
Foo.new.class.class_exec do
def bar; :ok; end
end
Another way to get class methods is to extend a module.
module FooMethods
def bar; :ok; end
end
module Foo
extend FooMethods
end
Foo.bar # => :ok
Note that with Modules, the methods are always defined as instance methods. This way they can be either extended into class scope or included into instance scope. Modules can also have class methods, using the exact same syntax / examples as shown above with classes. However there's not such as easy to load a module's class methods via include or extend.
How can [Time.now] be called in this fashion? Shouldn't there be an
instance of Time first created?
The Time.now method is a class method, not an instance method and therefore can be called directly on the Time class rather than an instance of it Time.new
Class methods are defined on the class themselves using the self keyword:
class Time
def self.now
# code
end
end
Time.now # works
Why can't I call the method [now] on its own? Am I right that it
relies on resources that it cannot find when called this way?
When you call a method "on its own" you're actually implicitly calling it on self:
self.now
The above is the same as just doing:
now
Why could I not call the method showTime on its own? But if I define
any method on the "global" level I can access it without referencing
the global object
You defined the showTime method on a specific class so you have to send that method to that class. When you define a method in the "global" scope you're implicitly defining it on self and the subsequent call to mymethod is actually self.mymethod so it will work.
Time.now is a class method.
To define a class method, you need to define the method with self. : def self.method_name
class Clock
#hours = 1
#minutes = 30
def self.showTime
puts "The time is: #{#hours}:#{#minutes}"
end
end
Clock.showTime
#=> The time is: 1:30
If you want to call now on its own, you can do so inside Time class :
class Time
puts now
#=> 2017-01-19 22:17:29 +0100
end

Using extend self in module

Before voting for closing due to question duplication I want to say that my question is really simple one (not asked in above mentioned questions).
There are two modules, one defines module method using extend self, another defines mixin method.
module A
extend self
def module_a_meth
"Called module_a_meth"
end
end
module B
def module_b_meth
"Called module_b_meth"
end
end
There is a class, where I both include and extend these modules:
class Test
include A
extend A
include B
extend B
end
When we includeing module, its methods become class' instance methods, when extending - class methods.
Question:
it doesn't matter for class, if methods in module defined as module methods or mixin methods, right? I mean, when included - EVERY method (either module methods or mixin methods) become instance methods, and when extended - either become class methods.
If I'm wrong - where is the difference?
obj = Test.new
puts obj.module_a_meth
puts obj.module_b_meth
puts Test.module_a_meth
puts Test.module_b_meth
#=> Called module_a_meth
#=> Called module_b_meth
#=> Called module_a_meth
#=> Called module_b_meth
EDIT
Please start your answer with Yes or No, since my question implies this type of answer :).
Regardless of whether you are using extend or include you are always copying over instance methods. The difference is where those instance methods live.
When you call Class#include you are "copying" all of the instance methods in the module to be instance methods in the class. It's similar to how inheritance work, and if you call Class#ancestors you'll see the module there.
When you call Object#extend you are copying all of the instance methods of the module to the object's singleton class. This is a class reserved just for this object instance that is created at runtime. This is how you get "class methods" (e.g. MyClass.hello_world); by adding them to the class's singleton. You can also do things like extend a particular object instance (e.g. s = String.new; s.extend(SomeModule); s.hello_world)
There are some other differences too. The context binding is different depending on whether you use extend or include. extend doesn't cause the module to show up in the ancestor chain while include does.
When trying to add both "class" and instance methods, one common pattern you'll see is doing things like this which uses the included callback to extend the base class with a ClassMethods module:
module MyModule
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def hello_world
end
end
end
ActiveSupport::Concerns also abstracts this pattern allowing you to add both instance and "class" methods in one call.
I personally prefer having modules only work with instance methods and using singleton methods (e.g. def self.my_method) to have scoped methods (sort of like how you would use private methods). This allows consumers to use either extend or include however they want and have it work as expected.
I'm not sure if that answers your question or not, but there's some info for you
Let's look at this in steps.
module A
puts "self = #{self}"
extend self
def module_a_meth
"Called module_a_meth"
end
end
class Test
end
Test.include A
#-> self = Test
Test.instance_methods.include?(:module_a_meth)
#=> true
Test.methods.include?(:module_a_meth)
#=> false - no class method
So include includes :module_a_meth as an instance method. As self is Test, the line:
extend self
is equivalent to:
extend Test
which of course makes no reference to the module. Now we extend and obtain the expected result:
Test.extend A
#=> true
Test.methods.include?(:module_a_meth)
#=> true
including and extending B is normal:
module B
def module_b_meth
"Called module_b_meth"
end
end
Test.include B
Test.instance_methods.include?(:module_b_meth)
#=> true
Test.extend B
Test.methods.include?(:module_b_meth)
#=> true
First of all, regarding the actual question: No :).
Class (or any other object) cares how methods are defined in a module you're including. Basically, method's in a module you've described are defined as mixin methods. extend self doesn't redefine methods to be a module methods, but, basically, duplicates them to both contexts.
It's pretty much a question about how does extend work, it's just a tricky case.
First of all, think of extend as an include in object's singleton class context. Those two definitions are equal:
module SomeModule
def hi
'hi'
end
end
class SomeClass
extend SomeModule
end
class SomeClass
class << self
include SomeModule
end
end
Given that, by using extend self in a module you're saying: Take all of the mixin methods I've defined and extend module's singleton class with them. This magic is a result of ruby's nature: an ability to re-open any definition. Here's how a verbose version of extend self would look like:
module Module1
def hi
'hi'
end
end
module Module1
extend Module1 # which is self
#### now "hi" is both here:
# def hi; end
#### and here:
# class << self; def hi; end
end
Module1.hi # => 'hi'
class SomeClass; include Module1; end;
SomeClass.new.hi # => 'hi'
__ EDIT __
Just a quick proof that object cares about how methods in a module are defined:
module SomeModule
def self.hi
'hi'
end
end
object = 'some string'
class << object
include SomeModule
end
object.hi # => NoMethodError: undefined method

Delegator through BasicObject transparency

Context: I am trying to put up a Decorator pattern in Ruby. As a Decorator should delegate all unknown methods to the underlying objects, I used the Delegator class.
I could have used SimpleDelegator but I wanted to fully understand what I was doing.
So the basic code I came out with was :
class Decorator < Delegator
def initialize(component)
super
#component = component
end
def __setobj__(o); #component = o end
def __getobj__; #component end
def send(s, *a); __send__(s, *a) end
end
Which is ~exactly the same as the implementation of SimpleDelegator. Seems good.
But the thing I did not want was for the code handling the Decorator to know it is manipulating a Decorator. I want full transparency.
At this moment Decorator.new(Object.new).class returned Decorator
So I tinkered a bit and came up with this :
class Decorator < Delegator
undef_method :==
undef_method :class
undef_method :instance_of?
# Stores the decorated object
def initialize(component)
super
#component = component
end
def __setobj__(o); #component = o end
def __getobj__; #component end
def send(s, *a); __send__(s, *a) end
end
This way, I can safely use class or instance_of? on my Decorated object, it will send the method to the underlying object via method_missing (which is implemented by Delegator).
The thing is : I don't understand why I had to undef :class and :instance_of?. I can see that BasicObject defines :== so I had to undefine it but what about those two ?
I looked at the BasicObject documentation and a bit in the C code but did not find anything. I looked the same at the Delegator documentation and code, and did not find anything either.
It seems Delegator include the Kernel module, but Kernel#class or Kernel#instance_of? don't exist.
Where those two method came from ? Why did I need to undefine them if they were not implemented at all ?
I guess I must be missing something about Ruby's object model or something.
Thanks.
You can get a hint by inspecting the method:
Decorator.instance_method(:class)
# => #<UnboundMethod: Decorator(#<Module:0x00000102137498>)#class>
The method's owner is Decorator but actually defined in #<Module:0x00000102137498>. So there is an anonymous module that defines it. Interesting... let's look at:
Decorator.ancestors
# => [Decorator, Delegator, #<Module:0x00000102137498>, BasicObject]
There's that module again, between Delegator and BasicObject. So Delegator doesn't directly derive from BasicObject. If you look at the source code in lib/delegate.rb you find:
class Delegator < BasicObject
kernel = ::Kernel.dup
kernel.class_eval do
[:to_s,:inspect,:=~,:!~,:===,:<=>,:eql?,:hash].each do |m|
undef_method m
end
end
include kernel
# ...
So a copy of the Kernel module is made, which doesn't have to_s, inspect, etc... but still has class and instance_of?. It's included in Delegator and that's where they come from.
Note that Object inherits the same methods by including the Kernel module (but it includes the full module, of course):
42.method(:class) # => #<Method: Fixnum(Kernel)#class>
This is stated in the Object doc:
Object mixes in the Kernel module, making the built-in kernel
functions globally accessible. Although the instance methods of Object
are defined by the Kernel module, we have chosen to document them here
for clarity.

Create property as method on class in Ruby

Rails has these cool properties that seem to be actually methods. For example:
class SomeController < ApplicationController
before_filter :authenticate!
end
What are these actually called and how would you create your own? For example, in one of my models I want to be able to have a dynamic property that selects an internal method for processing some results:
class MyModel < ActiveRecord::Base
active_method :some_class_method
end
How would I set this up so I can set active_method like that and be able to access the active_method symbol as an instance var?
Edit for elaboration:
So give this starter below, I need to figure out how to define "selected_method" so that it defines a accessor or instance variable so "called_selected_method" calls "method_b".
class MyClass
selected_method :method_b
def call_selected_method
end
private
def method_a
puts 'method_a'
end
def method_b
puts 'method_b'
end
end
c = MyClass.new
c.call_selected_method # should put 'method_b'
It's actually just a method call to a method defined on the class. before_filter is provided by a ruby Module, which is mixed in to ActionController.
Creating your own methods similar to before_filter is as easy as:
Define a class method on your Class
Call that method in any concrete implementations of your class.
Some example code:
class MyClass
class << self
def some_function(*args)
# your code here
end
end
some_function "foo"
end
If you wanted to abstract it further, you can put the class method in to a Module, and then include that module in to your class(es).
UPDATE:
In relation to your asking of how to get a call of some_function to set an instance variable on your class, you can't, as class methods cannot affect specific instances of that class.
I have to wonder, though... you're writing a method that will just act as a proxy to your other method, and would be hard-coded in to the class definition. That offers no benefit to you, and would just make your code redundantly complicated.

Resources