Unit testing an each function

James Edward Gray II wrote:

Hrm, I just discovered that Enumerable::Enumerator already exists
(require 'enumerator'), but I can't find docs on it. ruby-doc.org gives
me a 404 on the enumerator page

I believe James Britt said he had a copy of the docs but couldn't see the value in putting them up:

Well, no. What I said was, "There had been an older version on them on ruby-doc, though I think they got lost in the server shuffle.

I can add them again, if there is sufficient interest. But it seems that they're a bit avant garde for most people who wouldn't already have them locally anyway."

*I* can see the value, but I wasn't sure who else had a need for them that didn't already have a more convenient local copy.

And they *used* to be up but got lost in a menu re-org or something or other.

I filed a complaint, maybe you should add one too. :frowning:

OK, that frowny face really put me over the edge, so:

http://ruby-doc.org/core-1.9/

I'll add a link to the main page later on when I get home.

James Britt

···

On Oct 18, 2005, at 5:41 PM, Kevin Ballard wrote:

--

http://www.ruby-doc.org - The Ruby Documentation Site
http://www.rubyxml.com - News, Articles, and Listings for Ruby & XML
http://www.rubystuff.com - The Ruby Store for Ruby Stuff
http://www.jamesbritt.com - Playing with Better Toys

Hmm, isn't what you wrote an automatic Generator class? (See standard library.)

Yeah, I don't have a problem with it. I'm probably not the kind of guy who would using it, but if you and others would, go for it. I love sharing. :slight_smile:

James Edward Gray II

···

On Oct 18, 2005, at 6:32 PM, Kevin Ballard wrote:

James Edward Gray II wrote:

For what it's worth, I don't believe enumerator is what you built
here.

Do you think what I built here is worth packaging up into a gem?

Thank you. I'm sure it will help many people.

James Edward Gray II

···

On Oct 18, 2005, at 7:08 PM, James Britt wrote:

I filed a complaint, maybe you should add one too. :frowning:

OK, that frowny face really put me over the edge, so:

http://ruby-doc.org/core-1.9/

I'll add a link to the main page later on when I get home.

James Edward Gray II wrote:

Hmm, isn't what you wrote an automatic Generator class? (See
standard library.)

Not really. Generator basically gives you external iterators which you
can access element by element, so you can do things like iterate over 2
enumerables in step. What I wrote is basically just a convenience for
applying a method call to all the elements in a single enumerable.
After all,

  %w{a long list of words}.collect.length

is the same thing as

  %w{a long list of words}.collect { |item| item.length}

but easier to read.

Yeah, I don't have a problem with it. I'm probably not the kind of
guy who would using it, but if you and others would, go for it. I
love sharing. :slight_smile:

Ok, then I'll probably package it up tomorrow.

ES wrote:

Whoops, sent too soon! I was going to continue >to say that while this is
nice, for clarity of expression you might want to >state it this way:

   %w{a long list of words}.collect :length

But then that interferes with the ability to do

  [(1..5), (10..15)].each.each { |i| puts i }

(which was the original point of this exercise) or any other nested
enumerations such as

  [(1..5), (10..15)].collect.collect {|i| i + 1}

Brian Schröder wrote:

I'd understand this
> %w{a long list of words}.collect.length
as giving me the length of the return value of collect. Collect
returns an array so I'd expect the above to return five. Maybe it
would be better to write

%w{a long list of words}.collect_with :length

where in method missing something like this would happen

[...]

Again, same problem, plus the fact that I don't want to be using
method_missing as it would interfere with any existing method_missing

With the famous

   class Symbol
     def to_proc
       lambda { |obj| obj.send self }
     end
   end

you can get the same result via

   %w{a long list of words}.map(&:length).map(&:to_s)

I'd bet the Symbol#to_proc is somewhere in Nano.

I find that much harder to read, and it also precludes the possibility
of something like

  (1..100).reject.even?

This, of course, relies on a definition of Integer#even? and having the
reject method wrapped, but that's pretty easy:

  class Integer
    def even?
      (self % 2).zero?
    end
  end
  Enumerable::wrap_meth Enumerable, :reject

Granted, for a single use, you'd probably just want to do

  (1..100).reject { |i| (i % 2).zero? }

rather than defining a new method, but this example is just for
illustration.

Of course, it's really intended for dealing with nested enumerables,
like the [(1..5), (10..15)] example above, but it does simplify very
simple single-enumerable handling.

···

on the class. Pit Capitain wrote:

Kevin Ballard wrote:

James Edward Gray II wrote:

Hmm, isn't what you wrote an automatic Generator class? (See
standard library.)

Not really. Generator basically gives you external iterators which you
can access element by element, so you can do things like iterate over 2
enumerables in step. What I wrote is basically just a convenience for
applying a method call to all the elements in a single enumerable.
After all,

  %w{a long list of words}.collect.length

is the same thing as

  %w{a long list of words}.collect { |item| item.length}

but easier to read.

Yeah, I don't have a problem with it. I'm probably not the kind of
guy who would using it, but if you and others would, go for it. I
love sharing. :slight_smile:

Ok, then I'll probably package it up tomorrow.

Please do! This idiom is an improvement over dbrock's foo.each {.succ}
which still required a preprocessor.

E

James Edward Gray II wrote:
> Hmm, isn't what you wrote an automatic Generator class? (See
> standard library.)

Not really. Generator basically gives you external iterators which you
can access element by element, so you can do things like iterate over 2
enumerables in step. What I wrote is basically just a convenience for
applying a method call to all the elements in a single enumerable.
After all,

  %w{a long list of words}.collect.length

is the same thing as

  %w{a long list of words}.collect { |item| item.length}

but easier to read.

I'd understand this

  %w{a long list of words}.collect.length

as giving me the length of the return value of collect. Collect
returns an array so I'd expect the above to return five. Maybe it
would be better to write

%w{a long list of words}.collect_with :length

where in method missing something like this would happen

module Enumerable
  def method_missing(method, *methods, &block)
    if /(^.*)_with$/ =~ method.to_s
      send($1) do | a |
  methods.inject(a) { | r, m | r.send(m) }
      end
    else
      super
    end
  end
end

%w{a long list of words}.collect_with :length, :to_s
# => ["1", "4", "4", "2", "5"]

regards,

Brian

···

On 19/10/05, Kevin Ballard <kballard@gmail.com> wrote:

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

[snip]

  (1..100).reject.even?

[snip]

Just wanted to state that on second reading of this thread it again
did hurt in my eyes. If I read (1.100).reject I expect a resulting
array. And when I read the above I wondered shortly if even? works on
arrays maybe returning true if the array has an even number of
entries. Then I remembered the thread topic and started this text. So
a
  -1
from me for proposing this as an addition to the language.

regards,

Brian

···

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

ES wrote:

Kevin Ballard wrote:

James Edward Gray II wrote:

Hmm, isn't what you wrote an automatic Generator class? (See
standard library.)

Not really. Generator basically gives you external iterators which you
can access element by element, so you can do things like iterate over 2
enumerables in step. What I wrote is basically just a convenience for
applying a method call to all the elements in a single enumerable.
After all,

  %w{a long list of words}.collect.length

is the same thing as

  %w{a long list of words}.collect { |item| item.length}

but easier to read.

Yeah, I don't have a problem with it. I'm probably not the kind of
guy who would using it, but if you and others would, go for it. I
love sharing. :slight_smile:

Ok, then I'll probably package it up tomorrow.

Please do! This idiom is an improvement over dbrock's foo.each {.succ}
which still required a preprocessor.

Whoops, sent too soon! I was going to continue to say that while this is
nice, for clarity of expression you might want to state it this way:

   %w{a long list of words}.collect :length

E

Brian Schröder schrieb:

I'd understand this

%w{a long list of words}.collect.length

as giving me the length of the return value of collect. Collect
returns an array so I'd expect the above to return five. Maybe it
would be better to write

%w{a long list of words}.collect_with :length

where in method missing something like this would happen

module Enumerable
  def method_missing(method, *methods, &block)
    if /(^.*)_with$/ =~ method.to_s
      send($1) do | a |
  methods.inject(a) { | r, m | r.send(m) }
      end
    else
      super
    end
  end
end

%w{a long list of words}.collect_with :length, :to_s
# => ["1", "4", "4", "2", "5"]

With the famous

   class Symbol
     def to_proc
       lambda { |obj| obj.send self }
     end
   end

you can get the same result via

   %w{a long list of words}.map(&:length).map(&:to_s)

I'd bet the Symbol#to_proc is somewhere in Nano.

Regards,
Pit

Brian Schröder wrote:

> [snip]
>
> (1..100).reject.even?
>
> [snip]

Just wanted to state that on second reading of this thread it again
did hurt in my eyes. If I read (1.100).reject I expect a resulting
array. And when I read the above I wondered shortly if even? works on
arrays maybe returning true if the array has an even number of
entries. Then I remembered the thread topic and started this text. So
a
  -1
from me for proposing this as an addition to the language.

Except that (1..100).reject doesn't return an array at all unless a
block is supplied - it gives a LocalJumpError. All the enumerating
methods I've tested except for Enumerable#collect give an error when
called without a block (#collect without a block is equivalent to
#to_a). So with this change, the case where no block is supplied
becomes useful as opposed to useless (and in the #collect case, I can't
imagine anybody's actually relying on #collect being equivalent to
#to_a when called without a block, because they should be using #to_a
directly for that).

In any case, I wasn't proposing this as an addition to the language
(not that I would mind), I was simply proposing this as something I
should package up into a gem so people could use it if they wanted.

Thats interesting pit. Thank you. Though I'm quite shure I'd never use
either of the solutions proposed here, because I think they introduce
unreadability by uncommon magic. Better to write

%w{a long list of words}.map { | e | e.length.to_s }

which additionally has less line noise in it.

regards,

Brian

···

On 19/10/05, Pit Capitain <pit@capitain.de> wrote:

Brian Schröder schrieb:
> I'd understand this
>
>> %w{a long list of words}.collect.length
>
> as giving me the length of the return value of collect. Collect
> returns an array so I'd expect the above to return five. Maybe it
> would be better to write
>
> %w{a long list of words}.collect_with :length
>
> where in method missing something like this would happen
>
> module Enumerable
> def method_missing(method, *methods, &block)
> if /(^.*)_with$/ =~ method.to_s
> send($1) do | a |
> methods.inject(a) { | r, m | r.send(m) }
> end
> else
> super
> end
> end
> end
>
> %w{a long list of words}.collect_with :length, :to_s
> # => ["1", "4", "4", "2", "5"]

With the famous

   class Symbol
     def to_proc
       lambda { |obj| obj.send self }
     end
   end

you can get the same result via

   %w{a long list of words}.map(&:length).map(&:to_s)

I'd bet the Symbol#to_proc is somewhere in Nano.

Regards,
Pit

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

Hello Kevin,

it is clear that reject without a block does not work, it was more a
question of visual parsing. Reject without a block has no meaning,
because we need to tell what to reject. And telling this is done with
a block. Your quite intelligent magic gives IMHO a wrong meaning to
the dot operator. You seem not to call .even? on the result of a
reject.

Well effectively you do, but I read chained methods as doing a chain
of succeding operations on a chain of objects, and that is not what I
read when I read (1..100).reject.even? Therefore I proposed
(1..100).reject :even?, because there it is made clearer that even is
given to reject to do something.

Nonetheless go ahed and package it as a gem. I just wanted to voice
what was disturbing me with this syntax.

Best regards,

Brian

···

On 20/10/05, Kevin Ballard <kballard@gmail.com> wrote:

Brian Schröder wrote:
> > [snip]
> >
> > (1..100).reject.even?
> >
> > [snip]
>
> Just wanted to state that on second reading of this thread it again
> did hurt in my eyes. If I read (1.100).reject I expect a resulting
> array. And when I read the above I wondered shortly if even? works on
> arrays maybe returning true if the array has an even number of
> entries. Then I remembered the thread topic and started this text. So
> a
> -1
> from me for proposing this as an addition to the language.

Except that (1..100).reject doesn't return an array at all unless a
block is supplied - it gives a LocalJumpError. All the enumerating
methods I've tested except for Enumerable#collect give an error when
called without a block (#collect without a block is equivalent to
#to_a). So with this change, the case where no block is supplied
becomes useful as opposed to useless (and in the #collect case, I can't
imagine anybody's actually relying on #collect being equivalent to
#to_a when called without a block, because they should be using #to_a
directly for that).

In any case, I wasn't proposing this as an addition to the language
(not that I would mind), I was simply proposing this as something I
should package up into a gem so people could use it if they wanted.

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

Brian Schröder wrote:

Hello Kevin,

it is clear that reject without a block does not work, it was more a
question of visual parsing. Reject without a block has no meaning,
because we need to tell what to reject. And telling this is done with
a block. Your quite intelligent magic gives IMHO a wrong meaning to
the dot operator. You seem not to call .even? on the result of a
reject.

Well effectively you do, but I read chained methods as doing a chain
of succeding operations on a chain of objects, and that is not what I
read when I read (1..100).reject.even? Therefore I proposed
(1..100).reject :even?, because there it is made clearer that even is
given to reject to do something.

Nonetheless go ahed and package it as a gem. I just wanted to voice
what was disturbing me with this syntax.

I understand your disturbance, but the syntax you propose makes the
primary use of this idiom impossible, which is

  [(1..5),(10..15)].each.each { |i| puts i }

What would you suggest, making

  [(1..5),(10..15)].each(:each) { |i| puts i }

behave that way? That looks even more wrong then what my code is doing.
And what if you have even further nesting?

  [[(1..3), (5..8)], [(4..7), (2..6)]].each.each.each { |i| puts i }

Would that be

  [[(1..3), (5..8)], [(4..7), (2..6)]].each(:each, :each) { |i| puts i
}

in your syntax? That's even *harder* to read.

Do you see any way to provide the proper behaviour without using the
syntax my code supports?

Sorry, I do not see a better syntax. But I have to admit that I have
no idea what would be the result of

[[(1..3), (5..8)], [(4..7), (2..6)]].each.each.each { |i| puts i }

(Well if I think long enough, maybe you mean something like

  [[(1..3), (5..8)], [(4..7), (2..6)]].each do | row |
    row.each do | range |
      range.each do |i| puts i end
    end
  end

Which I would prefer about the "new" idiom, but other people may not.

regards,

Brian

···

On 21/10/05, Kevin Ballard <kballard@gmail.com> wrote:

Brian Schröder wrote:
> Hello Kevin,
>
> it is clear that reject without a block does not work, it was more a
> question of visual parsing. Reject without a block has no meaning,
> because we need to tell what to reject. And telling this is done with
> a block. Your quite intelligent magic gives IMHO a wrong meaning to
> the dot operator. You seem not to call .even? on the result of a
> reject.
>
> Well effectively you do, but I read chained methods as doing a chain
> of succeding operations on a chain of objects, and that is not what I
> read when I read (1..100).reject.even? Therefore I proposed
> (1..100).reject :even?, because there it is made clearer that even is
> given to reject to do something.
>
> Nonetheless go ahed and package it as a gem. I just wanted to voice
> what was disturbing me with this syntax.

I understand your disturbance, but the syntax you propose makes the
primary use of this idiom impossible, which is

  [(1..5),(10..15)].each.each { |i| puts i }

What would you suggest, making

  [(1..5),(10..15)].each(:each) { |i| puts i }

behave that way? That looks even more wrong then what my code is doing.
And what if you have even further nesting?

  [[(1..3), (5..8)], [(4..7), (2..6)]].each.each.each { |i| puts i }

Would that be

  [[(1..3), (5..8)], [(4..7), (2..6)]].each(:each, :each) { |i| puts i
}

in your syntax? That's even *harder* to read.

Do you see any way to provide the proper behaviour without using the
syntax my code supports?

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

Brian Schröder wrote:

Sorry, I do not see a better syntax. But I have to admit that I have
no idea what would be the result of

[[(1..3), (5..8)], [(4..7), (2..6)]].each.each.each { |i| puts i }

(Well if I think long enough, maybe you mean something like

  [[(1..3), (5..8)], [(4..7), (2..6)]].each do | row |
    row.each do | range |
      range.each do |i| puts i end
    end
  end

Which I would prefer about the "new" idiom, but other people may not.

Yes, that is what the construct means. Each successive call is one
deeper level of enumeration. If you understand what the nested
enumeration semantics mean, then it's not hard to read.

Kevin Ballard wrote:

Brian Schröder wrote:

Sorry, I do not see a better syntax. But I have to admit that I have
no idea what would be the result of

[[(1..3), (5..8)], [(4..7), (2..6)]].each.each.each { |i| puts i }

This is *really* hard to read if you just see:

   @some_array.each.each.each {|i| puts i}

(Well if I think long enough, maybe you mean something like

[[(1..3), (5..8)], [(4..7), (2..6)]].each do | row |
   row.each do | range |
     range.each do |i| puts i end
   end
end

Which I would prefer about the "new" idiom, but other people may not.

Yes, that is what the construct means. Each successive call is one
deeper level of enumeration. If you understand what the nested
enumeration semantics mean, then it's not hard to read.

You are also happily ignoring the non-enumerable confusion that this
may cause. Of course, this being a library, you are free to do as you
please.

E