Skip to content

Instantly share code, notes, and snippets.

@jwdunne
Created November 23, 2014 21:08
Show Gist options
  • Save jwdunne/417ed3cf6e19062776e5 to your computer and use it in GitHub Desktop.
Save jwdunne/417ed3cf6e19062776e5 to your computer and use it in GitHub Desktop.
require './ri'
class PrinterJobs < Interface
def queue_job; end
def cancel_job; end
end
class InkjetJobs
def queue_job
puts "Queuing job"
end
def cancel_job
puts "Cancelling Job"
end
end
class BadPrinterJobs
def queue_job(job)
puts "Queuing job: #{job}"
end
def cancel_job(job)
end
end
# Ruby Interfaces
require 'set'
class InterfaceError < Exception; end
class Interface
def self.ensure(obj)
unless conforms?(obj)
raise InterfaceError,
"#{obj.class.name} does not conform to #{self.name} interface"
end
end
def self.conforms?(obj)
same_methods?(obj) && all_same_arity?(obj)
end
def self.same_methods?(obj)
obj_methods = obj.class.instance_methods(false)
return false if own_methods.empty? ^ obj_methods.empty?
own_methods.to_set.subset?(obj_methods.to_set)
end
def self.all_same_arity?(obj)
return false unless same_methods?(obj)
own_methods.inject(true) do |same_arity, method|
same_arity && same_arity?(obj, method)
end
end
def self.same_arity?(obj, method)
return false unless same_methods?(obj)
new.method(method).arity == obj.method(method).arity
end
def self.own_methods
instance_methods(false)
end
end
require './ri'
require './example'
describe Interface, "#ensure" do
it "throws an exception when obj non-conforming" do
expect { Interface.ensure(Time.new) }.to raise_error(InterfaceError)
end
end
describe Interface, "#conforms?" do
it "returns false when obj non-conforming" do
expect(Interface.conforms?(Time.new)).to be(false)
end
it "returns true when obj conforming" do
expect(Interface.conforms?(Interface.new)).to be(true)
end
end
describe Interface, "#all_same_arity?" do
it "returns false when one or more methods do not have same arity" do
expect(PrinterJobs.all_same_arity?(BadPrinterJobs.new)).to be(false)
end
it "returns true when all methods have same arity" do
expect(PrinterJobs.all_same_arity?(InkjetJobs.new)).to be(true)
end
end
describe Interface, "#same_arity?" do
it "returns false when a method does not have the same arity" do
expect(PrinterJobs.same_arity?(BadPrinterJobs.new, :queue_job)).to be(false)
end
it "returns true when a method does have the same arity" do
expect(PrinterJobs.same_arity?(InkjetJobs.new, :queue_job)).to be(true)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment