At Tue, 17 Nov 2009 06:48:42 +0900,
Yehuda Katz <wyc...@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 = 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 <sh...@ruby-lang.org>
At Tue, 17 Nov 2009 13:18:29 +0900,
Yehuda Katz <wyc...@gmail.com> wrote:
> 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.
My patch first searches the constants of the receiver of class_eval, and
if it fails, then searches outer classes or modules. As a result, a
constant in the receiver may hide a constant in an outer class or
module.
My patch is useful if you know the receiver of class_eval, but you
don't know it, right?
Back to the example of MimeResponds:
module ActionController
module MimeResponds
extend ActiveSupport::Concern
included do
inheritable_accessor :responder, :mimes_for_respond_to,
:instance_writer => false
self.responder = Responder
clear_respond_to
end
end
end
class Foo
Responder = "this is not a responder which MimeResponds requires"
include ActionController::MimeResponds
end
The author of MimeResponds doesn't know that Foo defines Responder in
it, and it breaks the code (with my patch).
Did I catch your point?
If so, I agree that my patch is not useful in this situation.
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.
I guess we have four options now:
(1) As you suggested, revert to the behavior of Ruby 1.8, and add a
new method (or flag) to enable the new behavior.
(2) Separate class variable lookup from constant lookup, and revert
constant lookup to the behavior of Ruby 1.8.
(3) Change nothing. You should always use the fully qualified form of
constant lookup.
(4) Apply my patch. You should still use the fully qualified form of
constant lookup, if you don't know the receiver of class_eval.
--
Shugo Maeda <sh...@ruby-lang.org>
> 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
2009/11/17 Shugo Maeda <sh...@ruby-lang.org>:
> I guess we have four options now:
>
> (1) As you suggested, revert to the behavior of Ruby 1.8, and add a
> new method (or flag) to enable the new behavior.
My proposal is as follows:
(1) Revert instance_eval, class_eval, and module_eval back to the
behavior of 1.8.
(2) But do not revert instance_exec, class_exec, and module_exec.
I have attached a patch.
My patch also reverts the behavior of class variables, but it may be
unnecessary.
--
Shugo Maeda
2009/11/22 Yehuda Katz <wyc...@gmail.com>:
> Shugo,
> I like this a lot. One final suggestion: instance_eval and class_eval should
> take arguments like instance_exec. Then, the only difference between
> instance_eval and instance_exec would be the constant lookup scope.
> It also should not break any 1.8 code since instance_eval does not take
> arguments in 1.8.
What do you think of this suggestion, Matz?
--
Shugo Maeda
In message "Re: [ruby-core:26861] Re: Ruby constant lookup"
on Mon, 23 Nov 2009 01:41:22 +0900, Shugo Maeda <sh...@ruby-lang.org> writes:
|What do you think of this suggestion, Matz?
I am not sure I get the whole picture of this change and influence
from it. Let me discuss with you, when I get back home. OK?
matz.
2009/11/23 Yukihiro Matsumoto <ma...@ruby-lang.org>:
> |What do you think of this suggestion, Matz?
>
> I am not sure I get the whole picture of this change and influence
> from it. Let me discuss with you, when I get back home. OK?
OK, have a nice trip.
--
Shugo Maeda
2009/11/18 Rick DeNatale <rick.d...@gmail.com>:
> 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.
Does my patch fix the problem?
If not, it may be a different problem.
Would you create a minimal program which reproduces the problem?
--
Shugo Maeda
I don't know. I haven't had a chance to try.
>
> If not, it may be a different problem.
> Would you create a minimal program which reproduces the problem?
I'll try. It's not the biggest problem on my list right now though.
Thanks for the attention.
Well I tried to apply the patch. It's been a while since I've built 1.9.
I did an svn update, applied the patch, then
autoconf
./configure
make
and get a syntax error in lex.c
clude/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o parse.o -c parse.c
In file included from parse.y:6049:
lex.c:1: error: expected identifier or ‘(’ before ‘<<’ token
Your patch doesn't seem to touch this file. So i did
svn revert -R .
make clean
make
and got the same error.
→ svn log -l3
------------------------------------------------------------------------
r25889 | nobu | 2009-11-23 02:06:54 -0500 (Mon, 23 Nov 2009) | 4 lines
* thread_pthread.c (RUBY_STACK_MIN, RUBY_STACK_SPACE): delay for
platforms where PTHREAD_STACK_MIN is not compile time constant.
[ruby-dev:39751]
------------------------------------------------------------------------
r25888 | nobu | 2009-11-22 21:26:47 -0500 (Sun, 22 Nov 2009) | 2 lines
* dln.c (dln_find_1): removed duplication.
------------------------------------------------------------------------
r25887 | nobu | 2009-11-22 20:55:17 -0500 (Sun, 22 Nov 2009) | 2 lines
* dln.c (dln_find_1): fixed commit miss.
------------------------------------------------------------------------
Am I doing this with the right revision?
2009/11/23 Rick DeNatale <rick.d...@gmail.com>:
> I did an svn update, applied the patch, then
> autoconf
> ./configure
> make
>
> and get a syntax error in lex.c
>
> clude/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
> -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o parse.o -c parse.c
> In file included from parse.y:6049:
> lex.c:1: error: expected identifier or ‘(’ before ‘<<’ token
>
> Your patch doesn't seem to touch this file. So i did
> svn revert -R .
> make clean
> make
>
> and got the same error.
Can you try the following commands?
$ rm lex.c
$ make
If it fails, please show me your lex.c.
--
Shugo Maeda
~/rubysource/ruby1.9 [svn:]
→ rm lex.c
~/rubysource/ruby1.9 [svn:]
→ make
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses
-Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers
-Wshorten-64-to-32 -Wno-long-long -pipe -I.
-I.ext/include/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o main.o -c main.c
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses
-Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers
-Wshorten-64-to-32 -Wno-long-long -pipe -I.
-I.ext/include/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o miniprelude.o -c miniprelude.c
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses
-Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers
-Wshorten-64-to-32 -Wno-long-long -pipe -I.
-I.ext/include/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o class.o -c class.c
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses
-Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers
-Wshorten-64-to-32 -Wno-long-long -pipe -I.
-I.ext/include/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o enum.o -c enum.c
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses
-Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers
-Wshorten-64-to-32 -Wno-long-long -pipe -I.
-I.ext/include/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o error.o -c error.c
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses
-Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers
-Wshorten-64-to-32 -Wno-long-long -pipe -I.
-I.ext/include/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o eval.o -c eval.c
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses
-Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers
-Wshorten-64-to-32 -Wno-long-long -pipe -I.
-I.ext/include/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o load.o -c load.c
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses
-Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers
-Wshorten-64-to-32 -Wno-long-long -pipe -I.
-I.ext/include/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o proc.o -c proc.c
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses
-Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers
-Wshorten-64-to-32 -Wno-long-long -pipe -I.
-I.ext/include/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o gc.o -c gc.c
gc.c: In function ‘rb_node_newnode’:
gc.c:1105: warning: implicit conversion shortens 64-bit value into a
32-bit value
+ cp ./lex.c.blt lex.c
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses
-Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers
-Wshorten-64-to-32 -Wno-long-long -pipe -I.
-I.ext/include/x86_64-darwin10.2.0 -I./include -I. -DRUBY_EXPORT
-D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -o parse.o -c parse.c
parse.y:9840: error: redefinition of ‘rb_reserved_word’
keywords:82: error: previous definition of ‘rb_reserved_word’ was here
parse.y: In function ‘rb_reserved_word’:
parse.y:9841: warning: return makes pointer from integer without a cast
make: *** [parse.o] Error 1
Here's the lex.c (I just realized that this was generated by lex/flex
--
> Here's the lex.c
Oh oh, it looks like I forgot the link to lex.c
2009/11/24 Rick DeNatale <rick.d...@gmail.com>:
>> Here's the lex.c
>
>
> Oh oh, it looks like I forgot the link to lex.c
>
> http://gist.github.com/241120
Your lex.c was copied from lex.c.blt, which looks old.
Please check out the latest source:
$ svn co http://svn.ruby-lang.org/repos/ruby/trunk ruby-trunk
--
Shugo Maeda
2009/11/22 Yehuda Katz <wyc...@gmail.com>:
> I like this a lot. One final suggestion: instance_eval and class_eval should
> take arguments like instance_exec. Then, the only difference between
> instance_eval and instance_exec would be the constant lookup scope.
> It also should not break any 1.8 code since instance_eval does not take
> arguments in 1.8.
I talked with Yehuda on Skype, and confirmed his suggestion.
* If no arguments are passed to instance_eval or class_eval, it should
behave the same as 1.8.
* If any arguments are passed to instance_eval or class_eval, it
should yield them to a block.
This does not break any 1.8 code because instance_eval and class_eval
raise ArgumentError if both arguments and a block are given.
--
Shugo Maeda
2009/11/24 Shugo Maeda <sh...@ruby-lang.org>:
> * If no arguments are passed to instance_eval or class_eval, it should
> behave the same as 1.8.
instance_eval does not yield the receiver in Ruby 1.9.
This change is introduced as a result of the following discussion:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/7365
Should instance_eval yield the receiver or not?
--
Shugo Maeda
If this were a democracy <G>, I'd vote to make it work as it does in
1.8 and yield the receiver.
2009/11/23 Yukihiro Matsumoto <ma...@ruby-lang.org>:
> |What do you think of this suggestion, Matz?
>
> I am not sure I get the whole picture of this change and influence
> from it. Let me discuss with you, when I get back home. OK?
I have discussed the issue with Matz.
He has rejected my proposal because it's not coherent.
# Strictly speaking, he said "suji ga warui",
# but I can't translate it into English:(
Instead, he would like to revert all of instance_eval, instance_exec,
class_eval, and class_exec to the behavior of 1.8 (including class
variables). It also means that instance_eval does not passes its
arguments to given blocks. If it does, instance_exec gets
unnecessary.
I agree with him, but any objections?
--
Shugo Maeda
2009/12/1 Shugo Maeda <sh...@ruby-lang.org>:
> Instead, he would like to revert all of instance_eval, instance_exec,
> class_eval, and class_exec to the behavior of 1.8 (including class
> variables). It also means that instance_eval does not passes its
> arguments to given blocks. If it does, instance_exec gets
> unnecessary.
>
> I agree with him, but any objections?
I have just commited it to the SVN trunk.
--
Shugo Maeda