On Tue, Nov 17, 2009 at 1:29 AM, Shugo Maeda <shugo / ruby-lang.org> wrote: > However, I guess "to add the dynamic scope _after_ the lexical scope, > rather than _before_ it" doesn't affect class variable lookup, because > only the first element of Module.nesting is used during class variable > lookup. Maeda-san, I'm intrigued by this thread, because I have a suspicion that it might have something to do with a mystery I've been unable to understand which seems to relate to the differences in 1.9 in either the eval methods, class variable access, or both. I've recently converted a Rails application to run on 1.9, and have a strange phenomenon that if I am using Ruby 1.9 as my 'default' ruby the rails generator scripts fail $ which ruby /Users/rick/.rvm/ruby-1.9.1-p243/bin/ruby $ script/generate model foo undefined method `exists' for #<ActiveSupport::BufferedLogger:0x00000102b3a250> In order to run script/generate I need to switch to Ruby 1.8 This rails project makes use of the logbuddy gem http://github.com/relevance/log_buddy defines a module, whose init method is run when the gem is intialized: module LogBuddy # Configure and include LogBuddy into Object. # You can pass in any of the following configuration options: # # * <tt>:logger</tt> - the logger instance that LogBuddy should use (if not provided, # tries to default to RAILS_DEFAULT_LOGGER, and then to a STDOUT logger). # * <tt):log_to_stdout</tt> - whether LogBuddy should _also_ log to STDOUT, very helpful for Autotest (default is +true+). def self.init(options = {}) @logger = options[:logger] @log_to_stdout = options.has_key?(:log_to_stdout) ? options[:log_to_stdout] : true mixin_to_object end # Add the LogBuddy::Mixin to Object instance and class level. def self.mixin_to_object Object.class_eval { include LogBuddy::Mixin extend LogBuddy::Mixin } end class << self include LogBuddy::Utils def logger return @logger if @logger @logger = init_default_logger end def log_to_stdout? @log_to_stdout end private def init_default_logger if Object.const_defined?("RAILS_DEFAULT_LOGGER") @logger = Object.const_get("RAILS_DEFAULT_LOGGER") else require 'logger' @logger = Logger.new(STDOUT) end end end end and LogBuddy::Mixin looks (in part) like this: module LogBuddy module Mixin def logger LogBuddy.logger end end end Now the generate script is blowing up because Rails generators also expect a method named logger and expect it to return a different kind of logger. That logger method is implemented as a cattr (another bit of ActiveSupport 'metamagic' module Rails # Rails::Generator is a code generation platform tailored for the Rails # web application framework. module Generator # The base code generator is bare-bones. It sets up the source and # destination paths and tells the logger whether to keep its trap shut. class Base # ... cattr_accessor :logger end end end and cattr_accessor calls both cattr_reader and cattr_writer, cattr_reader generates class and instance methods class Class def cattr_reader(*syms) syms.flatten.each do |sym| next if sym.is_a?(Hash) class_eval(<<-EOS, __FILE__, __LINE__) unless defined? @@#{sym} # unless defined? @@hair_colors @@#{sym} = nil # @@hair_colors = nil end # end # def self.#{sym} # def self.hair_colors @@#{sym} # @@hair_colors end # end # def #{sym} # def hair_colors @@#{sym} # @@hair_colors end # end EOS end end def cattr_writer(*syms) # code snipped for brevity. end def cattr_accessor(*syms) cattr_reader(*syms) cattr_writer(*syms) end end In Ruby 1.8 things work as expected, in an instance of Rails::Generator::Base or one of its subclasses, the logger method produced by cattr_reader is found when the logger method is invoked. But for some reason I haven't been able to decipher, in Ruby 1.9 the logger method generated by the cattr_reader method isn't found, and the Object#logger method defined by LogBuddy is executed instead. I'd love any help in understanding what's going on here. -- Rick DeNatale Blog: http://talklikeaduck.denhaven2.com/ Twitter: http://twitter.com/RickDeNatale WWR: http://www.workingwithrails.com/person/9021-rick-denatale LinkedIn: http://www.linkedin.com/in/rickdenatale