I'm a bit confused about how Ruby handles the creation of Enumerators. Block-based iteration makes sense and is working for me; I am still confused how the return of an Enumerator is supposed to function code-wise.
Here is the code I am working with:
VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame( int argc,
VALUE* args,
VALUE rb_self ) {
rb_thread_t* c_thread = GET_THREAD();
// Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp ) );
// c_top_of_control_frame describes the top edge of the stack trace
// set c_top_of_control_frame to the first frame in <main>
rb_control_frame_t* c_top_of_control_frame = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME( (void *)( c_thread->stack + c_thread->stack_size ) ) );
// for each control frame:
while ( c_current_context_frame < c_top_of_control_frame ) {
VALUE rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
// if we don't have a block, return enumerator
RETURN_ENUMERATOR( rb_self, 0, NULL );
// otherwise, yield the block
rb_yield( rb_frame_hash );
c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
}
return Qnil;
}
How would the final line in the while loop be called in the case of an Enumerator?
Does all of my loop activity have to take place before calls to RETURN_ENUMERATOR (since RETURN_ENUMERATOR presumably has to come before rb_yield())?
What if I want something to happen once the internal iteration finishes? With the block I can simply put it after the while loop; presumably the same works in the case of an Enumerator- but how? It seems like every time through the loop it returns an Enumerator, so how does the Enumerator know to return the appropriate corresponding object? rb_yield gets rb_frame_hash as a passed arg, but RETURN_ENUMERATOR seems to take the args that are relayed to the method when the Enumerator calls the method internally. So clearly the Enumerator is calling the method itself- perhaps with some sort of internal block that simply returns the instance of rb_frame_hash?
Any insight into the internals is appreciated.
-Asher