evil-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (10) hide show
  1. data/COPYING +56 -0
  2. data/NEWS +7 -0
  3. data/README +15 -0
  4. data/Rakefile +109 -0
  5. data/lib/evil.rb +691 -0
  6. data/setup.rb +1360 -0
  7. data/test/tc_all.rb +8 -0
  8. data/test/tc_inline.rb +11 -0
  9. data/test/test-extract.rb +112 -0
  10. 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
@@ -0,0 +1,7 @@
1
+ = NEWS
2
+
3
+ This file sums up important changes that happened between releases.
4
+
5
+ == evil-ruby 0.1.0
6
+ * Fixed to work in Ruby 1.9 as well as 1.8
7
+ * Removed features that caused crashs
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".
@@ -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
@@ -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