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 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 sources -a http://gems.github.com
11
- $ sudo gem install rkh-mixico
12
-
13
- without:
14
- $ ruby setup.rb config
15
- $ ruby setup.rb setup
16
- $ sudo ruby setup.rb install
17
-
18
- % source code %
19
- mixico is written in c. it is very quick (basically atomic.)
20
-
21
- it is released under an MIT license. see COPYING.
22
-
23
- % the long of it %
24
- this is just a small bit of code and it has yet to prove itself, but
25
- i believe this discovery could spawn a small following. i assure you:
26
- it is practical.
27
-
28
- while mining through the ftp site of the recently departed guy decoux,
29
- an exquisite french hacker, i read of a lost module for reparenting
30
- modules in different directions. this 'prop' extension is most heavily
31
- elucidated in a thread beginning with [ruby-talk:20293]. the extension
32
- itself is vanished, so we are left with a sort example and a diagram.
33
-
34
- the diagram appears in a reply to hal fulton (who asks where this
35
- 'insert' method is that guy is using between modules):
36
-
37
- from [ruby-talk:20296]:
38
-
39
- >>>>> "H" == Hal E Fulton <hal9000 / hypermetrics.com> writes:
40
-
41
- H> What is "insert" anyway? Did you mean "include"
42
- H> or did I miss something?
43
-
44
- No, this not "include" but really "insert" (i.e. another way)
45
-
46
- For 2 classes A < B you have
47
-
48
-
49
- extend put the class here
50
- |
51
- |
52
- |
53
- v
54
- meta-A <========= meta-B
55
- ^ ^
56
- insert put | |
57
- the class ====> | |
58
- here | |
59
- A <========= B
60
- ^
61
- |
62
- |
63
- include put the class here
64
-
65
- You have method specifics to the metaclass
66
-
67
- even if we had the code for 'prop', we wouldn't be able to build
68
- it. these messages date back to 25 aug 2001, when ruby 1.6.4 was
69
- current.
70
-
71
- i began trying to recreate this intriguing work by trying to get
72
- guy's example code to work. while i've not yet completed that work,
73
- i stumbled upon another idea.
74
-
75
- when a module is mixed into an object, the module itself appears
76
- to be in the inheritance chain (Module.ancestors):
77
-
78
- module Mixin; end
79
-
80
- class GuineaPig; end
81
-
82
- sylvain = GuineaPig.new
83
- sylvain.extend Mixin
84
- class << sylvain
85
- p ancestors
86
- end
87
-
88
- the printed list for test subject 'sylvain' is:
89
- [Mixin, GuineaPig, Object, Kernel]
90
-
91
- this means 'sylvain' will respond to methods in the Mixin module
92
- first, then in the GuineaPig class and so on up. however, the
93
- Mixin module isn't REALLY in the inheritance chain. ruby creates
94
- an object of type T_ICLASS that is a proxy class. a symbolic link
95
- to the Mixin module.
96
-
97
- sylvain ==> #<Mixin> ==> GuineaPig ==> Object ==> Kernel
98
-
99
- the #<Mixin> object is useless in actual Ruby. you can't print it out.
100
- it doesn't have any methods. you can pass it around in a variable, but
101
- that's it.
102
-
103
- again, it's a symbolic link to the Mixin module and its superclass is
104
- GuineaPig. one of these objects is created every time you mixin.
105
-
106
- on to this:
107
-
108
- require 'mixico'
109
-
110
- so, mixico adds two methods: disable_mixin and enable_mixin.
111
-
112
- class << sylvain
113
- @m = disable_mixin Mixin
114
- p ancestors
115
- end
116
-
117
- which prints: [GuineaPig, Object, Kernel]
118
-
119
- class << sylvain
120
- enable_mixin @m
121
- p ancestors
122
- end
123
-
124
- which prints: [Mixin, GuineaPig, Object, Kernel]
125
-
126
- % how is this practical? %
127
-
128
- my immediate concern is to stop using instance_eval. i use it in
129
- markaby a lot. and it gets used once in shoes.
130
-
131
- instance_eval can help give you syntax like this:
132
-
133
- Markaby.html do
134
- head do
135
- title "feral cat colonies worldwide"
136
- meta :name => "ROBOTS", :content => "ALL"
137
- end
138
- end
139
-
140
- nice, readable tags, right?
141
-
142
- it's nice because instance_eval redirects all your methods inside
143
- the block to a specific object. the problem is that it alters `self`
144
- and redirects instance and class variables as well.
145
-
146
- if you've got an instance variable you want to use inside the block,
147
- you need to save it in a local variable before entering the block.
148
- same with `self`.
149
-
150
- def to_html
151
- obj = self
152
- Markaby.html do
153
- head do
154
- title obj.friendly_title
155
- meta :name => "ROBOTS", :content => "ALL"
156
- end
157
- end
158
- end
159
-
160
- this is annoying to remember. it's often the source of bugs.
161
-
162
- mixico, on the other hand, can be used to redirect the methods
163
- without changing `self` and swallowing up the ivars.
164
-
165
- module Mixin
166
- def head ...
167
- def title ...
168
- def meta ...
169
- end
170
-
171
- we you enable the mixin with mixico, it'll send the methods through
172
- the proxy class. and when you disable it, you're back to normal.
173
- no sign of the mixin at all.
174
-
175
- % maintenance %
176
- Until _why might reappear someday, this project is maintained by Konstantin Haase (rkh).
177
- konstantin.mailinglists <at> googlemail <dot> com
178
- http://github.com/rkh/mixico
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
@@ -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
@@ -1,6 +1,6 @@
1
- require 'mkmf'
2
-
3
- dir_config("mixico")
4
- have_library("c", "main")
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")
@@ -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
- static VALUE mixin_eval, mixout_eval;
10
-
11
- static VALUE
12
- rb_mod_disable_mixin(VALUE module, VALUE super)
13
- {
14
- VALUE p, kid;
15
-
16
- Check_Type(super, T_MODULE);
17
- for (kid = module, p = RCLASS(module)->super; p; kid = p, p = RCLASS(p)->super) {
18
- if (BUILTIN_TYPE(p) == T_ICLASS) {
19
- if (RBASIC(p)->klass == super) {
20
- RCLASS(kid)->super = RCLASS(p)->super;
21
- rb_clear_cache_by_class(module);
22
- return p;
23
- }
24
- }
25
- }
26
-
27
- return Qnil;
28
- }
29
-
30
- static VALUE
31
- rb_mod_enable_mixin(VALUE module, VALUE mixin)
32
- {
33
- VALUE p;
34
-
35
- Check_Type(mixin, T_ICLASS);
36
- Check_Type(RBASIC(mixin)->klass, T_MODULE);
37
- for (p = module; p; p = RCLASS(p)->super) {
38
- if (RCLASS(p)->super == RCLASS(mixin)->super) {
39
- RCLASS(p)->super = mixin;
40
- rb_clear_cache_by_class(module);
41
- return RBASIC(mixin)->klass;
42
- }
43
- }
44
-
45
- return Qnil;
46
- }
47
-
48
- static VALUE
49
- rb_mod_mixin_object(VALUE target, VALUE obj)
50
- {
51
- VALUE singleton = rb_singleton_class(obj);
52
- NEWOBJ(iclass, struct RClass);
53
- OBJSETUP(iclass, rb_cClass, T_ICLASS);
54
-
55
- Check_Type(target, T_MODULE);
56
- if (!ROBJECT(obj)->iv_tbl)
57
- ROBJECT(obj)->iv_tbl = st_init_numtable();
58
-
59
- iclass->iv_tbl = ROBJECT(obj)->iv_tbl;
60
- iclass->m_tbl = RCLASS(singleton)->m_tbl;
61
- iclass->super = RCLASS(target)->super;
62
- RBASIC(iclass)->klass = singleton;
63
-
64
- OBJ_INFECT(iclass, obj);
65
- OBJ_INFECT(iclass, target);
66
- RCLASS(target)->super = iclass;
67
- rb_clear_cache_by_class(target);
68
-
69
- return Qnil;
70
- }
71
-
72
- void Init_mixico()
73
- {
74
- rb_define_method(rb_cModule, "disable_mixin", rb_mod_disable_mixin, 1);
75
- rb_define_method(rb_cModule, "enable_mixin", rb_mod_enable_mixin, 1);
76
- rb_define_method(rb_cModule, "mixin_an_object", rb_mod_mixin_object, 1);
77
-
78
- rb_eval_string(
79
- "class Proc\n" \
80
- " def includes_mixin? mod\n" \
81
- " (class << binding.eval('self'); self end).include? mod\n" \
82
- " end\n" \
83
- " def mixin mod\n" \
84
- " binding.eval('self').extend mod\n" \
85
- " end\n" \
86
- " def mixout mod\n" \
87
- " (class << binding.eval('self'); self end).disable_mixin mod\n" \
88
- " end\n" \
89
- "end\n" \
90
- "\n" \
91
- "class Module\n" \
92
- " def mix_eval mod, &blk\n" \
93
- " if blk.includes_mixin? mod\n" \
94
- " blk.call\n" \
95
- " else\n" \
96
- " blk.mixin mod\n" \
97
- " begin\n" \
98
- " blk.call\n" \
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
+ }