forked from rubinius/rubinius
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathglobal.rb
159 lines (131 loc) · 3.84 KB
/
global.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
##
# 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