General Ruby Programming questions

Hi,

I’m writing a Ruby app at the moment, and have some questions I hope you
can help me with:

(a) string->class

I have a string containing the name of a class, and want to get the
corresponding Class object. My current approach is:
Module.class_eval(classname)

Is this the best approach?

(b) changing “require” searchpath

The $: variable holds the path used to locate files when the "require"
command is used. However this variable is read-only. In Perl, it is
possible to modify the equivalent path; can this be done in ruby?

The reason I want this is that I want to run my test harness from one
directory, and pick up my in-development code from some other directory.
Using “require ‘…/xmldigester.rb’” doesn’t work, because all the
requires in that required file resolve against $:.

© how invoke “hidden” methods?

I have a class Digester which responds to SAX events generated by REXML.
However I don’t want methods like “start_element” to be public on
Digester, because this is just untidy: these methods are “internal” to
the Digester class, and should not be available for ordinary users of
this class.

In Java, I would declare package-scope methods on the Digester class,
then write an adapter class which implements SaxContentHandler, and
forwards calls to its methods to the appropriate Digester object
methods.

However Ruby doesn’t have “package-scope” methods. Any idea how I
achieve a similar effect in Ruby?

(d) iterating in reverse

I have an Array object, and wish to iterate over its members in reverse.
I would prefer not to have to create a new Array object in order to do
this iteration. Is there any way other than writing
for(i=array.length-1; i>=0; --i) …

Thanks,

Simon

Simon Kitching wrote:

Hi,

Moin!

I have a string containing the name of a class, and want to get the
corresponding Class object. My current approach is:
Module.class_eval(classname)
Is this the best approach?

It isn’t – an user might inject arbitary code. Use this instead:

irb(main):001:0> Object.const_get(‘Class’)
=> Class

(b) changing “require” searchpath
The $: variable holds the path used to locate files when the “require”
command is used. However this variable is read-only. In Perl, it is
possible to modify the equivalent path; can this be done in ruby?

It might be read-only, but that doesn’t mean that you can’t change the
object which it refers to:

irb(main):002:0> $:.push(‘new’)
=> […, ‘new’]

(c) how invoke “hidden” methods?

Simply send the message a method invocation would produce yourself:

irb(main):003:0> 5.send(:rand)
=> 0.748920713318512

(d) iterating in reverse
I have an Array object, and wish to iterate over its members in reverse.
I would prefer not to have to create a new Array object in order to do
this iteration. Is there any way other than writing

irb(main):004:0> [1, 2, 3].reverse_each { |item| puts item }
3
2
1

Regards,
Florian Groß

Simon Kitching wrote:

Hi,

Moin!

I have a string containing the name of a class, and want to get the
corresponding Class object. My current approach is:
Module.class_eval(classname)
Is this the best approach?

It isn’t – an user might inject arbitary code. Use this instead:

irb(main):001:0>> Object.const_get(‘Class’)
=>> Class

That won’t work for class names like “Test::Unit::TestCase”. This is
discussed on the Wiki. Search “class” and you’ll find it I’m sure.

[…]

Gavin

···

On Thursday, October 16, 2003, 9:00:04 AM, Florian wrote:

Hi Florian…

Moin!

?? This isn’t a greeting I’ve heard of before…

Anyway, Kia Ora!

(c) how invoke “hidden” methods?

Simply send the message a method invocation would produce yourself:

irb(main):003:0> 5.send(:rand)
=> 0.748920713318512

Whoa! So private methods can be called after all???!

Not the end of the world, I guess. After all, Python doesn’t support
private methods at all, right? Still a bit odd in my opinion.

Is there any reason why Ruby allows private methods to be invoked like
this? (rather than provide a tidy alternative for problems like mine).

Anyway, you answered all my questions in one swoop - thanks!

Regards,

Simon

···

On Thu, 2003-10-16 at 12:00, Florian Gross wrote:

Simon Kitching wrote:

(b) changing “require” searchpath
The $: variable holds the path used to locate files when the “require”
command is used. However this variable is read-only. In Perl, it is
possible to modify the equivalent path; can this be done in ruby?

It might be read-only, but that doesn’t mean that you can’t change the
object which it refers to:

irb(main):002:0> $:.push(‘new’)
=> […, ‘new’]

You really want to unshift here, the Array is read front to back, so new
libs that override base libs won’t get require’d.

(d) iterating in reverse
I have an Array object, and wish to iterate over its members in reverse.
I would prefer not to have to create a new Array object in order to do
this iteration. Is there any way other than writing

irb(main):004:0> [1, 2, 3].reverse_each { |item| puts item }
3
2
1

You can also use reverse. An Array is smart, reverse takes constant time.

[1,2,3].reverse.map do |i| i * 2 end

···

Florian Gross (flgr@ccan.de) wrote:


Eric Hodel - drbrain@segment7.net - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

I believe I’m giving a fairly accurate paraphrase of matz when I say
that Ruby doesn’t prevent you from writing sloppy code, it just makes it
look ugly enough so that you don’t do it.

Scary things tend to look scary in Ruby.
Evil things tend to look evil in Ruby.

···

Simon Kitching (simon@ecnetwork.co.nz) wrote:

(c) how invoke “hidden” methods?

Simply send the message a method invocation would produce yourself:

irb(main):003:0> 5.send(:rand)
=> 0.748920713318512

Whoa! So private methods can be called after all???!

Not the end of the world, I guess. After all, Python doesn’t support
private methods at all, right? Still a bit odd in my opinion.

Is there any reason why Ruby allows private methods to be invoked like
this? (rather than provide a tidy alternative for problems like mine).


Eric Hodel - drbrain@segment7.net - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

[Simon wrote:]

(c) how invoke “hidden” methods?

Simply send the message a method invocation would produce yourself:

irb(main):003:0> 5.send(:rand)
=> 0.748920713318512

Whoa! So private methods can be called after all???!

Not the end of the world, I guess. After all, Python doesn’t support
private methods at all, right? Still a bit odd in my opinion.

Is there any reason why Ruby allows private methods to be invoked like
this? (rather than provide a tidy alternative for problems like mine).

It may help to think of it not as a method being invoked, rather a message
being sent. The object decides how it wishes to respond to that message.

After all, you can’t invoke a method that doesn’t exist, but you can get a
response back from a message that doesn’t have a corresponding method, if
you get my drift.

class X
def method_missing(sym, *args)
5
end
end

x = X.new
x.foo # → 5
x.bar # → 5
x.quux # → 5
x.method(:foo) # → NameError: undefined method ‘foo’
x.nil? # → false

Gavin

W liście z czw, 16-10-2003, godz. 01:26, Eric Hodel pisze:

You can also use reverse. An Array is smart, reverse takes constant time.

VALUE
rb_ary_reverse(ary)
VALUE ary;
{

[...]

while (p1 < p2) {
    tmp = *p1;
    *p1++ = *p2;
    *p2-- = tmp;
}

Doesn’t look like constant time for me.

···


__("< Marcin Kowalczyk
__/ qrczak@knm.org.pl
^^ Blog człowieka poczciwego.

Eric Hodel wrote:

Is there any reason why Ruby allows private methods to be invoked like
this? (rather than provide a tidy alternative for problems like mine).

I believe I’m giving a fairly accurate paraphrase of matz when I say
that Ruby doesn’t prevent you from writing sloppy code, it just makes it
look ugly enough so that you don’t do it.

And if you really want to trap such calls you can override ‘send’:

module SafeSend
alias evil_unsafe_send send
def send( m, *args )
msg = “No sending of private messages!”
raise msg if self.private_methods.include? m.to_s
evil_unsafe_send( m, *args )
end
end

class Foo
include SafeSend

end

···

Simon Kitching (simon@ecnetwork.co.nz) wrote:

Yes, that’s clear.

However I could still rephrase my original question as:

Why doesn’t ruby throw a NoMethodError exception when a message is
sent to a method which is private using the “send” feature?

The purpose of marking a method as private is to indicate that the only
valid invocation of the code within that method is when the invoker is
another method on the same class (java convention) or the same object
(ruby convention).

Quite often private methods don’t preserve class invariants. And
exposing methods that can break class invariants to the outside world is
never a good idea.

As I said, it’s no big deal. Perl, javascript and (as far as I know)
Python don’t support the concept of private methods at all.

However I am curious to know if there is a real justification for
allowing private methods to be invoked via “send”, or if it just an
accident that this works. Ruby takes encapsulation so seriously in many
other ways…

Cheers,

Simon

PS: I did eventually find that class lookup implementation on the wiki.
I think it would be really nice to have this in the std libs (eg as a
class method on the Class or Object classes).

def get_class(name)
name.split(/::/).inject(Object) {|p,n|
p.const_get(n)
}
end

···

On Thu, 2003-10-16 at 13:06, Gavin Sinclair wrote:

[Simon wrote:]

(c) how invoke “hidden” methods?

Simply send the message a method invocation would produce yourself:

irb(main):003:0> 5.send(:rand)
=> 0.748920713318512

Whoa! So private methods can be called after all???!

Not the end of the world, I guess. After all, Python doesn’t support
private methods at all, right? Still a bit odd in my opinion.

Is there any reason why Ruby allows private methods to be invoked like
this? (rather than provide a tidy alternative for problems like mine).

It may help to think of it not as a method being invoked, rather a message
being sent. The object decides how it wishes to respond to that message.

After all, you can’t invoke a method that doesn’t exist, but you can get a
response back from a message that doesn’t have a corresponding method, if
you get my drift.

Ah yes, you’re right. My sample must have been too small to show the
difference.

···

Marcin ‘Qrczak’ Kowalczyk (qrczak@knm.org.pl) wrote:

W li?cie z czw, 16-10-2003, godz. 01:26, Eric Hodel pisze:

You can also use reverse. An Array is smart, reverse takes constant time.

Doesn’t look like constant time for me.


Eric Hodel - drbrain@segment7.net - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

Hah! Consider my questions answered :slight_smile:

I love the way Ruby can override default behaviours…

Regards,

Simon

···

On Thu, 2003-10-16 at 13:14, James Britt wrote:

Eric Hodel wrote:

Simon Kitching (simon@ecnetwork.co.nz) wrote:

Is there any reason why Ruby allows private methods to be invoked like
this? (rather than provide a tidy alternative for problems like mine).

I believe I’m giving a fairly accurate paraphrase of matz when I say
that Ruby doesn’t prevent you from writing sloppy code, it just makes it
look ugly enough so that you don’t do it.

And if you really want to trap such calls you can override ‘send’:

module SafeSend
alias evil_unsafe_send send
def send( m, *args )
msg = “No sending of private messages!”
raise msg if self.private_methods.include? m.to_s
evil_unsafe_send( m, *args )
end
end

class Foo
include SafeSend

end

[Simon wrote:]

PS: I did eventually find that class lookup implementation on the wiki.
I think it would be really nice to have this in the std libs (eg as a
class method on the Class or Object classes).

http://www.rubygarden.org/ruby?FindClassesByName

def get_class(name)
name.split(/::/).inject(Object) {|p,n|
p.const_get(n)
}
end

I’ll add this to extensions.rubyforge.org within a few days. At first
blush, Kernel seems the right place to put it.

Gavin

W liście z czw, 16-10-2003, godz. 02:14, James Britt pisze:

And if you really want to trap such calls you can override ‘send’:

And then if someone really wants to invoke a private method, he will
just add a public forwarding method.

You could try to protect against all that, but what for?

···


__("< Marcin Kowalczyk
__/ qrczak@knm.org.pl
^^ Blog człowieka poczciwego.

Hello,

I am facing compilation problems with ruby.
The version is 1.8.0 being compiled on RedHat Linux 7.2
Please help.
The error report of compilation is attached.

Regards and best wishes.
Shailesh.

tomail (5.74 KB)

Marcin ‘Qrczak’ Kowalczyk wrote:

W li¶cie z czw, 16-10-2003, godz. 02:14, James Britt pisze:

And if you really want to trap such calls you can override ‘send’:

And then if someone really wants to invoke a private method, he will
just add a public forwarding method.

You could try to protect against all that, but what for?

I suspect that ‘send’ is most used when a specific method name is
unknown until run time, and you want to dynamicaly invoke a method.
However, there’s the chance one could inadvertantly call a private
method; adding some protective measures to ‘send’ would help block this.

Sure it’s true that one can always hack around such measures, but the
idea is to raise the bar. (And I suppose some combinbation of
overriding ‘method_added’ and inspecting the call stack could be thrown
in to make things harder.)

James

— S R Chansarkar shailesh@cair.res.in wrote:

Hello,

I am facing compilation problems with ruby.
The version is 1.8.0 being compiled on RedHat Linux 7.2
Please help.
The error report of compilation is attached.

Regards and best wishes.
Shailesh.

[…snip…]

I suspect your problem is that you’re using GCC3.x.x try going back to
2.9.x

– Thomas Adam

···

=====
Thomas Adam

“The Linux Weekend Mechanic” – www.linuxgazette.com


Want to chat instantly with your online friends? Get the FREE Yahoo!
Messenger http://mail.messenger.yahoo.co.uk

Thank you thank you thank you.

I’ve been trying to wrap hash style accessor methods around arbitrary
getters and setters. (Kinda like Daniel Berger’s “Perl Idioms” but in
reverse - so that it works on mixed in attributes & accessors.) Don’t
ask why, it seemed like a good idea at the time. Started out hard
coding keys to be forwarded to methods, discarded as cumbersome, then
tried ‘eval’, and then ‘method’. This one seems to do the trick though.

Just writing as a reminder: there’s lots of newbies reading and we
really appreciate all the smarts & knowledge flying around here.

David

···

On Thursday, October 16, 2003, at 10:46 AM, James Britt wrote:

I suspect that ‘send’ is most used when a specific method name is
unknown until run time, and you want to dynamicaly invoke a method.
However, there’s the chance one could inadvertantly call a private
method; adding some protective measures to ‘send’ would help block
this.

Sure it’s true that one can always hack around such measures, but the
idea is to raise the bar. (And I suppose some combinbation of
overriding ‘method_added’ and inspecting the call stack could be
thrown in to make things harder.)

James

Thank you thank you thank you.

I’ve been trying to wrap hash style accessor methods around arbitrary
getters and setters. (Kinda like Daniel Berger’s “Perl Idioms” but in
reverse - so that it works on mixed in attributes & accessors.) Don’t
ask why, it seemed like a good idea at the time. Started out hard
coding keys to be forwarded to methods, discarded as cumbersome, then
tried ‘eval’, and then ‘method’. This one seems to do the trick though.

Just writing as a reminder: there’s lots of newbies reading and we
really appreciate all the smarts & knowledge flying around here.

David

···

On Thursday, October 16, 2003, at 10:46 AM, James Britt wrote:

I suspect that ‘send’ is most used when a specific method name is
unknown until run time, and you want to dynamicaly invoke a method.
However, there’s the chance one could inadvertantly call a private
method; adding some protective measures to ‘send’ would help block
this.

Sure it’s true that one can always hack around such measures, but the
idea is to raise the bar. (And I suppose some combinbation of
overriding ‘method_added’ and inspecting the call stack could be
thrown in to make things harder.)

James

Hello,

Following is the gcc version being used.
···

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-98)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Regards and best wishes.
Shailesh.

I suspect your problem is that you’re using GCC3.x.x try going back to
2.9.x

– Thomas Adam

=====
Thomas Adam

“The Linux Weekend Mechanic” – www.linuxgazette.com


Want to chat instantly with your online friends? Get the FREE Yahoo!
Messenger http://mail.messenger.yahoo.co.uk