--Multipart_Tue_Nov_17_11:41:43_2009-1 Content-Type: text/plain; charset=US-ASCII Hi, At Tue, 17 Nov 2009 06:48:42 +0900, Yehuda Katz <wycats / gmail.com> wrote: > For instance, you can do the following in Rails: > > module ActionController::MimeResponds > extend ActiveSupport::Concern > > included do > inheritable_accessor :responder, :mimes_for_respond_to, > :instance_writer false > self.responder ctionController::Responder > clear_respond_to > end > end Do you mean that `self.responder ctionController::Responder' can be replaced by `self.responder esponder' on Ruby 1.8? Then, does it really work on Ruby 1.8? I guess MimeResponds should be nested in ActionController as follows: module ActionController module MimeResponds ... end end > > This is a wrapper around the very common: > > def self.included(klass) > klass.class_eval do > # code here > end > end For Matz and Koichi (and other people who aren't familiar with Rails), included and append_features are overridden in ActiveSupport::Concern as follows: def included(base il, &block) if base.nil? @_included_block lock else super end end def append_features(base) if super ... base.class_eval(&@_included_block) if instance_variable_defined?("@_incl uded_block") end end > Because I understand the utility in the Ruby 1.9 approach, I would like to > suggest that users be allowed to choose which scoping they want. I suggest > that module_eval, by default, revert to Ruby 1.8 behavior. I also suggest > that we add a new method (or flag to module_eval) to enable the new > behavior. I basically prefer the behavior of Ruby 1.9. I think class variables should especially be lookuped like Ruby 1.9 because they can't be accessed outside of a class or its instance. Then, I guess your problem may be able to fixed differently. The problem is not that Ruby 1.9 prepends the receiver of class_eval to the constant lookup path, but that a wrapper of class_eval can't be implemented on Ruby 1.9. The following program works on both Ruby 1.8 and 1.9: class Foo end module ActionController Responder This is a Responder" module MimeResponds Foo.class_eval do p Responder end end end However, the following program doesn't work on Ruby 1.9: def my_class_eval(klass, &block) klass.class_eval(&block) end class Foo end module ActionController Responder This is a Responder" module MimeResponds my_class_eval(Foo) do p Responder end end end It's because class_eval prepends the reciver to the constant lookup path at the time of invocation of class_eval. I think it should prepends the receiver to the constant lookup path which the given block holds. I have attached a patch to fix it. If it's acceptable, I'll write a test and commit them. -- Shugo Maeda <shugo / ruby-lang.org> --Multipart_Tue_Nov_17_11:41:43_2009-1 Content-Type: application/octet-stream; type=patch Content-Disposition: attachment; filename="class_eval.diff" Content-Transfer-Encoding: 7bit Index: insns.def --- insns.def (revision 25805) +++ insns.def (working copy) @@ -944,7 +944,7 @@ defineclass rb_bug("unknown defineclass type: %d", (int)define_type); } - COPY_CREF(class_iseq->cref_stack, vm_cref_push(th, klass, NOEX_PUBLIC)); + COPY_CREF(class_iseq->cref_stack, vm_cref_push(th, klass, NOEX_PUBLIC, NULL)); /* enter scope */ vm_push_frame(th, class_iseq, Index: vm_eval.c --- vm_eval.c (revision 25805) +++ vm_eval.c (working copy) @@ -17,7 +17,7 @@ static inline VALUE vm_yield_with_cref(rb_thread_t static inline VALUE vm_yield(rb_thread_t *th, int argc, const VALUE *argv); static inline VALUE vm_backtrace(rb_thread_t *th, int lev); static int vm_backtrace_each(rb_thread_t *th, int lev, rb_backtrace_iter_func *iter, void *arg); -static NODE *vm_cref_push(rb_thread_t *th, VALUE klass, int noex); +static NODE *vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr); static VALUE vm_exec(rb_thread_t *th); static void vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref); static int vm_collect_local_variables_in_heap(rb_thread_t *th, VALUE *dfp, VALUE ary); @@ -1100,13 +1100,14 @@ yield_under(VALUE under, VALUE self, VALUE values) { rb_thread_t *th ET_THREAD(); rb_block_t block, *blockptr; - NODE *cref m_cref_push(th, under, NOEX_PUBLIC); + NODE *cref; if ((blockptr C_GUARDED_PTR_REF(th->cfp->lfp[0])) ! ) { block blockptr; block.self elf; th->cfp->lfp[0] C_GUARDED_PTR(&block); } + cref m_cref_push(th, under, NOEX_PUBLIC, &block); if (values Qundef) { return vm_yield_with_cref(th, 0, 0, cref); @@ -1120,7 +1121,7 @@ yield_under(VALUE under, VALUE self, VALUE values) static VALUE eval_under(VALUE under, VALUE self, VALUE src, const char *file, int line) { - NODE *cref m_cref_push(GET_THREAD(), under, NOEX_PUBLIC); + NODE *cref m_cref_push(GET_THREAD(), under, NOEX_PUBLIC, NULL); if (rb_safe_level() > ) { StringValue(src); Index: vm_insnhelper.c --- vm_insnhelper.c (revision 25805) +++ vm_insnhelper.c (working copy) @@ -1066,14 +1066,17 @@ vm_get_cref(const rb_iseq_t *iseq, const VALUE *lf } static NODE * -vm_cref_push(rb_thread_t *th, VALUE klass, int noex) +vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr) { rb_control_frame_t *cfp m_get_ruby_level_caller_cfp(th, th->cfp); NODE *cref EW_BLOCK(klass); cref->nd_file ; cref->nd_visi oex; - if (cfp) { + if (blockptr) { + cref->nd_next m_get_cref(blockptr->iseq, blockptr->lfp, blockptr->dfp); + } + else if (cfp) { cref->nd_next m_get_cref(cfp->iseq, cfp->lfp, cfp->dfp); } --Multipart_Tue_Nov_17_11:41:43_2009-1--