Forum: Ruby Nubish questions about syntax and gems

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 rosco (Guest)
on 2005-11-26 15:57
(Received via mailing list)
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?

2) 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.

3) 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 :)

4) 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!
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 dblack (Guest)
on 2005-11-26 16:26
(Received via mailing list)
Hi --

On Sat, 26 Nov 2005, Ross Bamford 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 :-)

> 3) 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
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 rosco (Guest)
on 2005-11-26 17:06
(Received via mailing list)
On Sat, 26 Nov 2005 15:24:36 -0000, David A. Black <dblack@wobblini.net>
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 :) 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 ;)

Thanks again!
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2005-11-26 17:10
(Received via mailing list)
On 11/26/05, Ross Bamford <rosco@roscopeco.remove.co.uk> 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.

>
> 2) 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 :)

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
Dce0999389d102f9a313af625375304c?d=identicon&s=25 dooby (Guest)
on 2005-11-26 17:18
(Received via mailing list)
Ross Bamford 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&m...

>
> 2) 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


>
> 3) Does this
>

Awesome answer from Dr. Black !

>
> 4) And finally, not exactly a Ruby question, but relevant here I hope?
> With a RubyGem, [...]

Pass on 4  ;)
Hope someone else can help.


daz
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 rosco (Guest)
on 2005-11-26 20:08
(Received via mailing list)
Hi Sean,

On Sat, 26 Nov 2005 16:08:19 -0000, Sean O'Halpin
<sean.ohalpin@gmail.com>
wrote:

>>                  end
> end
>

Ahh, I should have known to check Module :) 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 :)

>   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 :(

I'll probably be asking again after I confuse myself some more ;)

Cheers for your reply.
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2005-11-26 21:00
(Received via mailing list)
On 11/26/05, Ross Bamford <rosco@roscopeco.remove.co.uk> 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 :)

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 ;)

> 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 :(

@@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
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 rosco (Guest)
on 2005-11-26 21:16
(Received via mailing list)
On Sat, 26 Nov 2005 16:14:24 -0000, daz <dooby@d10.karoo.co.uk> wrote:

>
> http://www.outerbody.com/ruby/ri.do?class=Module&m...
>

Cheers :) 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  ;)
> Hope someone else can help.
>
>
> daz
>

Thanks for your reply :)
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 dblack (Guest)
on 2005-11-26 22:45
(Received via mailing list)
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
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 rosco (Guest)
on 2005-11-26 22:49
(Received via mailing list)
On Sat, 26 Nov 2005 19:58:57 -0000, Sean O'Halpin
<sean.ohalpin@gmail.com>
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 :)
>
> 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 :)

> [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 ;)
>

:) 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 ;)

>> 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 :(
>
> @@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,
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2005-11-27 00:54
(Received via mailing list)
On 11/26/05, David A. Black <dblack@wobblini.net> 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! :)
They are far too fragile.

Regards,

Sean
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 rosco (Guest)
on 2005-11-27 01:34
(Received via mailing list)
On Sat, 26 Nov 2005 21:44:00 -0000, David A. Black <dblack@wobblini.net>
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,
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 dblack (Guest)
on 2005-11-27 01:38
(Received via mailing list)
Hi --

On Sun, 27 Nov 2005, Ross Bamford 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
This topic is locked and can not be replied to.