remix 0.4.8 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,5 @@
1
+ 16/11/2010 version 0.4.9
2
+ * added __attached__ method
1
3
  15/11/2010 version 0.4.8
2
4
  * all extend-based methods now return self
3
5
  * added documentation on blocks (@yield)
@@ -21,6 +21,16 @@ VALUE rb_swap_modules(VALUE self, VALUE mod1, VALUE mod2);
21
21
  rb_raise(rb_eTypeError, "Must be a T_MODULE, T_CLASS, T_ICLASS, T_OBJECT, or T_FALSE type."); \
22
22
  } while(0)
23
23
 
24
+ /* Tiny utility method to return an object attached to a singleton */
25
+ static VALUE
26
+ rb_singleton_attached(VALUE self)
27
+ {
28
+ if(FL_TEST(self, FL_SINGLETON))
29
+ return rb_iv_get(self, "__attached__");
30
+ else
31
+ return Qnil;
32
+ }
33
+
24
34
  /* a modified version of include_class_new from class.c */
25
35
  static VALUE
26
36
  j_class_new(VALUE module, VALUE sup)
@@ -365,5 +375,8 @@ Init_remix()
365
375
  rb_define_method(mModuleExtensions, "uninclude", rb_uninclude, -1);
366
376
  rb_define_alias(mModuleExtensions, "remove_module", "uninclude");
367
377
  rb_define_method(mModuleExtensions, "replace_module", rb_replace_module, 2);
378
+
379
+ rb_define_method(mModuleExtensions, "__attached__", rb_singleton_attached, 0);
380
+
368
381
  }
369
382
 
@@ -1,5 +1,13 @@
1
1
  module Remix
2
2
  module ModuleExtensions
3
+
4
+ # Utility method to return object associated with a singleton class
5
+ # @return Object associated with singleton
6
+ # @example
7
+ # class C; end
8
+ # C.singleton_class.__attached__ #=> C
9
+ def __attached__() end
10
+
3
11
  # Includes a module at a particular index in the ancestor
4
12
  # chain.
5
13
  #
@@ -0,0 +1,116 @@
1
+ module Remix
2
+ module ModuleExtensions
3
+
4
+ # Includes a module at a particular index in the ancestor
5
+ # chain.
6
+ #
7
+ # @param [Fixnum] index The index where the module will be included
8
+ # (must be > 1.)
9
+ # @param [Module] mod The module to include
10
+ # @return [Module] The receiver
11
+ # @example
12
+ # P.ancestors #=> [P, M, N]
13
+ # P.include_at 2, O
14
+ # P.ancestors #=> [P, M, O, N]
15
+ def include_at(index, mod) end
16
+
17
+ # Includes a module below a specific module in the ancestor chain.
18
+ # @param [Module] mod1 Module with position
19
+ # @param [Module] mod2 Module that will be included
20
+ # @return [Module] The receiver
21
+ # @example
22
+ # M.ancestors #=> [M, A, B]
23
+ # M.include_below B, J
24
+ # M.ancestors #=> [M, A, J, B]
25
+ def include_below(mod1, mod2) end
26
+
27
+ # Includes a module above a specific module in the ancestor chain.
28
+ # @param [Module] mod1 Module with position
29
+ # @param [Module] mod2 Module that will be included
30
+ # @return [Module] The receiver
31
+ # @example
32
+ # M.ancestors #=> [M, A, B]
33
+ # M.include_above B, J
34
+ # M.ancestors #=> [M, A, B, J]
35
+ def include_above(mod1, mod) end
36
+
37
+ # Includes a module at top of ancestor chain
38
+ # @param [Module] mod Module that will be included
39
+ # @return [Module] The receiver
40
+ # @example
41
+ # M.ancestors #=> [M, A, B]
42
+ # M.include_at_top J
43
+ # M.ancestors #=> [M, A, B, J]
44
+ def include_at_top(mod) end
45
+
46
+ # Moves a module up one position in the ancestor chain.
47
+ # Module must already be in ancestor chain.
48
+ # @param [Module] mod The module to move up
49
+ # @return [Module] The receiver
50
+ # @example
51
+ # M.ancestors #=> [M, A, B]
52
+ # M.module_move_up A
53
+ # M.ancestors #=> [M, B, A]
54
+ def module_move_up(mod) end
55
+
56
+ # Moves a module down one position in the ancestor chain.
57
+ # Module must already be in ancestor chain.
58
+ # @param [Module] mod The module to move down
59
+ # @return [Module] The receiver
60
+ # @example
61
+ # M.ancestors #=> [M, A, B]
62
+ # M.module_move_down B
63
+ # M.ancestors #=> [M, B, A]
64
+ def module_move_down(mod) end
65
+
66
+ # Unincludes a module from an ancestor chain with optional recursion
67
+ # for nested modules.
68
+ # @param [Module] mod The module to uninclude
69
+ # @param [Boolean] recurse Set to true to remove nested modules
70
+ # @return [Module] The receiver
71
+ # @example Without recursion
72
+ # module C
73
+ # include A, B
74
+ # end
75
+ # M.ancestors #=> [M, C, A, B]
76
+ # M.uninclude C
77
+ # M.ancestors #=> [M, A, B]
78
+ # @example With recursion
79
+ # module C
80
+ # include A, B
81
+ # end
82
+ # M.ancestors #=> [M, C, A, B]
83
+ # M.uninclude C, true
84
+ # M.ancestors #=> [M]
85
+ def uninclude(mod, recurse = false) end
86
+
87
+ # Swaps the position of two modules that already exist in an
88
+ # ancestor chain.
89
+ # @param [Module] mod1 Module to swap
90
+ # @param [Module] mod2 Module to swap
91
+ # @return [Module] The receiver
92
+ # @example
93
+ # M.ancestors #=> [M, A, B, C, D]
94
+ # M.swap_modules A, D
95
+ # M.ancestors #=> [M, D, B, C, A]
96
+ def swap_modules(mod1, mod2) end
97
+
98
+ # Replaces a module with another module that is not already in the
99
+ # ancestor chain.
100
+ # @param [Module] mod1 The module to be replaced
101
+ # @param [Module] mod2 The module that will replace
102
+ # @return [Module] The receiver
103
+ # @example
104
+ # J = Module.new
105
+ # M.ancestors #=> [M, A, B]
106
+ # M.replace_module B, J
107
+ # M.ancestors #=> [M, A, J]
108
+ def replace_module(mod1, mod2) end
109
+
110
+ # Prepares the receiver's ancestor chain for remixing. This method
111
+ # is called automatically by all remixing methods and should
112
+ # never need to be invoked by the user.
113
+ # @return [Object] The receiver
114
+ def ready_remix() end
115
+ end
116
+ end
@@ -1,4 +1,4 @@
1
1
  module Remix
2
- VERSION = "0.4.8"
2
+ VERSION = "0.4.9"
3
3
  end
4
4
 
@@ -0,0 +1,4 @@
1
+ module Remix
2
+ VERSION = "0.4.9"
3
+ end
4
+
@@ -206,6 +206,13 @@ describe 'Test basic remix functionality' do
206
206
  end
207
207
  end
208
208
 
209
+ describe '__attached__' do
210
+ it 'should return the correct attached object' do
211
+ o = Object.new
212
+ o.singleton_class.__attached__.should == o
213
+ end
214
+ end
215
+
209
216
  describe 'module_move_up' do
210
217
  it 'should move module up the chain' do
211
218
  M.ancestors[1..2].should == [A, B]
@@ -0,0 +1,269 @@
1
+ direc = File.dirname(__FILE__)
2
+ require 'rubygems'
3
+ require "#{direc}/../lib/remix"
4
+ require 'bacon'
5
+
6
+ class Module
7
+ public :include, :remove_const
8
+ end
9
+
10
+ puts "testing Remix version #{Remix::VERSION}..."
11
+ puts "Ruby version: #{RUBY_VERSION}"
12
+
13
+ describe 'Test basic remix functionality' do
14
+ before do
15
+ A = Module.new { def hello; :hello; end }
16
+ B = Module.new
17
+ C = Module.new
18
+ J = Module.new
19
+
20
+ M = Module.new
21
+
22
+ M.include A, B
23
+ M.extend A, B
24
+
25
+ C1 = Class.new
26
+ C2 = Class.new(C1)
27
+ C2.include A
28
+ end
29
+
30
+ after do
31
+ Object.remove_const(:A)
32
+ Object.remove_const(:B)
33
+ Object.remove_const(:C)
34
+ Object.remove_const(:M)
35
+ Object.remove_const(:J)
36
+ Object.remove_const(:C1)
37
+ Object.remove_const(:C2)
38
+ end
39
+
40
+ describe 'extend-based methods' do
41
+ describe 'extend_after' do
42
+ it 'should insert module into correct position in singleton class' do
43
+ M.extend_above B, J
44
+ M.singleton_class.ancestors
45
+ M.singleton_class.ancestors[0..2].should == [A, B, J]
46
+ end
47
+ end
48
+
49
+ describe 'temp_extend' do
50
+ it 'should temporarily extend the module for the duration of a block' do
51
+ lambda { B.hello }.should.raise NoMethodError
52
+ B.temp_extend(A) do
53
+ B.hello.should == :hello
54
+ end
55
+ lambda { B.hello }.should.raise NoMethodError
56
+ end
57
+
58
+ it 'should execute before and after hooks prior to and after running the temp_extend block' do
59
+ lambda { B.hello }.should.raise NoMethodError
60
+ B.instance_variable_defined?(:@before).should == false
61
+ B.instance_variable_defined?(:@after).should == false
62
+ B.temp_extend(A,
63
+ :before => proc { B.instance_variable_set(:@before, true) },
64
+ :after => proc { B.instance_variable_set(:@after, true) } ) do
65
+ B.instance_variable_get(:@before).should == true
66
+ B.instance_variable_defined?(:@after).should == false
67
+ B.hello.should == :hello
68
+ end
69
+ B.instance_variable_get(:@after).should == true
70
+ B.instance_variable_get(:@before).should == true
71
+ lambda { B.hello }.should.raise NoMethodError
72
+ end
73
+
74
+ describe 'temp_extend_safe' do
75
+ it 'should temporarily extend the module for the duration of a block in a threadsafe manner' do
76
+ lambda { B.hello }.should.raise NoMethodError
77
+ B.temp_extend_safe(A) do
78
+ B.hello.should == :hello
79
+ end
80
+ lambda { B.hello }.should.raise NoMethodError
81
+ end
82
+ end
83
+
84
+ describe 'unextend' do
85
+ it 'should unextend the module' do
86
+ C.include A, B
87
+ M.extend C
88
+ M.singleton_class.ancestors[0..2].should == [C, A, B]
89
+ M.unextend C
90
+ M.singleton_class.ancestors[0..1].should == [A, B]
91
+ end
92
+
93
+ it 'should unextend the nested module' do
94
+ C.include A, B
95
+ M.extend C
96
+ M.extend J
97
+ M.singleton_class.ancestors[0..3].should == [J, C, A, B]
98
+ M.unextend C, true
99
+ M.singleton_class.ancestors[0..1].should == [J, Module]
100
+ end
101
+
102
+ it 'should unextend the class of the object' do
103
+ o = C2.new
104
+ o.singleton_class.ancestors.first.should == C2
105
+ o.unextend(C2)
106
+ o.singleton_class.ancestors.first.should == A
107
+ end
108
+ end
109
+
110
+ describe 'replace_extended_module' do
111
+ it 'should replace the class of the object with a module' do
112
+ o = C2.new
113
+ o.singleton_class.ancestors.first.should == C2
114
+ o.replace_extended_module C2, J
115
+ o.singleton_class.ancestors.first.should == J
116
+ end
117
+ end
118
+ end
119
+
120
+ describe 'include-based methods' do
121
+ describe 'include_after' do
122
+ it 'should insert module into correct position' do
123
+ M.include_after A, C
124
+ M.ancestors[2].should == C
125
+ end
126
+ end
127
+
128
+ describe 'temp_include' do
129
+ it 'should temporarily include the module for the duration of a block' do
130
+ lambda { "john".hello }.should.raise NoMethodError
131
+ String.temp_include(A) do
132
+ "john".hello.should == :hello
133
+ end
134
+ lambda { "john".hello }.should.raise NoMethodError
135
+ end
136
+
137
+ it 'should execute before and after hooks prior to and after running the temp_include block' do
138
+ lambda { B.hello }.should.raise NoMethodError
139
+ B.instance_variable_defined?(:@before).should == false
140
+ B.instance_variable_defined?(:@after).should == false
141
+ B.temp_include(A,
142
+ :before => proc { B.instance_variable_set(:@before, true) },
143
+ :after => proc { B.instance_variable_set(:@after, true) } ) do
144
+ B.instance_variable_get(:@before).should == true
145
+ B.instance_variable_defined?(:@after).should == false
146
+ end
147
+ B.instance_variable_get(:@after).should == true
148
+ B.instance_variable_get(:@before).should == true
149
+ lambda { B.hello }.should.raise NoMethodError
150
+ end
151
+
152
+ end
153
+
154
+ describe 'temp_include_safe' do
155
+ it 'should temporarily include the module for the duration of a block in a threadsafe manner' do
156
+ lambda { "john".hello }.should.raise NoMethodError
157
+ String.temp_include_safe(A) do
158
+ "john".hello.should == :hello
159
+ end
160
+ lambda { "john".hello }.should.raise NoMethodError
161
+ end
162
+ end
163
+
164
+ describe 'include_before' do
165
+ it 'should insert module into correct position' do
166
+ M.include_before B, C
167
+ M.ancestors[2].should == C
168
+ end
169
+ end
170
+
171
+ describe 'include_at_top' do
172
+ it 'should insert module at top of chain' do
173
+ M.include_at_top C
174
+ M.ancestors.last.should == C
175
+ end
176
+ end
177
+
178
+ describe 'swap_modules' do
179
+ it 'should interchange modules' do
180
+ M.ancestors[1..2].should == [A, B]
181
+ M.swap_modules A, B
182
+ M.ancestors[1..2].should == [B, A]
183
+ end
184
+
185
+ it 'should do a no-op when source/dest modules are the same' do
186
+ M.ancestors[1..2].should == [A, B]
187
+ M.swap_modules A, A
188
+ M.ancestors[1..2].should == [A, B]
189
+ M.swap_modules B, B
190
+ M.ancestors[1..2].should == [A, B]
191
+ end
192
+
193
+ it 'should handle huge ancestor chains without crashing or returning the wrong result' do
194
+ size = 100
195
+ m = Module.new
196
+ size.times do
197
+ m.include Module.new
198
+ end
199
+
200
+ m.ancestors.size.should == size + 1
201
+ size.times do
202
+ m.swap_modules(m.ancestors[rand(size - 1) + 1],
203
+ m.ancestors[rand(size - 1) + 1])
204
+ end
205
+ m.ancestors.size.should == size + 1
206
+ end
207
+ end
208
+
209
+ describe 'module_move_up' do
210
+ it 'should move module up the chain' do
211
+ M.ancestors[1..2].should == [A, B]
212
+ M.module_move_up A
213
+ M.ancestors[1..2].should == [B, A]
214
+ end
215
+ end
216
+
217
+ describe 'module_move_down' do
218
+ it 'should move module down the chain' do
219
+ M.ancestors[1..2].should == [A, B]
220
+ M.module_move_down B
221
+ M.ancestors[1..2].should == [B, A]
222
+ end
223
+ end
224
+
225
+ describe 'include_at' do
226
+ it 'should include module at specified index' do
227
+ M.include_at(1, C)
228
+ M.ancestors[1].should == C
229
+ end
230
+ end
231
+
232
+ describe 'remove_module' do
233
+ it 'should remove the module' do
234
+ M.ancestors[1..2].should == [A, B]
235
+ M.remove_module A
236
+ M.ancestors[1..2].should == [B]
237
+ end
238
+
239
+ it 'should remove recursively if second parameter is true' do
240
+ klass = Module.new
241
+ klass.include J, M, C
242
+ klass.ancestors[1..-1].should == [J, M, A, B, C]
243
+ klass.remove_module M, true
244
+ klass.ancestors[1..-1].should == [J, C]
245
+ end
246
+ end
247
+
248
+ describe 'replace_module' do
249
+ it 'should replace the module with another' do
250
+ M.ancestors[1..2].should == [A, B]
251
+ M.replace_module B, C
252
+ M.ancestors[1..2].should == [A, C]
253
+ end
254
+
255
+
256
+ it 'should replace a class with a module' do
257
+ C2.ancestors[0..2].should == [C2, A, C1]
258
+ C2.replace_module C1, B
259
+ C2.ancestors[0..2].should == [C2, A, B]
260
+ end
261
+
262
+ it 'should raise when replace_module target is the root module of the chain' do
263
+ M.ancestors[0..2].should == [M, A, B]
264
+ lambda { M.replace_module M, J }.should.raise RuntimeError
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remix
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 29
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 4
8
- - 8
9
- version: 0.4.8
9
+ - 9
10
+ version: 0.4.9
10
11
  platform: ruby
11
12
  authors:
12
13
  - John Mair (banisterfiend)
@@ -14,7 +15,7 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-11-15 00:00:00 +13:00
18
+ date: 2010-11-16 00:00:00 +13:00
18
19
  default_executable:
19
20
  dependencies: []
20
21
 
@@ -31,9 +32,12 @@ files:
31
32
  - ext/remix/compat.h
32
33
  - ext/remix/remix.c
33
34
  - lib/remix/c_docs.rb
35
+ - lib/remix/c_docs_flymake.rb
34
36
  - lib/remix/version.rb
37
+ - lib/remix/version_flymake.rb
35
38
  - lib/remix.rb
36
39
  - test/test.rb
40
+ - test/test_flymake.rb
37
41
  - test/test_with_object2module.rb
38
42
  - CHANGELOG
39
43
  - README.markdown
@@ -52,6 +56,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
52
56
  requirements:
53
57
  - - ">="
54
58
  - !ruby/object:Gem::Version
59
+ hash: 3
55
60
  segments:
56
61
  - 0
57
62
  version: "0"
@@ -60,6 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
65
  requirements:
61
66
  - - ">="
62
67
  - !ruby/object:Gem::Version
68
+ hash: 3
63
69
  segments:
64
70
  - 0
65
71
  version: "0"