mixico 0.1.1 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +22 -22
- data/README +179 -178
- data/ext/mixico/compat.h +22 -0
- data/ext/mixico/extconf.rb +6 -6
- data/ext/mixico/mixico.c +98 -106
- data/lib/mixico.rb +82 -0
- data/lib/mixico/version.rb +3 -0
- data/setup.rb +1585 -1585
- data/test/test.rb +34 -0
- metadata +20 -6
data/COPYING
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
Copyright (c) 2008 why the lucky stiff
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person
|
4
|
-
obtaining a copy of this software and associated documentation
|
5
|
-
files (the "Software"), to deal in the Software without restriction,
|
6
|
-
including without limitation the rights to use, copy, modify, merge,
|
7
|
-
publish, distribute, sublicense, and/or sell copies of the Software,
|
8
|
-
and to permit persons to whom the Software is furnished to do so,
|
9
|
-
subject to the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
15
|
-
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
16
|
-
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
17
|
-
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
18
|
-
SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
19
|
-
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
20
|
-
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
-
SOFTWARE.
|
1
|
+
Copyright (c) 2008 why the lucky stiff
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without restriction,
|
6
|
+
including without limitation the rights to use, copy, modify, merge,
|
7
|
+
publish, distribute, sublicense, and/or sell copies of the Software,
|
8
|
+
and to permit persons to whom the Software is furnished to do so,
|
9
|
+
subject to the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
15
|
+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
16
|
+
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
17
|
+
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
18
|
+
SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
19
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
20
|
+
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
data/README
CHANGED
@@ -1,178 +1,179 @@
|
|
1
|
-
% mixico %
|
2
|
-
disable and re-enable mixins for ruby.
|
3
|
-
|
4
|
-
% quick summary %
|
5
|
-
there's no way i'm keeping this short. i'm sorry, but you're going to
|
6
|
-
have to really read this once.
|
7
|
-
|
8
|
-
% installation %
|
9
|
-
with gem:
|
10
|
-
$ gem
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
$ ruby setup.rb
|
15
|
-
$ ruby setup.rb
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
this
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
H>
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
sylvain
|
83
|
-
sylvain
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
def
|
167
|
-
def
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
1
|
+
% mixico %
|
2
|
+
disable and re-enable mixins for ruby.
|
3
|
+
|
4
|
+
% quick summary %
|
5
|
+
there's no way i'm keeping this short. i'm sorry, but you're going to
|
6
|
+
have to really read this once.
|
7
|
+
|
8
|
+
% installation %
|
9
|
+
with gem:
|
10
|
+
$ gem install mixico -s http://gemcutter.org
|
11
|
+
|
12
|
+
without:
|
13
|
+
$ ruby setup.rb config
|
14
|
+
$ ruby setup.rb setup
|
15
|
+
$ sudo ruby setup.rb install
|
16
|
+
|
17
|
+
% source code %
|
18
|
+
mixico is written in c. it is very quick (basically atomic.)
|
19
|
+
|
20
|
+
it is released under an MIT license. see COPYING.
|
21
|
+
|
22
|
+
% the long of it %
|
23
|
+
this is just a small bit of code and it has yet to prove itself, but
|
24
|
+
i believe this discovery could spawn a small following. i assure you:
|
25
|
+
it is practical.
|
26
|
+
|
27
|
+
while mining through the ftp site of the recently departed guy decoux,
|
28
|
+
an exquisite french hacker, i read of a lost module for reparenting
|
29
|
+
modules in different directions. this 'prop' extension is most heavily
|
30
|
+
elucidated in a thread beginning with [ruby-talk:20293]. the extension
|
31
|
+
itself is vanished, so we are left with a sort example and a diagram.
|
32
|
+
|
33
|
+
the diagram appears in a reply to hal fulton (who asks where this
|
34
|
+
'insert' method is that guy is using between modules):
|
35
|
+
|
36
|
+
from [ruby-talk:20296]:
|
37
|
+
|
38
|
+
>>>>> "H" == Hal E Fulton <hal9000 / hypermetrics.com> writes:
|
39
|
+
|
40
|
+
H> What is "insert" anyway? Did you mean "include"
|
41
|
+
H> or did I miss something?
|
42
|
+
|
43
|
+
No, this not "include" but really "insert" (i.e. another way)
|
44
|
+
|
45
|
+
For 2 classes A < B you have
|
46
|
+
|
47
|
+
|
48
|
+
extend put the class here
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
v
|
53
|
+
meta-A <========= meta-B
|
54
|
+
^ ^
|
55
|
+
insert put | |
|
56
|
+
the class ====> | |
|
57
|
+
here | |
|
58
|
+
A <========= B
|
59
|
+
^
|
60
|
+
|
|
61
|
+
|
|
62
|
+
include put the class here
|
63
|
+
|
64
|
+
You have method specifics to the metaclass
|
65
|
+
|
66
|
+
even if we had the code for 'prop', we wouldn't be able to build
|
67
|
+
it. these messages date back to 25 aug 2001, when ruby 1.6.4 was
|
68
|
+
current.
|
69
|
+
|
70
|
+
i began trying to recreate this intriguing work by trying to get
|
71
|
+
guy's example code to work. while i've not yet completed that work,
|
72
|
+
i stumbled upon another idea.
|
73
|
+
|
74
|
+
when a module is mixed into an object, the module itself appears
|
75
|
+
to be in the inheritance chain (Module.ancestors):
|
76
|
+
|
77
|
+
module Mixin; end
|
78
|
+
|
79
|
+
class GuineaPig; end
|
80
|
+
|
81
|
+
sylvain = GuineaPig.new
|
82
|
+
sylvain.extend Mixin
|
83
|
+
class << sylvain
|
84
|
+
p ancestors
|
85
|
+
end
|
86
|
+
|
87
|
+
the printed list for test subject 'sylvain' is:
|
88
|
+
[Mixin, GuineaPig, Object, Kernel]
|
89
|
+
|
90
|
+
this means 'sylvain' will respond to methods in the Mixin module
|
91
|
+
first, then in the GuineaPig class and so on up. however, the
|
92
|
+
Mixin module isn't REALLY in the inheritance chain. ruby creates
|
93
|
+
an object of type T_ICLASS that is a proxy class. a symbolic link
|
94
|
+
to the Mixin module.
|
95
|
+
|
96
|
+
sylvain ==> #<Mixin> ==> GuineaPig ==> Object ==> Kernel
|
97
|
+
|
98
|
+
the #<Mixin> object is useless in actual Ruby. you can't print it out.
|
99
|
+
it doesn't have any methods. you can pass it around in a variable, but
|
100
|
+
that's it.
|
101
|
+
|
102
|
+
again, it's a symbolic link to the Mixin module and its superclass is
|
103
|
+
GuineaPig. one of these objects is created every time you mixin.
|
104
|
+
|
105
|
+
on to this:
|
106
|
+
|
107
|
+
require 'mixico'
|
108
|
+
|
109
|
+
so, mixico adds two methods: disable_mixin and enable_mixin.
|
110
|
+
|
111
|
+
class << sylvain
|
112
|
+
@m = disable_mixin Mixin
|
113
|
+
p ancestors
|
114
|
+
end
|
115
|
+
|
116
|
+
which prints: [GuineaPig, Object, Kernel]
|
117
|
+
|
118
|
+
class << sylvain
|
119
|
+
enable_mixin @m
|
120
|
+
p ancestors
|
121
|
+
end
|
122
|
+
|
123
|
+
which prints: [Mixin, GuineaPig, Object, Kernel]
|
124
|
+
|
125
|
+
% how is this practical? %
|
126
|
+
|
127
|
+
my immediate concern is to stop using instance_eval. i use it in
|
128
|
+
markaby a lot. and it gets used once in shoes.
|
129
|
+
|
130
|
+
instance_eval can help give you syntax like this:
|
131
|
+
|
132
|
+
Markaby.html do
|
133
|
+
head do
|
134
|
+
title "feral cat colonies worldwide"
|
135
|
+
meta :name => "ROBOTS", :content => "ALL"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
nice, readable tags, right?
|
140
|
+
|
141
|
+
it's nice because instance_eval redirects all your methods inside
|
142
|
+
the block to a specific object. the problem is that it alters `self`
|
143
|
+
and redirects instance and class variables as well.
|
144
|
+
|
145
|
+
if you've got an instance variable you want to use inside the block,
|
146
|
+
you need to save it in a local variable before entering the block.
|
147
|
+
same with `self`.
|
148
|
+
|
149
|
+
def to_html
|
150
|
+
obj = self
|
151
|
+
Markaby.html do
|
152
|
+
head do
|
153
|
+
title obj.friendly_title
|
154
|
+
meta :name => "ROBOTS", :content => "ALL"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
this is annoying to remember. it's often the source of bugs.
|
160
|
+
|
161
|
+
mixico, on the other hand, can be used to redirect the methods
|
162
|
+
without changing `self` and swallowing up the ivars.
|
163
|
+
|
164
|
+
module Mixin
|
165
|
+
def head ...
|
166
|
+
def title ...
|
167
|
+
def meta ...
|
168
|
+
end
|
169
|
+
|
170
|
+
we you enable the mixin with mixico, it'll send the methods through
|
171
|
+
the proxy class. and when you disable it, you're back to normal.
|
172
|
+
no sign of the mixin at all.
|
173
|
+
|
174
|
+
% maintenance %
|
175
|
+
Until _why might reappear someday, this project is maintained by Konstantin Haase (rkh).
|
176
|
+
konstantin.mailinglists <at> googlemail <dot> com
|
177
|
+
http://github.com/rkh/mixico
|
178
|
+
* updated for Ruby 1.9 by banisterfiend
|
179
|
+
http://github.com/banister
|
data/ext/mixico/compat.h
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
/* contains basic macros to facilitate ruby 1.8 and ruby 1.9 compatibility */
|
2
|
+
|
3
|
+
#ifndef GUARD_COMPAT_H
|
4
|
+
#define GUARD_COMPAT_H
|
5
|
+
|
6
|
+
#include <ruby.h>
|
7
|
+
|
8
|
+
/* macros for backwards compatibility with 1.8 */
|
9
|
+
#ifndef RUBY_19
|
10
|
+
# define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
|
11
|
+
# define RCLASS_SUPER(c) (RCLASS(c)->super)
|
12
|
+
# define RCLASS_IV_TBL(c) (RCLASS(c)->iv_tbl)
|
13
|
+
# define OBJ_UNTRUSTED OBJ_TAINTED
|
14
|
+
# define FALSE 0
|
15
|
+
# define TRUE 1
|
16
|
+
# include "st.h"
|
17
|
+
#endif
|
18
|
+
|
19
|
+
/* a useful macro. cannot use ordinary CLASS_OF as it does not return an lvalue */
|
20
|
+
#define KLASS_OF(c) (RBASIC(c)->klass)
|
21
|
+
|
22
|
+
#endif
|
data/ext/mixico/extconf.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require 'mkmf'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
create_makefile("mixico")
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
# 1.9 compatibility
|
4
|
+
$CFLAGS += " -DRUBY_19" if RUBY_VERSION =~ /1.9/
|
5
|
+
|
6
|
+
create_makefile("mixico")
|
data/ext/mixico/mixico.c
CHANGED
@@ -1,106 +1,98 @@
|
|
1
|
-
//
|
2
|
-
// mixico.c
|
3
|
-
// an extension for enabling and disabling mixins
|
4
|
-
//
|
5
|
-
// released under an MIT license
|
6
|
-
//
|
7
|
-
#include <ruby.h>
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
" ensure\n" \
|
100
|
-
" blk.mixout mod\n" \
|
101
|
-
" end\n" \
|
102
|
-
" end\n" \
|
103
|
-
" end\n" \
|
104
|
-
"end\n" \
|
105
|
-
);
|
106
|
-
}
|
1
|
+
//
|
2
|
+
// mixico.c
|
3
|
+
// an extension for enabling and disabling mixins
|
4
|
+
//
|
5
|
+
// released under an MIT license
|
6
|
+
//
|
7
|
+
#include <ruby.h>
|
8
|
+
#include "compat.h"
|
9
|
+
|
10
|
+
static VALUE mixin_eval, mixout_eval;
|
11
|
+
|
12
|
+
#ifdef RUBY_19
|
13
|
+
static VALUE
|
14
|
+
class_alloc(VALUE flags, VALUE klass)
|
15
|
+
{
|
16
|
+
rb_classext_t *ext = ALLOC(rb_classext_t);
|
17
|
+
NEWOBJ(obj, struct RClass);
|
18
|
+
OBJSETUP(obj, klass, flags);
|
19
|
+
obj->ptr = ext;
|
20
|
+
RCLASS_IV_TBL(obj) = 0;
|
21
|
+
RCLASS_M_TBL(obj) = 0;
|
22
|
+
RCLASS_SUPER(obj) = 0;
|
23
|
+
RCLASS_IV_INDEX_TBL(obj) = 0;
|
24
|
+
return (VALUE)obj;
|
25
|
+
}
|
26
|
+
#endif
|
27
|
+
|
28
|
+
static VALUE
|
29
|
+
rb_mod_disable_mixin(VALUE module, VALUE super)
|
30
|
+
{
|
31
|
+
VALUE p, kid;
|
32
|
+
|
33
|
+
Check_Type(super, T_MODULE);
|
34
|
+
for (kid = module, p = RCLASS_SUPER(module); p; kid = p, p = RCLASS_SUPER(p)) {
|
35
|
+
if (BUILTIN_TYPE(p) == T_ICLASS) {
|
36
|
+
if (KLASS_OF(p) == super) {
|
37
|
+
RCLASS_SUPER(kid) = RCLASS_SUPER(p);
|
38
|
+
rb_clear_cache_by_class(module);
|
39
|
+
return p;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
return Qnil;
|
45
|
+
}
|
46
|
+
|
47
|
+
static VALUE
|
48
|
+
rb_mod_enable_mixin(VALUE module, VALUE mixin)
|
49
|
+
{
|
50
|
+
VALUE p;
|
51
|
+
|
52
|
+
Check_Type(mixin, T_ICLASS);
|
53
|
+
Check_Type(KLASS_OF(mixin), T_MODULE);
|
54
|
+
for (p = module; p; p = RCLASS_SUPER(p)) {
|
55
|
+
if (RCLASS_SUPER(p) == RCLASS_SUPER(mixin)) {
|
56
|
+
RCLASS_SUPER(p) = mixin;
|
57
|
+
rb_clear_cache_by_class(module);
|
58
|
+
return KLASS_OF(mixin);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
return Qnil;
|
63
|
+
}
|
64
|
+
|
65
|
+
static VALUE
|
66
|
+
rb_mod_mixin_object(VALUE target, VALUE obj)
|
67
|
+
{
|
68
|
+
VALUE singleton = rb_singleton_class(obj);
|
69
|
+
|
70
|
+
#ifdef RUBY_19
|
71
|
+
VALUE iclass = class_alloc(T_ICLASS, rb_cClass);
|
72
|
+
#else
|
73
|
+
NEWOBJ(iclass, struct RClass);
|
74
|
+
OBJSETUP(iclass, rb_cClass, T_ICLASS);
|
75
|
+
#endif
|
76
|
+
Check_Type(target, T_MODULE);
|
77
|
+
if (!RCLASS_IV_TBL(obj))
|
78
|
+
RCLASS_IV_TBL(obj) = st_init_numtable();
|
79
|
+
|
80
|
+
RCLASS_IV_TBL(iclass) = RCLASS_IV_TBL(obj);
|
81
|
+
RCLASS_M_TBL(iclass) = RCLASS_M_TBL(singleton);
|
82
|
+
RCLASS_SUPER(iclass) = RCLASS_SUPER(target);
|
83
|
+
KLASS_OF(iclass) = singleton;
|
84
|
+
|
85
|
+
OBJ_INFECT(iclass, obj);
|
86
|
+
OBJ_INFECT(iclass, target);
|
87
|
+
RCLASS_SUPER(target) = (VALUE)iclass;
|
88
|
+
rb_clear_cache_by_class(target);
|
89
|
+
|
90
|
+
return Qnil;
|
91
|
+
}
|
92
|
+
|
93
|
+
void Init_mixico()
|
94
|
+
{
|
95
|
+
rb_define_method(rb_cModule, "disable_mixin", rb_mod_disable_mixin, 1);
|
96
|
+
rb_define_method(rb_cModule, "enable_mixin", rb_mod_enable_mixin, 1);
|
97
|
+
rb_define_method(rb_cModule, "mixin_an_object", rb_mod_mixin_object, 1);
|
98
|
+
}
|