Nubish questions about syntax and gems


#1

Hi folks.

I’m getting on really well with Ruby (I’ve not enjoyed programming this
much for ages :)) but I’ve a few (probably simple) questions I’m hoping
you might be able to help with.

  1. Is this the right way to define a method with a dynamic name?

     eval <<-EOC
       def #{method_name}
         'You called #{method_name}'
       end
     EOC
    

it seems to(?) work, but I wonder if theres a better way?

  1. I’m struggling with boolean attributes, and question marks.
    attr_accessor (etc) won’t allow me to pass those names in (I guess
    because
    they’re illegal instance var names). I tried:

    attr_accessor :is_green
    alias is_green? is_green

which works, but again it strikes me theres probably a better way that
I’ve missed.

  1. Does this

    class MyClass
    @field = “one”
    end

create a class or instance variable? And from that, does

class MyClass
  @@field = "one"
end

create a class variable on MyClass, Class, or something else? I’ve tried
a
few experiments and am more confused than when I started :slight_smile:

  1. And finally, not exactly a Ruby question, but relevant here I hope?
    With a RubyGem, is it possible to install additional files besides
    binaries? I’d like to install some manpages along with libs and bin. I
    considered misusing the C extension build, but I don’t know if it’d work
    and it seems a bit nasty…

Thanks in advance!


#2

Hi –

On Sat, 26 Nov 2005, Ross B. wrote:

Hi folks.

I’m getting on really well with Ruby (I’ve not enjoyed programming this much
for ages :)) but I’ve a few (probably simple) questions I’m hoping you might
be able to help with.

Let me zero in on one of your questions (I’m sure you’ll get multiple
replies :slight_smile:

  1. Does this

class MyClass
@field = “one”
end

create a class or instance variable?

@var is always an instance variable; @@var is always a class variable.
Let me stick to the former.

There’s a simple way to get a handle on instance variables:

At every moment during runtime, there is a current or default object
– “self”. Every time you see:

@var

you are seeing an instance variable that belongs to “self”, the
current object. There’s never any ambiguity.

“self”, in turn, can be any object, including a Class object. So,
when in doubt, ask what “self” is:

class C
puts “In class definition body scope”
puts self # C (the class object)
@var = 1
puts @var # 1

 def some_method
   puts "In instance method scope"
   puts self                       # an instance of C
   puts @var                       # nil
 end

end

c = C.new
c.some_method

As you’ll see from the output, the fact that the object C (the Class
object) assigns to its instance variable @var does not affect the @var
of an instance of C (which is uninitialized and therefore nil).

You can think of class objects as wearing two hats: the “special case”
hat of being an object factory, and the “civilian” hat of just being
an object. It’s in “civilian” mode that class objects possess
instance variables of their own, on the same footing as all other
objects.

David


#3

On Sat, 26 Nov 2005 15:24:36 -0000, David A. Black removed_email_address@domain.invalid
wrote:

“self”, in turn, can be any object, including a Class object. So,
puts self # an instance of C

You can think of class objects as wearing two hats: the “special case”
hat of being an object factory, and the “civilian” hat of just being
an object. It’s in “civilian” mode that class objects possess
instance variables of their own, on the same footing as all other
objects.

David,

That’s a good explanation, thanks for that :slight_smile: So I guess it makes sense
that I can’t access, say @var, in the class as @@var in instance
methods.
I think I was adding extra confusion for myself with that assumption.

Theres a lot of scope in these nuances, my mind is starting to work
overtime :wink:

Thanks again!


#4

On 11/26/05, Ross B. removed_email_address@domain.invalid wrote:

I hope can answer some of your questions:

  1. Is this the right way to define a method with a dynamic name?

            eval <<-EOC
              def #{method_name}
                'You called #{method_name}'
              end
            EOC
    

it seems to(?) work, but I wonder if theres a better way?

You can also use define_method, but it has limitations:

class A
def hello
puts “hello”
end
end

a = A.new
a.hello

method_name = “hello”
A.class_eval {
define_method method_name do
puts “You called #{method_name}”
end
}

a.hello
– OUTPUT –
hello
You called hello

You can’t define methods that take blocks (as you can’t pass a block
argument to a block) which means that you need to use your original
method
(eval + string) if you want to dynamically create a method that takes
a block argument.

Also note the differences in scope between using “def … end” and a
define_method + a closure.

  1. I’m struggling with boolean attributes, and question marks.
    attr_accessor (etc) won’t allow me to pass those names in (I guess because
    they’re illegal instance var names). I tried:

    attr_accessor :is_green
    alias is_green? is_green
    

which works, but again it strikes me theres probably a better way that
I’ve missed.

I can’t think of a standard way to do this that is quicker but you could
do this:

class Module
def predicate(*names)
names.each do |name|
attr_accessor name
alias_method “#{name}?”, name
end
end
end

class A
predicate :is_green
end

a = A.new
a.is_green = true
p a.is_green?
– OUTPUT –
true

     @@field = "one"
   end

create a class variable on MyClass, Class, or something else? I’ve tried a
few experiments and am more confused than when I started :slight_smile:

Just to add a comment to David’s explanation.

class A
@foo = “A’s foo”
end
p A.instance_eval { @foo }

A.instance_eval { @foo = “A’s foo again” }

class A
puts @foo
end
– OUTPUT –
A’s foo
A’s foo again

The thing to get your head around is that a class is an object in its
own right
(i.e. it is an instance of class Class).

When you open a class (with say “class A”), all the subsequent
statements
are executed in the context of that class instance object.

Regarding @@class_variables - they work a bit like globals within a
class hierarchy. For example:

class Model
@@models = []

def models
@@models
end
end

class Element < Model
@@models = [‘Hello from Element’]
end

class Schema < Model
@@models = [‘Hello from Schema’]
end

e = Element.new
p e.models
END
[“Hello from Schema”]

In other words, they do not belong to a class as such but a class
hierarchy.
(Note how setting @@models in Schema has changed it for Element).

Personally, I avoid using @@class_variables and use class instance
variables
(with accessors) instead - much less chance of accidentally stomping on
another class’s state.

Regards,

Sean


#5

Hi Sean,

On Sat, 26 Nov 2005 16:08:19 -0000, Sean O’Halpin
removed_email_address@domain.invalid
wrote:

             end

end

Ahh, I should have known to check Module :slight_smile: I’m still getting used to
methods coming from all angles.

You can’t define methods that take blocks (as you can’t pass a block
argument to a block) which means that you need to use your original
method
(eval + string) if you want to dynamically create a method that takes
a block argument.

Interesting, I didn’t know that (about block args to blocks). I guess if
I
wanted to pass a block in that way, I’d have to get a Proc for the
closure? I’ve seen code like:

some_method(proc { |s| s.do_something })

which seems a bit nasty to me.

Also note the differences in scope between using “def … end” and a
define_method + a closure.

Okay, I’m with you there.

I’ve missed.
end
true

Nice one. Gotta get used to this ‘effectively adding keywords’ thing
too.
I’ve gotten around the fact that class definitions can call methods, now
I
need to get used to it being my methods :slight_smile:

puts @foo
end
– OUTPUT –
A’s foo
A’s foo again

The thing to get your head around is that a class is an object in its
own right
(i.e. it is an instance of class Class).

This is where I am going around in circles. It’s an instance of Class,
but
it also has a class, Class. So, Class.class == Class. Is that right ?

When you open a class (with say “class A”), all the subsequent statements
are executed in the context of that class instance object.

Yes, I kind of got that, but I wasn’t thinking about it properly. I’ve
been playing around with bindings and instance_eval a bit, and the 'self

current object’ idea I have to say makes a lot of sense. I see now
though,
that theres more depth here than I first thought when it comes to the
class definition.

END
[“Hello from Schema”]

In other words, they do not belong to a class as such but a class
hierarchy

Hmm, I think I need to go back to the book on class variables. I can’t
quite see how they fit in, especially with respect to singleton class
and
stuff. Thanks for your explanation, though - it’s just me :frowning:

I’ll probably be asking again after I confuse myself some more :wink:

Cheers for your reply.


#6

Ross B. wrote:

Hi folks.

I’m getting on really well with Ruby (I’ve not enjoyed programming this
much for ages :)) but I’ve a few (probably simple) questions I’m hoping
you might be able to help with.

  1. Is this the right way to define a method with a dynamic name?

http://www.outerbody.com/ruby/ri.do?class=Module&method=define_method

  1. I’m struggling with boolean attributes, and question marks.
    attr_accessor (etc) won’t allow me to pass those names in (I guess because
    they’re illegal instance var names). I tried:

attr_accessor :is_green
alias is_green? is_green

Suggest to stick with something like this:

class Roo
attr_accessor :colour
def initialize
@colour = :white
end

def is_green?
@colour == :green
end
end

r = Roo.new
p r.is_green? #-> false
r.colour = :green
p r.is_green? #-> true

  1. Does this

Awesome answer from Dr. Black !

  1. And finally, not exactly a Ruby question, but relevant here I hope?
    With a RubyGem, […]

Pass on 4 :wink:
Hope someone else can help.

daz


#7

On Sat, 26 Nov 2005 16:14:24 -0000, daz removed_email_address@domain.invalid wrote:

http://www.outerbody.com/ruby/ri.do?class=Module&method=define_method

Cheers :slight_smile: I was missing quite a bit there…

Suggest to stick with something like this:
end

r = Roo.new
p r.is_green? #-> false
r.colour = :green
p r.is_green? #-> true

Definitely agree, I prefer to keep as much immutable as possible (too
many
years of Java I guess :P). I just thought there might be a convenient
way
to do setters, and keep the Rdoc [RW] or whatever identifiers correct at
the same time.

Pass on 4 :wink:
Hope someone else can help.

daz

Thanks for your reply :slight_smile:


#8

On 11/26/05, Ross B. removed_email_address@domain.invalid wrote:

Hi Sean,

Hi Ross,

I guess if I
wanted to pass a block in that way, I’d have to get a Proc for the
closure? I’ve seen code like:

   some_method(proc { |s| s.do_something })

which seems a bit nasty to me.

Yes - you’d have to pass it as a regular argument.

Nice one. Gotta get used to this ‘effectively adding keywords’ thing too.
I’ve gotten around the fact that class definitions can call methods, now I
need to get used to it being my methods :slight_smile:

A class definition is executable code. The ability to define methods
that execute within the class definition is one of the most powerful
techniques available in Ruby.

[snip stuff about a class being an instance of Class]

This is where I am going around in circles. It’s an instance of Class, but
it also has a class, Class. So, Class.class == Class. Is that right ?

Yes. If it’s any consolation, it took me a fair bit of head scratching
before the ‘aha’ moment :wink:

Hmm, I think I need to go back to the book on class variables. I can’t
quite see how they fit in, especially with respect to singleton class and
stuff. Thanks for your explanation, though - it’s just me :frowning:

@@class_variables seem to be a bit of a hack to me (at least in 1.8.x).
The double ‘@’ is deliberately ugly. They obey different scoping rules
to other variables in that they look for the nearest enclosing class
regardless of self.

This is a little test that (to me) shows how wacky the scoping rules
are for class variables:

class A
@@foo = “class variable foo”
@foo = “class instance variable foo”
def self.evaluate(txt)
instance_eval txt
end
def self.eval_block(&block)
instance_eval &block
end
end

begin
p A.instance_eval { @@foo }
rescue => e
puts e
end

@@foo = “hi”

p A.instance_eval { [self, @@foo, @foo] }
p A.evaluate("[self, @@foo, @foo]")
p A.eval_block { [self, @@foo, @foo] }

class B
@@foo = “B’s class variable foo”
@foo = “B instance foo”
def self.eval_block(&block)
instance_eval &block
end
end

p B.eval_block { [self, @@foo, @foo] }
END
uninitialized class variable @@foo in Object
[A, “hi”, “class instance variable foo”]
[A, “class variable foo”, “class instance variable foo”]
[A, “hi”, “class instance variable foo”]
[B, “B’s class variable foo”, “B instance foo”]

I’d be grateful if anyone can explain this behaviour (i.e. why the
call to B.eval_block gets B’s class variable but the call to A gets
the outer scope).

Regards,

Sean


#9

Hi –

On Sun, 27 Nov 2005, Sean O’Halpin wrote:

instance_eval &block

end
call to B.eval_block gets B’s class variable but the call to A gets
the outer scope).

What you’ve got basically is:

class A
@@foo = “A’s class variable foo”
end
@@foo = “Object’s class variable foo”
class B
@@foo = “B’s class variable foo”
end

Since B is a subclass of Object, setting B’s @@foo also sets Object’s
@@foo. The reason A’s @@foo (when you see it via the instance eval)
does not change is that if you create a subclass’s class variable
first, and then the superclass’s (in this case, A and Object,
respectively), they are separate:

irb(main):002:0> class A; end; class B < A; @@foo = 1; end; class A;
@@foo = 2; puts @@foo; end
2
=> nil
irb(main):003:0> class B; puts @@foo; end
1

David


#10

On 11/26/05, David A. Black removed_email_address@domain.invalid wrote:

Since B is a subclass of Object, setting B’s @@foo also sets Object’s
@@foo.

Thanks David - that explains it. (Obvious of course now you point it
out).
Makes me even less likely to use class variables! :slight_smile:
They are far too fragile.

Regards,

Sean


#11

On Sat, 26 Nov 2005 21:44:00 -0000, David A. Black removed_email_address@domain.invalid
wrote:

Since B is a subclass of Object, setting B’s @@foo also sets Object’s
1
David

That’s pretty subtle. Definitely one for the notebook.

Cheers,


#12

On Sat, 26 Nov 2005 19:58:57 -0000, Sean O’Halpin
removed_email_address@domain.invalid
wrote:

which seems a bit nasty to me.

Yes - you’d have to pass it as a regular argument.

I get the feeling that eval is the more general solution. I’ll stick
with
that.

Nice one. Gotta get used to this ‘effectively adding keywords’ thing
too.
I’ve gotten around the fact that class definitions can call methods,
now I
need to get used to it being my methods :slight_smile:

A class definition is executable code. The ability to define methods
that execute within the class definition is one of the most powerful
techniques available in Ruby.

I’m starting to see that now. The flexibility has really shaken me up, I
must say :slight_smile:

[snip stuff about a class being an instance of Class]

This is where I am going around in circles. It’s an instance of Class,
but
it also has a class, Class. So, Class.class == Class. Is that right ?

Yes. If it’s any consolation, it took me a fair bit of head scratching
before the ‘aha’ moment :wink:

:slight_smile: Don’t worry, I’ve been falling around in the dark for a few weeks now

it’s only the past few days that I’ve started getting these moments of
clarity. It’s probably no coincidence that I’ve developed a reflex where
i
type ‘irb’ a lot :wink:

Hmm, I think I need to go back to the book on class variables. I can’t
quite see how they fit in, especially with respect to singleton class
and
stuff. Thanks for your explanation, though - it’s just me :frowning:

@@class_variables seem to be a bit of a hack to me (at least in 1.8.x).
The double ‘@’ is deliberately ugly. They obey different scoping rules
to other variables in that they look for the nearest enclosing class
regardless of self.

Have to agree, so far they seem pretty counter-intuitive to me.

This is a little test that (to me) shows how wacky the scoping rules
are for class variables:

[ … ]
I’d be grateful if anyone can explain this behaviour (i.e. why the
call to B.eval_block gets B’s class variable but the call to A gets
the outer scope).

The scoping issues are beyond me right now, but it seems pretty bizarre
that outer scope is ignored there. I noticed that if you modify it thus:

class A
@@foo = “class variable foo”
@foo = “class instance variable foo”
def self.evaluate(txt)
instance_eval txt
end
def self.eval_block(&block)
instance_eval &block
end
end

begin
p A.instance_eval { @@foo }
rescue => e
puts e
end

@@foo = “hi”

p A.instance_eval { [self, @@foo, @foo] }
p A.evaluate("[self, @@foo, @foo]")
p A.eval_block { [self, @@foo, @foo] }

class B
@@foo = “B’s class variable foo”
@foo = “B instance foo”
def self.eval_block(&block)
instance_eval &block
end
end

p B.eval_block { [self, @@foo, @foo] }

class C
@@foo = “C’s class variable foo”
@foo = “C instance foo”
def self.eval_block(&block)
instance_eval &block
end
end

N.B. Not C, just B again

p B.eval_block { [self, @@foo, @foo] }

END
uninitialized class variable @@foo in Object
[A, “hi”, “class instance variable foo”]
[A, “class variable foo”, “class instance variable foo”]
[A, “hi”, “class instance variable foo”]
[B, “B’s class variable foo”, “B instance foo”]
[B, “C’s class variable foo”, “B instance foo”]

To me, that seems stranger still. It seems that it’s getting the last
defined @@foo, no matter what?

Cheers,


#13

Hi –

On Sun, 27 Nov 2005, Ross B. wrote:

@@foo = "B's class variable foo"

2
=> nil
irb(main):003:0> class B; puts @@foo; end
1
David

That’s pretty subtle. Definitely one for the notebook.

Keep in mind too that class variable behavior is due to change in 2.0
(and I guess 1.9 too). The new behavior is supposed to be more
strictly class-scoped, rather than hierarchy scoped.

David