mixico 0.1.1 → 0.1.3

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/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
+ }