作者godfat (godfat 真常)
看板Ruby
标题[Ruby] constants
时间Mon Feb 25 18:06:56 2008
我想试试一种特殊的 namespace 机制,希望能解决一团混乱的 monkey patching,
使得大家都能各自任意扩充自己想要的东西。大概像是这种感觉:
namesapce :std do
class Array
def orz
puts 'orz'
end
end
end
[].orz # 失败
using_namespace :std
[].orz # orz
using_namespace nil
[].orz # 失败
using :std, :Array
[].orz # orz
unusing :std, :Array
[].orz # 失败
using :std, :Array, :orz
[].orz # orz
unusing :std, :Array, :orz
[].orz # 失败
不过稍微小试身手就问题重重.............快昏倒了。
於是开始可以体会为什麽标准这麽难推,又为什麽标准推这麽慢。
这种时候就开始觉得虽然推标准的成本非常高,但还是非常有价值的。
唉,不多说了,看程式码。以下只是稍微小试身手,
基本上还是很 rough 的东西,因为光是这部份就没办法解决了,
根本就没办法深入写下去。所以我大概要放弃这个想法了吧....
这里有个结论,1.8.6 能丢掉时我一定要立刻丢掉 =_=
他的行为完完全全不符合我的预期,问题根本无法解决...
目前 svn trunk 的版本,则是「部份」符合预期...
有没有多一个 lambda 有差异。如果直接写 mod.module_eavl,
这符合预期。可是如果是把 proc 用 & pass 过去,问题就产生了。
至於 string 形式的 eval 则是正常。但总不能到处都用 string eval 吧...
很神奇的则是,rubinius 则是完全符合我的预期!
不知道该不该鼓掌.......因为他跑我的 ludy test 是会失败的,
死在 Symbol#to_proc 会有问题。好像是 lambda{|*args|} 那个 * 会有问题。
(我记得 jruby 这部份也很容易有问题)
jruby 我懒得试了,安装他会打乱我的设定,而且他的状况也从来没好过....
每一个版本的行为都完全不同,这还真不知道到底要怎麽写下去。
module Kernel
private
def using_namespace ns
if ns.nil?
Module.module_eval do
alias_method :const_missing, :__const_missing__
undef_method :__const_missing__
end
else
Module.module_eval do
alias_method :__const_missing__, :const_missing
define_method :const_missing do |const|
const_get(ns.to_s.capitalize).const_get const
end
end
end
end
def namespace ns, &block
mod = Module.new
Object.const_set ns.to_s.capitalize, mod
mod.module_eval &block
end
end
namespace :std do
N = 29
end
require 'test/unit'
class ContantsTest < Test::Unit::TestCase
def test_a_global
assert_raise NameError do
N
end
end
def test_b_std
assert_equal 29, Std::N
end
def test_c_using_std
using_namespace :std
assert_equal 29, N
end
def test_d_using_nil
using_namespace nil
assert 29, Std::N
end
def test_e_global
assert_raise NameError do
N
end
end
end
测试结果是:
godfat ~/p/ludy> multiruby lib/ludy/namespace.rb
VERSION = 1.8.6-p111
Loaded suite lib/ludy/namespace
Started
FE.EF
Finished in 0.007992 seconds.
1) Failure:
test_a_global(ContantsTest) [lib/ludy/namespace.rb:33]:
<NameError> exception expected but none was thrown.
2) Error:
test_b_std(ContantsTest):
NameError: uninitialized constant Std::N
lib/ludy/namespace.rb:38:in `test_b_std'
3) Error:
test_d_using_nil(ContantsTest):
NameError: uninitialized constant Std::N
lib/ludy/namespace.rb:46:in `test_d_using_nil'
4) Failure:
test_e_global(ContantsTest) [lib/ludy/namespace.rb:49]:
<NameError> exception expected but none was thrown.
5 tests, 3 assertions, 2 failures, 2 errors
RESULT = 256
VERSION = trunk
Loaded suite lib/ludy/namespace
Started
F...F
Finished in 0.016097 seconds.
1) Failure:
test_a_global(ContantsTest) [lib/ludy/namespace.rb:33]:
<NameError> exception expected but none was thrown.
2) Failure:
test_e_global(ContantsTest) [lib/ludy/namespace.rb:49]:
<NameError> exception expected but none was thrown.
5 tests, 5 assertions, 2 failures, 0 errors
RESULT = 256
VERSION = rubinius
Loaded suite lib/ludy/namespace
Started
.....
Finished in 0.01434 seconds.
5 tests, 5 assertions, 0 failures, 0 errors
RESULT = 0
TOTAL RESULT = 2 failures out of 3
Passed: rubinius
Failed: 1.8.6-p111, trunk
整理整理,考虑 post 到 ruby-talk 或 ruby-core 上看看...
ruby 的 consistency 实在是很差,老是碰到问题...
不过 mats 都说了,他觉得 convenience 比 consistency 重要
所以会碰到这些讨厌的问题,大概也没办法吧.... orz
--
「行け!Loki!」
(rocky ロッキー)
-Gurumin ぐるみん 王子? XD
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.128.121.85
1F:→ godfat:嗯... 绕几个弯,其实还做得下去。只是做法就完全不同了 02/25 21:06
2F:→ godfat:改到现在又变成 1.8.6 正确其他错误 :x 02/25 23:07
3F:→ godfat:又变成需要部份 1.8 部份 1.9 @@ 看来是困难重重... 02/25 23:18