evilr 1.0.0-x86-mingw32
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.
- data/MIT-LICENSE +19 -0
- data/README.rdoc +148 -0
- data/Rakefile +41 -0
- data/ext/evilr/evilr.c +993 -0
- data/ext/evilr/extconf.rb +7 -0
- data/lib/1.8/evilr.so +0 -0
- data/lib/1.9/evilr.so +0 -0
- data/lib/evilr.rb +1 -0
- data/spec/evilr_spec.rb +1157 -0
- metadata +88 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010-2011 Jeremy Evans
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
19
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
= evilr
|
2
|
+
|
3
|
+
evilr subverts ruby's runtime and lets you do things you shouldn't
|
4
|
+
do, such as changing the classes of objects. It's inspired by
|
5
|
+
evil.rb, but is a C extension as opposed to ruby code that uses DL.
|
6
|
+
|
7
|
+
== Why?
|
8
|
+
|
9
|
+
It's a good way to learn about how ruby works under the hood. It's
|
10
|
+
fun to push the boundries of ruby's runtime, to see the difference
|
11
|
+
between what's just not allowed (i.e. changing classes) and what's
|
12
|
+
not possible for technical reasons (i.e. sharing singleton classes,
|
13
|
+
instance variables, or method tables).
|
14
|
+
|
15
|
+
== Installation
|
16
|
+
|
17
|
+
gem install evilr
|
18
|
+
|
19
|
+
== What evil is currently available?
|
20
|
+
|
21
|
+
* Object
|
22
|
+
* class= : Change the class of an object
|
23
|
+
* detach_singleton_class : Make current singleton class not a
|
24
|
+
singleton, becoming the object's main class.
|
25
|
+
* dup_singleton_class : Make a copy of the current singleton
|
26
|
+
class as a regular class.
|
27
|
+
* evilr_debug_print : Print method ancestry chain to standard
|
28
|
+
output.
|
29
|
+
* extend_between : Given a module and a block, calls the block
|
30
|
+
repeatedly with two arguments, each a module or class in the super
|
31
|
+
chain. The first time the block returns true, the module argument
|
32
|
+
given to the method is inserted between the given extended modules.
|
33
|
+
Starts with the object's singleton class and continues until
|
34
|
+
the object's class. If the argument given already extends the
|
35
|
+
object, will remove it and reinsert it. If the argument is
|
36
|
+
already included in the object's class, raises an exception.
|
37
|
+
* pop_singleton_class : Remove closest singleton class from the
|
38
|
+
object
|
39
|
+
* push_singleton_class : Add a new singleton class to the object
|
40
|
+
in front of any existing singleton class.
|
41
|
+
* remove_singleton_class : Remove an object's singleton class
|
42
|
+
and any modules that extend the object.
|
43
|
+
* remove_singleton_classes : Remove all singleton classes
|
44
|
+
and extended modules.
|
45
|
+
* set_singleton_class : Take a given class and make it the object's
|
46
|
+
singleton class, replacing any existing singleton class.
|
47
|
+
* swap : Completely swap two objects (singleton class, class,
|
48
|
+
instance variables).
|
49
|
+
* swap_singleton_class : Swap an object's singleton class with
|
50
|
+
another object's singleton class.
|
51
|
+
* swap_instance_variables: Swap two instance's instance variables.
|
52
|
+
* unextend : Remove a module that extends the object from the super
|
53
|
+
chain.
|
54
|
+
* unfreeze : Unfreeze the object.
|
55
|
+
* Kernel
|
56
|
+
* segfault : Dereferences NULL.
|
57
|
+
* seppuku : kill -KILL's the current process.
|
58
|
+
* set_safe_level : Allows you to lower ruby's $SAFE level.
|
59
|
+
* Module
|
60
|
+
* include_between : Given a module and a block, calls the block
|
61
|
+
repeatedly with two arguments, each a module or class in the super
|
62
|
+
chain. The first time the block returns true, the module argument
|
63
|
+
given to the method is inserted between the given modules. Continues
|
64
|
+
until the end of the super chain. If the argument given is already
|
65
|
+
included, will remove it and reinsert it.
|
66
|
+
* swap_method_tables : Swap the method tables of the receiver with
|
67
|
+
the ones in the given module/class.
|
68
|
+
* to_class : Return a copy of the module as a class.
|
69
|
+
* uninclude : Remove the given module from the super chain, including
|
70
|
+
going into superclasses if the receiver is a class.
|
71
|
+
* Class
|
72
|
+
* detach_singleton : If the class is a singleton class, remove
|
73
|
+
its singleton status.
|
74
|
+
* inherit : Allows inheriting from multiple classes, basically
|
75
|
+
including them as modules.
|
76
|
+
* singleton_class_instance : If the class is a singleton class,
|
77
|
+
return the related instance.
|
78
|
+
* superclass= : Modify the superclass of the receiver.
|
79
|
+
* to_module : Return a copy of the class as a module.
|
80
|
+
* UnboundMethod
|
81
|
+
* force_bind : Bind the method to the object even if it is a different
|
82
|
+
class than the method.
|
83
|
+
* Proc
|
84
|
+
* self : Get the default receiver of the proc's methods
|
85
|
+
* self= : Change the default receiver of the proc's methods
|
86
|
+
* Empty
|
87
|
+
* A class with no superclass, only allocate, new, initialize, and
|
88
|
+
superclass defined. More basic than even BasicObject.
|
89
|
+
|
90
|
+
== Good bugs
|
91
|
+
|
92
|
+
If bugs are evil in good code, then surely bugs in evil code are good:
|
93
|
+
|
94
|
+
http://github.com/jeremyevans/evilr/issues
|
95
|
+
|
96
|
+
== Contributing
|
97
|
+
|
98
|
+
I'm happy to accept more evil, hopefully without good bugs and with
|
99
|
+
evil specs:
|
100
|
+
|
101
|
+
http://github.com/jeremyevans/evilr
|
102
|
+
|
103
|
+
evilr currently requires:
|
104
|
+
|
105
|
+
* rake
|
106
|
+
* rake-compiler
|
107
|
+
* rspec
|
108
|
+
|
109
|
+
== Running the specs
|
110
|
+
|
111
|
+
Even evil code should have specs! The default rake task runs the
|
112
|
+
specs:
|
113
|
+
|
114
|
+
rake
|
115
|
+
|
116
|
+
== Platforms Tested
|
117
|
+
|
118
|
+
=== Operating Systems/Platforms
|
119
|
+
|
120
|
+
* OpenBSD (amd64, i386)
|
121
|
+
* Linux (i386)
|
122
|
+
* Windows XP (i386)
|
123
|
+
|
124
|
+
=== Compiler Versions
|
125
|
+
|
126
|
+
* gcc 4.2.1
|
127
|
+
* gcc 4.4.5
|
128
|
+
|
129
|
+
== Ruby Versions
|
130
|
+
|
131
|
+
* ruby 1.8.6
|
132
|
+
* ruby 1.8.7
|
133
|
+
* ruby 1.9.2
|
134
|
+
|
135
|
+
ruby 1.9.1 is not supported. It mostly works but has spec failures.
|
136
|
+
|
137
|
+
If your platform, compiler version, or ruby version is not listed
|
138
|
+
above, please test and send me a report including:
|
139
|
+
|
140
|
+
* Your operating system and platform (e.g. i386, x86_64/amd64)
|
141
|
+
* Your compiler
|
142
|
+
* Your ruby version
|
143
|
+
* The output of rake
|
144
|
+
|
145
|
+
== Author
|
146
|
+
|
147
|
+
Jeremy Evans <code@jeremyevans.net>
|
148
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require "rake"
|
2
|
+
require "rake/clean"
|
3
|
+
|
4
|
+
CLEAN.include %w'*.core doc ext/evilr/Makefile ext/evilr/evilr.o ext/evilr/evilr.so lib tmp evilr-*.gem'
|
5
|
+
|
6
|
+
desc "Build the gem"
|
7
|
+
task :gem do
|
8
|
+
sh %{gem build evilr.gemspec}
|
9
|
+
end
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'rake/extensiontask'
|
13
|
+
Rake::ExtensionTask.new('evilr')
|
14
|
+
dependencies = [:compile]
|
15
|
+
rescue LoadError
|
16
|
+
dependencies = []
|
17
|
+
end
|
18
|
+
|
19
|
+
begin
|
20
|
+
require "spec/rake/spectask"
|
21
|
+
|
22
|
+
Spec::Rake::SpecTask.new("spec" => dependencies) do |t|
|
23
|
+
t.spec_files = ["spec/evilr_spec.rb"]
|
24
|
+
end
|
25
|
+
task :default => :spec
|
26
|
+
|
27
|
+
rescue LoadError
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Start an IRB shell using the extension"
|
31
|
+
task :irb => dependencies do
|
32
|
+
require 'irb'
|
33
|
+
$:.unshift 'lib'
|
34
|
+
require 'evilr'
|
35
|
+
c = IRB.conf
|
36
|
+
def c.[]=(k,v)
|
37
|
+
super unless k == :SCRIPT
|
38
|
+
end
|
39
|
+
IRB.start
|
40
|
+
end
|
41
|
+
|
data/ext/evilr/evilr.c
ADDED
@@ -0,0 +1,993 @@
|
|
1
|
+
#include <signal.h>
|
2
|
+
#include <string.h>
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <sys/types.h>
|
5
|
+
#include <unistd.h>
|
6
|
+
|
7
|
+
#include <ruby.h>
|
8
|
+
#ifdef RUBY19
|
9
|
+
#include <ruby/st.h>
|
10
|
+
#else
|
11
|
+
#include <st.h>
|
12
|
+
#endif
|
13
|
+
|
14
|
+
/* ruby uses a magic number for this, arguably the only time
|
15
|
+
* it is more evil that evilr. */
|
16
|
+
#ifndef SAFE_LEVEL_MAX
|
17
|
+
#define SAFE_LEVEL_MAX 4
|
18
|
+
#endif
|
19
|
+
|
20
|
+
/* Partial struct definition == evil */
|
21
|
+
struct METHOD {
|
22
|
+
VALUE recv;
|
23
|
+
VALUE rclass;
|
24
|
+
ID id;
|
25
|
+
};
|
26
|
+
|
27
|
+
#ifdef RUBY19
|
28
|
+
struct BLOCK {
|
29
|
+
VALUE self;
|
30
|
+
VALUE *lfp;
|
31
|
+
VALUE *dfp;
|
32
|
+
void *block_iseq;
|
33
|
+
VALUE proc;
|
34
|
+
};
|
35
|
+
#else
|
36
|
+
/* More partial definition evil */
|
37
|
+
struct BLOCK {
|
38
|
+
void *var;
|
39
|
+
void *body;
|
40
|
+
VALUE self;
|
41
|
+
};
|
42
|
+
#endif
|
43
|
+
|
44
|
+
/* Ruby 1.8.6 support */
|
45
|
+
#ifndef RCLASS_SUPER
|
46
|
+
#define RCLASS_SUPER(c) RCLASS(c)->super
|
47
|
+
#endif
|
48
|
+
#ifndef RCLASS_IV_TBL
|
49
|
+
#define RCLASS_IV_TBL(c) RCLASS(c)->iv_tbl
|
50
|
+
#endif
|
51
|
+
#ifndef RCLASS_M_TBL
|
52
|
+
#define RCLASS_M_TBL(c) RCLASS(c)->m_tbl
|
53
|
+
#endif
|
54
|
+
|
55
|
+
#define OBJECT_SIZE sizeof(struct RClass)
|
56
|
+
#define RBASIC_SET_KLASS(o, c) (RBASIC(o)->klass = c)
|
57
|
+
#define RBASIC_KLASS(o) (RBASIC(o)->klass)
|
58
|
+
#define RBASIC_FLAGS(o) (RBASIC(o)->flags)
|
59
|
+
#define IS_SINGLETON_CLASS(o) (FL_TEST(o, FL_SINGLETON))
|
60
|
+
#define HAS_SINGLETON_CLASS(o) (FL_TEST(RBASIC_KLASS(o), FL_SINGLETON))
|
61
|
+
|
62
|
+
#ifdef RUBY19
|
63
|
+
#define RCLASS_SET_SUPER(o, c) (RCLASS(o)->ptr->super = c)
|
64
|
+
#else
|
65
|
+
#define RCLASS_SET_SUPER(o, c) (RCLASS(o)->super = c)
|
66
|
+
#define ROBJECT_IVPTR(o) (ROBJECT(o)->iv_tbl)
|
67
|
+
extern int ruby_safe_level;
|
68
|
+
#endif
|
69
|
+
|
70
|
+
VALUE empty;
|
71
|
+
ID evilr__attached;
|
72
|
+
ID evilr__bind;
|
73
|
+
ID evilr__clone;
|
74
|
+
|
75
|
+
/* Helper functions */
|
76
|
+
|
77
|
+
/* Raise TypeError if an immediate value is given. */
|
78
|
+
static void evilr__check_immediate(VALUE self) {
|
79
|
+
if (SPECIAL_CONST_P(self)) {
|
80
|
+
rb_raise(rb_eTypeError, "can't use immediate value");
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
/* Raise TypeError if either self or other is an immediate value. */
|
85
|
+
static void evilr__check_immediates(VALUE self, VALUE other) {
|
86
|
+
evilr__check_immediate(self);
|
87
|
+
evilr__check_immediate(other);
|
88
|
+
}
|
89
|
+
|
90
|
+
/* Raise TypeError if self doesn't have the given ruby internal type
|
91
|
+
* number (e.g. T_OBJECT). */
|
92
|
+
static void evilr__check_type(unsigned int type, VALUE self) {
|
93
|
+
if (BUILTIN_TYPE(self) != type) {
|
94
|
+
rb_raise(rb_eTypeError, "incompatible type used");
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
/* Return the ruby internal type number that instances of the
|
99
|
+
* given class use. */
|
100
|
+
static unsigned int evilr__class_type(VALUE klass) {
|
101
|
+
evilr__check_type(T_CLASS, klass);
|
102
|
+
return BUILTIN_TYPE(rb_obj_alloc(klass));
|
103
|
+
}
|
104
|
+
|
105
|
+
/* Raise TypeError if instances of the given class don't have the
|
106
|
+
* given ruby internal type number. */
|
107
|
+
static void evilr__check_class_type(unsigned int type, VALUE self) {
|
108
|
+
if (evilr__class_type(self) != type) {
|
109
|
+
rb_raise(rb_eTypeError, "incompatible type used");
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
/* Raise TypeError if the given value has the ruby internal type number T_DATA. */
|
114
|
+
static void evilr__check_data_type(VALUE self) {
|
115
|
+
if (BUILTIN_TYPE(self) == T_DATA) {
|
116
|
+
rb_raise(rb_eTypeError, "incompatible type used");
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
/* Return the next class in the super chain, skipping any iclasses (included modules).
|
121
|
+
* Returns NULL if this is the last class in the super chain. */
|
122
|
+
static VALUE evilr__next_class(VALUE klass) {
|
123
|
+
VALUE c;
|
124
|
+
for (c = RCLASS_SUPER(klass); c && BUILTIN_TYPE(c) != T_CLASS; c = RCLASS_SUPER(c)); /* empty */
|
125
|
+
return c;
|
126
|
+
}
|
127
|
+
|
128
|
+
/* If the given class includes no modules, return it. Otherwise, return the last iclass
|
129
|
+
* before the next class in the super chain. */
|
130
|
+
static VALUE evilr__iclass_before_next_class(VALUE klass) {
|
131
|
+
VALUE c, i = NULL;
|
132
|
+
for (c = RCLASS_SUPER(klass); c && BUILTIN_TYPE(c) != T_CLASS; i = c, c = RCLASS_SUPER(c)); /* empty */
|
133
|
+
return i == NULL ? klass : i;
|
134
|
+
}
|
135
|
+
|
136
|
+
/* Walk the super chain from klass until either before or an iclass for mod is encountered. If
|
137
|
+
* before is encountered first, return NULL. If an iclass for mod is encountered first, return
|
138
|
+
* the iclass. */
|
139
|
+
static VALUE evilr__iclass_matching_before(VALUE klass, VALUE mod, VALUE before) {
|
140
|
+
VALUE c;
|
141
|
+
for (c = RCLASS_SUPER(klass); c && c != before; c = RCLASS_SUPER(c)) {
|
142
|
+
if (BUILTIN_TYPE(c) == T_ICLASS && RBASIC_KLASS(c) == mod) {
|
143
|
+
return c;
|
144
|
+
}
|
145
|
+
}
|
146
|
+
return NULL;
|
147
|
+
}
|
148
|
+
|
149
|
+
/* If there is an iclass for mod anywhere in the super chain of klass, return the iclass.
|
150
|
+
* Otherwise, return NULL. */
|
151
|
+
static VALUE evilr__iclass_matching(VALUE klass, VALUE mod) {
|
152
|
+
return evilr__iclass_matching_before(klass, mod, NULL);
|
153
|
+
}
|
154
|
+
|
155
|
+
/* If self has a singleton class, set the superclass of the
|
156
|
+
* singleton class to the given klass, keeping all modules
|
157
|
+
* that are included in the singleton class. Otherwise, set the
|
158
|
+
* object's klass to the given klass. */
|
159
|
+
void evilr__reparent_singleton_class(VALUE self, VALUE klass) {
|
160
|
+
VALUE self_klass = RBASIC_KLASS(self);
|
161
|
+
|
162
|
+
if (IS_SINGLETON_CLASS(self_klass)) {
|
163
|
+
RCLASS_SET_SUPER(evilr__iclass_before_next_class(self_klass), klass);
|
164
|
+
rb_clear_cache_by_class(self_klass);
|
165
|
+
} else {
|
166
|
+
RBASIC_SET_KLASS(self, klass);
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
/* Set the superclass of self to the given klass, keeping all
|
171
|
+
* modules that are included in the class. */
|
172
|
+
void evilr__reparent_class(VALUE self, VALUE klass) {
|
173
|
+
RCLASS_SET_SUPER(evilr__iclass_before_next_class(self), klass);
|
174
|
+
rb_clear_cache_by_class(self);
|
175
|
+
}
|
176
|
+
|
177
|
+
/* Raise TypeError if self is an immediate value or if klass is
|
178
|
+
* not a Class. */
|
179
|
+
void evilr__check_obj_and_class(VALUE self, VALUE klass) {
|
180
|
+
evilr__check_immediates(self, klass);
|
181
|
+
evilr__check_type(T_CLASS, klass);
|
182
|
+
}
|
183
|
+
|
184
|
+
/* If no arguments are given, return Object. If an argument is
|
185
|
+
* given and it is a class object whose instances use the ruby
|
186
|
+
* internal class number T_OBJECT, return that class. If an argument
|
187
|
+
* is given and it isn't a class or it's instances don't use T_OBJECT,
|
188
|
+
* return a TypeError. Otherwise, return an ArgumentError. */
|
189
|
+
static VALUE evilr__optional_class(int argc, VALUE *argv) {
|
190
|
+
VALUE klass;
|
191
|
+
|
192
|
+
switch(argc) {
|
193
|
+
case 0:
|
194
|
+
klass = rb_cObject;
|
195
|
+
break;
|
196
|
+
case 1:
|
197
|
+
klass = argv[0];
|
198
|
+
evilr__check_class_type(T_OBJECT, klass);
|
199
|
+
break;
|
200
|
+
default:
|
201
|
+
rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
|
202
|
+
break;
|
203
|
+
}
|
204
|
+
return klass;
|
205
|
+
}
|
206
|
+
|
207
|
+
/* Make the given klass the singleton class of self. */
|
208
|
+
void evilr__make_singleton(VALUE self, VALUE klass) {
|
209
|
+
FL_SET(klass, FL_SINGLETON);
|
210
|
+
RBASIC_SET_KLASS(self, klass);
|
211
|
+
rb_singleton_class_attached(klass, self);
|
212
|
+
}
|
213
|
+
|
214
|
+
/* Check that super is a Class object whose instances use the same internal
|
215
|
+
* type number as instances of klass, and that the instances don't use
|
216
|
+
* type number T_DATA. */
|
217
|
+
void evilr__check_compatible_classes(VALUE klass, VALUE super) {
|
218
|
+
evilr__check_immediate(super);
|
219
|
+
evilr__check_type(T_CLASS, super);
|
220
|
+
evilr__check_class_type(evilr__class_type(klass), super);
|
221
|
+
evilr__check_data_type(rb_obj_alloc(klass));
|
222
|
+
}
|
223
|
+
|
224
|
+
/* Walk the super chain starting with the given iclass and include
|
225
|
+
* the modules related to each iclass into the mod such that the
|
226
|
+
* order of the initial iclass super chain and mod's super chain are
|
227
|
+
* the same. */
|
228
|
+
void evilr__include_iclasses(VALUE mod, VALUE iclass) {
|
229
|
+
if (iclass && BUILTIN_TYPE(iclass) == T_ICLASS) {
|
230
|
+
evilr__include_iclasses(mod, RCLASS_SUPER(iclass));
|
231
|
+
rb_include_module(mod, RBASIC_KLASS(iclass));
|
232
|
+
}
|
233
|
+
rb_clear_cache_by_class(mod);
|
234
|
+
}
|
235
|
+
|
236
|
+
/* Ruby methods */
|
237
|
+
|
238
|
+
/* call-seq:
|
239
|
+
* class=(klass) -> Object
|
240
|
+
*
|
241
|
+
* Modifies the receiver's class to be +klass+. The receiver's current class
|
242
|
+
* and any singleton class (and any modules that extend the object) are
|
243
|
+
* ignored. If the receiver is an immediate or instances of +klass+ don't use the
|
244
|
+
* same internal type as the receiver, a +TypeError+ is raised.
|
245
|
+
*/
|
246
|
+
static VALUE evilr_class_e(VALUE self, VALUE klass) {
|
247
|
+
evilr__check_immediate(self);
|
248
|
+
evilr__check_type(evilr__class_type(klass), self);
|
249
|
+
evilr__check_data_type(self);
|
250
|
+
|
251
|
+
RBASIC_SET_KLASS(self, klass);
|
252
|
+
return self;
|
253
|
+
}
|
254
|
+
|
255
|
+
/* call-seq:
|
256
|
+
* evilr_debug_print -> nil
|
257
|
+
*
|
258
|
+
* Prints to stdout the receiver and all entries in the receiver's klass's super chain,
|
259
|
+
* using the pointers of the current entry, it's klass, iv_tbl, m_tbl, and super entry,
|
260
|
+
* as well as the entry's flags. If Class or Module is given, uses their
|
261
|
+
* super chain, not the super chain of their klass. If the receiver is an immediate value,
|
262
|
+
* a +TypeError+ is raised. */
|
263
|
+
static VALUE evilr_debug_print(VALUE self) {
|
264
|
+
if (self == NULL) {
|
265
|
+
return Qnil;
|
266
|
+
}
|
267
|
+
evilr__check_immediate(self);
|
268
|
+
switch(BUILTIN_TYPE(self)) {
|
269
|
+
case T_CLASS:
|
270
|
+
case T_ICLASS:
|
271
|
+
case T_MODULE:
|
272
|
+
printf("self %p klass %p flags 0x%lx iv_tbl %p m_tbl %p super %p\n", (void *)self, (void *)RBASIC_KLASS(self), RBASIC_FLAGS(self), (void *)RCLASS_IV_TBL(self), (void *)RCLASS_M_TBL(self), (void *)RCLASS_SUPER(self));
|
273
|
+
self = RCLASS_SUPER(self);
|
274
|
+
break;
|
275
|
+
default:
|
276
|
+
printf("self %p klass %p flags 0x%lx iv_tbl/ptr %p\n", (void *)self, (void *)RBASIC_KLASS(self), RBASIC_FLAGS(self), (void *)ROBJECT_IVPTR(self));
|
277
|
+
self = RBASIC_KLASS(self);
|
278
|
+
break;
|
279
|
+
}
|
280
|
+
return evilr_debug_print(self);
|
281
|
+
}
|
282
|
+
|
283
|
+
|
284
|
+
/* call-seq:
|
285
|
+
* swap(other) -> self
|
286
|
+
*
|
287
|
+
* Swap the contents of the receiver with +other+:
|
288
|
+
*
|
289
|
+
* a = []
|
290
|
+
* b = {}
|
291
|
+
* a.swap(b) # => {}
|
292
|
+
* a # => {}
|
293
|
+
* b # => []
|
294
|
+
*
|
295
|
+
* You cannot swap a Class or Module except with another
|
296
|
+
* Class or Module, and you can only swap a Class with a Class and
|
297
|
+
* a Module with a Module (no swapping a Class with Module), and you
|
298
|
+
* cannot swap immediate values. If an invalid swap attempt is
|
299
|
+
* detected, a +TypeError+ is raised.*/
|
300
|
+
static VALUE evilr_swap(VALUE self, VALUE other) {
|
301
|
+
char tmp[OBJECT_SIZE];
|
302
|
+
evilr__check_immediates(self, other);
|
303
|
+
if ((BUILTIN_TYPE(self) == T_MODULE || BUILTIN_TYPE(self) == T_CLASS ||
|
304
|
+
BUILTIN_TYPE(other) == T_MODULE || BUILTIN_TYPE(other) == T_CLASS) &&
|
305
|
+
BUILTIN_TYPE(self) != BUILTIN_TYPE(other)) {
|
306
|
+
rb_raise(rb_eTypeError, "incompatible types used");
|
307
|
+
}
|
308
|
+
memcpy(tmp, ROBJECT(self), OBJECT_SIZE);
|
309
|
+
memcpy(ROBJECT(self), ROBJECT(other), OBJECT_SIZE);
|
310
|
+
memcpy(ROBJECT(other), tmp, OBJECT_SIZE);
|
311
|
+
return self;
|
312
|
+
}
|
313
|
+
|
314
|
+
/* call-seq:
|
315
|
+
* swap_instance_variables(other) -> self
|
316
|
+
*
|
317
|
+
* Swaps only the instance variables of the receiver and +other+.
|
318
|
+
* You can only swap the instance variables between two objects that
|
319
|
+
* use the internal type number T_OBJECT, or between Classes and Modules.
|
320
|
+
* You cannot swap instance variables of immediate values, since they
|
321
|
+
* do not have instance variables. Invalid swap attempts will raise
|
322
|
+
* +TypeError+. */
|
323
|
+
static VALUE evilr_swap_instance_variables(VALUE self, VALUE other) {
|
324
|
+
#ifndef RUBY19
|
325
|
+
struct st_table *tmp;
|
326
|
+
#endif
|
327
|
+
evilr__check_immediates(self, other);
|
328
|
+
|
329
|
+
switch(BUILTIN_TYPE(self)) {
|
330
|
+
case T_OBJECT:
|
331
|
+
if (BUILTIN_TYPE(other) != T_OBJECT) {
|
332
|
+
goto bad_types;
|
333
|
+
}
|
334
|
+
break;
|
335
|
+
case T_MODULE:
|
336
|
+
case T_CLASS:
|
337
|
+
if (BUILTIN_TYPE(other) != T_MODULE && BUILTIN_TYPE(other) != T_CLASS) {
|
338
|
+
goto bad_types;
|
339
|
+
}
|
340
|
+
break;
|
341
|
+
default:
|
342
|
+
bad_types:
|
343
|
+
rb_raise(rb_eTypeError, "incompatible types used");
|
344
|
+
}
|
345
|
+
|
346
|
+
#ifdef RUBY19
|
347
|
+
if (BUILTIN_TYPE(self) == T_MODULE || BUILTIN_TYPE(self) == T_CLASS) {
|
348
|
+
struct st_table *tmp;
|
349
|
+
tmp = RCLASS_IV_TBL(self);
|
350
|
+
RCLASS(self)->ptr->iv_tbl = RCLASS_IV_TBL(other);
|
351
|
+
RCLASS(other)->ptr->iv_tbl = tmp;
|
352
|
+
} else {
|
353
|
+
char tmp[OBJECT_SIZE];
|
354
|
+
memcpy(tmp, &(ROBJECT(self)->as), sizeof(ROBJECT(tmp)->as));
|
355
|
+
memcpy(&(ROBJECT(self)->as), &(ROBJECT(other)->as), sizeof(ROBJECT(self)->as));
|
356
|
+
memcpy(&(ROBJECT(other)->as), tmp, sizeof(ROBJECT(other)->as));
|
357
|
+
}
|
358
|
+
#else
|
359
|
+
/* RClass and RObject have iv_tbl at same position in the structure
|
360
|
+
* so no funny business is needed */
|
361
|
+
tmp = ROBJECT_IVPTR(self);
|
362
|
+
ROBJECT(self)->iv_tbl = ROBJECT_IVPTR(other);
|
363
|
+
ROBJECT(other)->iv_tbl = tmp;
|
364
|
+
#endif
|
365
|
+
return self;
|
366
|
+
}
|
367
|
+
|
368
|
+
/* call-seq:
|
369
|
+
* swap_method_tables(other) -> self
|
370
|
+
*
|
371
|
+
* Swap the method table of the receiver with the method table of the given
|
372
|
+
* class or module. If +other+ is not a class or module, raise a +TypeError+. */
|
373
|
+
static VALUE evilr_swap_method_tables(VALUE self, VALUE other) {
|
374
|
+
struct st_table *tmp;
|
375
|
+
|
376
|
+
evilr__check_immediate(other);
|
377
|
+
if(BUILTIN_TYPE(other) != T_MODULE && BUILTIN_TYPE(other) != T_CLASS) {
|
378
|
+
rb_raise(rb_eTypeError, "non-class or module used");
|
379
|
+
}
|
380
|
+
|
381
|
+
tmp = RCLASS_M_TBL(self);
|
382
|
+
RCLASS(self)->m_tbl = RCLASS_M_TBL(other);
|
383
|
+
RCLASS(other)->m_tbl = tmp;
|
384
|
+
rb_clear_cache_by_class(self);
|
385
|
+
rb_clear_cache_by_class(other);
|
386
|
+
return self;
|
387
|
+
}
|
388
|
+
|
389
|
+
/* call-seq:
|
390
|
+
* swap_singleton_class(other) -> self
|
391
|
+
*
|
392
|
+
* Swap the singleton classes of the receiver and +other+. If either
|
393
|
+
* the receiver or +other+ is an immediate, a +TypeError+ is raised.
|
394
|
+
* If either object does not have a singleton class, an empty singleton
|
395
|
+
* class is created for it before swapping. Any modules that extend
|
396
|
+
* either object are swapped as well.
|
397
|
+
* */
|
398
|
+
static VALUE evilr_swap_singleton_class(VALUE self, VALUE other) {
|
399
|
+
VALUE tmp;
|
400
|
+
|
401
|
+
evilr__check_immediates(self, other);
|
402
|
+
|
403
|
+
/* Create singleton classes to be swapped if they doesn't exist */
|
404
|
+
(void)rb_singleton_class(other);
|
405
|
+
(void)rb_singleton_class(self);
|
406
|
+
|
407
|
+
tmp = rb_obj_class(other);
|
408
|
+
evilr__reparent_singleton_class(other, rb_obj_class(self));
|
409
|
+
evilr__reparent_singleton_class(self, tmp);
|
410
|
+
|
411
|
+
tmp = RBASIC_KLASS(self);
|
412
|
+
RBASIC_SET_KLASS(self, RBASIC_KLASS(other));
|
413
|
+
RBASIC_SET_KLASS(other, tmp);
|
414
|
+
|
415
|
+
/* Attach each singleton class to its object */
|
416
|
+
rb_singleton_class_attached(RBASIC_KLASS(self), self);
|
417
|
+
rb_singleton_class_attached(RBASIC_KLASS(other), other);
|
418
|
+
|
419
|
+
return self;
|
420
|
+
}
|
421
|
+
|
422
|
+
/* call-seq:
|
423
|
+
* unfreeze -> self
|
424
|
+
*
|
425
|
+
* Unfreezes the given object. Will raise a +SecurityError+ if
|
426
|
+
* <tt>$SAFE</tt> > 0. Has no effect if the object is not yet frozen. */
|
427
|
+
static VALUE evilr_unfreeze(VALUE self) {
|
428
|
+
if (rb_safe_level() > 0) {
|
429
|
+
rb_raise(rb_eSecurityError, "can't unfreeze objects when $SAFE > 0");
|
430
|
+
}
|
431
|
+
FL_UNSET(self, FL_FREEZE);
|
432
|
+
return self;
|
433
|
+
}
|
434
|
+
|
435
|
+
/* call-seq:
|
436
|
+
* set_safe_level=(int) -> int
|
437
|
+
*
|
438
|
+
* Sets the <tt>$SAFE</tt> level to the given integer. If the number is
|
439
|
+
* greater than 4, sets it to 4. Allows lowering the <tt>$SAFE</tt> level
|
440
|
+
* by passing an integer lower than the current level. Returns the value
|
441
|
+
* passed in. */
|
442
|
+
static VALUE evilr_set_safe_level(VALUE self, VALUE safe) {
|
443
|
+
int s = NUM2INT(safe);
|
444
|
+
if (s > SAFE_LEVEL_MAX) {
|
445
|
+
s = SAFE_LEVEL_MAX;
|
446
|
+
}
|
447
|
+
#ifdef RUBY19
|
448
|
+
rb_set_safe_level_force(s);
|
449
|
+
#else
|
450
|
+
ruby_safe_level = s;
|
451
|
+
#endif
|
452
|
+
return safe;
|
453
|
+
}
|
454
|
+
|
455
|
+
/* call-seq:
|
456
|
+
* uninclude(mod) -> mod || nil
|
457
|
+
*
|
458
|
+
* Unincludes the given module +mod+ from the receiver or any of the receiver's
|
459
|
+
* ancestors. Walks the super chain of the receiver, and if an iclass for +mod+ is
|
460
|
+
* encountered, the super chain is modified to skip that iclass. Returns +mod+ if
|
461
|
+
* an iclass for mod was present in the super chain, and +nil+ otherwise. If +mod+ is
|
462
|
+
* not a Module, a +TypeError+ is raised. */
|
463
|
+
static VALUE evilr_uninclude(VALUE klass, VALUE mod) {
|
464
|
+
VALUE cur, prev;
|
465
|
+
|
466
|
+
evilr__check_immediate(mod);
|
467
|
+
evilr__check_type(T_MODULE, mod);
|
468
|
+
|
469
|
+
for (prev = klass, cur = RCLASS_SUPER(klass); cur ; prev = cur, cur = RCLASS_SUPER(cur)) {
|
470
|
+
if (BUILTIN_TYPE(prev) == T_CLASS) {
|
471
|
+
rb_clear_cache_by_class(prev);
|
472
|
+
}
|
473
|
+
if (BUILTIN_TYPE(cur) == T_ICLASS && RBASIC_KLASS(cur) == mod) {
|
474
|
+
RCLASS_SET_SUPER(prev, RCLASS_SUPER(cur));
|
475
|
+
return mod;
|
476
|
+
}
|
477
|
+
}
|
478
|
+
|
479
|
+
return Qnil;
|
480
|
+
}
|
481
|
+
|
482
|
+
/* call-seq:
|
483
|
+
* unextend(mod) -> mod || nil
|
484
|
+
*
|
485
|
+
* Unextends the given module +mod+ from the receiver. If the receiver's class includes the
|
486
|
+
* module, does not uninclude it, so this should not affect any other objects besides the
|
487
|
+
* receiver. If +mod+ already extended the object, returns +mod+, otherwise returns +nil+.
|
488
|
+
* Raises +TypeError+ if +mod+ is not a Module or if the receiver is an immediate. */
|
489
|
+
static VALUE evilr_unextend(VALUE self, VALUE mod) {
|
490
|
+
VALUE prev, cur;
|
491
|
+
|
492
|
+
evilr__check_immediates(self, mod);
|
493
|
+
evilr__check_type(T_MODULE, mod);
|
494
|
+
|
495
|
+
self = rb_singleton_class(self);
|
496
|
+
rb_clear_cache_by_class(self);
|
497
|
+
for (prev = self, cur = RCLASS_SUPER(self); cur && BUILTIN_TYPE(cur) != T_CLASS; prev = cur, cur = RCLASS_SUPER(cur)) {
|
498
|
+
if (BUILTIN_TYPE(cur) == T_ICLASS && RBASIC_KLASS(cur) == mod) {
|
499
|
+
RCLASS_SET_SUPER(prev, RCLASS_SUPER(cur));
|
500
|
+
return mod;
|
501
|
+
}
|
502
|
+
}
|
503
|
+
|
504
|
+
return Qnil;
|
505
|
+
}
|
506
|
+
|
507
|
+
#define INCLUDE_BETWEEN_VAL(x) (x) ? (BUILTIN_TYPE(x) == T_ICLASS ? RBASIC_KLASS(x) : (x)) : Qnil
|
508
|
+
/* call-seq:
|
509
|
+
* include_between(mod){|p, c| } -> mod || nil
|
510
|
+
*
|
511
|
+
* Walks the receiver's super chain, yielding the previous and current entries in
|
512
|
+
* the super chain at every step. The first time the block returns +true+, +mod+ is
|
513
|
+
* inserted into the super chain between the two values, and the method returns
|
514
|
+
* immediately. Raises +TypeError+ if +mod+ is not a Module.
|
515
|
+
* If the block ever returns +true+, the return value is +mod+. If
|
516
|
+
* the block never returns +true+, the return value is +nil+. On the first block call,
|
517
|
+
* the first block argument is the receiver, and on the last block call, the last block
|
518
|
+
* argument is +nil+. */
|
519
|
+
static VALUE evilr_include_between(VALUE klass, VALUE mod) {
|
520
|
+
VALUE iclass, prev, cur;
|
521
|
+
|
522
|
+
evilr__check_immediate(mod);
|
523
|
+
evilr__check_type(T_MODULE, mod);
|
524
|
+
|
525
|
+
/* Create ICLASS for module by inserting it and removing it.
|
526
|
+
* If module already in super chain, will change it's position. */
|
527
|
+
rb_include_module(klass, mod);
|
528
|
+
iclass = evilr__iclass_matching(klass, mod);
|
529
|
+
evilr_uninclude(klass, mod);
|
530
|
+
|
531
|
+
for (prev = klass, cur = RCLASS_SUPER(klass); prev ; prev = cur, cur = cur ? RCLASS_SUPER(cur) : cur) {
|
532
|
+
if (BUILTIN_TYPE(prev) == T_CLASS) {
|
533
|
+
rb_clear_cache_by_class(prev);
|
534
|
+
}
|
535
|
+
if (rb_yield_values(2, INCLUDE_BETWEEN_VAL(prev), INCLUDE_BETWEEN_VAL(cur)) == Qtrue) {
|
536
|
+
RCLASS_SET_SUPER(prev, iclass);
|
537
|
+
RCLASS_SET_SUPER(iclass, cur);
|
538
|
+
return mod;
|
539
|
+
}
|
540
|
+
}
|
541
|
+
return Qnil;
|
542
|
+
}
|
543
|
+
|
544
|
+
/* call-seq:
|
545
|
+
* extend_between(mod){|p, c| } -> mod || nil
|
546
|
+
*
|
547
|
+
* Walks the receiver's singleton class's super chain until it reaches the receiver's
|
548
|
+
* class, yielding the previous and current entries in the super chain at every step.
|
549
|
+
* The first time the block returns +true+, +mod+ is inserted into the super chain
|
550
|
+
* between the two values and the method returns immediately. Raises +TypeError+ if
|
551
|
+
* +mod+ is not a Module or if the receiver is an immediate.
|
552
|
+
* If the block ever returns +true+, the return value is
|
553
|
+
* +mod+. If the block never returns +true+, the return value is +nil+. On the first block call,
|
554
|
+
* the first block argument is the receiver's singleton class, and on the last block call,
|
555
|
+
* the last block argument is the receiver's class. */
|
556
|
+
static VALUE evilr_extend_between(VALUE self, VALUE mod) {
|
557
|
+
VALUE sc, iclass, klass, prev, cur;
|
558
|
+
|
559
|
+
evilr__check_immediates(self, mod);
|
560
|
+
evilr__check_type(T_MODULE, mod);
|
561
|
+
|
562
|
+
sc = rb_singleton_class(self);
|
563
|
+
klass = rb_obj_class(self);
|
564
|
+
rb_extend_object(self, mod);
|
565
|
+
iclass = evilr__iclass_matching_before(sc, mod, klass);
|
566
|
+
if (iclass == NULL) {
|
567
|
+
rb_raise(rb_eArgError, "module already included in object's class");
|
568
|
+
}
|
569
|
+
evilr_unextend(self, mod);
|
570
|
+
|
571
|
+
for (prev = sc, cur = RCLASS_SUPER(sc); prev && prev != klass; prev = cur, cur = cur ? RCLASS_SUPER(cur) : cur) {
|
572
|
+
if (rb_yield_values(2, INCLUDE_BETWEEN_VAL(prev), INCLUDE_BETWEEN_VAL(cur)) == Qtrue) {
|
573
|
+
RCLASS_SET_SUPER(prev, iclass);
|
574
|
+
RCLASS_SET_SUPER(iclass, cur);
|
575
|
+
return mod;
|
576
|
+
}
|
577
|
+
}
|
578
|
+
return Qnil;
|
579
|
+
}
|
580
|
+
|
581
|
+
/* call-seq:
|
582
|
+
* detach_singleton -> self
|
583
|
+
*
|
584
|
+
* If the receiver is a singleton class, it is transformed into a
|
585
|
+
* regular class and it is detached from the instance. Note that
|
586
|
+
* this means it becomes the class of the object to which it was previous
|
587
|
+
* attached. If the receiver is not a singleton class, has no effect.
|
588
|
+
* Returns the receiver. */
|
589
|
+
static VALUE evilr_detach_singleton(VALUE klass) {
|
590
|
+
if (IS_SINGLETON_CLASS(klass)) {
|
591
|
+
FL_UNSET(klass, FL_SINGLETON);
|
592
|
+
if (RCLASS_IV_TBL(klass)) {
|
593
|
+
st_delete(RCLASS_IV_TBL(klass), (st_data_t*)&evilr__attached, 0);
|
594
|
+
}
|
595
|
+
}
|
596
|
+
return klass;
|
597
|
+
}
|
598
|
+
|
599
|
+
/* call-seq:
|
600
|
+
* detach_singleton_class -> Class
|
601
|
+
*
|
602
|
+
* If the receiver has a singleton class, it is detached from the
|
603
|
+
* receiver and becomes the receiver's class. If the receiver is
|
604
|
+
* an immediate, a +TypeError+ is raised. Returns the (possibly new) class
|
605
|
+
* of the receiver. */
|
606
|
+
static VALUE evilr_detach_singleton_class(VALUE self) {
|
607
|
+
evilr__check_immediate(self);
|
608
|
+
return evilr_detach_singleton(RBASIC_KLASS(self));
|
609
|
+
}
|
610
|
+
|
611
|
+
/* call-seq:
|
612
|
+
* dup_singleton_class(klass=Object) -> Class || nil
|
613
|
+
*
|
614
|
+
* If the receiver has a singleton class, a copy of the class is returned,
|
615
|
+
* and the superclass of that class is set to the given +klass+. Any
|
616
|
+
* modules that extend the object become modules included in the returned class.
|
617
|
+
* If the receiver does not have a singleton class, +nil+ is returned and no
|
618
|
+
* changes are made. If the receiver is an immediate, a +TypeError+ is raised. */
|
619
|
+
static VALUE evilr_dup_singleton_class(int argc, VALUE *argv, VALUE self) {
|
620
|
+
VALUE klass;
|
621
|
+
evilr__check_immediate(self);
|
622
|
+
|
623
|
+
if (!HAS_SINGLETON_CLASS(self)) {
|
624
|
+
return Qnil;
|
625
|
+
}
|
626
|
+
klass = evilr__optional_class(argc, argv);
|
627
|
+
self = rb_singleton_class_clone(self);
|
628
|
+
evilr__reparent_class(self, klass);
|
629
|
+
FL_UNSET(self, FL_SINGLETON);
|
630
|
+
return self;
|
631
|
+
}
|
632
|
+
|
633
|
+
/* call-seq:
|
634
|
+
* push_singleton_class(klass) -> klass
|
635
|
+
*
|
636
|
+
* Makes the given class the closest singleton class of the receiver, without changing any
|
637
|
+
* existing singleton class relationships. Designed to be used with +pop_singleton_class+
|
638
|
+
* to implement a method table stack on an object. If the receiver is an immediate or
|
639
|
+
* +klass+ is not a class, raises +TypeError+. */
|
640
|
+
static VALUE evilr_push_singleton_class(VALUE self, VALUE klass) {
|
641
|
+
evilr__check_obj_and_class(self, klass);
|
642
|
+
evilr__reparent_class(evilr__iclass_before_next_class(klass), RBASIC_KLASS(self));
|
643
|
+
evilr__make_singleton(self, klass);
|
644
|
+
return klass;
|
645
|
+
}
|
646
|
+
|
647
|
+
/* call-seq:
|
648
|
+
* pop_singleton_class -> Class || nil
|
649
|
+
*
|
650
|
+
* Removes the closest singleton class from the receiver and returns it.
|
651
|
+
* If the receiver does not have a singleton class, does nothing and returns +nil+.
|
652
|
+
* Designed to be used with +push_singleton_class+
|
653
|
+
* to implement a method table stack on an object. If the receiver is an immediate,
|
654
|
+
* raises +TypeError+. */
|
655
|
+
static VALUE evilr_pop_singleton_class(VALUE self) {
|
656
|
+
VALUE klass;
|
657
|
+
|
658
|
+
evilr__check_immediate(self);
|
659
|
+
klass = RBASIC_KLASS(self);
|
660
|
+
|
661
|
+
if (IS_SINGLETON_CLASS(klass)) {
|
662
|
+
RBASIC_SET_KLASS(self, evilr__next_class(klass));
|
663
|
+
} else {
|
664
|
+
klass = Qnil;
|
665
|
+
}
|
666
|
+
return klass;
|
667
|
+
}
|
668
|
+
|
669
|
+
/* call-seq:
|
670
|
+
* remove_singleton_classes -> nil
|
671
|
+
*
|
672
|
+
* Removes all singleton classes from the receiver. Designed to be used with
|
673
|
+
* +push_singleton_class+ and +pop_singleton_class+ to implement a method table
|
674
|
+
* stack on an object, this clears the stack. If the receiver is an immediate,
|
675
|
+
* raises +TypeError+. */
|
676
|
+
static VALUE evilr_remove_singleton_classes(VALUE self) {
|
677
|
+
evilr__check_immediate(self);
|
678
|
+
RBASIC_SET_KLASS(self, rb_obj_class(self));
|
679
|
+
return Qnil;
|
680
|
+
}
|
681
|
+
|
682
|
+
/* call-seq:
|
683
|
+
* set_singleton_class(klass) -> klass
|
684
|
+
*
|
685
|
+
* Makes the given +klass+ the singleton class of the receiver,
|
686
|
+
* ignoring any existing singleton class and modules extending the receiver.
|
687
|
+
* Modules already included in +klass+ become modules that extend the receiver.
|
688
|
+
* If the receiver is an immediate or +klass+ is not a Class,
|
689
|
+
* raises +TypeError+. */
|
690
|
+
static VALUE evilr_set_singleton_class(VALUE self, VALUE klass) {
|
691
|
+
evilr__check_obj_and_class(self, klass);
|
692
|
+
RCLASS_SET_SUPER(evilr__iclass_before_next_class(klass), rb_obj_class(self));
|
693
|
+
rb_clear_cache_by_class(klass);
|
694
|
+
evilr__make_singleton(self, klass);
|
695
|
+
return klass;
|
696
|
+
}
|
697
|
+
|
698
|
+
/* call-seq:
|
699
|
+
* remove_singleton_class -> klass || nil
|
700
|
+
*
|
701
|
+
* Removes the singleton class of the receiver, detaching it from the
|
702
|
+
* receiver and making it a regular class. If the receiver does not
|
703
|
+
* currently have a singleton class, returns +nil+. If the receiver is an
|
704
|
+
* immediate, raises +TypeError+. */
|
705
|
+
static VALUE evilr_remove_singleton_class(VALUE self) {
|
706
|
+
VALUE klass;
|
707
|
+
evilr__check_immediate(self);
|
708
|
+
|
709
|
+
if (HAS_SINGLETON_CLASS(self)) {
|
710
|
+
klass = evilr_detach_singleton_class(self);
|
711
|
+
RBASIC_SET_KLASS(self, evilr__next_class(klass));
|
712
|
+
} else {
|
713
|
+
klass = Qnil;
|
714
|
+
}
|
715
|
+
return klass;
|
716
|
+
}
|
717
|
+
|
718
|
+
/* call-seq:
|
719
|
+
* singleton_class_instance -> Object || nil
|
720
|
+
*
|
721
|
+
* Returns the object attached to the singleton class.
|
722
|
+
* If the class does not have an object attached to it (possibly because
|
723
|
+
* it isn't a singleton class), returns +nil+. */
|
724
|
+
static VALUE evilr_singleton_class_instance(VALUE klass) {
|
725
|
+
VALUE obj;
|
726
|
+
if(RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass), evilr__attached, &obj)) {
|
727
|
+
return obj;
|
728
|
+
}
|
729
|
+
return Qnil;
|
730
|
+
}
|
731
|
+
|
732
|
+
/* call-seq:
|
733
|
+
* to_module -> Module
|
734
|
+
*
|
735
|
+
* Makes a copy of the class, converts the copy to a module, and returns it. The
|
736
|
+
* returned module can be included in other classes. */
|
737
|
+
static VALUE evilr_to_module(VALUE klass) {
|
738
|
+
VALUE mod, iclass;
|
739
|
+
|
740
|
+
if (IS_SINGLETON_CLASS(klass)) {
|
741
|
+
if((mod = evilr_singleton_class_instance(klass))) {
|
742
|
+
mod = rb_singleton_class_clone(mod);
|
743
|
+
(void)evilr_detach_singleton(mod);
|
744
|
+
} else {
|
745
|
+
rb_raise(rb_eTypeError, "singleton class without attached instance");
|
746
|
+
}
|
747
|
+
} else {
|
748
|
+
mod = rb_obj_clone(klass);
|
749
|
+
}
|
750
|
+
|
751
|
+
RBASIC_SET_KLASS(mod, rb_cModule);
|
752
|
+
iclass = RCLASS_SUPER(mod);
|
753
|
+
RCLASS_SET_SUPER(mod, NULL);
|
754
|
+
FL_UNSET(mod, T_MASK);
|
755
|
+
FL_SET(mod, T_MODULE);
|
756
|
+
evilr__include_iclasses(mod, iclass);
|
757
|
+
|
758
|
+
return mod;
|
759
|
+
}
|
760
|
+
|
761
|
+
/* call-seq:
|
762
|
+
* to_class(klass=Object) -> Class
|
763
|
+
*
|
764
|
+
* Makes a copy of the module, converts the copy to a class, and returns it. The
|
765
|
+
* returned class can then have instances created from it. The +klass+ argument
|
766
|
+
* sets the superclass of the returned class. If +klass+ is not a Class,
|
767
|
+
* raises +TypeError+. */
|
768
|
+
static VALUE evilr_to_class(int argc, VALUE *argv, VALUE self) {
|
769
|
+
VALUE klass = evilr__optional_class(argc, argv);
|
770
|
+
|
771
|
+
self = rb_obj_clone(self);
|
772
|
+
RBASIC_SET_KLASS(self, rb_singleton_class(klass));
|
773
|
+
RCLASS_SET_SUPER(self, klass);
|
774
|
+
FL_UNSET(self, T_MASK);
|
775
|
+
FL_SET(self, T_CLASS);
|
776
|
+
return self;
|
777
|
+
}
|
778
|
+
|
779
|
+
/* call-seq:
|
780
|
+
* flags -> Integer
|
781
|
+
*
|
782
|
+
* Returns the internal flags value of the receiver as an +Integer+. Raises +TypeError+
|
783
|
+
* if the receiver is an immediate. */
|
784
|
+
static VALUE evilr_flags(VALUE self) {
|
785
|
+
evilr__check_immediate(self);
|
786
|
+
return UINT2NUM(RBASIC_FLAGS(self));
|
787
|
+
}
|
788
|
+
|
789
|
+
/* call-seq:
|
790
|
+
* superclass=(klass) -> klass
|
791
|
+
*
|
792
|
+
* Modifies the superclass of the current class to be the given
|
793
|
+
* class. Any modules included in the receiver remain included.
|
794
|
+
* Raises +TypeError+ if klass is not a Class or if the receiver
|
795
|
+
* and class are not compatible (where their instances use
|
796
|
+
* different internal types). */
|
797
|
+
static VALUE evilr_superclass_e(VALUE klass, VALUE super) {
|
798
|
+
VALUE iclass;
|
799
|
+
evilr__check_compatible_classes(klass, super);
|
800
|
+
iclass = evilr__iclass_before_next_class(klass);
|
801
|
+
RCLASS_SET_SUPER(iclass, super);
|
802
|
+
rb_clear_cache_by_class(klass);
|
803
|
+
return super;
|
804
|
+
}
|
805
|
+
|
806
|
+
/* call-seq:
|
807
|
+
* inherit(*classes) -> self
|
808
|
+
*
|
809
|
+
* Make copies of all given +classes+ as modules, and includes
|
810
|
+
* those modules in the receiver. Raises +TypeError+ if any of the
|
811
|
+
* +classes+ is not a Class or is not compatible with the receiver. */
|
812
|
+
static VALUE evilr_inherit(int argc, VALUE* argv, VALUE klass) {
|
813
|
+
int i;
|
814
|
+
|
815
|
+
for(i = 0; i < argc; i++) {
|
816
|
+
evilr__check_compatible_classes(klass, argv[i]);
|
817
|
+
rb_include_module(klass, evilr_to_module(argv[i]));
|
818
|
+
}
|
819
|
+
|
820
|
+
return klass;
|
821
|
+
}
|
822
|
+
|
823
|
+
/* call-seq:
|
824
|
+
* force_bind(object) -> Method
|
825
|
+
*
|
826
|
+
* Returns a +Method+ object bound to the given object. Doesn't
|
827
|
+
* check that the method is compatible with the object, unlike +bind+. */
|
828
|
+
static VALUE evilr_force_bind(VALUE self, VALUE obj) {
|
829
|
+
struct METHOD *data;
|
830
|
+
|
831
|
+
evilr__check_immediate(obj);
|
832
|
+
self = rb_funcall(self, evilr__clone, 0);
|
833
|
+
/* Data_Get_Struct seems to complain about types on 1.9,
|
834
|
+
* so skip the type check. */
|
835
|
+
data = (struct METHOD*)DATA_PTR(self);
|
836
|
+
data->rclass = CLASS_OF(obj);
|
837
|
+
return rb_funcall(self, evilr__bind, 1, obj);
|
838
|
+
}
|
839
|
+
|
840
|
+
/* call-seq:
|
841
|
+
* self -> Object
|
842
|
+
*
|
843
|
+
* Returns the self of the receiver, which is the default context
|
844
|
+
* used in evaluating the receiver. */
|
845
|
+
static VALUE evilr_self(VALUE self) {
|
846
|
+
struct BLOCK *data;
|
847
|
+
data = (struct BLOCK*)DATA_PTR(self);
|
848
|
+
return data->self;
|
849
|
+
}
|
850
|
+
|
851
|
+
/* call-seq:
|
852
|
+
* self=(object) -> object
|
853
|
+
*
|
854
|
+
* Sets the self of the receiver to the given object, modifying the
|
855
|
+
* used in evaluating the receiver. Example:
|
856
|
+
*
|
857
|
+
* p = Proc.new{self[:a]}
|
858
|
+
* h1 = {:a=>1}
|
859
|
+
* h2 = {:a=>2}
|
860
|
+
* p.self = h1
|
861
|
+
* p.call # => 1
|
862
|
+
* p.self = h2
|
863
|
+
* p.call # => 2
|
864
|
+
* */
|
865
|
+
static VALUE evilr_self_e(VALUE self, VALUE obj) {
|
866
|
+
struct BLOCK *data;
|
867
|
+
data = (struct BLOCK*)DATA_PTR(self);
|
868
|
+
data->self = obj;
|
869
|
+
return data->self;
|
870
|
+
}
|
871
|
+
|
872
|
+
/* call-seq:
|
873
|
+
* segfault
|
874
|
+
*
|
875
|
+
* Dereferences the NULL pointer, which should cause SIGSEGV
|
876
|
+
* (a segmentation fault), and the death of the process, though
|
877
|
+
* it could possibly be rescued. */
|
878
|
+
static VALUE evilr_segfault(VALUE self) {
|
879
|
+
self = *(char *)NULL;
|
880
|
+
return self;
|
881
|
+
}
|
882
|
+
|
883
|
+
/* call-seq:
|
884
|
+
* seppuku
|
885
|
+
*
|
886
|
+
* Kills the current process with SIGKILL, which should
|
887
|
+
* terminate the process immediately without any recovery possible. */
|
888
|
+
static VALUE evilr_seppuku(VALUE self) {
|
889
|
+
kill(getpid(), SIGKILL);
|
890
|
+
return self;
|
891
|
+
}
|
892
|
+
|
893
|
+
/* call-seq:
|
894
|
+
* allocate -> object
|
895
|
+
*
|
896
|
+
* Allocate memory for the new instance. Basically a copy of
|
897
|
+
* +rb_class_allocate_instance+. */
|
898
|
+
static VALUE evilr_empty_alloc(VALUE klass) {
|
899
|
+
NEWOBJ(obj, struct RObject);
|
900
|
+
OBJSETUP(obj, klass, T_OBJECT);
|
901
|
+
return (VALUE)obj;
|
902
|
+
}
|
903
|
+
|
904
|
+
/* call-seq:
|
905
|
+
* new(*args)-> object
|
906
|
+
*
|
907
|
+
* Allocates memory for the instance and then calls initialize
|
908
|
+
* on the object. */
|
909
|
+
static VALUE evilr_empty_new(int argc, VALUE* argv, VALUE klass) {
|
910
|
+
VALUE obj;
|
911
|
+
obj = evilr_empty_alloc(klass);
|
912
|
+
rb_obj_call_init(obj, argc, argv);
|
913
|
+
return obj;
|
914
|
+
}
|
915
|
+
|
916
|
+
/* call-seq:
|
917
|
+
* superclass -> Class || nil
|
918
|
+
*
|
919
|
+
* Returns the superclass of the class, or nil if current class is
|
920
|
+
* +Empty+. Basically a copy of the standard superclass method,
|
921
|
+
* without some checking. */
|
922
|
+
static VALUE evilr_empty_superclass(VALUE klass) {
|
923
|
+
return klass == empty ? Qnil : evilr__next_class(klass);
|
924
|
+
}
|
925
|
+
|
926
|
+
/* call-seq:
|
927
|
+
* initialize -> self
|
928
|
+
*
|
929
|
+
* Returns the receiver. */
|
930
|
+
static VALUE evilr_empty_initialize(VALUE self) {
|
931
|
+
return self;
|
932
|
+
}
|
933
|
+
|
934
|
+
/* Empty is an almost completely empty class, even more basic than
|
935
|
+
* BasicObject. It has no parent class, and only implements
|
936
|
+
* +allocate+, +new+, +initialize+, and +superclass+. All other
|
937
|
+
* behavior must be added by the user. Note that if you want to
|
938
|
+
* call a method defined in Object, Kernel, or BasicObject that
|
939
|
+
* isn't defined in Empty, you can use <tt>UndefinedMethod#force_bind</tt>,
|
940
|
+
* to do so:
|
941
|
+
*
|
942
|
+
* Object.instance_method(:puts).force_bind(Empty.new).call()
|
943
|
+
*/
|
944
|
+
void Init_evilr(void) {
|
945
|
+
empty = rb_define_class("Empty", rb_cObject);
|
946
|
+
rb_define_alloc_func(empty, evilr_empty_alloc);
|
947
|
+
rb_define_singleton_method(empty, "new", evilr_empty_new, -1);
|
948
|
+
rb_define_singleton_method(empty, "superclass", evilr_empty_superclass, 0);
|
949
|
+
rb_define_method(empty, "initialize", evilr_empty_initialize, 0);
|
950
|
+
RCLASS_SET_SUPER(empty, NULL);
|
951
|
+
rb_global_variable(&empty);
|
952
|
+
|
953
|
+
evilr__attached = rb_intern("__attached__");
|
954
|
+
evilr__bind = rb_intern("bind");
|
955
|
+
evilr__clone = rb_intern("clone");
|
956
|
+
|
957
|
+
rb_define_method(rb_cObject, "class=", evilr_class_e, 1);
|
958
|
+
rb_define_method(rb_cObject, "evilr_debug_print", evilr_debug_print, 0);
|
959
|
+
rb_define_method(rb_cObject, "extend_between", evilr_extend_between, 1);
|
960
|
+
rb_define_method(rb_cObject, "flags", evilr_flags, 0);
|
961
|
+
rb_define_method(rb_cObject, "detach_singleton_class", evilr_detach_singleton_class, 0);
|
962
|
+
rb_define_method(rb_cObject, "dup_singleton_class", evilr_dup_singleton_class, -1);
|
963
|
+
rb_define_method(rb_cObject, "pop_singleton_class", evilr_pop_singleton_class, 0);
|
964
|
+
rb_define_method(rb_cObject, "push_singleton_class", evilr_push_singleton_class, 1);
|
965
|
+
rb_define_method(rb_cObject, "remove_singleton_class", evilr_remove_singleton_class, 0);
|
966
|
+
rb_define_method(rb_cObject, "remove_singleton_classes", evilr_remove_singleton_classes, 0);
|
967
|
+
rb_define_method(rb_cObject, "set_singleton_class", evilr_set_singleton_class, 1);
|
968
|
+
rb_define_method(rb_cObject, "swap", evilr_swap, 1);
|
969
|
+
rb_define_method(rb_cObject, "swap_instance_variables", evilr_swap_instance_variables, 1);
|
970
|
+
rb_define_method(rb_cObject, "swap_singleton_class", evilr_swap_singleton_class, 1);
|
971
|
+
rb_define_method(rb_cObject, "unextend", evilr_unextend, 1);
|
972
|
+
rb_define_method(rb_cObject, "unfreeze", evilr_unfreeze, 0);
|
973
|
+
|
974
|
+
rb_define_method(rb_mKernel, "segfault", evilr_segfault, 0);
|
975
|
+
rb_define_method(rb_mKernel, "seppuku", evilr_seppuku, 0);
|
976
|
+
rb_define_method(rb_mKernel, "set_safe_level", evilr_set_safe_level, 1);
|
977
|
+
|
978
|
+
rb_define_method(rb_cModule, "include_between", evilr_include_between, 1);
|
979
|
+
rb_define_method(rb_cModule, "swap_method_tables", evilr_swap_method_tables, 1);
|
980
|
+
rb_define_method(rb_cModule, "to_class", evilr_to_class, -1);
|
981
|
+
rb_define_method(rb_cModule, "uninclude", evilr_uninclude, 1);
|
982
|
+
|
983
|
+
rb_define_method(rb_cClass, "detach_singleton", evilr_detach_singleton, 0);
|
984
|
+
rb_define_method(rb_cClass, "inherit", evilr_inherit, -1);
|
985
|
+
rb_define_method(rb_cClass, "singleton_class_instance", evilr_singleton_class_instance, 0);
|
986
|
+
rb_define_method(rb_cClass, "superclass=", evilr_superclass_e, 1);
|
987
|
+
rb_define_method(rb_cClass, "to_module", evilr_to_module, 0);
|
988
|
+
|
989
|
+
rb_define_method(rb_cUnboundMethod, "force_bind", evilr_force_bind, 1);
|
990
|
+
|
991
|
+
rb_define_method(rb_cProc, "self", evilr_self, 0);
|
992
|
+
rb_define_method(rb_cProc, "self=", evilr_self_e, 1);
|
993
|
+
}
|