Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A tad of meta-programming needed

4 views
Skip to first unread message

RichardOnRails

unread,
Jan 17, 2011, 12:28:12 AM1/17/11
to
I've got the following hash set up and it works fine. But this took
more typing than programming.

h = {:name=>$1, :n_shares=>$2, :opened_MDY=>$3, :closed_MDY=>$4,
:proceeds=>$5, :cost=> $6, :gain_Loss=>$7
}

So I'd like to get the following to work:

field_names =%w<Name Shares Opened_MDY Closed_MDY Proceeds Cost
GainLoss>
h = {}
(1..field_names.size).each { |i| h[field_names[i]] = eval($ +
i.to_s) }

But concatenating the character "$" with the value of i converted to a
string, followed be evaluating that as a local variable isn't working
as I coded it. Can it be easily corrected?

Thanks in Advance,
Richard

Josh Cheek

unread,
Jan 17, 2011, 1:05:11 AM1/17/11
to
[Note: parts of this message were removed to make it a legal post.]

The matchdata object implements the same inteface as a hash. If that is all
you need, on 1.9 you could just name the capture groups, then use the
MatchData object and not have to do any assignment/creation at all.
(Assuming this data is based on the pastie you posted earlier, this code
would work)


RUBY_VERSION # => "1.9.2"

line = "Apple 1.1234 1/2/3 4/5/6 $1,234.56 $7 ($5)"

regex = /^(?<name> .+ )\s
(?<n_shares> \d+\.\d{4} )\s+
(?<opened_MDY> \d\d?\/ \d\d?\/ \d\d? )\s+
(?<closed_MDY> \d\d?\/ \d\d?\/ \d\d? )\s+
(?<proceeds> [\$\d,\.]+ )\s+
(?<cost> [\$\d,\.]+ )\s+
(?<gain_Loss> [\(\)\$,\d \.]+ )\s*
$/x

result = regex.match(line)
result # => #<MatchData "Apple 1.1234 1/2/3 4/5/6
$1,234.56 $7 ($5)" name:"Apple" n_shares:"1.1234" opened_MDY:"1/2/3"
closed_MDY:"4/5/6" proceeds:"$1,234.56" cost:"$7" gain_Loss:"($5)">
result[ :name ] # => "Apple"
result[ :n_shares ] # => "1.1234"
result[ :opened_MDY ] # => "1/2/3"
result[ :closed_MDY ] # => "4/5/6"
result[ :proceeds ] # => "$1,234.56"
result[ :cost ] # => "$7"
result[ :gain_Loss ] # => "($5)"

Su Zhang

unread,
Jan 17, 2011, 2:10:03 AM1/17/11
to
> eval($ + i.to_s)

eval('$' + i.to_s)

or simply:

eval("$#{i}")

--
Posted via http://www.ruby-forum.com/.

botp

unread,
Jan 17, 2011, 7:38:20 AM1/17/11
to
On Mon, Jan 17, 2011 at 2:05 PM, Josh Cheek <josh....@gmail.com> wrote:
> On Sun, Jan 16, 2011 at 11:30 PM, RichardOnRails <
> The matchdata object implements the same inteface as a hash. If that is all
> you need, on 1.9 you could just name the capture groups, then use the
> MatchData object and not have to do any assignment/creation at all.
> (Assuming this data is based on the pastie you posted earlier, this code
> would work)
> RUBY_VERSION # => "1.9.2"
> line = "Apple 1.1234 1/2/3 4/5/6 $1,234.56 $7 ($5)"
> regex = /^(?<name>       .+                       )\s
>          (?<n_shares>   \d+\.\d{4}               )\s+
>          (?<opened_MDY> \d\d?\/  \d\d?\/  \d\d?  )\s+
>          (?<closed_MDY> \d\d?\/  \d\d?\/  \d\d?  )\s+
>          (?<proceeds>   [\$\d,\.]+               )\s+
>          (?<cost>       [\$\d,\.]+               )\s+
>          (?<gain_Loss>  [\(\)\$,\d \.]+          )\s*
>        $/x
> result = regex.match(line)

or for older reg engines, they can do parallel assignments w array or splat

something like

_,:name,:n_shares,:opened = regex.match(line).to_a

or

_,:name,:n_shares,:opened = *regex.match(line)

best regards -botp

RichardOnRails

unread,
Jan 17, 2011, 9:43:28 AM1/17/11
to

Hi Josh,

Wow! I posted this question ~ midnight and shutdown for the night,
except for re-reading the Reflections chapter in Pragmatic's
"Programming Ruby". 2nd ed.

Got up at 9, expecting to tackle this problem again, but first opened
this thread hopefully, and was rewarded with a tutorial on part of
MatchData applicable to my goal. That's too good to be true.

> The matchdata object implements the same inteface as a hash. If that is all

> you need ...
That is precisely all I need.

> on 1.9 ...
I've been running 1.8.6 for a good while. I've been tempted to
advance to to 1.9.x in get Look Ahead or Look Behind in regex's,
whichever in missing in 1.8.6. But now I've got a definite purpose to
upgrade!

Thank you very much for your excellent solution. I'm burdened this
problem because the IRS wants tax reports for past years when I lost a
little money as a day trader in the stock market. You might be
surprised at how many trades you can amass in a year if you're at it
almost every weekday each year. The IRS has instituted a new rule
which took effect this year: brokerages must report not merely
proceeds from sales, but also the related cost and hence the gain or
loss. Duh! Hopefully, the new rule will preclude the recurrence of
this issue.

Best wishes,
Richard
An innocent citizen :-)

I won't need to beg for any more help for a good while, I hope.

Best wish

RichardOnRails

unread,
Jan 17, 2011, 10:03:04 AM1/17/11
to

Hi Su Zhang,

That failure was annoying me greatly. Thanks for restoring my sanity.

I'm sticking with option 1. It's easier to interpret at a glance
IMHO. But thanks for pointing out the more succinct alternative.

Best wishes,
Richard

RichardOnRails

unread,
Jan 17, 2011, 3:40:07 PM1/17/11
to
On Jan 17, 7:38 am, botp <botp...@gmail.com> wrote:

Hi botp,

Thanks for that very interesting approach. It's beautifully
succinct. I tried running it on my WinXP-Pro/SP3 machine running Ruby
1.8.6 and was unsuccessful in running your example. I probably
overlooked some detail, for which I apologize.

Here's what I ran:
_, :name, :shares, :opened_MDY, :closed_MDY, :proceeds, :cost, :gainLoss
= regex.match(line).to_a

I got:
ProcessTaxData.rb:116: syntax error, unexpected ',', expecting tCOLON2
or '[' or '.'

_, :name, :shares, :opened_MDY, :closed_MDY, :proceeds, :cost, :gainLoss
= regex.match(line).to_a
^

I ran this in SciTE 1.74, where the output is rendered in monotype
font, I believe. So SciTE actually displayed the "^" under the "m" of
the ":name" symbol, despite the rendering above.

While the symbols didn't work, using local variables did in this
simple test:
string = "abc 123x45"
regex = /(\w+)\s*(\d+)/

puts "Test 1"
_, @x, @y = regex.match(string).to_a
puts @x, @y # => abc and 123 on successive lines

Do you have a working example with symbols you could provide me? And
what version of Ruby ran it?

Again, thanks for helping with my Ruby education.

Best wishes,
Richard

Robert Klemme

unread,
Jan 20, 2011, 8:19:42 AM1/20/11
to
On Mon, Jan 17, 2011 at 9:40 PM, RichardOnRails
<RichardDummy...@uscomputergurus.com> wrote:

> Do you have a working example with symbols you could provide me?  And
> what version of Ruby ran it?

Basically you need a mapping from symbols to group indexes to make
named groups work in 1.8. There are several ways you can do that

1. manual

names = [:foo, :bar, :baz]
..
md = rx.match str
puts md[names.index(:foo) + 1]

2. semi automatic

names = [:foo, :bar, :baz]

def names.get(md, name)
md[names.index(:foo) + 1]
end
..
md = rx.match str
puts names.get(md, :foo)

3. or even

class MatchData
attr_accessor :names

def get(name)
self[names.index(name) + 1]
end
end
..
md = rx.match str
md.names = names
puts md.get(:foo)

Further variants are possible. But I'd switch to 1.9 soon - because
it's faster and has a better regexp engine with named captures.

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

RichardOnRails

unread,
Jan 22, 2011, 9:44:55 PM1/22/11
to
On Jan 20, 8:19 am, Robert Klemme <shortcut...@googlemail.com> wrote:
> On Mon, Jan 17, 2011 at 9:40 PM, RichardOnRails
>

Hi Robert,

Thanks for your response. As usual, it seems to me, your response
was thorough.

> Further variants are possible. But I'd switch to 1.9 soon - because
> it's faster and has a better regexp engine with named captures.

Another responder pointed out the advantage of upgrading to 1.9,
which I will do in a couple of weeks.

My original wish was to use the values from a regex match ($1, $2 ...)
without explicitly listing those symbols in an expression. Rather I
wanted to extract the values from them in a loop. Having done some
Ruby meta-programming in past, but suffering from an increasingly
poor memory in my dotage, I jotted down "eval($ + i.to_s)", which
failed.

Su Zhang on this thread corrected my error: "put the & in quotes",
along with alternatives. Problem solved.

Happily, I received a number of other approaches, which I saved
because I love to employ programmatic ways to avoid repetitive program
code. And now I have the good fortune of getting a bunch of clever
alternatives from you, which I will store with my other gifts.

Since my original problem has been solved, I'm going to keep on
pushing my project forward. But I treasure these gifts and promise to
employ them in my continuation education in art of Ruby programming.

Best wishes,
Richard

0 new messages