core/global.rb
##
# Stores global variables and global variable aliases.
module Rubinius
class GlobalVariables
def initialize
load_path = CoreDB.load_path
loaded_features = CoreDB.loaded_features
@internal = LookupTable.new
@internal[:$;] = nil
@internal[:$/] = "\n" # Input record separator
@internal[:$\] = nil # Output record separator
@internal[:$<] = ARGF
@internal[:$:] = load_path
@internal[:$-I] = load_path
@internal[:$"] = loaded_features
@internal[:$,] = nil # Output field separator
@internal[:$.] = 0
@internal[:$=] = false # ignore case, whatever that is
@internal[:$0] = nil
@internal[:$CONSOLE] = STDOUT
@internal[:$DEBUG] = false
@internal[:$LOADED_FEATURES] = loaded_features
@internal[:$LOAD_PATH] = load_path
@internal[:$SAFE] = 0
@internal[:$stderr] = STDERR
@internal[:$stdin] = STDIN
@internal[:$stdout] = STDOUT
@alias = LookupTable.new
@hooks = LookupTable.new
end
private :initialize
def key?(key)
@internal.key?(key) || @alias.key?(key)
end
def variables
@internal.keys + @alias.keys
end
def [](key)
if @internal.key? key
@internal[key]
elsif @hooks.key? key
@hooks[key][0].call(key)
elsif @alias.key? key
self[@alias[key]]
end
end
def []=(key, data)
if alias_key = @alias[key]
self[alias_key] = data
elsif @hooks.key? key
hook = @hooks[key]
val = hook[1].call(key, data)
if hook[2]
@internal[key] = val
end
val
else
@internal[key] = data
end
end
# Respects internal and alias, but not hooks. Useful to bypass
# normal read only checks.
def set!(key, data)
if alias_key = @alias[key]
set! alias_key, data
else
@internal[key] = data
end
end
def add_alias(current_name, alias_name)
current_name = current_name.to_sym
alias_name = alias_name.to_sym
if @internal.key? alias_name
@internal.delete alias_name
end
if @hooks.key? alias_name
@hooks.delete alias_name
end
@alias[alias_name] = current_name
end
def illegal_set(*args)
raise NameError, "unable to set global"
end
def set_hook(var, getter=nil, setter=nil, &block)
if block
if getter or setter
raise ArgumentError, "duplicate procs provided with block"
end
@hooks[var] = [block, method(:illegal_set)]
else
set_internal = false
set_internal = true if getter == :[]
if !getter
getter = method(:nil_return)
elsif getter.kind_of? Symbol
getter = method(getter)
end
unless getter.respond_to?(:call)
raise ArgumentError, "getter must respond to call"
end
if !setter
setter = method(:illegal_set)
elsif setter.kind_of? Symbol
setter = method(setter)
end
unless setter.respond_to?(:call)
raise ArgumentError, "setter must respond to call"
end
@hooks[var] = [getter, setter, set_internal]
end
end
def remove_hook(var)
@hooks.delete(var)
end
def nil_return
nil
end
def set_filter(var, block)
@hooks[var] = [method(:nil_return), block, true]
end
def raise_readonly(key, data)
raise NameError, "#{key} is a read-only global variable"
end
def read_only(*vars)
mo = method(:raise_readonly)
vars.each do |v|
set_filter v, mo
end
end
end
end