evil-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +56 -0
- data/NEWS +7 -0
- data/README +15 -0
- data/Rakefile +109 -0
- data/lib/evil.rb +691 -0
- data/setup.rb +1360 -0
- data/test/tc_all.rb +8 -0
- data/test/tc_inline.rb +11 -0
- data/test/test-extract.rb +112 -0
- metadata +59 -0
data/COPYING
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
evil-ruby is copyrighted free software by Florian Gross <flgr@ccan.de>.
|
2
|
+
You can redistribute it and/or modify it under either the terms of the GPL
|
3
|
+
(see http://www.gnu.org/licenses/gpl.html), or the conditions below:
|
4
|
+
|
5
|
+
1. You may make and give away verbatim copies of the source form of the
|
6
|
+
software without restriction, provided that you duplicate all of the
|
7
|
+
original copyright notices and associated disclaimers.
|
8
|
+
|
9
|
+
2. You may modify your copy of the software in any way, provided that
|
10
|
+
you do at least ONE of the following:
|
11
|
+
|
12
|
+
a) place your modifications in the Public Domain or otherwise
|
13
|
+
make them Freely Available, such as by posting said
|
14
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
15
|
+
the author to include your modifications in the software.
|
16
|
+
|
17
|
+
b) use the modified software only within your corporation or
|
18
|
+
organization.
|
19
|
+
|
20
|
+
c) give non-standard binaries non-standard names, with
|
21
|
+
instructions on where to get the original software distribution.
|
22
|
+
|
23
|
+
d) make other distribution arrangements with the author.
|
24
|
+
|
25
|
+
3. You may distribute the software in object code or binary form,
|
26
|
+
provided that you do at least ONE of the following:
|
27
|
+
|
28
|
+
a) distribute the binaries and library files of the software,
|
29
|
+
together with instructions (in the manual page or equivalent)
|
30
|
+
on where to get the original distribution.
|
31
|
+
|
32
|
+
b) accompany the distribution with the machine-readable source of
|
33
|
+
the software.
|
34
|
+
|
35
|
+
c) give non-standard binaries non-standard names, with
|
36
|
+
instructions on where to get the original software distribution.
|
37
|
+
|
38
|
+
d) make other distribution arrangements with the author.
|
39
|
+
|
40
|
+
4. You may modify and include the part of the software into any other
|
41
|
+
software (possibly commercial). But some files in the distribution
|
42
|
+
are not written by the author, so that they are not under these terms.
|
43
|
+
|
44
|
+
For the list of those files and their copying conditions, see the
|
45
|
+
file LEGAL.
|
46
|
+
|
47
|
+
5. The scripts and library files supplied as input to or produced as
|
48
|
+
output from the software do not automatically fall under the
|
49
|
+
copyright of the software, but belong to whomever generated them,
|
50
|
+
and may be sold commercially, and may be aggregated with this
|
51
|
+
software.
|
52
|
+
|
53
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
54
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
55
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
56
|
+
PURPOSE.
|
data/NEWS
ADDED
data/README
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
= README for evil-ruby
|
2
|
+
|
3
|
+
Extends Ruby's semantics by accessing its internals from pure Ruby code.
|
4
|
+
|
5
|
+
|
6
|
+
== Installation
|
7
|
+
|
8
|
+
De-compress archive and enter its top directory. Then type:
|
9
|
+
|
10
|
+
($ su)
|
11
|
+
# ruby setup.rb
|
12
|
+
|
13
|
+
This simple step installs this program under the default location of Ruby
|
14
|
+
libraries. You can also install files into your favorite directory by supplying
|
15
|
+
setup.rb with some options. Try "ruby setup.rb --help".
|
data/Rakefile
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/packagetask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'find'
|
5
|
+
|
6
|
+
readme = File.read("README").gsub("\r\n", "\n")
|
7
|
+
author_line = readme[/^\*\s*Author:.+$/].split(/\s+/, 2)[1] rescue nil
|
8
|
+
|
9
|
+
# Manual globals
|
10
|
+
|
11
|
+
PKG_AUTOREQUIRE = nil
|
12
|
+
PKG_RUBY_VERSION = '>= 1.8.4'
|
13
|
+
PKG_GEM_DEPENDENCIES = {}
|
14
|
+
PKG_RDOC_FILES = ['README', 'NEWS']
|
15
|
+
PKG_RDOC_OPTIONS = %w(--all --main README --title #{PKG_NAME})
|
16
|
+
PKG_FILES = PKG_RDOC_FILES + ['COPYING', 'setup.rb', 'Rakefile']
|
17
|
+
|
18
|
+
# Automatic globals
|
19
|
+
|
20
|
+
PKG_NAME, PKG_VERSION = *File.read("NEWS")[/^==.+$/].split(/\s+/)[1..2]
|
21
|
+
PKG_DESCRIPTION = readme.split(/\n{3,}/)[0].sub(/^=.+$\s*/, "") rescue nil
|
22
|
+
PKG_SUMMARY = readme[/^=.+$/].split(/--/)[1].strip rescue PKG_DESCRIPTION
|
23
|
+
PKG_HOMEPAGE = readme[/^\*\s*Homepage:.+$/].split(/\s+/, 2)[1] rescue nil
|
24
|
+
PKG_EMAIL = author_line[/<(.+)>/, 1] rescue nil
|
25
|
+
PKG_AUTHOR = author_line.sub(PKG_EMAIL, "").sub("<>", "").strip rescue nil
|
26
|
+
|
27
|
+
Find.find('lib/', 'test/', 'bin/') do |file|
|
28
|
+
if FileTest.directory?(file) and file[/\.svn/i] then
|
29
|
+
Find.prune
|
30
|
+
elsif !file[/\.DS_Store/i] then
|
31
|
+
PKG_FILES << file
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
PKG_FILES.reject! { |file| !File.file?(file) }
|
36
|
+
|
37
|
+
PKG_EXE_FILES, PKG_LIB_FILES = *%w(bin/ lib/).map do |dir|
|
38
|
+
PKG_FILES.grep(/#{dir}/i).reject { |f| File.directory?(f) }
|
39
|
+
end
|
40
|
+
|
41
|
+
PKG_EXE_FILES.map! { |exe| exe.sub(%r(^bin/), "") }
|
42
|
+
|
43
|
+
# Tasks
|
44
|
+
|
45
|
+
task :default => :test
|
46
|
+
|
47
|
+
# Test task
|
48
|
+
if File.exist?("test/") then
|
49
|
+
require 'rake/testtask'
|
50
|
+
|
51
|
+
Rake::TestTask.new do |test|
|
52
|
+
test.test_files = ['test/tc_all.rb']
|
53
|
+
end
|
54
|
+
else
|
55
|
+
task :test do
|
56
|
+
puts "No tests to run"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Doc task
|
61
|
+
Rake::RDocTask.new do |rd|
|
62
|
+
rd.rdoc_files.include(PKG_LIB_FILES, PKG_RDOC_FILES)
|
63
|
+
rd.options += PKG_RDOC_OPTIONS
|
64
|
+
end
|
65
|
+
|
66
|
+
# Tar task
|
67
|
+
Rake::PackageTask.new(PKG_NAME, PKG_VERSION) do |pkg|
|
68
|
+
pkg.need_tar = true
|
69
|
+
pkg.package_files = PKG_FILES
|
70
|
+
end
|
71
|
+
|
72
|
+
# Gem task
|
73
|
+
begin
|
74
|
+
require 'rake/gempackagetask'
|
75
|
+
|
76
|
+
spec = Gem::Specification.new do |spec|
|
77
|
+
spec.name = PKG_NAME
|
78
|
+
spec.version = PKG_VERSION
|
79
|
+
spec.summary = PKG_SUMMARY
|
80
|
+
spec.description = PKG_DESCRIPTION
|
81
|
+
|
82
|
+
spec.homepage = PKG_HOMEPAGE
|
83
|
+
spec.email = PKG_EMAIL
|
84
|
+
spec.author = PKG_AUTHOR
|
85
|
+
|
86
|
+
spec.has_rdoc = true
|
87
|
+
spec.extra_rdoc_files = PKG_RDOC_FILES
|
88
|
+
spec.rdoc_options += PKG_RDOC_OPTIONS
|
89
|
+
|
90
|
+
if File.exist?("test/") then
|
91
|
+
spec.test_files = ['test/tc_all.rb']
|
92
|
+
end
|
93
|
+
|
94
|
+
spec.required_ruby_version = PKG_RUBY_VERSION
|
95
|
+
(PKG_GEM_DEPENDENCIES || {}).each do |name, version|
|
96
|
+
spec.add_dependency(name, version)
|
97
|
+
end
|
98
|
+
|
99
|
+
spec.files = PKG_FILES
|
100
|
+
spec.executables = PKG_EXE_FILES
|
101
|
+
spec.autorequire = PKG_AUTOREQUIRE
|
102
|
+
end
|
103
|
+
|
104
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
105
|
+
pkg.need_zip = true
|
106
|
+
pkg.need_tar = true
|
107
|
+
end
|
108
|
+
rescue LoadError
|
109
|
+
end
|
data/lib/evil.rb
ADDED
@@ -0,0 +1,691 @@
|
|
1
|
+
# vim:sw=2
|
2
|
+
# Written in 2004 by Florian Gross <flgr@ccan.de> and
|
3
|
+
# Mauricio Julio Fern�ndez Pradier <batsman.geo@yahoo.com>
|
4
|
+
#
|
5
|
+
# This is licensed under the same license as Ruby.
|
6
|
+
|
7
|
+
module RubyInternal
|
8
|
+
Is_1_8 = RUBY_VERSION[/\A1.[678]/]
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'dl'
|
12
|
+
unless RubyInternal::Is_1_8
|
13
|
+
require 'dl/value'
|
14
|
+
require 'dl/import'
|
15
|
+
end
|
16
|
+
require 'dl/struct'
|
17
|
+
|
18
|
+
# Provides low-level access to Ruby's internals. Be
|
19
|
+
# careful when using this directly, because you can
|
20
|
+
# break Ruby with it.
|
21
|
+
module RubyInternal
|
22
|
+
DL::CPtr = DL::PtrData if Is_1_8
|
23
|
+
DL::SIZEOF_LONG = DL.sizeof("l") if Is_1_8
|
24
|
+
|
25
|
+
unless Is_1_8
|
26
|
+
class ::DL::CPtr
|
27
|
+
alias :old_store :[]=
|
28
|
+
def []=(idx, *args)
|
29
|
+
if args.size == 1 and args[0].is_a?(String) then
|
30
|
+
args[0] = args[0].ord
|
31
|
+
end
|
32
|
+
|
33
|
+
old_store(idx, *args)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
extend self
|
39
|
+
importer = Is_1_8 ? DL::Importable : DL::Importer
|
40
|
+
extend importer
|
41
|
+
|
42
|
+
dlload()
|
43
|
+
|
44
|
+
if Is_1_8
|
45
|
+
def typealias(new, old)
|
46
|
+
super(new, nil, nil, nil, old)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Qfalse = 0
|
51
|
+
Qtrue = 2
|
52
|
+
Qnil = 4
|
53
|
+
Qundef = 6
|
54
|
+
|
55
|
+
T_NONE = 0x00
|
56
|
+
T_NIL = 0x01
|
57
|
+
T_OBJECT = 0x02
|
58
|
+
T_CLASS = 0x03
|
59
|
+
T_ICLASS = 0x04
|
60
|
+
T_MODULE = 0x05
|
61
|
+
T_FLOAT = 0x06
|
62
|
+
T_STRING = 0x07
|
63
|
+
T_REGEXP = 0x08
|
64
|
+
T_ARRAY = 0x09
|
65
|
+
T_FIXNUM = 0x0a
|
66
|
+
T_HASH = 0x0b
|
67
|
+
T_STRUCT = 0x0c
|
68
|
+
T_BIGNUM = 0x0d
|
69
|
+
T_FILE = 0x0e
|
70
|
+
|
71
|
+
if Is_1_8
|
72
|
+
T_TRUE = 0x20
|
73
|
+
T_FALSE = 0x21
|
74
|
+
T_DATA = 0x22
|
75
|
+
T_MATCH = 0x23
|
76
|
+
T_SYMBOL = 0x24
|
77
|
+
|
78
|
+
T_BLOCK = 0x3b
|
79
|
+
T_UNDEF = 0x3c
|
80
|
+
T_VARMAP = 0x3d
|
81
|
+
T_SCOPE = 0x3e
|
82
|
+
T_NODE = 0x3f
|
83
|
+
|
84
|
+
T_MASK = 0x3f
|
85
|
+
else # 1.9 or higher
|
86
|
+
T_TRUE = 0x10
|
87
|
+
T_FALSE = 0x11
|
88
|
+
T_DATA = 0x12
|
89
|
+
T_MATCH = 0x13
|
90
|
+
T_SYMBOL = 0x14
|
91
|
+
|
92
|
+
T_BLOCK = 0x1b
|
93
|
+
T_UNDEF = 0x1c
|
94
|
+
T_VARMAP = 0x1d
|
95
|
+
T_SCOPE = 0x1e
|
96
|
+
T_NODE = 0x1f
|
97
|
+
|
98
|
+
T_MASK = 0x1f
|
99
|
+
end # constants
|
100
|
+
|
101
|
+
typealias "VALUE", "unsigned long"
|
102
|
+
typealias "ID", "unsigned long"
|
103
|
+
typealias "ulong", "unsigned long"
|
104
|
+
Basic = ["long flags", "VALUE klass"]
|
105
|
+
|
106
|
+
RBasic = struct Basic
|
107
|
+
|
108
|
+
RObject = struct(Basic + [
|
109
|
+
"st_table *iv_tbl"
|
110
|
+
])
|
111
|
+
|
112
|
+
RClass = struct(Basic + [
|
113
|
+
"st_table *iv_tbl",
|
114
|
+
"st_table *m_tbl",
|
115
|
+
"VALUE super"
|
116
|
+
])
|
117
|
+
|
118
|
+
RModule = RClass
|
119
|
+
|
120
|
+
RFloat = struct(Basic + [
|
121
|
+
"double value"
|
122
|
+
])
|
123
|
+
|
124
|
+
RString = struct(Basic + [
|
125
|
+
"long len",
|
126
|
+
"char *ptr",
|
127
|
+
"long capa"
|
128
|
+
])
|
129
|
+
|
130
|
+
RArray = struct(Basic + [
|
131
|
+
"long len",
|
132
|
+
"long capa",
|
133
|
+
"VALUE *ptr"
|
134
|
+
])
|
135
|
+
|
136
|
+
RRegexp = struct(Basic + [
|
137
|
+
"re_pattern_buffer *ptr",
|
138
|
+
"long len",
|
139
|
+
"char *str"
|
140
|
+
])
|
141
|
+
|
142
|
+
RHash = struct(Basic + [
|
143
|
+
"st_table *tbl",
|
144
|
+
"int iter_lev",
|
145
|
+
"VALUE ifnone"
|
146
|
+
])
|
147
|
+
|
148
|
+
RFile = struct(Basic + [
|
149
|
+
"OpenFile *fptr"
|
150
|
+
])
|
151
|
+
|
152
|
+
RData = struct(Basic + [
|
153
|
+
"void *dmark",
|
154
|
+
"void *dfree",
|
155
|
+
"void *data"
|
156
|
+
])
|
157
|
+
|
158
|
+
RStruct = struct(Basic + [
|
159
|
+
"long len",
|
160
|
+
"VALUE *ptr"
|
161
|
+
])
|
162
|
+
|
163
|
+
RBignum = struct(Basic + [
|
164
|
+
"char sign",
|
165
|
+
"long len",
|
166
|
+
"void *digits"
|
167
|
+
])
|
168
|
+
|
169
|
+
DMethod = struct [
|
170
|
+
"VALUE klass",
|
171
|
+
"VALUE rklass",
|
172
|
+
"long id",
|
173
|
+
"long oid",
|
174
|
+
"void *body"
|
175
|
+
]
|
176
|
+
|
177
|
+
FrameBase = [
|
178
|
+
"VALUE frame_self",
|
179
|
+
"int frame_argc",
|
180
|
+
"VALUE *frame_argv",
|
181
|
+
"ID frame_last_func",
|
182
|
+
"ID frame_orig_func",
|
183
|
+
"VALUE frame_last_class",
|
184
|
+
"FRAME *frame_prev",
|
185
|
+
"FRAME *frame_tmp",
|
186
|
+
"RNode *frame_node",
|
187
|
+
"int frame_iter",
|
188
|
+
"int frame_flags",
|
189
|
+
"ulong frame_uniq"
|
190
|
+
]
|
191
|
+
|
192
|
+
Frame = struct FrameBase
|
193
|
+
|
194
|
+
Block = struct([
|
195
|
+
"NODE *var",
|
196
|
+
"NODE *body",
|
197
|
+
"VALUE self",
|
198
|
+
] + FrameBase + [
|
199
|
+
"SCOPE *scope",
|
200
|
+
"VALUE klass",
|
201
|
+
"NODE *cref",
|
202
|
+
"int iter",
|
203
|
+
"int vmode",
|
204
|
+
"int flags",
|
205
|
+
"int uniq",
|
206
|
+
"RVarmap *dyna_vars",
|
207
|
+
"VALUE orig_thread",
|
208
|
+
"VALUE wrapper",
|
209
|
+
"VALUE block_obj",
|
210
|
+
"BLOCK *outer",
|
211
|
+
"BLOCK *prev"
|
212
|
+
])
|
213
|
+
|
214
|
+
STD_HASH_TYPE = struct [
|
215
|
+
"void *compare",
|
216
|
+
"void *hash"
|
217
|
+
]
|
218
|
+
|
219
|
+
typealias "ST_DATA_T", "unsigned long"
|
220
|
+
|
221
|
+
ST_TABLE_ENTRY = struct [
|
222
|
+
"int hash",
|
223
|
+
"ST_DATA_T key",
|
224
|
+
"ST_DATA_T record",
|
225
|
+
"ST_TABLE_ENTRY *next"
|
226
|
+
]
|
227
|
+
|
228
|
+
ST_TABLE = struct [
|
229
|
+
"ST_HASH_TYPE *type",
|
230
|
+
"int num_bins",
|
231
|
+
"int num_entries",
|
232
|
+
"ST_TABLE_ENTRY **bins"
|
233
|
+
]
|
234
|
+
|
235
|
+
FL_USHIFT = 11
|
236
|
+
FL_USER0 = 1 << (FL_USHIFT + 0)
|
237
|
+
FL_USER1 = 1 << (FL_USHIFT + 1)
|
238
|
+
FL_USER2 = 1 << (FL_USHIFT + 2)
|
239
|
+
FL_USER3 = 1 << (FL_USHIFT + 3)
|
240
|
+
FL_USER4 = 1 << (FL_USHIFT + 4)
|
241
|
+
FL_USER5 = 1 << (FL_USHIFT + 5)
|
242
|
+
FL_USER6 = 1 << (FL_USHIFT + 6)
|
243
|
+
FL_USER7 = 1 << (FL_USHIFT + 7)
|
244
|
+
|
245
|
+
FL_SINGLETON = FL_USER0
|
246
|
+
FL_MARK = 1 << 6
|
247
|
+
FL_FINALIZE = 1 << 7
|
248
|
+
FL_TAINT = 1 << 8
|
249
|
+
FL_EXIVAR = 1 << 9
|
250
|
+
FL_FREEZE = 1 << 10
|
251
|
+
|
252
|
+
# Executes a block of code that changes
|
253
|
+
# internal Ruby structures. This will
|
254
|
+
# make sure that neither the GC nor other
|
255
|
+
# Threads are run while the block is
|
256
|
+
# getting executed.
|
257
|
+
def critical
|
258
|
+
begin
|
259
|
+
if Is_1_8 then
|
260
|
+
old_critical = Thread.critical
|
261
|
+
Thread.critical = true
|
262
|
+
else
|
263
|
+
# Is it OK to do nothing on 1.9?
|
264
|
+
end
|
265
|
+
|
266
|
+
disabled_gc = !GC.disable
|
267
|
+
|
268
|
+
yield
|
269
|
+
ensure
|
270
|
+
GC.enable if disabled_gc
|
271
|
+
Thread.critical = old_critical if Is_1_8
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
module EmptyModule; end
|
276
|
+
def empty_iclass_ptr(force_new = false)
|
277
|
+
@empty_iclass_ptr ||= nil # avoid warning
|
278
|
+
return @empty_iclass_ptr if @empty_iclass_ptr and not force_new
|
279
|
+
result = Object.new
|
280
|
+
iptr = result.internal_ptr
|
281
|
+
ires = result.internal
|
282
|
+
newires = RClass.new(result.internal_ptr)
|
283
|
+
critical do
|
284
|
+
ires.flags &= ~T_MASK
|
285
|
+
ires.flags |= T_ICLASS
|
286
|
+
ires.klass = EmptyModule.internal_ptr.to_i
|
287
|
+
newires.m_tbl = EmptyModule.internal.m_tbl
|
288
|
+
end
|
289
|
+
@empty_iclass_ptr = iptr
|
290
|
+
return iptr
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
class Object
|
295
|
+
# Returns the singleton class of an Object.
|
296
|
+
# This is just a simple convenience method.
|
297
|
+
#
|
298
|
+
# obj = Object.new
|
299
|
+
# obj.singleton_class.class_eval do
|
300
|
+
# def x; end
|
301
|
+
# end
|
302
|
+
# obj.respond_to?(:x) # => true
|
303
|
+
def singleton_class
|
304
|
+
class << self; self; end
|
305
|
+
end
|
306
|
+
alias :meta_class :singleton_class
|
307
|
+
|
308
|
+
def internal_class
|
309
|
+
# we use this instead of a "cleaner" method (such as a
|
310
|
+
# hash with class => possible flags associations) because
|
311
|
+
# (1) the number of internal types won't change
|
312
|
+
# (2) it'd be slower
|
313
|
+
case internal_type
|
314
|
+
when RubyInternal::T_OBJECT
|
315
|
+
RubyInternal::RObject
|
316
|
+
when RubyInternal::T_CLASS, RubyInternal::T_ICLASS, RubyInternal::T_MODULE
|
317
|
+
RubyInternal::RModule
|
318
|
+
when RubyInternal::T_FLOAT
|
319
|
+
RubyInternal::RFloat
|
320
|
+
when RubyInternal::T_STRING
|
321
|
+
RubyInternal::RString
|
322
|
+
when RubyInternal::T_REGEXP
|
323
|
+
RubyInternal::RRegexp
|
324
|
+
when RubyInternal::T_ARRAY
|
325
|
+
RubyInternal::RArray
|
326
|
+
when RubyInternal::T_HASH
|
327
|
+
RubyInternal::RHash
|
328
|
+
when RubyInternal::T_STRUCT
|
329
|
+
RubyInternal::RStruct
|
330
|
+
when RubyInternal::T_BIGNUM
|
331
|
+
RubyInternal::RBignum
|
332
|
+
when RubyInternal::T_FILE
|
333
|
+
RubyInternal::RFile
|
334
|
+
when RubyInternal::T_DATA
|
335
|
+
RubyInternal::RData
|
336
|
+
else
|
337
|
+
raise "No internal class for #{self}"
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def internal_type
|
342
|
+
case self
|
343
|
+
when Fixnum then RubyInternal::T_FIXNUM
|
344
|
+
when NilClass then RubyInternal::T_NIL
|
345
|
+
when FalseClass then RubyInternal::T_FALSE
|
346
|
+
when TrueClass then RubyInternal::T_TRUE
|
347
|
+
when Symbol then RubyInternal::T_SYMBOL
|
348
|
+
else
|
349
|
+
RubyInternal::RBasic.new(self.internal_ptr).flags & RubyInternal::T_MASK
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def internal_ptr(*args)
|
354
|
+
raise(ArgumentError, "Can't get pointer to direct values.") \
|
355
|
+
if direct_value?
|
356
|
+
pos = self.object_id * 2
|
357
|
+
DL::CPtr.new(pos, *args)
|
358
|
+
end
|
359
|
+
|
360
|
+
def internal
|
361
|
+
raise(ArgumentError, "Can't get internal representation" +
|
362
|
+
" of direct values") \
|
363
|
+
if direct_value?
|
364
|
+
|
365
|
+
propagate_magic = nil # forward "declaration"
|
366
|
+
do_magic = lambda do |obj, id|
|
367
|
+
addr = obj.instance_eval { send(id) }
|
368
|
+
sklass = class << obj; self end
|
369
|
+
sklass.instance_eval do
|
370
|
+
define_method(id) do
|
371
|
+
case addr
|
372
|
+
when 0
|
373
|
+
return nil
|
374
|
+
else
|
375
|
+
begin
|
376
|
+
r = RubyInternal::RClass.new DL::CPtr.new(addr, 5 * DL::SIZEOF_LONG)
|
377
|
+
rescue RangeError
|
378
|
+
r = RubyInternal::RClass.new DL::CPtr.new(addr - 2**32, 5 * DL::SIZEOF_LONG)
|
379
|
+
end
|
380
|
+
propagate_magic.call r, true
|
381
|
+
end
|
382
|
+
class << r; self end.instance_eval { define_method(:to_i) { addr } }
|
383
|
+
r
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
propagate_magic = lambda do |obj, dosuper|
|
389
|
+
do_magic.call(obj, :klass)
|
390
|
+
do_magic.call(obj, :super) if dosuper
|
391
|
+
end
|
392
|
+
|
393
|
+
klass = internal_class
|
394
|
+
r = klass.new(internal_ptr)
|
395
|
+
|
396
|
+
case klass
|
397
|
+
when RubyInternal::RClass, RubyInternal::RModule
|
398
|
+
propagate_magic.call r, true
|
399
|
+
else
|
400
|
+
propagate_magic.call r, false
|
401
|
+
end
|
402
|
+
r
|
403
|
+
end
|
404
|
+
|
405
|
+
# Unfreeze a frozen Object. You will be able to make
|
406
|
+
# changes to the object again.
|
407
|
+
#
|
408
|
+
# obj = "Hello World".freeze
|
409
|
+
# obj.frozen? # => true
|
410
|
+
# obj.unfreeze
|
411
|
+
# obj.frozen? # => false
|
412
|
+
# obj.sub!("World", "You!")
|
413
|
+
# obj # => "Hello You!"
|
414
|
+
def unfreeze
|
415
|
+
if $SAFE > 0
|
416
|
+
raise(SecurityError, "Insecure operation `unfreeze' at level #{$SAFE}")
|
417
|
+
end
|
418
|
+
|
419
|
+
return self if direct_value?
|
420
|
+
|
421
|
+
self.internal.flags &= ~RubyInternal::FL_FREEZE
|
422
|
+
return self
|
423
|
+
end
|
424
|
+
|
425
|
+
# Returns true if the Object is one of the Objects which
|
426
|
+
# Ruby stores directly. Fixnums, Symbols, true, false and
|
427
|
+
# nil all are direct values.
|
428
|
+
#
|
429
|
+
# 5.direct_value? # => true
|
430
|
+
# :foo.direct_value? # => true
|
431
|
+
# "foo".direct_value? # => false
|
432
|
+
# 5.0.direct_value? # => false
|
433
|
+
def direct_value?
|
434
|
+
[Fixnum, Symbol, NilClass, TrueClass, FalseClass].any? do |klass|
|
435
|
+
klass === self
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
alias :immediate_value? :direct_value?
|
440
|
+
|
441
|
+
# Changes the class of an Object to a new one. This will
|
442
|
+
# change the methods available on the Object.
|
443
|
+
#
|
444
|
+
# foo_klass = Class.new {}
|
445
|
+
# obj = Object.new
|
446
|
+
# obj.class = foo_klass
|
447
|
+
# obj.class # => foo_klass
|
448
|
+
def class=(new_class)
|
449
|
+
raise(ArgumentError, "Can't change class of direct value.") \
|
450
|
+
if direct_value?
|
451
|
+
raise(ArgumentError, "Class has to be a Class.") \
|
452
|
+
unless new_class.is_a? Class
|
453
|
+
if self.class.to_internal_type and
|
454
|
+
new_class.to_internal_type and
|
455
|
+
self.class.to_internal_type != new_class.to_internal_type
|
456
|
+
msg = "Internal type of class isn't compatible with " +
|
457
|
+
"internal type of object."
|
458
|
+
raise(ArgumentError, msg)
|
459
|
+
end
|
460
|
+
if self.class.to_internal_type == RubyInternal::T_DATA
|
461
|
+
msg = "Internal type of class isn't compatible with " +
|
462
|
+
"internal type of object. (Both are T_DATA, but " +
|
463
|
+
"that doesn't imply that they're compatible.)"
|
464
|
+
raise(ArgumentError, msg)
|
465
|
+
end
|
466
|
+
self.internal.klass = new_class.internal_ptr.to_i
|
467
|
+
return self
|
468
|
+
end
|
469
|
+
|
470
|
+
# Shares the instance variables of two Objects with each
|
471
|
+
# other. If you make a change to such shared instance
|
472
|
+
# variables they will change at both Objects.
|
473
|
+
def share_instance_variables(from_obj)
|
474
|
+
raise(ArgumentError, "Can't share instance variables of" +
|
475
|
+
"direct values") \
|
476
|
+
if direct_value?
|
477
|
+
#FIXME: memleak (?)
|
478
|
+
self.internal.iv_tbl = from_obj.internal.iv_tbl
|
479
|
+
return instance_variables
|
480
|
+
end
|
481
|
+
|
482
|
+
# The Object will acquire a copy of +obj+'s singleton methods.
|
483
|
+
def grab_singleton_methods(obj)
|
484
|
+
original_sklass = class << obj; self end # make sure the singleton class is there
|
485
|
+
RubyInternal::critical do
|
486
|
+
original_sklass.internal.flags &= ~ RubyInternal::FL_SINGLETON
|
487
|
+
class << self; self end.module_eval{ include original_sklass.as_module }
|
488
|
+
original_sklass.internal.flags |= RubyInternal::FL_SINGLETON
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
class Class
|
494
|
+
# Changes the super class of a Class.
|
495
|
+
def superclass=(new_class)
|
496
|
+
k1 = superclass
|
497
|
+
if new_class.nil?
|
498
|
+
self.internal.super = RubyInternal.empty_iclass_ptr.to_i
|
499
|
+
else
|
500
|
+
raise(ArgumentError, "Value of class has to be a Class.") \
|
501
|
+
unless new_class.is_a?(Class)
|
502
|
+
raise(ArgumentError, "superclass= would create circular " +
|
503
|
+
"inheritance structure.") \
|
504
|
+
if new_class.ancestors.include?(self)
|
505
|
+
raise(ArgumentError, "Superclass type incompatible with own type.") \
|
506
|
+
if new_class.to_internal_type != self.to_internal_type
|
507
|
+
self.internal.super = new_class.internal_ptr.to_i
|
508
|
+
end
|
509
|
+
# invalidate the method cache
|
510
|
+
k1.instance_eval { public :__send__ rescue nil }
|
511
|
+
end
|
512
|
+
|
513
|
+
def to_internal_type
|
514
|
+
begin
|
515
|
+
self.allocate.internal.flags & RubyInternal::T_MASK
|
516
|
+
rescue
|
517
|
+
if self.superclass
|
518
|
+
self.superclass.to_internal_type
|
519
|
+
else
|
520
|
+
nil
|
521
|
+
end
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
# Will return the Class converted to a Module.
|
526
|
+
def as_module
|
527
|
+
result = nil
|
528
|
+
RubyInternal.critical do
|
529
|
+
fl_singleton = self.internal.flags & RubyInternal::FL_SINGLETON
|
530
|
+
begin
|
531
|
+
self.internal.flags &= ~ RubyInternal::FL_SINGLETON
|
532
|
+
result = self.clone
|
533
|
+
ensure
|
534
|
+
self.internal.flags |= fl_singleton
|
535
|
+
end
|
536
|
+
o = RubyInternal::RObject.new(result.internal_ptr)
|
537
|
+
o.flags &= ~ RubyInternal::T_MASK
|
538
|
+
o.flags |= RubyInternal::T_MODULE
|
539
|
+
o.klass = Module.internal_ptr.to_i
|
540
|
+
end
|
541
|
+
return result
|
542
|
+
end
|
543
|
+
|
544
|
+
# This will allow your Classes to inherit from multiple
|
545
|
+
# other Classes. If two Classes define the same method
|
546
|
+
# the last one will be used.
|
547
|
+
#
|
548
|
+
# bar_klass = Class.new { def bar; end }
|
549
|
+
# qux_klass = Class.new { def qux; end }
|
550
|
+
# foo_klass = Class.new do
|
551
|
+
# inherit bar_klass, qux_klass
|
552
|
+
# end
|
553
|
+
# foo = foo_klass.new
|
554
|
+
# foo.respond_to?(:bar) # => true
|
555
|
+
# foo.respond_to?(:qux) # => true
|
556
|
+
def inherit(*sources)
|
557
|
+
sources.each do |klass|
|
558
|
+
raise(ArgumentError, "Cyclic inherit detected.") \
|
559
|
+
if klass.ancestors.include?(self)
|
560
|
+
raise(ArgumentError, "Can only inherit from Classes.") \
|
561
|
+
unless klass.is_a?(Class)
|
562
|
+
# the following is needed cause otherwise we could end up inheriting
|
563
|
+
# e.g. a method from String that would assume the object has some
|
564
|
+
# internal structure (RString) and crash otherwise...
|
565
|
+
unless klass.to_internal_type == self.to_internal_type
|
566
|
+
raise(ArgumentError, "Inherit needs consistent internal types.")
|
567
|
+
end
|
568
|
+
include klass.as_module
|
569
|
+
extend klass.singleton_class.as_module
|
570
|
+
end
|
571
|
+
end
|
572
|
+
private :inherit
|
573
|
+
end
|
574
|
+
|
575
|
+
# Like Object, but this provides no methods at all.
|
576
|
+
# You can derivate your own Classes from this Class
|
577
|
+
# if you want them to have no preset methods.
|
578
|
+
#
|
579
|
+
# klass = Class.new(KernellessObject) { def inspect; end }
|
580
|
+
# klass.new.methods # raises NoMethodError
|
581
|
+
#
|
582
|
+
# Classes that are derived from KernellessObject
|
583
|
+
# won't call #initialize from .new by default.
|
584
|
+
#
|
585
|
+
# It is a good idea to define #inspect for subclasses,
|
586
|
+
# because Ruby will go into an endless loop when trying
|
587
|
+
# to create an exception message if it is not there.
|
588
|
+
class KernellessObject
|
589
|
+
class << self
|
590
|
+
def to_internal_type; ::Object.to_internal_type; end
|
591
|
+
|
592
|
+
def allocate
|
593
|
+
obj = ::Object.allocate
|
594
|
+
obj.class = self
|
595
|
+
return obj
|
596
|
+
end
|
597
|
+
|
598
|
+
alias :new :allocate
|
599
|
+
end
|
600
|
+
|
601
|
+
self.superclass = nil
|
602
|
+
end
|
603
|
+
|
604
|
+
class UnboundMethod
|
605
|
+
# Like UnboundMethod#bind this will bind an UnboundMethod
|
606
|
+
# to an Object. However this variant doesn't enforce class
|
607
|
+
# compatibility when it isn't needed. (It still needs
|
608
|
+
# compatible internal types however.)
|
609
|
+
#
|
610
|
+
# Currently it's also generally impossible to force_bind a
|
611
|
+
# foreign method to immediate objects.
|
612
|
+
#
|
613
|
+
# Here's an example:
|
614
|
+
#
|
615
|
+
# foo_klass = Class.new do
|
616
|
+
# def greet; "#{self.inspect} says 'Hi!'"; end
|
617
|
+
# end
|
618
|
+
# obj = []
|
619
|
+
# greet = foo_klass.instance_method(:greet)
|
620
|
+
# greet.bind(obj).call # raises TypeError
|
621
|
+
# greet.force_bind(obj).call # => "[] says 'Hi!'"
|
622
|
+
def force_bind(obj)
|
623
|
+
data = self.internal.data
|
624
|
+
source_class_addr = RubyInternal::DMethod.new(data).klass
|
625
|
+
source_class = ObjectSpace._id2ref(source_class_addr / 2)
|
626
|
+
|
627
|
+
if [Fixnum, Symbol, NilClass, TrueClass, FalseClass].any? do |klass|
|
628
|
+
klass <= source_class
|
629
|
+
end then
|
630
|
+
if not obj.is_a?(source_class) then
|
631
|
+
msg = "Immediate source class and non-immediate new " +
|
632
|
+
"receiver are incompatible"
|
633
|
+
raise(ArgumentError, msg)
|
634
|
+
else
|
635
|
+
return self.bind(obj)
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
if source_class.to_internal_type and
|
640
|
+
source_class.to_internal_type != RubyInternal::T_OBJECT and
|
641
|
+
source_class.to_internal_type != obj.class.to_internal_type
|
642
|
+
msg = "Internal type of source class and new receiver " +
|
643
|
+
"are incompatible"
|
644
|
+
raise(ArgumentError, msg)
|
645
|
+
end
|
646
|
+
|
647
|
+
result = nil
|
648
|
+
RubyInternal.critical do
|
649
|
+
prev_class = obj.internal.klass.to_i
|
650
|
+
begin
|
651
|
+
internal_obj = obj.internal
|
652
|
+
begin
|
653
|
+
internal_obj.klass = source_class_addr
|
654
|
+
result = self.bind(obj)
|
655
|
+
ensure
|
656
|
+
internal_obj.klass = prev_class
|
657
|
+
end
|
658
|
+
rescue TypeError
|
659
|
+
result = self.bind(obj)
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
return result
|
664
|
+
end
|
665
|
+
end
|
666
|
+
|
667
|
+
class Proc
|
668
|
+
def self
|
669
|
+
eval "self", self
|
670
|
+
end
|
671
|
+
|
672
|
+
# FIXME: look into possible signedness issues for large Fixnums (2**30 and higher)
|
673
|
+
def self=(new_self)
|
674
|
+
new_self_ptr = new_self.object_id
|
675
|
+
unless new_self.direct_value?
|
676
|
+
new_self_ptr = new_klass_ptr * 2
|
677
|
+
# new_self_ptr += 2 ** 32 if new_klass_ptr < 0 # FIXME: needed?
|
678
|
+
end
|
679
|
+
new_klass_ptr = class << new_self; self; end.object_id * 2 rescue nil.object_id
|
680
|
+
data = RubyInternal::RData.new(internal_ptr).data
|
681
|
+
block = RubyInternal::Block.new(data)
|
682
|
+
|
683
|
+
RubyInternal.critical do
|
684
|
+
block.self = new_self_ptr
|
685
|
+
block.klass = new_klass_ptr
|
686
|
+
end
|
687
|
+
|
688
|
+
return new_self
|
689
|
+
end
|
690
|
+
alias :context= :self=
|
691
|
+
end
|