evil-ruby 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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