module-import 0.1.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 ADDED
@@ -0,0 +1,69 @@
1
+ == Summary
2
+ selectively include module methods
3
+
4
+ == Author and License
5
+ Copyright (c) 2008 Greg Weber, http://gregweber.info
6
+ Licensed under the MIT license
7
+
8
+ == Usage
9
+
10
+ require 'rubygems'
11
+ require 'module-import'
12
+
13
+ module Foo
14
+ def foo; 'foo' end
15
+ def bar; 'bar' end
16
+ end
17
+
18
+ class Importer
19
+ import Foo, :bar
20
+ end
21
+ Importer.new.bar # => 'bar'
22
+ Importer.new.foo # => NoMethodError
23
+
24
+ class Importer
25
+ import Foo, :not_defined # => #not_defined not found in Foo (ImportError)
26
+ end
27
+
28
+
29
+ Giving no methods (or all methods) should behave the same as a normal include
30
+
31
+ class Importer2
32
+ import Foo, :foo, :bar
33
+ end
34
+ Importer.new.bar # => 'bar'
35
+ Importer.new.foo # => 'foo'
36
+
37
+ However, there is one important difference. New changes in the included module will not effect the class.
38
+ module Foo
39
+ undefine_method :foo
40
+ def bar; fail end
41
+ end
42
+ class Importer2
43
+ import Foo, :foo, :bar
44
+ end
45
+ Importer.new.bar # => 'bar'
46
+ Importer.new.foo # => 'foo'
47
+
48
+ == Install
49
+ gem install module-import
50
+
51
+ == Source
52
+ === browser
53
+ http://github.com/gregwebs/module-import/tree/master
54
+
55
+ === repository
56
+ git clone git://github.com/gregwebs/module-import.git
57
+
58
+ == Homepage
59
+ http://gregweber.info/projects/module-import.html
60
+
61
+ == RDoc documentation
62
+ included with the gem
63
+
64
+ == Notes
65
+ === Testing
66
+ 4:1 test:code ratio, I think I have all the corner cases covered. In particular, this does not break inheritance and everything works the same for importing into a module instead of a class.
67
+
68
+ === Implementation
69
+ Includes a duplicate of the module that has methods removed
@@ -0,0 +1 @@
1
+ Sun, 09 Mar 2008 12:30:11 -0500
@@ -0,0 +1,28 @@
1
+
2
+ <?xml version="1.0" encoding="iso-8859-1"?>
3
+ <!DOCTYPE html
4
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
+
7
+ <!--
8
+
9
+ Classes
10
+
11
+ -->
12
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
+ <head>
14
+ <title>Classes</title>
15
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
+ <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
+ <base target="docwin" />
18
+ </head>
19
+ <body>
20
+ <div id="index">
21
+ <h1 class="section-bar">Classes</h1>
22
+ <div id="index-entries">
23
+ <a href="classes/ImportError.html">ImportError</a><br />
24
+ <a href="classes/Kernel.html">Kernel</a><br />
25
+ </div>
26
+ </div>
27
+ </body>
28
+ </html>
@@ -0,0 +1,28 @@
1
+
2
+ <?xml version="1.0" encoding="iso-8859-1"?>
3
+ <!DOCTYPE html
4
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
+
7
+ <!--
8
+
9
+ Files
10
+
11
+ -->
12
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
+ <head>
14
+ <title>Files</title>
15
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
+ <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
+ <base target="docwin" />
18
+ </head>
19
+ <body>
20
+ <div id="index">
21
+ <h1 class="section-bar">Files</h1>
22
+ <div id="index-entries">
23
+ <a href="files/README.html">README</a><br />
24
+ <a href="files/lib/import_rb.html">lib/import.rb</a><br />
25
+ </div>
26
+ </div>
27
+ </body>
28
+ </html>
@@ -0,0 +1,27 @@
1
+
2
+ <?xml version="1.0" encoding="iso-8859-1"?>
3
+ <!DOCTYPE html
4
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
+
7
+ <!--
8
+
9
+ Methods
10
+
11
+ -->
12
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
+ <head>
14
+ <title>Methods</title>
15
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
+ <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
+ <base target="docwin" />
18
+ </head>
19
+ <body>
20
+ <div id="index">
21
+ <h1 class="section-bar">Methods</h1>
22
+ <div id="index-entries">
23
+ <a href="classes/Kernel.html#M000001">import (Kernel)</a><br />
24
+ </div>
25
+ </div>
26
+ </body>
27
+ </html>
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
5
+
6
+ <!--
7
+
8
+ RDoc Documentation
9
+
10
+ -->
11
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
12
+ <head>
13
+ <title>RDoc Documentation</title>
14
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
15
+ </head>
16
+ <frameset rows="20%, 80%">
17
+ <frameset cols="25%,35%,45%">
18
+ <frame src="fr_file_index.html" title="Files" name="Files" />
19
+ <frame src="fr_class_index.html" name="Classes" />
20
+ <frame src="fr_method_index.html" name="Methods" />
21
+ </frameset>
22
+ <frame src="files/README.html" name="docwin" />
23
+ </frameset>
24
+ </html>
@@ -0,0 +1,208 @@
1
+
2
+ body {
3
+ font-family: Verdana,Arial,Helvetica,sans-serif;
4
+ font-size: 90%;
5
+ margin: 0;
6
+ margin-left: 40px;
7
+ padding: 0;
8
+ background: white;
9
+ }
10
+
11
+ h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
12
+ h1 { font-size: 150%; }
13
+ h2,h3,h4 { margin-top: 1em; }
14
+
15
+ a { background: #eef; color: #039; text-decoration: none; }
16
+ a:hover { background: #039; color: #eef; }
17
+
18
+ /* Override the base stylesheet's Anchor inside a table cell */
19
+ td > a {
20
+ background: transparent;
21
+ color: #039;
22
+ text-decoration: none;
23
+ }
24
+
25
+ /* and inside a section title */
26
+ .section-title > a {
27
+ background: transparent;
28
+ color: #eee;
29
+ text-decoration: none;
30
+ }
31
+
32
+ /* === Structural elements =================================== */
33
+
34
+ div#index {
35
+ margin: 0;
36
+ margin-left: -40px;
37
+ padding: 0;
38
+ font-size: 90%;
39
+ }
40
+
41
+
42
+ div#index a {
43
+ margin-left: 0.7em;
44
+ }
45
+
46
+ div#index .section-bar {
47
+ margin-left: 0px;
48
+ padding-left: 0.7em;
49
+ background: #ccc;
50
+ font-size: small;
51
+ }
52
+
53
+
54
+ div#classHeader, div#fileHeader {
55
+ width: auto;
56
+ color: white;
57
+ padding: 0.5em 1.5em 0.5em 1.5em;
58
+ margin: 0;
59
+ margin-left: -40px;
60
+ border-bottom: 3px solid #006;
61
+ }
62
+
63
+ div#classHeader a, div#fileHeader a {
64
+ background: inherit;
65
+ color: white;
66
+ }
67
+
68
+ div#classHeader td, div#fileHeader td {
69
+ background: inherit;
70
+ color: white;
71
+ }
72
+
73
+
74
+ div#fileHeader {
75
+ background: #057;
76
+ }
77
+
78
+ div#classHeader {
79
+ background: #048;
80
+ }
81
+
82
+
83
+ .class-name-in-header {
84
+ font-size: 180%;
85
+ font-weight: bold;
86
+ }
87
+
88
+
89
+ div#bodyContent {
90
+ padding: 0 1.5em 0 1.5em;
91
+ }
92
+
93
+ div#description {
94
+ padding: 0.5em 1.5em;
95
+ background: #efefef;
96
+ border: 1px dotted #999;
97
+ }
98
+
99
+ div#description h1,h2,h3,h4,h5,h6 {
100
+ color: #125;;
101
+ background: transparent;
102
+ }
103
+
104
+ div#validator-badges {
105
+ text-align: center;
106
+ }
107
+ div#validator-badges img { border: 0; }
108
+
109
+ div#copyright {
110
+ color: #333;
111
+ background: #efefef;
112
+ font: 0.75em sans-serif;
113
+ margin-top: 5em;
114
+ margin-bottom: 0;
115
+ padding: 0.5em 2em;
116
+ }
117
+
118
+
119
+ /* === Classes =================================== */
120
+
121
+ table.header-table {
122
+ color: white;
123
+ font-size: small;
124
+ }
125
+
126
+ .type-note {
127
+ font-size: small;
128
+ color: #DEDEDE;
129
+ }
130
+
131
+ .xxsection-bar {
132
+ background: #eee;
133
+ color: #333;
134
+ padding: 3px;
135
+ }
136
+
137
+ .section-bar {
138
+ color: #333;
139
+ border-bottom: 1px solid #999;
140
+ margin-left: -20px;
141
+ }
142
+
143
+
144
+ .section-title {
145
+ background: #79a;
146
+ color: #eee;
147
+ padding: 3px;
148
+ margin-top: 2em;
149
+ margin-left: -30px;
150
+ border: 1px solid #999;
151
+ }
152
+
153
+ .top-aligned-row { vertical-align: top }
154
+ .bottom-aligned-row { vertical-align: bottom }
155
+
156
+ /* --- Context section classes ----------------------- */
157
+
158
+ .context-row { }
159
+ .context-item-name { font-family: monospace; font-weight: bold; color: black; }
160
+ .context-item-value { font-size: small; color: #448; }
161
+ .context-item-desc { color: #333; padding-left: 2em; }
162
+
163
+ /* --- Method classes -------------------------- */
164
+ .method-detail {
165
+ background: #efefef;
166
+ padding: 0;
167
+ margin-top: 0.5em;
168
+ margin-bottom: 1em;
169
+ border: 1px dotted #ccc;
170
+ }
171
+ .method-heading {
172
+ color: black;
173
+ background: #ccc;
174
+ border-bottom: 1px solid #666;
175
+ padding: 0.2em 0.5em 0 0.5em;
176
+ }
177
+ .method-signature { color: black; background: inherit; }
178
+ .method-name { font-weight: bold; }
179
+ .method-args { font-style: italic; }
180
+ .method-description { padding: 0 0.5em 0 0.5em; }
181
+
182
+ /* --- Source code sections -------------------- */
183
+
184
+ a.source-toggle { font-size: 90%; }
185
+ div.method-source-code {
186
+ background: #262626;
187
+ color: #ffdead;
188
+ margin: 1em;
189
+ padding: 0.5em;
190
+ border: 1px dashed #999;
191
+ overflow: hidden;
192
+ }
193
+
194
+ div.method-source-code pre { color: #ffdead; overflow: hidden; }
195
+
196
+ /* --- Ruby keyword styles --------------------- */
197
+
198
+ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
199
+
200
+ .ruby-constant { color: #7fffd4; background: transparent; }
201
+ .ruby-keyword { color: #00ffff; background: transparent; }
202
+ .ruby-ivar { color: #eedd82; background: transparent; }
203
+ .ruby-operator { color: #00ffee; background: transparent; }
204
+ .ruby-identifier { color: #ffdead; background: transparent; }
205
+ .ruby-node { color: #ffa07a; background: transparent; }
206
+ .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
207
+ .ruby-regexp { color: #ffa07a; background: transparent; }
208
+ .ruby-value { color: #7fffd4; background: transparent; }
@@ -0,0 +1,29 @@
1
+ class ImportError < Exception; end
2
+
3
+ module Kernel
4
+
5
+ # include a duplicate of the module with all uneeded instance methods removed
6
+ def import(mod, *meths)
7
+ include_module_copy = lambda do |block|
8
+ mod_dup = mod.dup
9
+ mod_dup.module_eval &block if block
10
+ include mod_dup
11
+ end
12
+
13
+ if meths.size == 0
14
+ include_module_copy.call(nil)
15
+
16
+ else
17
+ # get list of methods to remove module
18
+ ims = mod.instance_methods.map {|m| m.to_sym}
19
+ if (ims & meths).size != meths.size
20
+ raise ImportError, "##{(meths - ims).join(' and #')} not found in #{mod}"
21
+ end
22
+ ims = ims - meths
23
+
24
+ include_module_copy.call( lambda do
25
+ ims.each { |meth| remove_method meth }
26
+ end )
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,60 @@
1
+ rubyforge_project = "'module import'"
2
+ project = 'module-import'
3
+ desc "test"
4
+ task :test do
5
+ Dir[ 'spec/*' ].each do |file|
6
+ puts `spec #{file}`
7
+ exit $?.exitstatus if $?.exitstatus != 0
8
+ end
9
+ end
10
+
11
+ desc "release a new gem to rubyforge"
12
+ task :release => [:rdoc,:package] do
13
+ Dir.chdir('pkg') do
14
+ release = Dir['*.gem'].sort_by {|file| File.mtime(file)}.last
15
+ release =~ /^[^-]+-([.0-9]+).gem$/
16
+ `rubyforge login && rubyforge add_release #{project} #{project} #$1 #{release}`
17
+ end
18
+ end
19
+
20
+ desc "generate documentation"
21
+ task :rdoc do
22
+ fail unless system 'rdoc --force-update --quiet README lib/*'
23
+ end
24
+
25
+ namespace :readme do
26
+ desc "create html for website using coderay, use --silent option"
27
+ task :html => :rdoc do
28
+ require 'hpricot'
29
+ doc = open( 'doc/files/README.html' ) { |f| Hpricot(f) }
30
+ # find example code
31
+ doc.at('#description').search('pre').
32
+ select {|elem| elem.inner_html =~ /class |module /}.each do |ex|
33
+ # add coderay and undo what rdoc has done in the example code
34
+ ex.swap("<coderay lang='ruby'>#{ex.inner_html.gsub('&quot;', '"').gsub('&gt;','>')}</coderay>")
35
+ end
36
+ puts doc.at('#description').to_html
37
+ end
38
+ end
39
+
40
+ require 'rubygems'
41
+ require 'rake/gempackagetask'
42
+
43
+ spec = Gem::Specification.new do |s|
44
+ s.name = project
45
+ s.rubyforge_project = project
46
+ s.version = "0.1.0"
47
+ s.author = "Greg Weber"
48
+ s.email = "greg@gregweber.info"
49
+ s.homepage = "http://projects.gregweber.info/#{project}"
50
+ s.platform = Gem::Platform::RUBY
51
+ s.summary = "selectively import methods from modules"
52
+ s.files = Dir['./**'] + Dir['*/**']
53
+ s.require_path = "lib"
54
+ s.has_rdoc = true
55
+ s.extra_rdoc_files = ["README"]
56
+ end
57
+
58
+ Rake::GemPackageTask.new(spec) do |pkg|
59
+ pkg.need_tar = false
60
+ end
@@ -0,0 +1,136 @@
1
+ require File.dirname(__FILE__) + '/../lib/import'
2
+
3
+ def module_with_new
4
+ Module.new do
5
+ def self.new *args
6
+ (Class.new.send :include, self, *args).new
7
+ end
8
+ end
9
+ end
10
+
11
+ def class_with_super(superclass)
12
+ if superclass.is_a? Class
13
+ Class.new(superclass)
14
+ else
15
+ module_with_new().module_eval do
16
+ include superclass
17
+ end
18
+ end
19
+ end
20
+
21
+ def class_and_module(times=nil)
22
+ if !times or times == 1
23
+ [Class.new, module_with_new()]
24
+ else
25
+ [(0...times).map{|i| Class.new}, (0...times).map{|i| module_with_new()}]
26
+ end
27
+ end
28
+
29
+
30
+ # testing uses this module
31
+ module Foo
32
+ def extra_method; fail end
33
+
34
+ def foo; 'foo' end
35
+ def bar; 'bar' end
36
+
37
+ def another_extra_method; fail end
38
+ end
39
+
40
+ describe "import" do
41
+ it 'should import only the required methods' do
42
+ class_and_module.each do |k|
43
+ k.send :import, Foo, :bar
44
+ o = k.new
45
+ o.bar.should == 'bar'
46
+ lambda{o.foo}.should raise_error(NoMethodError)
47
+ end
48
+ end
49
+
50
+ it 'should raise an error when importing a method that does not exist' do
51
+ class_and_module.each {|k| lambda{ k.send :import, Foo, :foo, :not_defined, :bar }.
52
+ should raise_error(ImportError, /#not_defined/) }
53
+
54
+ class_and_module.each {|k| lambda{ k.send :import, Foo,
55
+ :not_defined, :foo, :_not_defined_, :bar, :__not_defined__ }.
56
+ should raise_error(ImportError, /#not_defined and #_not_defined_ and #__not_defined__/) }
57
+ end
58
+
59
+ it 'should import all methods if none are given' do
60
+ class_and_module.each do |c|
61
+ c.send :import, Foo
62
+ c.new.foo.should == 'foo'
63
+ c.new.bar.should == 'bar'
64
+
65
+ b = c.class.new
66
+ b.send :import, Foo, *(Foo.private_instance_methods)
67
+ c.instance_methods.sort.should == b.instance_methods.sort
68
+
69
+ a = c.class.new
70
+ a.send :include, Foo
71
+ a.instance_methods.sort.should == c.instance_methods.sort
72
+ end
73
+ end
74
+
75
+ it 'should not be effected by changes to the module' do
76
+ class_and_module(2).each do |imp,inc|
77
+ Bar = Module.new do
78
+ def foo; 'foo' end
79
+ end
80
+ bar_orig_ims = Bar.instance_methods
81
+
82
+ imp.send :import, Bar
83
+ inc.send :include, Bar
84
+
85
+ imp.instance_methods.sort.should == inc.instance_methods.sort
86
+ (bar_orig_ims - imp.instance_methods).should be_empty
87
+
88
+ [imp, inc].each do |klass|
89
+ k = klass.new
90
+ k.foo.should == 'foo'
91
+ lambda{k.bar}.should raise_error(NoMethodError)
92
+ end
93
+
94
+ Bar.module_eval do
95
+ def extra_method; fail end
96
+
97
+ def bar; 'bar' end
98
+ undef_method :foo
99
+
100
+ def another_extra_method; fail end
101
+ end
102
+
103
+ lambda{inc.new.foo}.should raise_error(NoMethodError)
104
+ inc.new.bar.should == 'bar'
105
+
106
+ imp.new.foo.should == 'foo'
107
+ lambda{imp.new.bar}.should raise_error(NoMethodError)
108
+
109
+ (imp.instance_methods - inc.instance_methods).should == ['foo']
110
+ (inc.instance_methods - imp.instance_methods).sort.should == (Bar.instance_methods - bar_orig_ims).sort
111
+ end
112
+ end
113
+
114
+ it 'should not effect calls to super' do
115
+ class_and_module.each do |a|
116
+ a.class_eval do
117
+ def foo; 'super' end
118
+ end
119
+ b = class_with_super(a)
120
+ b.new.foo.should == 'super'
121
+
122
+ b.class_eval { import Foo, :bar }
123
+ b.new.foo.should == 'super'
124
+
125
+ bo = b.new
126
+ class << bo
127
+ import(Foo, :foo)
128
+ end
129
+ bo.foo.should == 'foo'
130
+ b.new.foo.should == 'super'
131
+
132
+ b.class_eval { import Foo, :foo }
133
+ b.new.foo.should == 'foo'
134
+ end
135
+ end
136
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: module-import
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2008-03-09 00:00:00 -06:00
8
+ summary: selectively import methods from modules
9
+ require_paths:
10
+ - lib
11
+ email: greg@gregweber.info
12
+ homepage: http://projects.gregweber.info/module-import
13
+ rubyforge_project: module-import
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Greg Weber
31
+ files:
32
+ - ./doc
33
+ - ./lib
34
+ - ./pkg
35
+ - ./spec
36
+ - ./README
37
+ - ./rakefile
38
+ - doc/files
39
+ - doc/index.html
40
+ - doc/rdoc-style.css
41
+ - doc/fr_method_index.html
42
+ - doc/fr_class_index.html
43
+ - doc/fr_file_index.html
44
+ - doc/created.rid
45
+ - doc/classes
46
+ - lib/import.rb
47
+ - spec/import_spec.rb
48
+ - README
49
+ test_files: []
50
+
51
+ rdoc_options: []
52
+
53
+ extra_rdoc_files:
54
+ - README
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ requirements: []
60
+
61
+ dependencies: []
62
+