[Ruby] constants scope?
我想試試一種特殊的 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
→
02/25 21:06, , 1F
02/25 21:06, 1F
→
02/25 23:07, , 2F
02/25 23:07, 2F
→
02/25 23:18, , 3F
02/25 23:18, 3F
Ruby 近期熱門文章
PTT數位生活區 即時熱門文章