From: Yehuda Katz Date: 2009-11-17T13:18:29+09:00 Subject: [ruby-core:26777] Re: Ruby constant lookup --00c09f8e5d61f4a2590478896aa4 Content-Type: text/plain; charset=ISO-8859-1 Shugo, I agree that we should have both, but I think that the lexical scope case should win. Consider the case of RSpec: describe "Date" do it "equals itself" do Date.today.should == Date.today end end If we use dynamic scope first, then if RSpec adds Spec::Date, it will suddenly break this spec. Lexical scope is more intuitive, and is expected by many normal uses today. On the other hand, we want to be able to access class variables in the eval'ed scope. I think a good solution is to add the dynamic scope _after_ the lexical scope, rather than _before_ it. Yehuda Katz Developer | Engine Yard (ph) 718.877.1325 On Mon, Nov 16, 2009 at 6:41 PM, Shugo Maeda wrote: > Hi, > > At Tue, 17 Nov 2009 06:48:42 +0900, > Yehuda Katz 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 = ActionController::Responder > > clear_respond_to > > end > > end > > Do you mean that `self.responder = ActionController::Responder' can be > replaced > by `self.responder = Responder' 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 = nil, &block) > if base.nil? > @_included_block = block > 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 > --00c09f8e5d61f4a2590478896aa4 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
Shugo,

I agree that we should have both, but = I think that the lexical scope case should win. Consider the case of RSpec:=

describe "Date" do
=A0=A0it &= quot;equals itself" do
=A0=A0 =A0Date.today.should =3D=3D Date.today
=A0=A0end
end

If we use dynamic scope first, then if R= Spec adds Spec::Date, it will suddenly break this spec. Lexical scope is mo= re intuitive, and is expected by many normal uses today. On the other hand,= we want to be able to access class variables in the eval'ed scope. I t= hink a good solution is to add the dynamic scope _after_ the lexical scope,= rather than _before_ it.

Yehuda Katz
Developer | Engine Yard
(ph) 718.877.13= 25


On Mon, Nov 16, 2009 at 6:41 PM, Shugo M= aeda <shugo@rub= y-lang.org> wrote:
Hi,

At Tue, 17 Nov 2009 06:48:42 +0900,
Yehuda Katz <wycat= s@gmail.com> wrote:
> For instance, you can do the following in Rail= s:
>
> module ActionController::MimeResponds
> =A0 extend ActiveSupport::Concern
>
> =A0 =A0 included do
> =A0 =A0 =A0 inheritable_accessor :responder, :mimes_for_respond_to, > :instance_writer =3D> false
> =A0 =A0 =A0 self.responder =3D ActionController::Responder
> =A0 =A0 =A0 clear_respond_to
> =A0 =A0 end
> end

Do you mean that `self.responder =3D ActionController::Responder'= can be replaced
by `self.responder =3D Responder' 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
=A0module MimeResponds
=A0 =A0...
=A0end
end

> > This is a wrapper around the very common:
>
> def self.included(klass)
> =A0 klass.class_eval do
> =A0 =A0 # code here
> =A0 end
> end

For Matz and Koichi (and other people who aren't familiar with Ra= ils),
included and append_features are overridden in ActiveSupport::Concern
as follows:

=A0 =A0def included(base =3D nil, &block)
=A0 =A0 =A0if base.nil?
=A0 =A0 =A0 =A0@_included_block =3D block
=A0 =A0 =A0else
=A0 =A0 =A0 =A0super
=A0 =A0 =A0end
=A0 =A0end

=A0 =A0def append_features(base)
=A0 =A0 =A0if super
=A0 =A0 =A0 =A0...
=A0 =A0 =A0 =A0base.class_eval(&@_included_block) if instance_variable= _defined?("@_incl
uded_block")
=A0 =A0 =A0end
=A0 =A0end

> Because I understand the utility in the Ruby 1.9 approach, I would lik= e to
> suggest that users be allowed to choose which scoping they want. I sug= gest
> that module_eval, by default, revert to Ruby 1.8 behavior. I also sugg= est
> 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. =A0I think class variabl= es
should especially be lookuped like Ruby 1.9 because they can't be
accessed outside of a class or its instance. =A0Then, 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
=A0Responder =3D "This is a Responder"
=A0module MimeResponds
=A0 =A0Foo.class_eval do
=A0 =A0 =A0p Responder
=A0 =A0end
=A0end
end

However, the following program doesn't work on Ruby 1.9:

def my_class_eval(klass, &block)
=A0klass.class_eval(&block)
end

class Foo
end

module ActionController
=A0Responder =3D "This is a Responder"
=A0module MimeResponds
=A0 =A0my_class_eval(Foo) do
=A0 =A0 =A0p Responder
=A0 =A0end
=A0end
end

It's because class_eval prepends the reciver to the constant lookup
path at the time of invocation of class_eval. =A0I think it should
prepends the receiver to the constant lookup path which the given block
holds.

I have attached a patch to fix it. =A0If it's acceptable, I'll writ= e a
test and commit them.

--
Shugo Maeda <shugo@ruby-lang.org<= /a>>

--00c09f8e5d61f4a2590478896aa4--