Handling of arbitrary length arrays in arguments to printf b

Hi Folks,

I’m porting an error reporting system from Perl to Ruby as a way of
getting up the Ruby learning curve. Apologies in advance if my
question has already been answered - I did a cursory search and got
no hits.

I’m running up against my lack of detailed Ruby knowledge, and I was
wondering if someone could provide some advice - I’m sure that Ruby
supports what I want to do.

In the Perl world, I had a system where I could specify an error
message and a set of parameters to that message, as follows:

do_error(message, [parameters]);

for example:

do_error("param 1: '%s', param 2 : '%s', param 3 : '%s'",
		 "detail1", "detail2", "detail3");

would give the result:

param 1: 'detail1', param 2 : 'detail2', param 3 : 'detail3'

The perl implementation looks like this:

sub do_error {
my ($message, @params) = @_;

printf($message, @params);
}

As you can see, the idea is that the user is able to specify both
their error message and where in their message string various
parameters appear.

In this case, Perl was very obliging because parameter lists are
simply arrays. Passing an array into printf became equivalent to
passing the appropriate number of parameters.

So, in Ruby, I have the following code:

printf “#{@message}\n”, @params

Where class instance variable @params is an array. I have verified
that it really is an array and not getting mangled somewhere in my
class by using ‘@params.inspect’.

Unfortunately, it seems that Ruby is treating the array in what Perl
folks would call a “scalar context”. The printf is getting a mangled
version of the array contents and this is triggering a runtime error
from Ruby.

For example:

@params = ["foo", "bar"]
print @params.inspect
>>>  ["foo", "bar"]

printf("%s %s", @params)
>>> ErrorClasses.rb:32:in `printf': too few arguments (ArgumentError)

I did some experiments, and it appears that printf is actually seeing:
“foobar”
instead of the array of 2 elements. If I have the right number of ‘%
s’ conversion codes in the format string, I get this message because
Ruby thinks I’ve only passed on parameter, not many.

For the record, here’s the Ruby version I’m using

BigWhite:nick> ruby -v
ruby 1.8.4 (2005-12-24) [i686-darwin8.8.1]

What would Ruby’s code look like to achieve what I want?

Thanks in advance,

Nick

Nick P. wrote:

would give the result:

printf “#{@message}\n”, @params
For example:
instead of the array of 2 elements. If I have the right number of ‘%s’

Thanks in advance,

Nick

Welcome to Ruby!

Use the “*” (splat) operator to turn the array into a list of arguments.

printf “%s %s”, *@params

The unary asterisk is often called the “unary unarray” operator because
it has this effect on an array.

On 12/27/06, Nick P. [email protected] wrote:

supports what I want to do.

}

I did some experiments, and it appears that printf is actually seeing:

What would Ruby’s code look like to achieve what I want?

Thanks in advance,

Nick

Blind leading the blind here, (I’m a newbie), but I think I understand
what
you’re trying. Did I completely misunderstand or does this help?

@params = [“foo”, “bar”]
print @params.inspect
@params.each { |x| printf x }
output:
[“foo”, “bar”]foobar

@params = [“foo”, “bar”]
print @params.inspect
printf(“%s %s”, @params, @params)
output:
[“foo”, “bar”]foobar foobar

On Dec 27, 2006, at 1:54 PM, Nick P. wrote:

Hi Folks,

I’m porting an error reporting system from Perl to Ruby as a way of
getting up the Ruby learning curve. Apologies in advance if my
question has already been answered - I did a cursory search and got
no hits.

[snip perfect example of how to ask a question]

Since we have been discussing it recently, everyone should read
Nick’s entire post and hold it as the perfect example of how to ask
questions correctly.

Welcome to Ruby Nick!

James Edward G. II

On Dec 27, 2006, at 3:17 PM, Jason M. wrote:

Neat! How would you use that to return “bar stuff” with the
following?

@params = [“foo”, “bar”, “stuff”]
print @params.inspect
printf “%s %s”, *@params

irb(main):015:0> printf “%s %s”, *@params[1…-1]
bar stuff=> nil

ain’t it cool? :slight_smile:
-Mat

On 12/27/06, Timothy H. [email protected] wrote:

Welcome to Ruby!

Use the “*” (splat) operator to turn the array into a list of arguments.

printf “%s %s”, *@params

The unary asterisk is often called the “unary unarray” operator because
it has this effect on an array.

Neat! How would you use that to return “bar stuff” with the following?

@params = [“foo”, “bar”, “stuff”]
print @params.inspect
printf “%s %s”, *@params

I’m not sure that Ri Array#* is quite what I meant to look for.

I guess you’ll have to select the elements from the array.

AFAIK, the Array#* in only used to pack and unpack arrays into
argument lists (and other kinds of lists).
For example:

def multiple_returns
1, 2, 3, 4
end

a = multiple_returns # a=1
a, b = multiple_returns # a=1, b = 2
a, *b = multiple_returns # a=1, b = [2,3,4]

Hope you’ll get less n00b =P

cheers!

Jason M. wrote:

Neat! How would you use that to return “bar stuff” with the following?

@params = [“foo”, “bar”, “stuff”]
print @params.inspect
printf “%s %s”, *@params

You can’t. That’s not what “*” is for. The “unary unarray” operator is
primarily used for exactly the purpose you described, variable-length
argument lists. It has uses in other contexts, too, but they’re outside
the scope of your question.

If you want just some of the elements in the Array then you can use the
[] method and specify which elements you’re interested in. In your
example, @params[1,2] (“2 elements starting at element 1”) would do the
trick.

I’m not sure that Ri Array#* is quite what I meant to look for.

You’re right. In this context "" is a unary operator. Array# is a
method.

On 27.12.2006 21:03, Timothy H. wrote:

Nick P. wrote:

Hi Folks,

I seem to be missing Nick’s posting on the news side. I can see it on
the mailing list. Is this the gateway again or my news provider?

Regards

robert

On Dec 27, 2006, at 4:35 PM, Robert K. wrote:

On 27.12.2006 21:03, Timothy H. wrote:

Nick P. wrote:

Hi Folks,

I seem to be missing Nick’s posting on the news side. I can see it
on the mailing list. Is this the gateway again or my news provider?

The message was sent as multipart/alternative. The Gateway does not
currently support this, as explained at:

http://blog.grayproductions.net/articles/2006/12/01/what-is-the-ruby-
talk-gateway

If you want to change this, see:

http://blog.grayproductions.net/articles/2006/12/04/hacking-the-gateway

and:

http://blog.grayproductions.net/articles/2006/12/05/mail_to_news-rb

You can of course read Nick’s message in the mailing list archives:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/231436

Hope this helps.

James Edward G. II

On 27.12.2006 23:50, James Edward G. II wrote:

The message was sent as multipart/alternative. The Gateway does not

http://blog.grayproductions.net/articles/2006/12/05/mail_to_news-rb

You can of course read Nick’s message in the mailing list archives:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/231436

Hope this helps.

James Edward G. II

James, thanks for the heads up! I guess you looked at the message and
there was no HTML involved. But before I suggest a change of the
gateway code I’ll have to take a look. At the moment I’m imagining that
extracting the first part with “text/plain” would work - at least for
this posting. :slight_smile: But I can also see how that would increase the
processing needed per each email…

Kind regards

robert

Hi Everyone,

Thanks very much for your fast responses - the “unary unarray”
operator works great!

Thanks also for the kind welcome you’ve given me - it makes a big
difference.

Best wishes,

Nick

On Dec 27, 2006, at 3:03 PM, Timothy H. wrote:

Ruby supports what I want to do.

}

I did some experiments, and it appears that printf is actually

Welcome to Ruby!

Use the “*” (splat) operator to turn the array into a list of
arguments.

printf “%s %s”, *@params

The unary asterisk is often called the “unary unarray” operator
because it has this effect on an array.

Nick P.
[email protected]