A tad of meta-programming needed

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

On Sun, Jan 16, 2011 at 11:30 PM, RichardOnRails <
[email protected]> wrote:

GainLoss>

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 = /^(? .+ )\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+
(? [$\d,.]+ )\s+
(? [$\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)”

RichardOnRails wrote in post #975374:

eval($ + i.to_s)

eval(’$’ + i.to_s)

or simply:

eval("$#{i}")

On Mon, Jan 17, 2011 at 2:05 PM, Josh C. [email protected]
wrote:

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

On Jan 17, 1:05am, Josh C. [email protected] wrote:

h = {:name=>$1, :n_shares=>$2, :opened_MDY=>$3, :closed_MDY=>$4,

(Assuming this data is based on the pastie you posted earlier, this code
(? [$\d,.]+ )\s+
result[ :opened_MDY ] # => “1/2/3”
result[ :closed_MDY ] # => “4/5/6”
result[ :proceeds ] # => “$1,234.56”
result[ :cost ] # => “$7”
result[ :gain_Loss ] # => “($5)”

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

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

Best wish

On Jan 17, 7:38am, botp [email protected] wrote:

(?<n_shares>  \d+\.\d{4}        )\s+

something like

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

or

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

best regards -botp

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

On Jan 17, 2:10am, Su Zhang [email protected] wrote:

eval($ + i.to_s)

eval(’$’ + i.to_s)

or simply:

eval("$#{i}")


Posted viahttp://www.ruby-forum.com/.

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

On Mon, Jan 17, 2011 at 9:40 PM, RichardOnRails
[email protected] 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]

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

  1. 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

On Jan 20, 8:19am, Robert K. [email protected] wrote:

md[names.index(:foo) + 1]
def get(name)

Kind regards

robert


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

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

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs