Squeak has a concept of “protocols”, in which you can group related methods. Jason wanted me to throw together a protocol implementation in Ruby. Here’s a fast and easy implementation that I’ll probably never use in production code.
class Module
@protocols = {}
def protocols
@protocols ||= ancestors[1] ? ancestors[1].protocols.dup : {}
end
# def add_to_protocol
def protocol(protocol_name)
raise "A block is required" unless block_given?
protocols[protocol_name] ||= []
original_method_added = method(:method_added).unbind
(class << self; self; end).send(:define_method, :method_added) do |method_name|
protocols[protocol_name] << method_name.to_s
end
yield
ensure
class << self; remove_method(:method_added); end
original_method_added.bind(self)
end
end
if $0 == $PROGRAM_NAME
require 'test/unit'
class ProtocolTest < Test::Unit::TestCase
class TestClass
protocol "setters" do
def bar=
end
end
protocol "getters" do
def bar
end
end
def foobarbaz
end
protocol "getters" do
def foo
end
end
end # TestClass
class SonOfTestClass < TestClass; end
def test_should_have_bar_equals_in_setters_protocol
assert_equal ["bar="], TestClass.protocols["setters"].sort
end
def test_should_have_bar_and_foo_in_getters_protocol
assert_equal ["bar", "foo"], TestClass.protocols["getters"].sort
end
def test_foobarbaz_shouldnt_be_any_any_protocols
assert !TestClass.protocols.values.flatten.uniq.include?("foobarbaz")
end
def test_testclass_and_sonoftestclass_should_have_same_protocols_and_different_protocol_variables
assert TestClass.protocols.object_id != SonOfTestClass.protocols.object_id
assert_equal TestClass.protocols.values.flatten.sort, SonOfTestClass.protocols.values.flatten.sort
end
end
end
annealer