module-import 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -1,5 +1,5 @@
1
1
  == Summary
2
- selectively include module methods
2
+ selectively include module methods with Kernel#import
3
3
 
4
4
  == Author and License
5
5
  Copyright (c) 2008 Greg Weber, http://gregweber.info
@@ -42,6 +42,11 @@ However, there is one important difference. New changes in the included module
42
42
  Importer2.new.bar # => 'bar'
43
43
  Importer2.new.foo # => 'foo'
44
44
 
45
+ == WARNING!
46
+ There is no way for Kernel#import to track dependencies between methods! To help with this, by default, all private methods from the module will be imported unless the option :import_private is set to false
47
+ To write a module that works with this system well, your public methods should depend only on private methods.
48
+ To use this on someone else's module, you should either import the full module or write tests or inspect the source code of the module you are importing.
49
+
45
50
  == Install
46
51
  gem install module-import
47
52
 
data/Rakefile CHANGED
@@ -82,7 +82,7 @@ namespace :rcov do
82
82
  end
83
83
 
84
84
  desc "release a new gem to rubyforge"
85
- task :release => [:test,:rdoc,:website,:package] do
85
+ task :release => [:test,:record,:rdoc,:website,:package] do
86
86
  Dir.chdir('pkg') do
87
87
  release = Dir['*.gem'].sort_by {|file| File.mtime(file)}.last
88
88
  release =~ /^[^-]+-([.0-9]+).gem$/
@@ -137,7 +137,7 @@ require 'rake/gempackagetask'
137
137
  spec = Gem::Specification.new do |s|
138
138
  s.name = project
139
139
  s.rubyforge_project = project
140
- s.version = "0.3.0"
140
+ s.version = "0.4.0"
141
141
  s.author = "Greg Weber"
142
142
  s.email = "greg@gregweber.info"
143
143
  s.homepage = "http://projects.gregweber.info/#{project}"
@@ -556,7 +556,7 @@ span.run100 {
556
556
  </head>
557
557
  <body>
558
558
  <h3>C0 code coverage information</h3>
559
- <p>Generated on Wed Mar 12 17:24:18 -0500 2008 with <a href='http://eigenclass.org/hiki.rb?rcov'>rcov 0.8.0</a>
559
+ <p>Generated on Fri Mar 14 20:30:48 -0500 2008 with <a href='http://eigenclass.org/hiki.rb?rcov'>rcov 0.8.0</a>
560
560
  </p>
561
561
  <hr /><pre><span class='marked0'>Code reported as executed by Ruby looks like this...
562
562
  </span><span class='marked1'>and this: this line is also marked as covered.
@@ -151,7 +151,7 @@ table.report tr.dark {
151
151
  </head>
152
152
  <body>
153
153
  <h3>C0 code coverage information</h3>
154
- <p>Generated on Wed Mar 12 17:24:18 -0500 2008 with <a href='http://eigenclass.org/hiki.rb?rcov'>rcov 0.8.0</a>
154
+ <p>Generated on Fri Mar 14 20:30:48 -0500 2008 with <a href='http://eigenclass.org/hiki.rb?rcov'>rcov 0.8.0</a>
155
155
  </p>
156
156
  <hr /> <table class='report'>
157
157
  <thead>
@@ -167,21 +167,21 @@ table.report tr.dark {
167
167
  <tr class='light'>
168
168
  <td>TOTAL</td>
169
169
  <td class='lines_total'>
170
- <tt>1003</tt>
170
+ <tt>1015</tt>
171
171
  </td>
172
172
  <td class='lines_code'>
173
- <tt>612</tt>
173
+ <tt>624</tt>
174
174
  </td>
175
175
  <td>
176
176
  <table cellspacing='0' cellpadding='0' align='right'>
177
177
  <tr>
178
178
  <td>
179
- <tt class='coverage_total'>6.0%</tt>&nbsp;</td>
179
+ <tt class='coverage_total'>7.1%</tt>&nbsp;</td>
180
180
  <td>
181
181
  <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
182
182
  <tr>
183
- <td class='covered' width='6' />
184
- <td class='uncovered' width='94' />
183
+ <td class='covered' width='7' />
184
+ <td class='uncovered' width='93' />
185
185
  </tr>
186
186
  </table>
187
187
  </td>
@@ -192,12 +192,12 @@ table.report tr.dark {
192
192
  <table cellspacing='0' cellpadding='0' align='right'>
193
193
  <tr>
194
194
  <td>
195
- <tt class='coverage_code'>5.6%</tt>&nbsp;</td>
195
+ <tt class='coverage_code'>7.4%</tt>&nbsp;</td>
196
196
  <td>
197
197
  <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
198
198
  <tr>
199
- <td class='covered' width='6' />
200
- <td class='uncovered' width='94' />
199
+ <td class='covered' width='7' />
200
+ <td class='uncovered' width='93' />
201
201
  </tr>
202
202
  </table>
203
203
  </td>
@@ -253,10 +253,10 @@ table.report tr.dark {
253
253
  <a href='lib-module-import_rb.html'>lib/module-import.rb</a>
254
254
  </td>
255
255
  <td class='lines_total'>
256
- <tt>27</tt>
256
+ <tt>39</tt>
257
257
  </td>
258
258
  <td class='lines_code'>
259
- <tt>17</tt>
259
+ <tt>29</tt>
260
260
  </td>
261
261
  <td>
262
262
  <table cellspacing='0' cellpadding='0' align='right'>
@@ -556,7 +556,7 @@ span.run100 {
556
556
  </head>
557
557
  <body>
558
558
  <h3>C0 code coverage information</h3>
559
- <p>Generated on Wed Mar 12 17:24:18 -0500 2008 with <a href='http://eigenclass.org/hiki.rb?rcov'>rcov 0.8.0</a>
559
+ <p>Generated on Fri Mar 14 20:30:48 -0500 2008 with <a href='http://eigenclass.org/hiki.rb?rcov'>rcov 0.8.0</a>
560
560
  </p>
561
561
  <hr /><pre><span class='marked0'>Code reported as executed by Ruby looks like this...
562
562
  </span><span class='marked1'>and this: this line is also marked as covered.
@@ -580,10 +580,10 @@ span.run100 {
580
580
  <a href='lib-module-import_rb.html'>lib/module-import.rb</a>
581
581
  </td>
582
582
  <td class='lines_total'>
583
- <tt>27</tt>
583
+ <tt>39</tt>
584
584
  </td>
585
585
  <td class='lines_code'>
586
- <tt>17</tt>
586
+ <tt>29</tt>
587
587
  </td>
588
588
  <td>
589
589
  <table cellspacing='0' cellpadding='0' align='right'>
@@ -624,28 +624,40 @@ span.run100 {
624
624
  </span><span class="marked1"><a name="line3" /> 3 module Kernel
625
625
  </span><span class="inferred0"><a name="line4" /> 4
626
626
  </span><span class="inferred1"><a name="line5" /> 5 # abstraction:: only include the methods given by _meths_
627
- </span><span class="inferred0"><a name="line6" /> 6 # implementation:: includes a duplicate of _mod_ with all uneeded instance methods removed
628
- </span><span class="marked1"><a name="line7" /> 7 def import(mod, *meths)
627
+ </span><span class="inferred0"><a name="line6" /> 6 # implementation:: includes a duplicate of _mod_ with only the specified instance methods included. By default, all private methods will be included unless the option :import_private is set to false. If no methods are given,
628
+ </span><span class="marked1"><a name="line7" /> 7 def import(mod, *methods_or_options)
629
629
  </span><span class="marked0"><a name="line8" /> 8 mod_dup = mod.dup
630
630
  </span><span class="inferred1"><a name="line9" /> 9
631
- </span><span class="marked0"><a name="line10" />10 unless meths.empty?
632
- </span><span class="inferred1"><a name="line11" />11
633
- </span><span class="inferred0"><a name="line12" />12 # get list of methods to remove module
634
- </span><span class="marked1"><a name="line13" />13 ims = mod.instance_methods.map {|m| m.to_sym}
635
- </span><span class="marked0"><a name="line14" />14 removes = ims - meths
636
- </span><span class="inferred1"><a name="line15" />15
637
- </span><span class="marked0"><a name="line16" />16 if removes.size != (ims.size - meths.size)
638
- </span><span class="marked1"><a name="line17" />17 raise ImportError, &quot;##{(meths - ims).join(' and #')} not found in #{mod}&quot;
639
- </span><span class="inferred0"><a name="line18" />18 end
640
- </span><span class="inferred1"><a name="line19" />19
641
- </span><span class="marked0"><a name="line20" />20 mod_dup.module_eval do
642
- </span><span class="marked1"><a name="line21" />21 removes.each { |meth| remove_method meth }
643
- </span><span class="inferred0"><a name="line22" />22 end
644
- </span><span class="inferred1"><a name="line23" />23 end
645
- </span><span class="inferred0"><a name="line24" />24
646
- </span><span class="marked1"><a name="line25" />25 include mod_dup
647
- </span><span class="inferred0"><a name="line26" />26 end
648
- </span><span class="inferred1"><a name="line27" />27 end
631
+ </span><span class="marked0"><a name="line10" />10 unless methods_or_options.empty?
632
+ </span><span class="marked1"><a name="line11" />11 options, meths = methods_or_options.partition {|m| m.is_a?(Hash)}
633
+ </span><span class="inferred0"><a name="line12" />12
634
+ </span><span class="inferred1"><a name="line13" />13 # get list of methods to remove module
635
+ </span><span class="marked0"><a name="line14" />14 ims = mod.instance_methods
636
+ </span><span class="marked1"><a name="line15" />15 if options.first
637
+ </span><span class="marked0"><a name="line16" />16 if meths.empty?
638
+ </span><span class="marked1"><a name="line17" />17 fail ArgumentError,
639
+ </span><span class="inferred0"><a name="line18" />18 &quot;methods arguments required with options flags&quot;
640
+ </span><span class="inferred1"><a name="line19" />19 end
641
+ </span><span class="marked0"><a name="line20" />20 if options.first[:import_private] == false
642
+ </span><span class="marked1"><a name="line21" />21 ims += mod.private_instance_methods
643
+ </span><span class="inferred0"><a name="line22" />22 end
644
+ </span><span class="inferred1"><a name="line23" />23 end
645
+ </span><span class="marked0"><a name="line24" />24 ims.map! {|m| m.to_sym}
646
+ </span><span class="marked1"><a name="line25" />25 removes = ims - meths
647
+ </span><span class="inferred0"><a name="line26" />26
648
+ </span><span class="marked1"><a name="line27" />27 if removes.size != (ims.size - meths.size)
649
+ </span><span class="marked0"><a name="line28" />28 raise ImportError,
650
+ </span><span class="marked1"><a name="line29" />29 &quot;##{(meths - ims).join(' and #')} not found in #{mod}&quot;
651
+ </span><span class="inferred0"><a name="line30" />30 end
652
+ </span><span class="inferred1"><a name="line31" />31
653
+ </span><span class="marked0"><a name="line32" />32 mod_dup.module_eval do
654
+ </span><span class="marked1"><a name="line33" />33 removes.each { |meth| remove_method meth }
655
+ </span><span class="inferred0"><a name="line34" />34 end
656
+ </span><span class="inferred1"><a name="line35" />35 end
657
+ </span><span class="inferred0"><a name="line36" />36
658
+ </span><span class="marked1"><a name="line37" />37 include mod_dup
659
+ </span><span class="inferred0"><a name="line38" />38 end
660
+ </span><span class="inferred1"><a name="line39" />39 end
649
661
  </span></pre><hr /> <p>Generated using the <a href='http://eigenclass.org/hiki.rb?rcov'>rcov code coverage analysis tool for Ruby</a> version 0.8.0.</p><p>
650
662
  <a href='http://validator.w3.org/check/referer'>
651
663
  <img src='http://www.w3.org/Icons/valid-xhtml10' height='31' alt='Valid XHTML 1.0!' width='88' />
@@ -1 +1 @@
1
- Wed, 12 Mar 2008 17:24:20 -0500
1
+ Fri, 14 Mar 2008 20:30:52 -0500
@@ -3,18 +3,30 @@ class ImportError < Exception; end
3
3
  module Kernel
4
4
 
5
5
  # abstraction:: only include the methods given by _meths_
6
- # implementation:: includes a duplicate of _mod_ with all uneeded instance methods removed
7
- def import(mod, *meths)
6
+ # implementation:: includes a duplicate of _mod_ with only the specified instance methods included. By default, all private methods will be included unless the option :import_private is set to false. If no methods are given,
7
+ def import(mod, *methods_or_options)
8
8
  mod_dup = mod.dup
9
9
 
10
- unless meths.empty?
10
+ unless methods_or_options.empty?
11
+ options, meths = methods_or_options.partition {|m| m.is_a?(Hash)}
11
12
 
12
13
  # get list of methods to remove module
13
- ims = mod.instance_methods.map {|m| m.to_sym}
14
+ ims = mod.instance_methods
15
+ if options.first
16
+ if meths.empty?
17
+ fail ArgumentError,
18
+ "methods arguments required with options flags"
19
+ end
20
+ if options.first[:import_private] == false
21
+ ims += mod.private_instance_methods
22
+ end
23
+ end
24
+ ims.map! {|m| m.to_sym}
14
25
  removes = ims - meths
15
26
 
16
27
  if removes.size != (ims.size - meths.size)
17
- raise ImportError, "##{(meths - ims).join(' and #')} not found in #{mod}"
28
+ raise ImportError,
29
+ "##{(meths - ims).join(' and #')} not found in #{mod}"
18
30
  end
19
31
 
20
32
  mod_dup.module_eval do
@@ -1,5 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/../lib/module-import'
2
-
3
2
  # testing helpers
4
3
  def module_with_new
5
4
  Module.new do
@@ -27,14 +26,40 @@ def class_and_module(times=nil)
27
26
  end
28
27
  end
29
28
 
29
+ module ModuleDependencies
30
+ def self.included(mod)
31
+ mod.module_eval do
32
+ @@instance_method_dependencies = Hash.new
33
+ end
34
+
35
+ def mod.import_dependencies set=nil
36
+ if set
37
+ @@instance_method_dependencies = set
38
+ else
39
+ @@instance_method_dependencies
40
+ end
41
+ end
42
+ end
43
+ end
44
+
30
45
 
31
46
  # testing uses this module
32
47
  module Foo
33
48
  def extra_method; fail end
34
49
 
35
- def foo; 'foo' end
36
- def bar; 'bar' end
50
+ def foo; foo_dependency() end
51
+ def bar; bar_dependency end
52
+
53
+ protected
54
+ def protected_method
55
+ end
56
+
57
+ private
58
+ def foo_dependency; 'foo' end
59
+ def bar_dependency; 'bar' end
60
+ def private_extra_method; fail end
37
61
 
62
+ public
38
63
  def another_extra_method; fail end
39
64
  end
40
65
 
@@ -63,10 +88,6 @@ describe "import" do
63
88
  c.new.foo.should == 'foo'
64
89
  c.new.bar.should == 'bar'
65
90
 
66
- b = c.class.new
67
- b.send :import, Foo, *(Foo.private_instance_methods)
68
- c.instance_methods.sort.should == b.instance_methods.sort
69
-
70
91
  a = c.class.new
71
92
  a.send :include, Foo
72
93
  a.instance_methods.sort.should == c.instance_methods.sort
@@ -134,4 +155,28 @@ describe "import" do
134
155
  b.new.foo.should == 'foo'
135
156
  end
136
157
  end
158
+
159
+ it "should remove private methods when :import_private is false" do
160
+ class_and_module.each do |a|
161
+ b = Class.new do
162
+ import Foo, :foo, :import_private => false
163
+ end
164
+ lambda{b.new.foo}.should raise_error(NoMethodError, /foo_dependency/)
165
+
166
+ c = Class.new do
167
+ import Foo, :foo, :foo_dependency, :import_private => false
168
+ end
169
+ lambda{c.new.foo}.should_not raise_error
170
+ end
171
+ end
172
+
173
+ it "should fail when no methods given with :import_private flag" do
174
+ class_and_module.each do |a|
175
+ [true,false].each do |tf|
176
+ lambda{ Class.new do
177
+ import Foo, :import_private => tf
178
+ end }.should raise_error(ArgumentError)
179
+ end
180
+ end
181
+ end
137
182
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: module-import
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.0
7
- date: 2008-03-12 00:00:00 -05:00
6
+ version: 0.4.0
7
+ date: 2008-03-14 00:00:00 -05:00
8
8
  summary: selectively import methods from modules
9
9
  require_paths:
10
10
  - lib
@@ -34,10 +34,7 @@ files:
34
34
  - ./spec
35
35
  - ./Rakefile
36
36
  - ./README
37
- - ./example.rb
38
37
  - ./coverage
39
- - ./delete.html
40
- - ./module-import.rb
41
38
  - doc/files
42
39
  - doc/index.html
43
40
  - doc/rdoc-style.css
@@ -1,92 +0,0 @@
1
- <html>
2
- <body>
3
- &lt;div id=<span class="s"><span class="dl">&quot;</span><span class="k">description</span><span class="dl">&quot;</span></span>&gt;
4
- &lt;h2&gt;<span class="co">Summary</span>&lt;<span class="rx"><span class="dl">/</span><span class="k">h2&gt;
5
- &lt;p&gt;
6
- selectively include module methods
7
- &lt;</span><span class="dl">/</span></span>p&gt;
8
- &lt;h2&gt;<span class="co">Author</span> <span class="r">and</span> <span class="co">License</span>&lt;<span class="rx"><span class="dl">/</span><span class="k">h2&gt;
9
- &lt;p&gt;
10
- Copyright (c) 2008 Greg Weber, &lt;a href=&quot;http:</span><span class="dl">/</span></span>/gregweber.info<span class="s"><span class="dl">&quot;</span><span class="k">&gt;gregweber.info&lt;/a&gt; Licensed under the MIT
11
- license
12
- &lt;/p&gt;
13
- &lt;h2&gt;Usage&lt;/h2&gt;
14
- &lt;coderay lang=</span><span class="dl">&quot;</span></span>ruby<span class="s"><span class="dl">&quot;</span><span class="k">&gt;
15
- require 'rubygems'
16
- require 'module-import'
17
-
18
- module Foo
19
- def foo; 'foo' end
20
- def bar; 'bar' end
21
- end
22
-
23
- class Importer
24
- import Foo, :bar
25
- end
26
- Importer.new.bar # =&gt; 'bar'
27
- Importer.new.foo # =&gt; # NoMethodError
28
-
29
- class Importer
30
- import Foo, :not_defined # =&gt; #not_defined not found in Foo (ImportError)
31
- end
32
- &lt;/coderay&gt;
33
- &lt;p&gt;
34
- Giving no methods (or all methods) should behave the same as a normal
35
- include
36
- &lt;/p&gt;
37
- &lt;coderay lang=</span><span class="dl">&quot;</span></span>ruby<span class="s"><span class="dl">&quot;</span><span class="k">&gt;
38
- class Importer2
39
- import Foo # same as import Foo, :foo, :bar
40
- end
41
- Importer2.new.bar # =&gt; 'bar'
42
- Importer2.new.foo # =&gt; 'foo'
43
- &lt;/coderay&gt;
44
- &lt;p&gt;
45
- However, there is one important difference. New changes in the included
46
- module will not effect the class.
47
- &lt;/p&gt;
48
- &lt;coderay lang=</span><span class="dl">&quot;</span></span>ruby<span class="s"><span class="dl">&quot;</span><span class="k">&gt;
49
- module Foo
50
- undef_method :foo
51
- def bar; fail end
52
- end
53
- Importer2.new.bar # =&gt; 'bar'
54
- Importer2.new.foo # =&gt; 'foo'
55
- &lt;/coderay&gt;
56
- &lt;h2&gt;Install&lt;/h2&gt;
57
- &lt;p&gt;
58
- gem install module-import
59
- &lt;/p&gt;
60
- &lt;h2&gt;Source&lt;/h2&gt;
61
- &lt;h3&gt;browser&lt;/h3&gt;
62
- &lt;p&gt;
63
- &lt;a href=</span><span class="dl">&quot;</span></span>http<span class="sy">:/</span>/github.com/gregwebs/<span class="r">module</span>-import/tree/master<span class="s"><span class="dl">&quot;</span><span class="k">&gt;github.com/gregwebs/module-import/tree/master&lt;/a&gt;
64
- &lt;/p&gt;
65
- &lt;h3&gt;repository&lt;/h3&gt;
66
- &lt;p&gt;
67
- git clone git://github.com/gregwebs/module-import.git
68
- &lt;/p&gt;
69
- &lt;h2&gt;Homepage&lt;/h2&gt;
70
- &lt;p&gt;
71
- &lt;a href=</span><span class="dl">&quot;</span></span>http<span class="sy">:/</span>/gregweber.info/projects/<span class="r">module</span>-import.html<span class="s"><span class="dl">&quot;</span><span class="k">&gt;gregweber.info/projects/module-import.html&lt;/a&gt;
72
- &lt;/p&gt;
73
- &lt;h2&gt;RDoc documentation&lt;/h2&gt;
74
- &lt;p&gt;
75
- included with the gem
76
- &lt;/p&gt;
77
- &lt;h2&gt;Notes&lt;/h2&gt;
78
- &lt;h3&gt;Testing&lt;/h3&gt;
79
- &lt;p&gt;
80
- 4:1 test:code ratio, I think I have all the corner cases covered. In
81
- particular, this does not break inheritance and everything works the same
82
- for importing into a module instead of a class.
83
- &lt;/p&gt;
84
- &lt;h3&gt;Implementation&lt;/h3&gt;
85
- &lt;p&gt;
86
- Includes a duplicate of the module that has methods removed
87
- &lt;/p&gt;
88
-
89
- &lt;/div&gt;
90
- </span></span>
91
- </body>
92
- </html>
data/example.rb DELETED
@@ -1,48 +0,0 @@
1
- class ImportError < Exception; end
2
-
3
- module Kernel
4
-
5
- # abstraction:: only include the methods given by _meths_
6
- # implementation:: includes a duplicate of _mod_ with all uneeded instance methods removed
7
- def import(mod, *meths)
8
- mod_dup = mod.dup
9
-
10
- unless meths.empty?
11
-
12
- # get list of methods to remove module
13
- ims = mod.instance_methods.map {|m| m.to_sym}
14
- removes = ims - meths
15
-
16
- if removes.size != (ims.size - meths.size)
17
- raise ImportError, "##{(meths - ims).join(' and #')} not found in #{mod}"
18
- end
19
-
20
- mod_dup.module_eval do
21
- removes.each { |meth| remove_method meth }
22
- end
23
- end
24
-
25
- include mod_dup
26
- end
27
- end
28
- module Foo
29
- def foo; 'foo' end
30
- def bar; 'bar' end
31
- end
32
- class Importer
33
- import Foo, :bar
34
- end
35
- Importer.new.bar # => 'bar'
36
- class Importer
37
- end
38
- class Importer2
39
- import Foo # same as import Foo, :foo, :bar
40
- end
41
- Importer2.new.bar # => 'bar'
42
- Importer2.new.foo # => 'foo'
43
- module Foo
44
- undef_method :foo
45
- def bar; fail end
46
- end
47
- Importer2.new.bar # => 'bar'
48
- Importer2.new.foo # => 'foo'
File without changes