Class variables in class_eval

I’m confused, to say the least! I’m setting up caches on objects using a
class variable. It all works well until I try to extract it out to a
module
to mixin to other objects:

module HostBasedCache
def setup_cache(method, &method_proc)
@@cache_method = method_proc if block_given?
class_eval <<-METHOD
def self.#{method}(param)
#some stuff not relevant
puts @@cache_method.call(param)
#some stuff not relevant
end
METHOD
end
end

class MyObject

extend HostBasedCache
setup_cache(:find_with_roles) do |id|
User.find_by_id(id, :select => “users.id, roles.id”, :include => [
:roles
])
end

end

Unfortunately, when calling find_with_roles I’m told that @@cache_method
isn’t defined. Setting @@cache_method explicitly in MyObject (rather
than the
setup_cache) call makes everything work. I must be missing some scoping
problem - can anyone explain this to me, please?

Thanks a lot,

Mark

On 6/19/07, Mark S. [email protected] wrote:

I’m confused, to say the least! I’m setting up caches on objects using a
class variable.
My rule of thumb is, Do Not Use Class Variables, use Class Instance
Variables

It all works well until I try to extract it out to a module

end

end

end

Unfortunately, when calling find_with_roles I’m told that @@cache_method
isn’t defined. Setting @@cache_method explicitly in MyObject (rather than the
setup_cache) call makes everything work. I must be missing some scoping
problem - can anyone explain this to me, please?

Look at this slightly adapted code just using Class Instance Variables.
Does this solve your problem?

-------------------------8<----------------------------

module HostBasedCache

def setup_cache(method, &method_proc)
  @cache_method = method_proc if block_given?
  class_eval <<-METHOD
    def self.#{method}(param)
    #some stuff not relevant
      puts @cache_method.call(param)
    #some stuff not relevant
    end
  METHOD
end

end

class MyObject

extend HostBasedCache
setup_cache(:find_with_roles) do |id|

User.find_by_id(id, :select => “users.id, roles.id”, :include => [

:roles ])
puts "Hi there " << id.to_s
end

end

MyObject.find_with_roles( 42 )

-------------------------8<----------------------------
Cheers
Robert

Hi –

On Tue, 19 Jun 2007, Mark S. wrote:

On Tue, Jun 19, 2007 at 09:05:38PM +0900, Robert D. wrote:

Look at this slightly adapted code just using Class Instance Variables.
Does this solve your problem?

It does! I wasn’t aware that there are class instance variables as well as
class variables.

Anything that can be ‘self’ can have instance variables :slight_smile:

David

Is there a significant performance difference between these two ways to
call a method?
(a) Define the method in a module, then call it with
MODULE_NAME::METHOD_NAME
(b) Define the method in a class, then instantiate an object from the
class, then call the method with OBJECT_REFERENCE_VAR.METHOD_NAME

Purely for the convenience in naming methods, I’d love to do everything
in classes, but I can’t help suspecting that performance will suffer
somewhat if I instantiate objects when not really necessary.

On Tue, Jun 19, 2007 at 09:05:38PM +0900, Robert D. wrote:

Look at this slightly adapted code just using Class Instance Variables.
Does this solve your problem?

It does! I wasn’t aware that there are class instance variables as well
as
class variables.

Appreciated, thank you very much!

Mark

John N. Joyner wrote:

Is there a significant performance difference between these two ways to
call a method?
(a) Define the method in a module, then call it with
MODULE_NAME::METHOD_NAME
(b) Define the method in a class, then instantiate an object from the
class, then call the method with OBJECT_REFERENCE_VAR.METHOD_NAME

Purely for the convenience in naming methods, I’d love to do everything
in classes, but I can’t help suspecting that performance will suffer
somewhat if I instantiate objects when not really necessary.
Apologies! I had meant to start a new thread.

  • John

On Jun 23, 2007, at 10:28 AM, John Joyner wrote:

everything
in classes,

IMO that’s not a good reason. The main reason for grouping methods
into classes is to provide behavior to a set of objects where each
object maintains it own individual state. Another is that classes
support inheritance and modules don’t. In particular, every class you
define inherits great deal of commonly needed behavior from Object.

Also, I don’t see why naming is more convenient in classes than in
modules.

but I can’t help suspecting that performance will suffer
somewhat if I instantiate objects when not really necessary.

If you suspect this, test your hypothesis with the Benchmark library.

Apologies! I had meant to start a new thread.

Regards, Morton

On 6/22/07, John N. Joyner [email protected] wrote:

Is there a significant performance difference between these two ways to
call a method?
(a) Define the method in a module, then call it with
MODULE_NAME::METHOD_NAME

You don’t need to use ::, that’s mostly meant for constants and nested
class seperation.

Instead, do:

module MyModule

module_function

def whatever

end

end

you can also of course pass specific method names to module_function.

This lets you do:

MyModule.whatever

(b) Define the method in a class, then instantiate an object from the
class, then call the method with OBJECT_REFERENCE_VAR.METHOD_NAME

You can also make class methods.

class A
def self.whatever
end
end

A.whatever

This is useful when an object is stateful but doesn’t need to have
instances (or has behaviour at the class level and instance level)

Finally, to answer you question about performance, a big difference is
that modules can’t be instantiated. But I doubt that they will be
much less heavyweight than a class that you don’t create instances of,
or use just one instance. You’ll want to use profile memory usage to
be sure.

On 6/23/07, Robert D. [email protected] wrote:

extend M

C.my_fancy_method
--------------------- >8 -------------------

this might indeed be a useful pattern which is underused - citation David Black.

sure. It’s fairly OT from what was asked for though, but while we’re
here

I rarely find myself needing ‘just’ class methods, and I don’t like
doing a seperate call to mix them in, so i’d typically do something
like

module M

module ClassMethods
def whatever; end
end

def self.included(base)
base.extend(ClassMethods)
end

end

class C
include M
end

But if all you need is the class methods, and don’t mind using extend,
what you suggested works fine.

On 6/23/07, Gregory B. [email protected] wrote:
And to round up the picture and to keep David happy :wink:

--------------------- 8< ------------------
module M
def my_fancy_method

class C
extend M

C.my_fancy_method
--------------------- >8 -------------------

this might indeed be a useful pattern which is underused - citation
David Black.

Cheers
Robert