module-import 0.3.0 → 0.4.0

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