Print comparison

is it possible to print the comparison given as parameter in a method?

something like this:

mi(4==3)
def mi(param)
I want to know here that the param was 4==3
end

I know that I could pass mi(“4==3”) and in the method use eval(param)
but that’s not possible in my case, I need to give a real comparison.

On Thu, Feb 10, 2011 at 7:35 AM, Mario R. [email protected] wrote:

I know that I could pass mi(“4==3”) and in the method use eval(param)
but that’s not possible in my case, I need to give a real comparison.

mi(4==3) sees the 4==3 evaluated before #mi is called. So, the method
call ends up being mi(false).

Consider the following:

def mi(bool)
puts bool
end

mi(4==3)

If you look at the AST that is generated from that code, this is what
you get:

s(:block,
s(:defn,
:mi,
s(:args, :bool),
s(:scope, s(:block, s(:call, nil, :puts, s(:arglist, s(:lvar,
:bool)))))),
s(:call,
nil,
:mi,
s(:arglist, s(:call, s(:lit, 4), :==, s(:arglist, s(:lit, 3))))))

Pay particular attention to the second part. I have reformatted it to
emphasize a few things:

s(:call, nil, :mi,
s(:arglist,
s(:call, s(:lit, 4), :==,
s(:arglist, s(:lit, 3))))))

Look at the 3rd and 4th lines there. The #== method is being called on
4, with an arglist composed of 3. That method call happens first, and
the result of it is the argument placed into the #mi method call’s
arglist.

Depending on your actual use case, and on the ruby version that you
are using, you may be about to use ParseTree (gem install ParseTree)
to get the information that you want, but you might get better
guidance if you explain what your goal in wanting to do this actually
is.

Kirk H.
Software Engineer
Engine Y.

Well what I need to do is simple I need to store the comparison in a log
file and use the result of the comparison to return true or false on
that method.

Kirk H. wrote in post #980846:

I have to deal directly with the comparison and not with literals
because a third party is calling my log method and they are not going to
change the calls and they will be passing comparisons all time instead
of literals.

Josh C. wrote in post #980886:

On Thu, Feb 10, 2011 at 8:35 AM, Mario R. [email protected] wrote:

I know that I could pass mi(“4==3”) and in the method use eval(param)
but that’s not possible in my case, I need to give a real comparison.

Why isn’t it possible? I’ll assume because you aren’t dealing with
literals,
so you need to pass the references to the actual objects. If so, you
could
also pass the binding:

Person = Struct.new :name , :age do
def <=>(person)
age <=> person.age
end
include Comparable
end

bill = Person.new ‘Bill’ , 25
jenn = Person.new ‘Jenn’ , 17
carl = Person.new ‘Carl’ , 25

def mi( comparison , binding )
log comparison
eval comparison , binding
end

alias :log :puts

binding: http://ruby-doc.org/core/classes/Kernel.html#M001448

mi “bill == jenn” , binding # => false
mi “bill == carl” , binding # => true
mi “jenn == carl” , binding # => false

logged:

>> bill == jenn

>> bill == carl

>> jenn == carl

And as always, with eval, be careful: know where your input code is
coming
from, and be sure you can trust that source.

On Thu, Feb 10, 2011 at 10:22 AM, Mario R. [email protected] wrote:

I have to deal directly with the comparison and not with literals
because a third party is calling my log method and they are not going to
change the calls and they will be passing comparisons all time instead
of literals.

I’m repeating myself, but…

a == b

can be rewritten as

a.==(b)

It’s just calling the #== method on ‘a’.

mi(4==3)

is the same thing as

mi(4.==(3))

When your #mi method is called, it ends up looking something like this:

s(:call, nil, :mi, s(:arglist, s(:false)))

i.e. it gets ‘false’ as it’s sole argument.

There is no good solution to what you want to do.

A very bad solution might be something like this:

irb(main):001:0> class Fixnum
irb(main):002:1> def ==(val)
irb(main):003:2> $last_comparison = [self, :==, val]
irb(main):004:2> super
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> 1 == 2
=> false
irb(main):008:0> $last_comparison
=> [1, :==, 2]

i.e. override each of the methods on the objects that will be involved
in the comparisons to record their calls.

Then in your #mi method, you can use that record.

It’s bad because you should always be very reluctant to start changing
the operation of core things like comparison methods on Fixnum, but it
would achieve your goal.

Kirk H.
Software Engineer
Engine Y.

Something you could consider is passing a block:

def mi(&blk)
res = blk.call
end

mi { 4 == 3}

But that would only help if you were running in a Ruby environment where
you could convert the block back into its AST.

Or have a look at how rspec does it:

4.should == 3

That is, define Object#should which returns a wrapper object which
implements the comparison plus whatever side effects you want.

thanks a lot for your help

Kirk H. wrote in post #980912:

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