Created
January 17, 2014 15:25
-
-
Save jcinnamond/8475230 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module BasicContract | |
def self.included(base) | |
contract = Contract.new(base) | |
contract.require :ping | |
contract.require :pong => [:name] | |
contract.require :pung | |
contract.check! | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Contract | |
def initialize(base) | |
@base = base | |
@contracts = [] | |
end | |
def require(name) | |
contract = Requirement.new(name) | |
@contracts << contract | |
contract | |
end | |
def debug | |
puts @contracts.inspect | |
end | |
def check! | |
failures = Broken.new(@base) | |
@contracts.each do |contract| | |
contract.check(@base, failures) | |
end | |
raise failures if failures.any? | |
end | |
class Requirement | |
def initialize(requirements) | |
if requirements.is_a?(Hash) | |
requirements.each_pair do |name, args| | |
@name = name.to_sym | |
@args = [args].flatten | |
end | |
else | |
@name = requirements.to_sym | |
@args = [] | |
end | |
end | |
def check(base, failures) | |
if base.public_instance_methods.include?(@name) | |
method = base.instance_method(@name) | |
method_args = method.parameters.select { |p| p[0] == :keyreq }.last || [] | |
failures.missing_parameters(@name, @args - method_args) | |
failures.extra_parameters(@name, method_args - @args) | |
else | |
failures.missing_method(@name) | |
end | |
end | |
end | |
class Broken < StandardError | |
def initialize(base) | |
@base = base | |
@missing_methods = [] | |
@wrong_signatures = Hash.new { |h, key| h[key] = {missing: [], extra: []} } | |
end | |
def missing_method(method_name) | |
@missing_methods << method_name | |
end | |
def missing_parameters(method_name, parameter_names) | |
@wrong_signatures[method_name] [:missing] = parameter_names unless parameter_names.empty? | |
end | |
def extra_parameters(method_name, parameter_names) | |
@wrong_signatures[method_name][:extra] = parameter_names unless parameter_names.empty? | |
end | |
def any? | |
!(@missing_methods.empty? && @missing_parameters.empty?) | |
end | |
def to_s | |
str = "on #{@base.inspect}:\n" | |
if !@missing_methods.empty? | |
str << "\t(#{@missing_methods.count} missing methods)\n" | |
@missing_methods.each do |method_name| | |
str << "\t[missing] #{method_name}\n" | |
end | |
str << "\n" | |
end | |
if !@wrong_signatures.empty? | |
str << "\t(#{@wrong_signatures.count} methods with the wrong signature)\n" | |
@wrong_signatures.each do |method_name, details| | |
err = "" | |
missing = details[:missing] | |
err << " missing params: [#{missing.join(', ')}]" unless missing.empty? | |
extra = details[:extra] | |
err << " extra required params: [#{extra.join(', ')}]" unless extra.empty? | |
str << "\t[bad signature] #{method_name} -> #{err}\n" | |
end | |
str << "\n" | |
end | |
str | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ irb -I. -rcontract -rbasic_contract | |
irb(main):001:0> require 'test' | |
Contract::Broken: on Test: | |
(1 missing methods) | |
[missing] ping | |
(2 methods with the wrong signature) | |
[bad signature] pong -> missing params: [name] | |
[bad signature] pung -> extra required params: [keyreq, key] | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Test | |
def pong | |
end | |
def pung(key:) | |
end | |
include(BasicContract) | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment