interface 1.0.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/CHANGES +6 -0
- data/MANIFEST +14 -0
- data/README +82 -0
- data/lib/interface.rb +64 -0
- data/test/tc_interface.rb +53 -0
- metadata +44 -0
data/CHANGES
ADDED
data/MANIFEST
ADDED
data/README
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
== Description
|
2
|
+
This module provides Java style interfaces for Ruby, including a fairly
|
3
|
+
similar syntax. I don't necessarily believe in interfaces, but I wanted to
|
4
|
+
put it out there as proof that it could be done. Frankly, Java needs mixins
|
5
|
+
more than Ruby needs interfaces, but here you go.
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
=== Manual
|
10
|
+
ruby test/ts_interface.rb
|
11
|
+
ruby install.rb
|
12
|
+
|
13
|
+
=== Gem Install
|
14
|
+
ruby interface.gemspec
|
15
|
+
gem install interface-<version>.gem
|
16
|
+
|
17
|
+
== Synopsis
|
18
|
+
require "interface"
|
19
|
+
|
20
|
+
MyInterface = interface{
|
21
|
+
required_methods :foo, :bar, :baz
|
22
|
+
}
|
23
|
+
|
24
|
+
# Raises an error until 'baz' is defined
|
25
|
+
class MyClass
|
26
|
+
def foo
|
27
|
+
puts "foo"
|
28
|
+
end
|
29
|
+
def bar
|
30
|
+
puts "bar"
|
31
|
+
end
|
32
|
+
implements MyInterface
|
33
|
+
end
|
34
|
+
|
35
|
+
== General Notes
|
36
|
+
Subinterfaces work as well. See the test_sub.rb file under the 'test'
|
37
|
+
directory for a sample.
|
38
|
+
|
39
|
+
== Developer's Notes
|
40
|
+
A discussion on IRC with Mauricio Fernandez got us talking about traits.
|
41
|
+
During that discussion I remembered a blog entry by David Naseby. I
|
42
|
+
revisited his blog entry (at http://homepages.ihug.com.au/~naseby/33.html)
|
43
|
+
and took a closer look.
|
44
|
+
|
45
|
+
Keep in mind that I also happened to be thinking about Java at the moment
|
46
|
+
because of a recent job switch that involved coding in Java. I was also
|
47
|
+
trying to figure out what the purpose of interfaces were.
|
48
|
+
|
49
|
+
As I read the first page of David Naseby's article I realized that,
|
50
|
+
whether intended or not, he had implemented a rudimentary form of interfaces
|
51
|
+
for Ruby. When I discovered this, I talked about it some more with Mauricio
|
52
|
+
and he and I (mostly him) fleshed out the rest of the module, including some
|
53
|
+
syntax improvements. The result is syntax and functionality that is nearly
|
54
|
+
identical to Java.
|
55
|
+
|
56
|
+
I should note that, although I am listed as the author, this was mostly the
|
57
|
+
combined work of David Naseby and Mauricio Fernandez. I just happened to be
|
58
|
+
the guy that put it all together.
|
59
|
+
|
60
|
+
== Acknowledgements
|
61
|
+
This module was largely inspired and somewhat copied from a post by
|
62
|
+
David Naseby at http://homepages.ihug.com.au/~naseby/33.html. It was
|
63
|
+
subsequently modified almost entirely by Mauricio Fernandez through a
|
64
|
+
series of discussions on IRC.
|
65
|
+
|
66
|
+
== Copyright
|
67
|
+
(C) 2004 Daniel J. Berger
|
68
|
+
All rights reserved.
|
69
|
+
|
70
|
+
== Warranty
|
71
|
+
This package is provided "as is" and without any express or
|
72
|
+
implied warranties, including, without limitation, the implied
|
73
|
+
warranties of merchantability and fitness for a particular purpose.
|
74
|
+
|
75
|
+
== License
|
76
|
+
Ruby's
|
77
|
+
|
78
|
+
== Author
|
79
|
+
Daniel J. Berger (who mostly stole it from David Naseby, which was then
|
80
|
+
modified by Mauricio Fernandez)
|
81
|
+
djberg96 at gmail dot com
|
82
|
+
imperator on IRC (irc.freenode.net)
|
data/lib/interface.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Interface
|
2
|
+
Interface::VERSION = "1.0.0"
|
3
|
+
|
4
|
+
# Raised if a class or instance does not meet the interface requirements.
|
5
|
+
class MethodMissing < RuntimeError; end
|
6
|
+
|
7
|
+
# An alias for +extend+
|
8
|
+
def extends(o)
|
9
|
+
extend o
|
10
|
+
end
|
11
|
+
|
12
|
+
def extend_object(o)
|
13
|
+
return append_features(o) if Interface === o
|
14
|
+
append_features(class << o; self end)
|
15
|
+
included(o)
|
16
|
+
end
|
17
|
+
|
18
|
+
def append_features(mod)
|
19
|
+
return super if Interface === mod
|
20
|
+
inherited = (self.ancestors-[self]).select{|x| Interface === x}.
|
21
|
+
map{|x| x.instance_variable_get("@ids")}
|
22
|
+
ids = @ids + inherited.flatten
|
23
|
+
@unreq ||= []
|
24
|
+
(ids-@unreq).uniq.each do |id|
|
25
|
+
unless mod.instance_methods( true ).include?( id.to_s )
|
26
|
+
raise Interface::MethodMissing, id.to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
super mod
|
30
|
+
end
|
31
|
+
|
32
|
+
# Accepts an array of method names that define the interface. When this
|
33
|
+
# module is included/implemented, those method names must have already been
|
34
|
+
# defined.
|
35
|
+
def required_methods(*ids)
|
36
|
+
@ids = ids
|
37
|
+
end
|
38
|
+
|
39
|
+
# Accepts an array of method names that are removed as a requirement for
|
40
|
+
# implementation. Presumably, you would use this in a subinterface where
|
41
|
+
# you only wanted a partial implementation of an existing interface.
|
42
|
+
def unrequired_methods(*ids)
|
43
|
+
@unreq ||= []
|
44
|
+
@unreq += ids
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Accepts a block. There are only two methods you should ever pass to this
|
49
|
+
# block: required_methods and/or unrequired_methods.
|
50
|
+
#
|
51
|
+
# Subinterfaces will need to 'extend' their parent interface.
|
52
|
+
def interface(&block)
|
53
|
+
mod = Module.new
|
54
|
+
mod.extend Interface
|
55
|
+
mod.instance_eval(&block)
|
56
|
+
mod
|
57
|
+
end
|
58
|
+
|
59
|
+
class Module
|
60
|
+
# An alias for +include+. This should be the last statement in your class.
|
61
|
+
def implements m
|
62
|
+
include m
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#####################################################
|
2
|
+
# tc_interface.rb
|
3
|
+
#
|
4
|
+
# Test suite for the Interface module.
|
5
|
+
#####################################################
|
6
|
+
base = File.basename(Dir.pwd)
|
7
|
+
if base == "test" || base =~ /interface/
|
8
|
+
Dir.chdir("..") if base == "test"
|
9
|
+
$LOAD_PATH.unshift("lib")
|
10
|
+
end
|
11
|
+
|
12
|
+
require "test/unit"
|
13
|
+
require "interface"
|
14
|
+
|
15
|
+
TestInterface = interface{
|
16
|
+
required_methods :foo, :bar
|
17
|
+
}
|
18
|
+
|
19
|
+
TestSubInterface = interface{
|
20
|
+
extend TestInterface
|
21
|
+
required_methods :baz
|
22
|
+
}
|
23
|
+
|
24
|
+
class A; end
|
25
|
+
|
26
|
+
class B
|
27
|
+
def foo; end
|
28
|
+
def bar; end
|
29
|
+
end
|
30
|
+
|
31
|
+
class C < B
|
32
|
+
def baz; end
|
33
|
+
end
|
34
|
+
|
35
|
+
class TC_Interface < Test::Unit::TestCase
|
36
|
+
def test_version
|
37
|
+
assert_equal("1.0.0", Interface::VERSION)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_requirements_not_met
|
41
|
+
assert_raises(Interface::MethodMissing){
|
42
|
+
A.new.extend(TestInterface)
|
43
|
+
}
|
44
|
+
assert_raises(Interface::MethodMissing){
|
45
|
+
B.new.extend(TestSubInterface)
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_requirements_met
|
50
|
+
assert_nothing_raised{ B.new.extend(TestInterface) }
|
51
|
+
assert_nothing_raised{ C.new.extend(TestSubInterface) }
|
52
|
+
end
|
53
|
+
end
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.10
|
3
|
+
specification_version: 1
|
4
|
+
name: interface
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2005-06-05
|
8
|
+
summary: Java style interfaces for ruby
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: djberg96@gmail.com
|
12
|
+
homepage: http://www.rubyforge.org/projects/shards
|
13
|
+
rubyforge_project:
|
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
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
authors:
|
28
|
+
- Daniel J. Berger
|
29
|
+
files:
|
30
|
+
- lib/interface.rb
|
31
|
+
- README
|
32
|
+
- CHANGES
|
33
|
+
- MANIFEST
|
34
|
+
- test/tc_interface.rb
|
35
|
+
test_files:
|
36
|
+
- test/tc_interface.rb
|
37
|
+
rdoc_options: []
|
38
|
+
extra_rdoc_files:
|
39
|
+
- README
|
40
|
+
- CHANGES
|
41
|
+
executables: []
|
42
|
+
extensions: []
|
43
|
+
requirements: []
|
44
|
+
dependencies: []
|