[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Can anyone see the obvious msitake I've made?

Kev Jackson

3/29/2006 3:06:00 AM

Hi,

I'm hacking up some scripts and I have a lot of repetitive code ie:

#corporate name
@@ie.text_field(:id,
@test_data['pg_401']['corp_nm_fld']).value=@test_data['pg_401']['corp_nm']
@@ie.text_field(:id,
@test_data['pg_401']['corp_nm_kn_fld']).value=@test_data['pg_401']['corp_nm_kn']
#rep name
@@ie.text_field(:id,
@test_data['pg_401']['rep_j_pos_fld']).value=@test_data['pg_401']['rep_j_pos']
@@ie.text_field(:id,
@test_data['pg_401']['rep_nm_fld']).value=@test_data['pg_401']['rep_nm']
@@ie.text_field(:id,
@test_data['pg_401']['rep_nm_kn_fld']).value=@test_data['pg_401']['rep_nm_kn']
#telephone
@@ie.text_field(:id,
@test_data['pg_401']['tel_no_1_fld']).value=@test_data['pg_401']['tel_no_1']
@@ie.text_field(:id,
@test_data['pg_401']['tel_no_2_fld']).value=@test_data['pg_401']['tel_no_2']
...

It looks like a perfect place to use a macro to write out the call to
ie.text_field at run-time (especially because of the duplicated variables)

I've written a method_missing method in my base class and tried to
implement something like
@@ie.text_field(:id,
@test_data['pg_401']['tel_no_1_fld']).value=@test_data['pg_401']['tel_no_1']
=> text :id, :pg_401, :tel_no_1

This would dramatically reduce the amount of typing (and it'll reduce
the training time for the qc team who ultimately have to write these
scripts), and may allow me to refactor further so that the entire test
script could be constructed from a yml file on the fly - which would
save a *lot* of hassle.

Now I've changed @@ie to $ie as it makes more sense (watir and I only
want to be driving one ie window at once, so make it a global)

in my method_missing definition I have

when /text/=~m.id2name
#works
$ie.text_field(:id,
eval("$test_data['#{args[1].to_s}']['#{args[2]}_fld']").to_s).set(eval("$test_data['#{args[1].to_s}']['#{args[2]}']"))
#doesn't work args[0] = id
$ie.text_field("#{args[0].to_sym}",
eval("$test_data['#{args[1].to_s}']['#{args[2]}_fld']")).set(eval("$test_data['#{args[1].to_s}']['#{args[2]}']"))

What I want to do is to create a call to $ie.text_field with the correct
params - as you can see if I specify the symbol :id, it works perfectly
(not sure eval is the correct thing to use but it works), however if I
try to get the symbol from the args[] and then to_sym before executing,
I always get

testScenario(NewApplicationTest):
Watir::Exception::UnknownObjectException: Unable to locate object, using
id and
form:address1

However I've just tried (as I was typing this email)
$ie.text_field(eval("args[0].to_sym"),
eval("$test_data['#{args[1].to_s}']['#{args[2]}_fld']")).set(eval("$test_data['#{args[1].to_s}']['#{args[2]}']"))

And it works! :(

Can anyone explain why #{args[0].to_sym} is not actually evaluating to
the :id symbol, but eval(args[0].to_sym) does? Especially as the error
produced from watir is exactly the same as if I'd have typed:

$ie.text_field(:id, 'a_field_that_doesn't_exist')

Also if there is a better way to do this without using three eval calls
per method that I want to add (seems a little overkill to me)

Thanks
Kev


2 Answers

dblack

3/29/2006 3:31:00 AM

0

Dave Burt

3/29/2006 5:47:00 AM

0

Kev Jackson wrote:
> Can anyone see the obvious msitake I've made?

It's "msitake" - should be "mistake" ;)

No, really...

> ...
> @@ie.text_field(:id,
> @test_data['pg_401']['tel_no_2_fld']).value=@test_data['pg_401']['tel_no_2']
> ..
>
> It looks like a perfect place to use a macro to write out the call to
> ie.text_field at run-time (especially because of the duplicated variables)
>
> I've written a method_missing method in my base class and tried to
> implement something like
> @@ie.text_field(:id,
> @test_data['pg_401']['tel_no_1_fld']).value=@test_data['pg_401']['tel_no_1']
> => text :id, :pg_401, :tel_no_1
> ...
> Now I've changed @@ie to $ie as it makes more sense (watir and I only want
> to be driving one ie window at once, so make it a global)

This is the obvious solution to me:

# call: text "pg_401", "tel_no_1"
def text(test_id, field_name)
$ie.text_field(:id, $test_data[test_id][field_name + '_fld']).value =
$test_data[test_id][field_name]
end

> in my method_missing definition I have
>
> when /text/=~m.id2name

That will match any method call with "text" in the name. Why do you want
that? Just define the method you want ("text").

> #works
> $ie.text_field(:id,
> eval("$test_data['#{args[1].to_s}']['#{args[2]}_fld']").to_s).set(eval("$test_data['#{args[1].to_s}']['#{args[2]}']"))

You should not need eval to do this. Not at all. The above line is the same
as:
$ie.text_field(:id, ($test_data[args[1].to_s][args[2].to_s +
'_fld']).to_s).set(
$test_data[args[1].to_s][args[2].to_s])

Which you can simplify to this if you assume args[1] and args[2] are
strings:
$ie.text_field(:id, $test_data[args[1]][args[2] +
'_fld']).set($test_data[args[1]][args[2]])

Summary: less string interpolation, less to_s, and no eval. Keep it simple,
just deal with variables. You're just making it needlessly complicated and
confusing yourself.

> #doesn't work args[0] = id
> $ie.text_field("#{args[0].to_sym}",
> eval("$test_data['#{args[1].to_s}']['#{args[2]}_fld']")).set(eval("$test_data['#{args[1].to_s}']['#{args[2]}']"))

Let's look at this: "#{args[0].to_sym}"

args[0] is being cast to Symbol, then back to String because it's being
interpolated into one.

Hint: "#{x}" is just a strange way of writing x.to_s. If you expect x to be
a string, it's the same as just plain old x. "Anything in between quotes"
will always give you a string.

So, removing the evals and string interpolations, we get:
$ie.text_field(args[0].to_sym.to_s, $test_data[args[1].to_s][args[2].to_s
+ '_fld']).set(
$test_data[args[1].to_s][args[2].to_s])

And then we can remove all the to_s: the first one is an error (the obvious
mistake you're trying to locate), and the rest are unnecessary if we assume
we're being passed a string:
$ie.text_field(args[0].to_sym, $test_data[args[1]][args[2] +
'_fld']).set(
$test_data[args[1]][args[2]])

A little easier on the eyes?

> What I want to do is to create a call to $ie.text_field with the correct
> params - as you can see if I specify the symbol :id, it works perfectly
> (not sure eval is the correct thing to use but it works), however if I try
> to get the symbol from the args[] and then to_sym before executing, I
> always get
>
> testScenario(NewApplicationTest):
> Watir::Exception::UnknownObjectException: Unable to locate object, using
> id and
> form:address1

I would expect Watir to be a little more helpful by either accepting the
"id" that you're passing, or telling you that it doesn't know how to locate
objects using a string rather than the symbol it's expecting. I'll ask Bret
about improving this.

(As I explained earlier in this message, your "to_sym" was interpolated into
a string, so you were sending a string to text_field.)

> However I've just tried (as I was typing this email)
> $ie.text_field(eval("args[0].to_sym"),
> eval("$test_data['#{args[1].to_s}']['#{args[2]}_fld']")).set(eval("$test_data['#{args[1].to_s}']['#{args[2]}']"))
>
> And it works! :(
>
> Can anyone explain why #{args[0].to_sym} is not actually evaluating to the
> :id symbol, but eval(args[0].to_sym) does? Especially as the error
> produced from watir is exactly the same as if I'd have typed:

"#{1 + 1}" is the same as (1 + 1).to_s, as I explained earlier.
eval("1 + 1") is the same as (1 + 1).

Cheers,
Dave