Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.ruby > #2542 > unrolled thread
| Started by | Vahagn Hayrapetyan <vahagnh@gmail.com> |
|---|---|
| First post | 2011-04-08 13:19 -0500 |
| Last post | 2011-04-13 06:25 -0500 |
| Articles | 15 — 4 participants |
Back to article view | Back to comp.lang.ruby
Calling to_enum on a MatchData object Vahagn Hayrapetyan <vahagnh@gmail.com> - 2011-04-08 13:19 -0500
Re: Calling to_enum on a MatchData object 7stud -- <bbxx789_05ss@yahoo.com> - 2011-04-08 14:41 -0500
Re: Calling to_enum on a MatchData object 7stud -- <bbxx789_05ss@yahoo.com> - 2011-04-08 14:21 -0500
Re: Calling to_enum on a MatchData object 7stud -- <bbxx789_05ss@yahoo.com> - 2011-04-08 20:09 -0500
Re: Calling to_enum on a MatchData object Vahagn Hayrapetyan <vahagnh@gmail.com> - 2011-04-09 07:03 -0500
Re: Calling to_enum on a MatchData object 7stud -- <bbxx789_05ss@yahoo.com> - 2011-04-09 13:18 -0500
Re: Calling to_enum on a MatchData object Vahagn Hayrapetyan <vahagnh@gmail.com> - 2011-04-13 06:14 -0500
Re: Calling to_enum on a MatchData object Gary Wright <gwtmp01@mac.com> - 2011-04-09 14:25 -0500
Re: Calling to_enum on a MatchData object 7stud -- <bbxx789_05ss@yahoo.com> - 2011-04-09 17:17 -0500
Re: Calling to_enum on a MatchData object Vahagn Hayrapetyan <vahagnh@gmail.com> - 2011-04-13 06:28 -0500
Re: Calling to_enum on a MatchData object Gary Wright <gwtmp01@mac.com> - 2011-04-13 22:44 -0500
Re: Calling to_enum on a MatchData object 7stud -- <bbxx789_05ss@yahoo.com> - 2011-04-09 14:02 -0500
Re: Calling to_enum on a MatchData object Robert Klemme <shortcutter@googlemail.com> - 2011-04-13 06:45 -0500
Re: Calling to_enum on a MatchData object Vahagn Hayrapetyan <vahagnh@gmail.com> - 2011-04-14 11:13 -0500
Re: Calling to_enum on a MatchData object Vahagn Hayrapetyan <vahagnh@gmail.com> - 2011-04-13 06:25 -0500
| From | Vahagn Hayrapetyan <vahagnh@gmail.com> |
|---|---|
| Date | 2011-04-08 13:19 -0500 |
| Subject | Calling to_enum on a MatchData object |
| Message-ID | <840b7dcf34f7c1ae6b2b9d80a6b55b69@ruby-forum.com> |
Hi, I have the following snippet of code:
def x
File.open('screen.css') do |f|
while line = f.gets
file = line.match(/"(\w*.css)"/)
puts file.class #MatchData
puts file.methods #to_enum defined
e = file.to_enum
puts e.class #Enumerator
puts e.methods #each method defined
e.each do |entry|:
puts entry
end
end
end
end
The result of the regex operation gets stored in "file" as a MatchData
object. Then I convert it to an Enumerator object, which by all accounts
has an each method defined. Yet when I try to "e.each" here's what I
get:
undefined method `each' for #<MatchData "\"reset.css\"" 1:"reset.css">
(NoMethodError).
Then I check the docs for the MatchData class:
http://www.ruby-doc.org/core/classes/MatchData.html
and find that no, "to_enum" isn't defined. But then I don't understand
why
file.methods lists it, and why no error is generated when I call
file.to_enum.
Help really appreciated.
--
Posted via http://www.ruby-forum.com/.
[toc] | [next] | [standalone]
| From | 7stud -- <bbxx789_05ss@yahoo.com> |
|---|---|
| Date | 2011-04-08 14:41 -0500 |
| Message-ID | <0d13a1f47b5cfb398b7353d11d724f6f@ruby-forum.com> |
| In reply to | #2542 |
By the way, one way to get a handle on which instance methods a class defines itself and which are inherited is like this: not_inherited = false puts MatchData.instance_methods(not_inherited).sort #'false' means don't display inherited methods --output:-- == [] begin captures end eql? hash inspect length names offset post_match pre_match regexp size string to_a to_s values_at Then to find to_enum() you need to look in parent classes and any modules that MatchData includes. -- Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [next] | [standalone]
| From | 7stud -- <bbxx789_05ss@yahoo.com> |
|---|---|
| Date | 2011-04-08 14:21 -0500 |
| Message-ID | <c1dd7962cd9c06e4664e0fe89e6dab6f@ruby-forum.com> |
| In reply to | #2542 |
Vahagn Hayrapetyan wrote in post #991813:
> Hi, I have the following snippet of code:
>
> def x
> File.open('screen.css') do |f|
> while line = f.gets
> file = line.match(/"(\w*.css)"/)
> puts file.class #MatchData
> puts file.methods #to_enum defined
> e = file.to_enum
> puts e.class #Enumerator
> puts e.methods #each method defined
> e.each do |entry|
> puts entry
> end
> end
> end
> end
>
> The result of the regex operation gets stored in "file" as a MatchData
> object. Then I convert it to an Enumerator object, which by all accounts
> has an each method defined. Yet when I try to "e.each" here's what I
> get:
>
> undefined method `each' for #<MatchData "\"reset.css\"" 1:"reset.css">
> (NoMethodError).
>
> Then I check the docs for the MatchData class:
> http://www.ruby-doc.org/core/classes/MatchData.html
>
> and find that no, "to_enum" isn't defined.
to_enum() is defined in Object, and all classes inherit from Object.
You need to hook up an enumerator's each() method to *an iteration
method of another object*. You specify the iteration method as an
argument to to_enum(). If you don't specify an iteration method, the
default is each()--and the MatchData class does not define an each()
method. Hence your error.
--
Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [next] | [standalone]
| From | 7stud -- <bbxx789_05ss@yahoo.com> |
|---|---|
| Date | 2011-04-08 20:09 -0500 |
| Message-ID | <443ff01c7f2047f63b4e7ec934f4cc8a@ruby-forum.com> |
| In reply to | #2542 |
You also might want to use the synonym enum_for() instead of to_enum(), so that it is readily apparent that you are supposed to supply an argument. -- Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [next] | [standalone]
| From | Vahagn Hayrapetyan <vahagnh@gmail.com> |
|---|---|
| Date | 2011-04-09 07:03 -0500 |
| Message-ID | <e6e43a5fecbaa1960938d453c77314ee@ruby-forum.com> |
| In reply to | #2542 |
Thank you for your explanations, I can see now that :each is an
inherited method and it had to be ferreted out of the MatchData set of
methods.
So in order to use an enumerator, an object itself has to define an
(:each) method and then an enumerator just augments that. I agree that
enum_for(:some_method) is better syntax. This is what I've done just to
experiment:
def x
File.open('screen.css') do |f|
while line = f.gets
file = line.match(/" (\w* [.] css) "/xms)
puts file.class
puts file.respond_to?(:each) #false
file = line.match(/" (\w* [.] css) "/xms).captures
puts file.class #Array
puts file.class.instance_methods(false).sort #each is defined
e = file.enum_for(:each) #just the default
e.each do |entry| #now the enumerator works
puts entry
end
end
end
end
Regarding the regexp: yeah - I was using the universal matcher instead
of the dot character by mistake. It worked to fetch the filenames but it
was a false positive of course.
"It would be nice if the docs specified any parent class to make the
hierarchy easy to follow."
That would be helpful, definitely.
Cheers, Vahagn
--
Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [next] | [standalone]
| From | 7stud -- <bbxx789_05ss@yahoo.com> |
|---|---|
| Date | 2011-04-09 13:18 -0500 |
| Message-ID | <b5660160be5954fca0117643f7dcb9f1@ruby-forum.com> |
| In reply to | #2579 |
Vahagn Hayrapetyan wrote in post #991914:
> Thank you for your explanations, I can see now that :each is an
> inherited method and it had to be ferreted out of the MatchData set of
> methods.
>
I'm not sure what you are referring to because each() is neither defined
nor inherited in the MatchData class. Check the output of:
md = /h/.match('hello')
puts md.methods.sort
And Enumerator defines its own each() method.
> So in order to use an enumerator, an object itself has to define an
> (:each) method and then an enumerator just augments that.
No. An enumerator can be hooked up to any "iteration method" for an
object. An "iteration method" is any method that calls yield(). Here
is an example:
class Dog
def bark
yield 'woof'
yield 'whooooo'
yield 'ruuuff'
end
end
dog = Dog.new
e = dog.enum_for(:bark)
results = e.select{|sound| sound[0] == 'w'}
p results
--output:---
["woof", "whooooo"]
results = e.map{|sound| "#{sound.capitalize}!}" }
p results
--output:--
["Woof!}", "Whooooo!}", "Ruuuff!}"]
if e.include?('woof')
puts 'yes'
end
--output:--
yes
You may be confusing Enumer-ator with something you read about
Enumer-able. If you want to make the Enumer-able methods available to
your class, e.g. group_by(), each_slice(), select(), map(), include?(),
etc., then your class has to:
1) Define an each() method, and
2) include Enumerable
Now the confusing part: the Enumer-ator class defines a few of its own
methods, but it also includes Enumer-able, so an enumerator object has
both the Enumerator and Enumerable methods available to it.
An enumerator can also be hooked up to a block that you define:
e = Enumerator.new do |y|
10.upto(14) do |num|
y << num
end
end
results = e.map{|x| x + 5}
p results
--output:--
[15, 16, 17, 18, 19]
--
Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [next] | [standalone]
| From | Vahagn Hayrapetyan <vahagnh@gmail.com> |
|---|---|
| Date | 2011-04-13 06:14 -0500 |
| Message-ID | <344464c2400147e5f1dae39f855a89b7@ruby-forum.com> |
| In reply to | #2581 |
Hi,
> I'm not sure what you are referring to because each() is neither defined
> nor inherited in the MatchData class. Check the output of:
>
> md = /h/.match('hello')
> puts md.methods.sort
>
> And Enumerator defines its own each() method.
Sorry - I meant to say "enum_for / to_enum" was inherited and had to be
ferreted out. The reason why I made this mistake is because of this:
o = Object.new
e = o.enum_for #No argument given, so :each is implied. No errors!
e.next #NoMethodError: undefined method `each' for #<Object:0x12ed00>
o.respond_to?(:each) #false. Aha!
My confusion with this stems from line 2 above - that you can define a
method using a non-existent method as default argument and not get any
error message as a consequence of that. But hey - "Ruby is dynamic and
so is human nature", so I think I am going to like this behavior anyway.
> You may be confusing Enumer-ator with something you read about
> Enumer-able.
Exactly! I was mixing them up with regards to "each" and "yield". "The
Well-Grounded Rubyist" is a great book though.
Thanks again for your help - your examples are excellent.
--
Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [next] | [standalone]
| From | Gary Wright <gwtmp01@mac.com> |
|---|---|
| Date | 2011-04-09 14:25 -0500 |
| Message-ID | <0BEAEB78-76E6-4C9F-9EFD-55593D99E939@mac.com> |
| In reply to | #2579 |
On Apr 9, 2011, at 8:03 AM, Vahagn Hayrapetyan wrote:
> def x
> File.open('screen.css') do |f|
> while line = f.gets
> file = line.match(/" (\w* [.] css) "/xms)
> puts file.class
> puts file.respond_to?(:each) #false
> file = line.match(/" (\w* [.] css) "/xms).captures
> puts file.class #Array
> puts file.class.instance_methods(false).sort #each is defined
>
> e = file.enum_for(:each) #just the default
> e.each do |entry| #now the enumerator works
> puts entry
> end
>
> end
> end
> end
You are doing lots of unnecessary work there. Since MatchData#captures
returns an array and Array already defines each, you don't need to create
any enumerator at all to iterate through the #captures array:
> def x
> File.open('screen.css') do |f|
> while line = f.gets
> file = line.match(/" (\w* [.] css) "/xms)
> puts file.class
> puts file.respond_to?(:each) #false
> file = line.match(/" (\w* [.] css) "/xms).captures
> file.each do |entry|
> puts entry
> end
> end
> end
> end
Gary Wright
[toc] | [prev] | [next] | [standalone]
| From | 7stud -- <bbxx789_05ss@yahoo.com> |
|---|---|
| Date | 2011-04-09 17:17 -0500 |
| Message-ID | <9c1c8032cd68837519fae5f3e1d22028@ruby-forum.com> |
| In reply to | #2583 |
Gary Wright wrote in post #991944: > On Apr 9, 2011, at 8:03 AM, Vahagn Hayrapetyan wrote: >> e = file.enum_for(:each) #just the default >> e.each do |entry| #now the enumerator works >> puts entry >> end >> >> end >> end >> end > > > You are doing lots of unnecessary work there. Since MatchData#captures > returns an array and Array already defines each, you don't need to > create > any enumerator at all to iterate through the #captures array: > As the op said: >>> This is what I've done just to >>> experiment: -- Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [next] | [standalone]
| From | Vahagn Hayrapetyan <vahagnh@gmail.com> |
|---|---|
| Date | 2011-04-13 06:28 -0500 |
| Message-ID | <73925a01065aab0c89477b47574cf046@ruby-forum.com> |
| In reply to | #2589 |
>> You are doing lots of unnecessary work there. Since MatchData#captures
>> returns an array and Array already defines each, you don't need to
>> create
>> any enumerator at all to iterate through the #captures array:
>>
>
> As the op said:
>
>>>> This is what I've done just to
>>>> experiment:
Exactly - that was just to get proof of Enumerator working. In my
method, I just use :each of an Array object:
def x
File.open('screen.css') do |f|
while line = f.gets
file = line.match(/" (\w* [.] css) "/xms).captures
file.each do |entry|
puts entry
y(entry)
end
end
end
end
--
Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [next] | [standalone]
| From | Gary Wright <gwtmp01@mac.com> |
|---|---|
| Date | 2011-04-13 22:44 -0500 |
| Message-ID | <4C18FBB2-4C37-45C1-AE0D-858750CB9425@mac.com> |
| In reply to | #2745 |
On Apr 13, 2011, at 7:28 AM, Vahagn Hayrapetyan wrote: >>> You are doing lots of unnecessary work there. Since MatchData#captures >>> returns an array and Array already defines each, you don't need to >>> create >>> any enumerator at all to iterate through the #captures array: >>> >> >> As the op said: >> >>>>> This is what I've done just to >>>>> experiment: > > Exactly - that was just to get proof of Enumerator working. In my > method, I just use :each of an Array object: OK. I guess I didn't read closely enough. Gary Wright
[toc] | [prev] | [next] | [standalone]
| From | 7stud -- <bbxx789_05ss@yahoo.com> |
|---|---|
| Date | 2011-04-09 14:02 -0500 |
| Message-ID | <7de49bdd11ef30170f71c5d9f9258f9b@ruby-forum.com> |
| In reply to | #2542 |
Here's how you can use an enumerator to create an infinite array, from
which you can print out finite chunks:
e = Enumerator.new do |y|
(0..9).cycle do |x|
y << x
end
end
p e.take(15)
--output:--
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
--
Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [next] | [standalone]
| From | Robert Klemme <shortcutter@googlemail.com> |
|---|---|
| Date | 2011-04-13 06:45 -0500 |
| Message-ID | <BANLkTimpzFxDePrTvGfVBqOtOY5ssaUq-Q@mail.gmail.com> |
| In reply to | #2582 |
On Wed, Apr 13, 2011 at 1:25 PM, Vahagn Hayrapetyan <vahagnh@gmail.com> wrote:
> 7stud -- wrote in post #991942:
>> Here's how you can use an enumerator to create an infinite array--from
>> which you can print out finite chunks:
>>
>> e = Enumerator.new do |y|
>> (0..9).cycle do |num|
>> y << num
>> end
>> end
>>
>>
>> p e.take(15)
>>
>> --output:--
>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
>
> I just tried out (0..9).cycle {|n| puts n} in an irb session and had to
> Ctrl+C it to stop the loop. However when wrapped in a Enumerator like
> your example above, just an Enumerator::Generator object is returned.
> What happens to the infinite loop - does it still crunch the numbers out
> in the background or does it "stop" at some point? I looked at puts
> e.methods.sort
> but they aren't very revealing of what's going on with the loop...
The logic is a bit tricky. :-) The Enumerator::Generator is just
something which can enumerate something. There is no infinite loop
until you start iterating that instance via #each or any other method
defined in Enumerable. Actually the loop is "interrupted" every time
"y << num" is invoked.
Demonstration without infinite loop:
irb(main):003:0> e = Enumerator.new {|y| puts "+"; 5.times {|i| puts
"-#{i}"; y << i}}
=> #<Enumerator: #<Enumerator::Generator:0x1093d1a8>:each>
irb(main):004:0> e.each {|a| puts "*#{a}"}
+
-0
*0
-1
*1
-2
*2
-3
*3
-4
*4
=> 5
You can see how the block from line 4 and the last block in line 3 are
called interleavingly. Here's another way to look at it:
irb(main):013:0> e = Enumerator.new {|y| puts "+", y.class; y << 0}
=> #<Enumerator: #<Enumerator::Generator:0x1097b340>:each>
irb(main):014:0> e.each { puts caller(0) }
+
Enumerator::Yielder
(irb):14:in `block in irb_binding'
(irb):13:in `<<'
(irb):13:in `block in irb_binding'
(irb):14:in `each'
(irb):14:in `each'
(irb):14:in `irb_binding'
/opt/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'
..
/opt/bin/irb19:12:in `<main>'
=> #<Enumerator::Yielder:0x10978f14>
Actually the block of #each is invoked through Enumerator::Yielder#<<.
Kind regards
robert
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
[toc] | [prev] | [next] | [standalone]
| From | Vahagn Hayrapetyan <vahagnh@gmail.com> |
|---|---|
| Date | 2011-04-14 11:13 -0500 |
| Message-ID | <b03ecab53a05f89490b2be323de692ae@ruby-forum.com> |
| In reply to | #2746 |
> Posted by Robert K. (robert_k78) on 2011-04-13 13:45
> The logic is a bit tricky. :-) The Enumerator::Generator is just
> something which can enumerate something. There is no infinite loop
> until you start iterating that instance via #each or any other method
> defined in Enumerable. Actually the loop is "interrupted" every time
> "y << num" is invoked.
>
OK. So I guess this syntax:
e = Enumerator.new do |y|
(0..9).cycle do |num|
y << num
end
end
Is more declarative in that it just declares an enumerator without
setting off the infinite loop inside. To execute the loop one needs
something like:
e.take(15)
And then there is no infinite loop either, as the amount of iterations
is scoped by the argument to take().
Great examples in your post, I appreciate it!
--
Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [next] | [standalone]
| From | Vahagn Hayrapetyan <vahagnh@gmail.com> |
|---|---|
| Date | 2011-04-13 06:25 -0500 |
| Message-ID | <2ec5aead98ee85153308eb7b43e82adf@ruby-forum.com> |
| In reply to | #2582 |
7stud -- wrote in post #991942:
> Here's how you can use an enumerator to create an infinite array--from
> which you can print out finite chunks:
>
> e = Enumerator.new do |y|
> (0..9).cycle do |num|
> y << num
> end
> end
>
>
> p e.take(15)
>
> --output:--
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
I just tried out (0..9).cycle {|n| puts n} in an irb session and had to
Ctrl+C it to stop the loop. However when wrapped in a Enumerator like
your example above, just an Enumerator::Generator object is returned.
What happens to the infinite loop - does it still crunch the numbers out
in the background or does it "stop" at some point? I looked at puts
e.methods.sort
but they aren't very revealing of what's going on with the loop...
--
Posted via http://www.ruby-forum.com/.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.ruby
csiph-web