interface 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/CHANGES +6 -0
  2. data/MANIFEST +14 -0
  3. data/README +82 -0
  4. data/lib/interface.rb +64 -0
  5. data/test/tc_interface.rb +53 -0
  6. metadata +44 -0
data/CHANGES ADDED
@@ -0,0 +1,6 @@
1
+ == 1.0.0 - 5-Jun-2005
2
+ * Re-released on RubyForge.
3
+ * Some test suite and doc changes.
4
+
5
+ == 0.1.0 - 9-May-2004
6
+ * Initial release
data/MANIFEST ADDED
@@ -0,0 +1,14 @@
1
+ CHANGES
2
+ MANIFEST
3
+ README
4
+ install.rb
5
+ interface.gemspec
6
+
7
+ examples/test_instance.rb
8
+ examples/test_interface.rb
9
+ examples/test_sub.rb
10
+ examples/test_unrequire.rb
11
+
12
+ lib/interface.rb
13
+
14
+ test/tc_interface.rb
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: []