Adding in class attribute with a Module

Is it possible to add class attributes (cattr_accessor) using a module?
If so could you give an example?

Many thanks.

···

--
Posted via http://www.ruby-forum.com/.

Worked pretty much how I expected it to:

module TestModule
  attr_accessor :attribute
end

=> nil

class TestClass
  include TestModule
end

=> TestClass

tc = TestClass.new

=> #<TestClass:0x2dc17c8>

tc.attribute = "Hello, world"

=> "Hello, world"

puts tc.attribute

Hello, world
=> nil

Farrel

Hi --

···

On Mon, 10 Apr 2006, kris wrote:

Is it possible to add class attributes (cattr_accessor) using a module?
If so could you give an example?

There's no cattr_accessor method in Ruby. If you've written one, or
are using one written by someone else, you'll have to show us what it
does before we can tell you how to use it :slight_smile:

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!

I think the OP wanted class level attribute accessor, not instance level accessors. You showed how-to do instance level accessors:

  zdennis@lima:~$ irb
  irb(main):001:0> class A ; attr_accessor :foo ; end
  => nil
  irb(main):002:0> a = A.new
  => #<A:0xb7cdc8a8>
  irb(main):003:0> a.foo = 5
  => 5
  irb(main):004:0> a.foo
  => 5

but using mixins:

  irb(main):007:0> module M ; attr_accessor :foo ; end
  => nil
  irb(main):008:0> class B ; include M; end
  => B
  irb(main):009:0> b = B.new
  => #<B:0xb7cb20a4>
  irb(main):010:0> b.foo = 5
  => 5
  irb(main):011:0> b.foo
  => 5

I think OP wants the equivalent of:

  irb(main):012:0> class C ; class << self ; attr_accessor :foo ; end ; end
  => nil
  irb(main):013:0> C.foo = 5
  => 5
  irb(main):014:0> C.foo
  => 5

But with using mixins. The OP should just open up the instance of the class and include the module there. For example:

  irb(main):015:0> class D
  irb(main):016:1> class << self
  irb(main):017:2> include M
  irb(main):018:2> end
  irb(main):019:1> end
  => #<Class:D>
  irb(main):020:0> D.foo = 99
  => 99
  irb(main):021:0> D.foo
  => 99

Zach

Farrel Lifson wrote:

···

Worked pretty much how I expected it to:

module TestModule
attr_accessor :attribute
end

=> nil

class TestClass
include TestModule
end

=> TestClass

tc = TestClass.new

=> #<TestClass:0x2dc17c8>

tc.attribute = "Hello, world"

=> "Hello, world"

puts tc.attribute

Hello, world
=> nil

Farrel

Thanks very much for all the examples. I think I need to clarify,
basically I have a base class called "System" from which all my models
decend. This class has a class attribute called user_id which is set to
the current_user every request by application.rb:

BASE MODEL CLASS
class System < ActiveRecord::Base
  cattr_accessor :user_id
end

MODEL
class Documents < System
  # this model know the current user's id
end

APPLICATION CONTROLLER
class ApplicationController < ActionController::Base
   before_filter :set_user

  # set class attribute for all models
  def set_user
    if logged_in?
      System.user_id = current_user.id
    end
  end
end

By using a class attribute instead of a instance attribute I can set the
current user id for all models at once.

This works but I want to use a module/mixin instead of inheritance.

Many thanks again.

PS. I didnt write cattr_accessor. I'm using Rails but I dont think it is
opart of that?

unknown wrote:

···

Hi --

On Mon, 10 Apr 2006, kris wrote:

Is it possible to add class attributes (cattr_accessor) using a module?
If so could you give an example?

There's no cattr_accessor method in Ruby. If you've written one, or
are using one written by someone else, you'll have to show us what it
does before we can tell you how to use it :slight_smile:

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!
Ruby for Rails

--
Posted via http://www.ruby-forum.com/\.

There's an easier way:

class D
extend M
end

or

class D;end
D.extend M

There are other options (e.g. use #included) but it depends what the
OP really wants.

Kind regards

robert

···

2006/4/10, zdennis <zdennis@mktec.com>:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I think the OP wanted class level attribute accessor, not instance level accessors. You showed how-to do instance level accessors:

  zdennis@lima:~$ irb
  irb(main):001:0> class A ; attr_accessor :foo ; end
  => nil
  irb(main):002:0> a = A.new
  => #<A:0xb7cdc8a8>
  irb(main):003:0> a.foo = 5
  => 5
  irb(main):004:0> a.foo
  => 5

but using mixins:

  irb(main):007:0> module M ; attr_accessor :foo ; end
  => nil
  irb(main):008:0> class B ; include M; end
  => B
  irb(main):009:0> b = B.new
  => #<B:0xb7cb20a4>
  irb(main):010:0> b.foo = 5
  => 5
  irb(main):011:0> b.foo
  => 5

I think OP wants the equivalent of:

  irb(main):012:0> class C ; class << self ; attr_accessor :foo ; end ; end
  => nil
  irb(main):013:0> C.foo = 5
  => 5
  irb(main):014:0> C.foo
  => 5

But with using mixins. The OP should just open up the instance of the class and include the module there. For example:

  irb(main):015:0> class D
  irb(main):016:1> class << self
  irb(main):017:2> include M
  irb(main):018:2> end
  irb(main):019:1> end
  => #<Class:D>
  irb(main):020:0> D.foo = 99
  => 99
  irb(main):021:0> D.foo
  => 99

cattr_accessor is a Railsism. It is not part of standard Ruby.

I'm undecided whether it should be or not, but it is potentially very useful.

You will need to add an "included" hook. See "ri Module#included".

-austin

···

On 4/10/06, kris <krisleech@interkonect.com> wrote:

PS. I didnt write cattr_accessor. I'm using Rails but I dont think it is
opart of that?

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

Robert Klemme wrote:

There's an easier way:

class D
extend M
end

or

class D;end
D.extend M

Right you are. thx Robert!

Zach

Hi --

···

On Mon, 10 Apr 2006, Austin Ziegler wrote:

On 4/10/06, kris <krisleech@interkonect.com> wrote:

PS. I didnt write cattr_accessor. I'm using Rails but I dont think it is
opart of that?

cattr_accessor is a Railsism. It is not part of standard Ruby.

I'm undecided whether it should be or not, but it is potentially very useful.

If it ever is, I think it needs a new name. It's a wrapper for class
variables, but class variables, in my view, are not really suitable
for implementing "attributes", because they are not uniquely
associated with one object. I don't like the sprawl of the concept of
an "attribute" of a class-hierarchy-plus-instances-of-those-classes.

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!

Its very useful, the trouble is the models can't see the session (for
good reasons) but they need information from the controller level, such
as current logged in user, and passing it every time you create a model
is a pain and can easily be forgottern. Using cattr_accessor you can set
and forget.

Is this maybe a question better asked on the Rails forum?

Austin Ziegler wrote:

···

On 4/10/06, kris <krisleech@interkonect.com> wrote:

PS. I didnt write cattr_accessor. I'm using Rails but I dont think it is
opart of that?

cattr_accessor is a Railsism. It is not part of standard Ruby.

I'm undecided whether it should be or not, but it is potentially very
useful.

You will need to add an "included" hook. See "ri Module#included".

-austin

--
Posted via http://www.ruby-forum.com/\.

Is there an easy way to extend classes with both class and object
methods at the same time?

  module M
    def self.create
      # would do something special here
      new
    end
    def objmethod
    end
  end

  class A
    extend M
  end

  a.create # <-- nope, doesn't work

I sometimes have a number of classes that I want to share
implementation, but that don't have an "isa" relationship. Modules are
great for this, but when that implementation includes both object and
class methods, I'm not sure what to do.

Sam

···

On Mon, Apr 10, 2006 at 08:57:04PM +0900, Robert Klemme wrote:

There's an easier way:

class D
extend M
end

or

class D;end
D.extend M

dblack@wobblini.net wrote:

Hi --

PS. I didnt write cattr_accessor. I'm using Rails but I dont think it is
opart of that?

cattr_accessor is a Railsism. It is not part of standard Ruby.

I'm undecided whether it should be or not, but it is potentially very useful.

If it ever is, I think it needs a new name. It's a wrapper for class
variables, but class variables, in my view, are not really suitable
for implementing "attributes", because they are not uniquely
associated with one object.

But isn't a class an instance of Class?

Foo = Class.new # instance object of class Class
f = Foo.new # instance object of class Foo

I don't like the sprawl of the concept of
an "attribute" of a class-hierarchy-plus-instances-of-those-classes.

The 'attribute' concept is messy as it is, but this class use seems to be a natural extension of the 'methods that get/set an object variable of the same name' idea.

···

On Mon, 10 Apr 2006, Austin Ziegler wrote:

On 4/10/06, kris <krisleech@interkonect.com> wrote:

--

James Britt

“Design depends largely on constraints.”
  — Charles Eames

If it ever is, I think it needs a new name. It's a wrapper for class
variables, but class variables, in my view, are not really suitable
for implementing "attributes"...

I am using the as attributes, but a class variable would be better.
And if they where var's you could add getter/setter methods to make them
look like attributes.

Inside a model:

  self.created_by = System.current_user.id
  self.save

It would be better if I could get rid of the System bit and just do:

  self.created_by = current_user.id

···

--
Posted via http://www.ruby-forum.com/\.

Kris wrote:

Its very useful, the trouble is the models can't see the session (for
good reasons) but they need information from the controller level, such
as current logged in user, and passing it every time you create a model
is a pain and can easily be forgottern. Using cattr_accessor you can set
and forget.

It is useful, the question is, is it useful for ruby to have this functionality in the core language.

Is this maybe a question better asked on the Rails forum?

There is a rails-aspect and a ruby-aspect to what you brought up. For the type of question you will probably get answers from
either list, although the one from the ruby list will be more ruby-specific, whereas the answer from the rails list may be more
rails framework related.

Zach

Sam Roberts wrote:

There's an easier way:

class D
extend M
end

or

class D;end
D.extend M

Is there an easy way to extend classes with both class and object
methods at the same time?

  module M
    def self.create
      # would do something special here
      new
    end
    def objmethod
    end
  end

  class A
    extend M
  end

  a.create # <-- nope, doesn't work

This is because you created the 'create' method as a class-like method on the mdoule, a module method. You need to create it as an
instance level method. It seems to do this cleanly you'd want to separate this into two modules, one for instance level methods
and one intended for class-level use:

  irb(main):017:0> module ClassLevelAddons
  irb(main):018:1> def create
  irb(main):019:2> new
  irb(main):020:2> end
  irb(main):021:1> end
  => nil
  irb(main):022:0> module InstanceLevelAddons
  irb(main):023:1> def foo
  irb(main):024:2> "bar"
  irb(main):025:2> end
  irb(main):026:1> end
  => nil
  irb(main):027:0> class A
  irb(main):028:1> extend ClassLevelAddons
  irb(main):029:1> include InstanceLevelAddons
  irb(main):030:1> end
  => A
  irb(main):031:0> A.create
  => #<A:0xb7c9dc1c>
  irb(main):032:0> A.new.foo
  => "bar"

For organizational concerns you could always let one module be in charge:

  irb(main):001:0> module M
  irb(main):002:1> module ClassLevelAddons
  irb(main):003:2> def create; new ; end
  irb(main):004:2> end
  irb(main):005:1>
  irb(main):006:1* def foo
  irb(main):007:2> "bar"
  irb(main):008:2> end
  irb(main):009:1>
  irb(main):010:1* def self.included( clazz )
  irb(main):011:2> clazz.extend( ClassLevelAddons )
  irb(main):012:2> end
  irb(main):013:1> end
  => nil
  irb(main):014:0> class A ; include M; end
  => A
  irb(main):015:0> A.create
  => #<A:0x2bfc5e8>
  irb(main):016:0> A.new.foo
  => "bar"
  irb(main):017:0>

The above lets M take care of the work, so your class doesn't have to think about it. This is the method that Robert Klemme was
refering to, Module::included

Zach

···

On Mon, Apr 10, 2006 at 08:57:04PM +0900, Robert Klemme wrote:

James Britt wrote:

I don't like the sprawl of the concept of
an "attribute" of a class-hierarchy-plus-instances-of-those-classes.

I think this is what you are referring to David, and I think it is strange to:

zdennis@lima:~$ irb
irb(main):001:0> class A
irb(main):002:1> @@myvar = 5
irb(main):003:1> class << self ; @myvar = 10 ; end
irb(main):004:1> end
=> 10
irb(main):005:0> A.instance_variables
=>
irb(main):006:0> A.class_variables
=> ["@@myvar"]
irb(main):007:0> a = class A ; class << self ; self ; end ; end
=> #<Class:A>
irb(main):008:0> a.instance_variables
=> ["@myvar"]
irb(main):009:0> a.instance_eval "@myvar"
=> 10
irb(main):010:0> A.module_eval "@@myvar"
=> 5
irb(main):011:0>

It seems like, @@myvar and @myvar should refer to the same reference point. I would expect @@ to signify a class level attribute,
which is actually an instance attribute on the class itself. In my head that makes sense.

>
The 'attribute' concept is messy as it is, but this class use seems to
be a natural extension of the 'methods that get/set an object variable
of the same name' idea.

+1

Zach

Hi --

···

On Tue, 11 Apr 2006, James Britt wrote:

dblack@wobblini.net wrote:

Hi --

On Mon, 10 Apr 2006, Austin Ziegler wrote:

On 4/10/06, kris <krisleech@interkonect.com> wrote:

PS. I didnt write cattr_accessor. I'm using Rails but I dont think it is
opart of that?

cattr_accessor is a Railsism. It is not part of standard Ruby.

I'm undecided whether it should be or not, but it is potentially very useful.

If it ever is, I think it needs a new name. It's a wrapper for class
variables, but class variables, in my view, are not really suitable
for implementing "attributes", because they are not uniquely
associated with one object.

But isn't a class an instance of Class?

Of course, but class variables aren't per-class, so using them to
implement "attributes" of a class object doesn't make sense.

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!

I was hoping that I was missing some clever way to do it with just one
module. Guess not. But the self.included hook is a good idea. The two
modules become an implementation detail, and thats good enough.

Thanks,
Sam

···

On Tue, Apr 11, 2006 at 02:46:24AM +0900, zdennis wrote:

> Is there an easy way to extend classes with both class and object
> methods at the same time?

  irb(main):010:1* def self.included( clazz )
  irb(main):011:2> clazz.extend( ClassLevelAddons )
  irb(main):012:2> end
  irb(main):013:1> end

The above lets M take care of the work, so your class doesn't have to
think about it. This is the method that Robert Klemme was refering to,
Module::included

"It is useful, the question is, is it useful for ruby to have this
functionality in the core language."

I have only really used Ruby in the context of Rails so couldn't really
answer that one, but with regards to Model-Controller-View, which is not
just a concept used by Rails it is very useful.

I can see class attributes/var's being very useful in general though.

···

--
Posted via http://www.ruby-forum.com/.

Hi --

James Britt wrote:

Actually I wrote this bit :slight_smile:

I don't like the sprawl of the concept of
an "attribute" of a class-hierarchy-plus-instances-of-those-classes.

I think this is what you are referring to David, and I think it is strange to:

zdennis@lima:~$ irb
irb(main):001:0> class A
irb(main):002:1> @@myvar = 5
irb(main):003:1> class << self ; @myvar = 10 ; end
irb(main):004:1> end
=> 10
irb(main):005:0> A.instance_variables
=>
irb(main):006:0> A.class_variables
=> ["@@myvar"]
irb(main):007:0> a = class A ; class << self ; self ; end ; end
=> #<Class:A>
irb(main):008:0> a.instance_variables
=> ["@myvar"]
irb(main):009:0> a.instance_eval "@myvar"
=> 10
irb(main):010:0> A.module_eval "@@myvar"
=> 5
irb(main):011:0>

It seems like, @@myvar and @myvar should refer to the same reference
point. I would expect @@ to signify a class level attribute, which
is actually an instance attribute on the class itself. In my head
that makes sense.

I disagree. If @@myvar is just the instance variable @myvar of some
class object, then it would presumably have exactly the same scope as
that instance variable -- in which case, there's no reason for it to
exist. If it's visible to other objects (i.e., when 'self' is
something other than the class object), then it isn't the same as an
instance variable anyway.

I wouldn't want to see any crossover between class variables and
instance variables. A class object's instance variables are strictly
the business of the class in its "civilian" capacity as a regular
object. Class variables, on the other hand, are a special case.
The two things are really not related conceptually at all.

David

···

On Tue, 11 Apr 2006, zdennis wrote:

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!