Forum: Ruby why the object doesn't respond to its method?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
73700e119917433681f2e8f3e4369f74?d=identicon&s=25 Li CN (alex-osu3)
on 2008-10-12 19:35
Hi all,

I want to find out if an object responses to a method. while I can tell
that the excel object(in this script) responses to method 'Visible or
visible', my codes DO NOT come true. Any idea?


Thank very much,

Li


C:\Users\Alex>irb
irb(main):001:0> require 'win32ole'
=> true
irb(main):002:0>
irb(main):003:0* excel=WIN32OLE.new("excel.application")
=> #<WIN32OLE:0x389d638>
irb(main):004:0> excel.Visible=true
=> true
irb(main):005:0> puts excel.respond_to?("visible")
false
=> nil
irb(main):006:0> puts excel.respond_to?("Visible")
false
=> nil
irb(main):007:0>
irb(main):008:0* puts excel.respond_to?('visible')
false
=> nil
irb(main):009:0> puts excel.respond_to?('Visible')
false
=> nil
irb(main):010:0>
irb(main):011:0* puts excel.respond_to?(:visible)
false
=> nil
irb(main):012:0> puts excel.respond_to?(:Visible)
false
=> nil
irb(main):013:0>
7a561ec0875fcbbe3066ea8fe288ec77?d=identicon&s=25 Sebastian Hungerecker (Guest)
on 2008-10-12 19:47
(Received via mailing list)
Li Chen wrote:
> Hi all,
>
> I want to find out if an object responses to a method. while I can tell
> that the excel object(in this script) responses to method 'Visible or
> visible', my codes DO NOT come true. Any idea?

My guess is that WIN32OLE handles the call to Visibile via
method_missing and
does not redefine respond_to? to return true for methods handled by
method_missing.
Or, given that in your code you only ever called Visible= and never just
Visible, it might actually be the case that it does not respond to
Visible,
though that is admittedly unlikely.

HTH,
Sebastian
Da33a4ac652c1c8900392a8599206640?d=identicon&s=25 Thomas B. (tpreal)
on 2008-10-12 20:00
Li Chen wrote:
> Hi all,
>
> I want to find out if an object responses to a method. while I can tell
> that the excel object(in this script) responses to method 'Visible or
> visible', my codes DO NOT come true. Any idea?

Hello. First, in your code you actually do not call the method Visible,
you call the method Visible= and it's a big difference, generally.

But you won't find the method Visible= neither, as, as said above, the
capitalised ole methods are handled by method_missing. You can see a
list of ole methods like this:
excel.ole_methods
This gives an array of all the methods, where you can see Visible twice,
once it is the method Visible and once Visible=, but you cannot tell one
from another at a glance. To get just a list of, say, setters, to find
the method Visible=, you write excel.ole_put_methods, and to get a list
of getters (or probably other methods, but with exclusion of setters)
you write excel.ole_get_methods.

Now there's one more problem - the list doesn't contain strings, but
WIN32OLE_METHOD objects. I do not actually know how to handle this, but
this is how you can check if Visible= is among the methods of the
object:
excel.ole_put_methods.find{|m| m.name=="Visible"}
The above line returns nil iff excel does not respond to Visible=.

TPR.
73700e119917433681f2e8f3e4369f74?d=identicon&s=25 Li CN (alex-osu3)
on 2008-10-12 23:04
Thomas B. wrote:
>> Now there's one more problem - the list doesn't contain strings, but
> WIN32OLE_METHOD objects. I do not actually know how to handle this, but
> this is how you can check if Visible= is among the methods of the
> object:
> excel.ole_put_methods.find{|m| m.name=="Visible"}
> The above line returns nil iff excel does not respond to Visible=.
>
> TPR.

Hi Thomas,

I find the method "Visible" but not"Visible=" here but the
respond_to?("Visible") still return false. I don't know how to explain
it.

Li

C:\Users\Alex>irb
irb(main):001:0> require 'win32ole'
=> true
irb(main):002:0>
irb(main):003:0* excel=WIN32OLE.new("excel.application")
=> #<WIN32OLE:0x398d638>
irb(main):004:0>
irb(main):005:0*
irb(main):006:0* puts "first method"
first method
=> nil
irb(main):007:0> excel.ole_get_methods.each do |e|
irb(main):008:1*   if "#{e}"=="Visible"
irb(main):009:2>      puts "find Visible"
irb(main):010:2>      elsif "#{e}"=="Visible="
irb(main):011:2>        puts "find Visible="
irb(main):012:2>        else
irb(main):013:2*          #puts "no method"
irb(main):014:2*          end
irb(main):015:1> end
find Visible
=> [Application, ...MANY METHODS HERE... HighQualityModeForGraphics]
irb(main):016:0>
irb(main):017:0* puts "second methods"
second methods
=> nil
irb(main):018:0> excel.ole_put_methods.each do |e|
irb(main):019:1*   if "#{e}"=="Visible"
irb(main):020:2>      puts "find Visible"
irb(main):021:2>      elsif "#{e}"=="Visible="
irb(main):022:2>        puts "find Visible="
irb(main):023:2>        else
irb(main):024:2*          #puts "no method"
irb(main):025:2*          end
irb(main):026:1>
irb(main):027:1* end
find Visible
=> [ActivePrinter,...MANY METHODS HERE...
LargeOperationCellThousandCount,HighQualityModeForGraphics]
irb(main):028:0>
irb(main):029:0* puts excel.respond_to?("Visible")
false
=> nil
irb(main):030:0>
Da33a4ac652c1c8900392a8599206640?d=identicon&s=25 Thomas B. (tpreal)
on 2008-10-12 23:23
Li Chen wrote:
> Hi Thomas,
>
> I find the method "Visible" but not"Visible=" here but the
> respond_to?("Visible") still return false. I don't know how to explain
> it.

This is correct. As it has been said, the respond_to? doesn't work with
ole methods as they are served by metod_missing, which means that there
are no such methods defined for this object. A sample to illustrate
this:

class K
  def method_missing(m)
    puts "Inside qwe" if m==:qwe
  end
end
k=K::new
k.respond_to? :qwe #=> false
k.qwe ## prints: Inside qwe

So you are not able to check if there is an ole method using
respond_to?. I hoped I stated it clearly in the above post, but
apparently not.

Now the other problem: when you write excel.Visible=true, you call the
method Visible=, but, as already stated, respond_to? :Visible= will not
detect the presence of this method. You have to look for this method in
the ole_methods table.

In general, ole methods are divided into two groups - setters (those
that you call with = at the end, like Visible=) and other methods (those
without =, like when you call excel.Visible (it returns the current
status) or any other of similar methods. But in the ole_methods table,
they are all reported without the =, that's why you see two elements
Visible in the table returned by excel.ole_methods. To distinguish
between them, it's better to look up the method you are looking for in
the specific ole methods table, so: you look for setters inside
excel.ole_put_methods, and for other methods inside
excel.ole_get_methods. So, to check if there is a method called Visible
(without =, the getter), you run this code:
excel.ole_get_methods.find{|m| m.name=="Visible"}
It returns nil if the method is not present and calling excel.Visible
will raise an error, and a non-nil value if the ole method is present.
But if you want to check if there is a setter, that is, a method named
Visible=, then you have to look it up in the other table:
excel.ole_put_methods.find{|m| m.name=="Visible"}
Again, nil means no method, non-nil means that method Visible= is
present for the object. Note that in the last code line there is no
"Visible=", but "Visible", and this is because ole setters in the ole
methods table do not have the = in name, even though they are setters.
And that's the very reason why we must look up setters and getters in
two distinct tables.

If you want, you can add a method like ole_respond_to? to the class
WIN32OLE, like this:

class WIN32OLE
  def ole_respond_to?(m)
    m=m.to_s
    if m[-1]==?=
      m=m[0...-1]
      table=ole_put_methods
    else
      table=ole_get_methods
    end
    !!table.find{|om| om.to_s==m}
  end
end

excel.ole_respond_to? :Visible= #=> true

Not tested carefully, so rather don't use it unless you can understand
it.

Hope this helps.

TPR.
73700e119917433681f2e8f3e4369f74?d=identicon&s=25 Li CN (alex-osu3)
on 2008-10-13 00:34
Hi Thomas,


Thank you very much for the detailed explanation.

It is my understanding from your reply that I should look for
ole_get_methods for the methods of "getter" and look for ole_put_methods
for methods of "setter".

Question 1: In the following scripts both getters and setters have
method "Voice" but respond_to?() responses to both of them as "fasle".
It seems to me that respond_to?() cannot detect the methods in either
getters or setters. Is it true? If this is case what methods can be
detected by  respond_to?() ?


Question 2: There are ole_put_methods, ole_get_methods, and ole_methods
in WIN32OLE. From your post now I know  the differences among
ole_put_methods and ole_get_methods. But how about ole_methods? I only
know it will return more methods. And most of them cannot detected by
respond_to?(),either.


Li



C:\Users\Alex>irb
irb(main):001:0> require 'win32ole'
=> true
irb(main):002:0>
irb(main):003:0* voice=WIN32OLE.new('SAPI.SpVoice')
=> #<WIN32OLE:0x280e934>
irb(main):004:0>
irb(main):005:0* puts "1-getters"
1-getters
=> nil
irb(main):006:0> puts

=> nil
irb(main):007:0> puts voice.ole_get_methods.sort{|x,y|x.to_s<=>y.to_s}
AlertBoundary
AllowAudioOutputFormatChangesOnNextSet
AudioOutput
AudioOutputStream
EventInterests
Priority
Rate
Status
SynchronousSpeakTimeout
Voice
Volume
=> nil
irb(main):008:0> puts

=> nil
irb(main):009:0>
irb(main):010:0* puts "2-setters="
2-setters=
=> nil
irb(main):011:0> puts

=> nil
irb(main):012:0> puts voice.ole_put_methods.sort{|x,y|x.to_s<=>y.to_s}
AlertBoundary
AllowAudioOutputFormatChangesOnNextSet
AudioOutput
AudioOutputStream
EventInterests
Priority
Rate
SynchronousSpeakTimeout
Voice
Volume
=> nil
irb(main):013:0> puts

=> nil
irb(main):014:0>
irb(main):015:0* puts "respond to 1-getters"
respond to 1-getters
=> nil
irb(main):016:0> puts voice.respond_to?("Voice")
false
=> nil
irb(main):017:0>
irb(main):018:0* puts "respond to 2-setters="
respond to 2-setters=
=> nil
irb(main):019:0> puts voice.respond_to?("Voice")
false
=> nil
irb(main):020:0>
Da33a4ac652c1c8900392a8599206640?d=identicon&s=25 Thomas B. (tpreal)
on 2008-10-13 09:26
Li Chen wrote:
> It seems to me that respond_to?() cannot detect the methods in either
> getters or setters. Is it true? If this is case what methods can be
> detected by respond_to?() ?

The ole methods cannot be detected by respond_to?. This is exactly what
I have been trying to communicate to you, since the first post.

In general, respond_to? detects all methods of all object. Ole objects
are sort of exception here - ole methods are not detected by
respond_to?, but other methods are. If you have any object of any of the
standard Ruby classes, it will always work as expected - respond_to?
returns true iff the object responds to this method.

> But how about ole_methods? I only
> know it will return more methods. And most of them cannot detected by
> respond_to?(),either.

It just returns all the ole methods, both setters and non-setters, all
messed up together. You will see that excel.ole_methods includes a
method named Visible twice - one of them is the setter and the other is
the getter. The only way to tell which is which (the only that I know
for now, but note that I was never really working with ole objects) is
to call the method's return_type method, like this:

irb(main):075:0> voice.ole_methods.select{|m| m.to_s=="Voice"}.each{|m|
p m.return_type_detail}
["PTR", "USERDEFINED", "ISpeechObjectToken"]
["VOID"]

But I don't know how to interpret the results. But we at least see now
that these are two distinct methods, even though both are reported to be
named Voice.

TPR.
73700e119917433681f2e8f3e4369f74?d=identicon&s=25 Li CN (alex-osu3)
on 2008-10-13 19:36
HI Thomas,

Thank you very much for your time and the help.


Li
73700e119917433681f2e8f3e4369f74?d=identicon&s=25 Li CN (alex-osu3)
on 2008-10-14 16:59
Hi Thomas,

I guess I figure out why the object doesn't respond to its method in
win32ole.

Based on my other post  this week someone points to me that I need to
pass more parameters into the method.

Please see the following scripts:
Ruby will complain if I write fs.Open(file) but it works if another
parameter 2 is passed.

But right now I still can't figure out how to pass the right
parameter(in this sample is 2).


Li


###############################
require 'win32ole'
fs=WIN32OLE.new('SAPI.SpFileStream')

p fs.ole_method("open").params

file='c:/test.txt'


fs.Open(file,2) #least two params
fs.write("data")
fs.Close
This topic is locked and can not be replied to.