Enumerable and WIN32OLE

I make a lot of use of the WIN32OLE library, with many thanks to Nobu
Nakada.

One of my common idioms is to take a WIN32OLE object that implements
the IEnumerable interface and extend it with the Ruby Enumerable Mix
in. Thus:

  rows = @ole_worksheet.usedRange.rows.extend Enumerable
  rows.select do |row|
    entire_row = row.entireRow
    entire_row.columns(1).text == '' and # comment
    entire_row.columns(2).text != '' # no action
  end

It strikes me that it might be reasonable to expect the Ruby win32ole
library to do this for me automatically. Do you agree?

Bret

[email protected] wrote:

One of my common idioms is to take a WIN32OLE object that implements
the IEnumerable interface and extend it with the Ruby Enumerable Mix
in. Thus:

It strikes me that it might be reasonable to expect the Ruby win32ole
library to do this for me automatically. Do you agree?

Yes, I’ve expected that on occasion, and I think it would be a nifty
feature indeed. Enumerable’s methods don’t clash with common COM
collection methods, as far as I can see.

The reason it’s not included already is that each is called as
dynamically as any other OLE method; it’s not determined before the call
whether or not the object actually implements IEnum. So either you’d
have to do this check on instantiation (probably in ole_set_member(),
the function that associates a WIN32OLE object with its COM object), or
you could include Enumerable in WIN32OLE itself.

I’m not sure how expensive it would be in terms of performance, adding
this check to ole_set_member().

Masaki S.?

Cheers,
Dave

Hello, sorry for being too late to reply.

In message “Re: Enumerable and WIN32OLE”
on 06/09/27, Dave B. [email protected] writes:

Yes, I’ve expected that on occasion, and I think it would be a nifty
feature indeed. Enumerable’s methods don’t clash with common COM
collection methods, as far as I can see.

Enumerable#find method clashes the ‘find’ method of Excel Range object.
This is the (only) reason why WIN32OLE does not include Enumerable.

WIN32OLE class has ‘each’ method (WIN32OLE#each is defined),
and you can use Enumerable’s methods by adding the following code.
class WIN32OLE
include Enumerable
end

Regards,
Masaki S.

In message “Re: Enumerable and WIN32OLE”
on 06/09/29, Masaki S. [email protected] writes:

In message “Re: Enumerable and WIN32OLE”
on 06/09/27, Dave B. [email protected] writes:

Yes, I’ve expected that on occasion, and I think it would be a nifty
feature indeed. Enumerable’s methods don’t clash with common COM
collection methods, as far as I can see.

Enumerable#find method clashes the ‘find’ method of Excel Range object.
This is the (only) reason why WIN32OLE does not include Enumerable.

Enumerable#select method clashes the ‘select’ method of Excel Range
object.
And I think this case is more painful than the ‘find’ case.

Regards,
Masaki S.

Masaki S. wrote:

Enumerable#find method clashes the ‘find’ method of Excel Range object.
This is the (only) reason why WIN32OLE does not include Enumerable.

Enumerable#select method clashes the ‘select’ method of Excel Range object.
And I think this case is more painful than the ‘find’ case.

You’re right, we don’t want to break people’s range.find or range.select
calls (at least in Ruby 1.8).

What about something like this, though? For these methods, a block is
always provided. For a COM method call, a block is never provided. Why
not dispatch depending on block_given?

class WIN32OLE
include Enumerable
%w( find select ).each do |m|
alias_method “enum_#{m}”, m
define_method m do |*args|
if block_given?
send(“enum_#{m}”, *args) {|*a| yield *a }
else
invoke m, *args
end
end
end
end

My preference for writing code for OLE is to use uppercase method calls
(range.Select) and save lowercase for Ruby methods. But this should
provide compatibility for people who have range.select in their code.
IEnums should have Enumerable.

Cheers,
Dave

In message “Re: Enumerable and WIN32OLE”
on 06/09/30, Dave B. [email protected] writes:

What about something like this, though? For these methods, a block is
always provided. For a COM method call, a block is never provided. Why
not dispatch depending on block_given?

Some Enumerable’s methods does not need a block, for example,
Enumerable#max.
So, I hesitate to implement your idea.
(I am not sure that there are OLE methods whose name is “max”.)

My preference for writing code for OLE is to use uppercase method calls
(range.Select) and save lowercase for Ruby methods. But this should
provide compatibility for people who have range.select in their code.

I prefer this approach.
In Win32OLE, WIN32OLE includes Enumerable.
If you want to call original method(range.select),
you should use range.Select.
(And Win32OLE does not provide the compatibility.
I have no idea to provide the compatibility.)

Or,
In Win32OLE, WIN32OLE does not include Enumerable.
If you want to use Enumerable’s method,
you add the following code at your own risk.
class WIN32OLE
include Enumerable
end

IEnums should have Enumerable.

I agree with you, but I have no idea that all things work well.

Regards,
Masaki S.

Hello,
In message “Re: Enumerable and WIN32OLE”
on 06/10/01, Dave B. [email protected] writes:

Some Enumerable’s methods does not need a block, for example, Enumerable#max.
So, I hesitate to implement your idea.
(I am not sure that there are OLE methods whose name is “max”.)

I had an earlier version of the code I posted that went through
Enumerable.instance_methods but skipped specific methods that don’t need
blocks (min, max, to_a, entries, grep, sort, zip, /enum_./, /.?$/).
You can probably dismiss this option as well as what I wrote, just for
being so inconsistent. I don’t prefer this option, but I think it does
strike a valuable balance between POLS and compatibility.

I think I understand your code skip the methods that don’t need
blocks.
But, for example, if there is an OLE methods whose name is “max”,
then, I am afraid that we might have the same problem.
Which method does the following code call (in your posted code)?
OLE method max or Enumerable#max?

ole = WIN32OLE.new(…)
ole.max

Do I misunderstand you?

Looking at where String’s going in Ruby (apparently becoming
non-Enumerable in 1.9) another option could be to leave Enumerable out
of WIN32OLE itself, but provide an enum method to return an enumerator
object:

class WIN32OLE
def enum
Enumerable::Enumerator.new(self)
end
end

Hmm, please give me some time to investigate it.
(If there is OLE “enum” method, I think we might have the same problem
…)

Regards,
Masaki S.

Masaki S. wrote:

In message “Re: Enumerable and WIN32OLE”
on 06/09/30, Dave B. [email protected] writes:

What about something like this, though? For these methods, a block is
always provided. For a COM method call, a block is never provided. Why
not dispatch depending on block_given?

Some Enumerable’s methods does not need a block, for example, Enumerable#max.
So, I hesitate to implement your idea.
(I am not sure that there are OLE methods whose name is “max”.)

I had an earlier version of the code I posted that went through
Enumerable.instance_methods but skipped specific methods that don’t need
blocks (min, max, to_a, entries, grep, sort, zip, /enum_./, /.?$/).
You can probably dismiss this option as well as what I wrote, just for
being so inconsistent. I don’t prefer this option, but I think it does
strike a valuable balance between POLS and compatibility.

I prefer this approach.
In Win32OLE, WIN32OLE includes Enumerable.
If you want to call original method(range.select),
you should use range.Select.
(And Win32OLE does not provide the compatibility.
I have no idea to provide the compatibility.)

I don’t think this is a bad idea, but the incompatibility issue needs
considering. I think it’s worth it.

Or,
In Win32OLE, WIN32OLE does not include Enumerable.
If you want to use Enumerable’s method,
you add the following code at your own risk.
class WIN32OLE
include Enumerable
end

This (what we currently have) is deficient in the principle of least
surprise and utility. You should not have to explicitly include or
extend Enumerable on a WIN32OLE IEnum object.

Looking at where String’s going in Ruby (apparently becoming
non-Enumerable in 1.9) another option could be to leave Enumerable out
of WIN32OLE itself, but provide an enum method to return an enumerator
object:

class WIN32OLE
def enum
Enumerable::Enumerator.new(self)
end
end

Cheers,
Dave

Masaki S. wrote:

Do I misunderstand you?
No, that’s right, that is still an issue, only for (min, max, entries,
sort, grep).

Hmm, please give me some time to investigate it.
(If there is OLE “enum” method, I think we might have the same problem …)

I missed something in the Enumerator API: the method Object#to_enum does
what I intended “enum” to do.

Cheers,
Dave