Got to be a better way to code class variables

I’m trying to set up an object with overridable defaults, so it will act
like this:

s1 = Smee.new
=> #<Smee:0x102007618 @middle=nil, @front=nil, @back=nil>

s1.middle = ‘hi’
=> “hi”

s1
=> #<Smee:0x102007618 @middle=“hi”, @front=nil, @back=nil>

Smee.front = “O”
=> “O”

s2 = Smee.new
=> #<Smee:0x101ffdbb8 @middle=nil, @front=“O”, @back=nil>

s1 => #<Smee:0x102007618 @middle=“hi”, @front=“O”, @back=nil>
Smee.middle = “utu”
=> “utu”

s1.middle
=> “hi”

s2.middle
=> “utu”

So I can set the properties of an instance of Smee, but if I don’t set
them, or if I set them back to nil, then the corresponding values that I
set on the class will take their place.

This is the closest thing I’ve gotten so far and it seems ludicrously
clunky.

class Smee
attr_writer :front, :middle, :back

class << self
  attr_accessor :front, :middle, :back
end

def front
  @front || Smee.front
end

def middle
  @middle || Smee.middle
end

def back
  @back || Smee.back
end

end

I’d like to have other methods that worked the same on the class and the
instance, but the only way I can figure out how is to type every single
method twice. There has got to be some terribly clever ruby-esque way
of including instance methods as class methods or vice versa, no?

Dave H. wrote:

s2 = Smee.new

  @front || Smee.front

I’d like to have other methods that worked the same on the class and the instance, but the only way I can figure out how is to type every single method twice. There has got to be some terribly clever ruby-esque way of including instance methods as class methods or vice versa, no?

Some metaprogging…

module Overridable
def overridable(*names)
names.each do |name|
attr_writer name
(class << self; self; end).class_eval do
attr_accessor name
end
class_eval %{
def #{name}
@#{name} || self.class.#{name}
end
}
end
end
end

class Smee
extend Overridable

overridable :front
self.front = 12
end

sm0 = Smee.new

sm1 = Smee.new
sm1.front = 56

p sm0.front, sm1.front

2010/6/22 Joel VanderWerf [email protected]

Dave H. wrote:

I’m trying to set up an object with overridable defaults, so it will act like this:

Question is, do you really need this:

I’d like to have other methods that worked the same on the class and the instance, but the only way I can figure out how is to type every single method twice. There has got to be some terribly clever ruby-esque way of including instance methods as class methods or vice versa, no?

? You only need setters on the class if you want to be able to modify
the default. If not, you can use a different approach (see below).

Some metaprogging…

Some more metaprogramming:

Kind regards

robert

Dave H. wrote:

class Smee
extend SmeeCore # including it for the class
include SmeeCore # including it for the instances
end

If you want the extend to happen automatically when you include a
module, you can define an included method on M that does it:

module M
def foo
“FOO”
end
def self.included©
c.extend M
end
end

class C
include M
end

p C.foo
p C.new.foo

On Jun 22, 2010, at 1:06 , Robert K. wrote:

2010/6/22 Joel VanderWerf [email protected]

Dave H. wrote:

I’m trying to set up an object with overridable defaults, so it will act like this:

Question is, do you really need this:

Good question. I’m not sure yet.

I’d like to have other methods that worked the same on the class and the instance, but the only way I can figure out how is to type every single method twice. There has got to be some terribly clever ruby-esque way of including instance methods as class methods or vice versa, no?

? You only need setters on the class if you want to be able to modify
the default. If not, you can use a different approach (see below).

What I’m trying to do is save myself a bunch of time and effort coding a
web site. The class will contain the ‘default’ web page, and then
various routines will be able to tweak the title, or the main contents,
to fit the specific page the user is on. But, I’d also like to be able
to change the ‘default’ page properties as well, as conditions warrant.
I could just store everything in some kind of cloud-y, tree-y, nest-y
sort of structure, but the class/instance structure seemed like a good
place to start.*

Then when I tried it, and ended up with rather goofy looking code, it
became an opportunity to learn more about Ruby. Playing with Joel’s code
taught me something absolutely nifty-keen: the difference between
“include” and “extend”.

I made a brief mention in my original post that I also wanted to have
some methods that would also appear on both the class and the instance.
I ended up with this solution:

module SmeeCore
def pushmepullyu
@back = @front
end
def double
@front = @front * 2
end
end

class Smee
extend SmeeCore # including it for the class
include SmeeCore # including it for the instances
end

  • I suspect I’m going to discover that the class properties are more
    global than I’d originally thought, and my instance properties are going
    to have to become a lot more sophisticated and start handling ‘regional’
    defaults: less than global, more than local.