Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

contract stuff

  • Loading branch information...
commit 262659eb2399fc6193f841b7b80058f09d3653d2 1 parent a9704d7
@ryanbrunner ryanbrunner authored
View
2  contract.gemspec
@@ -19,6 +19,6 @@ Gem::Specification.new do |s|
s.require_paths = ["lib"]
# specify any dependencies here; for example:
- # s.add_development_dependency "rspec"
+ s.add_development_dependency "rspec"
# s.add_runtime_dependency "rest-client"
end
View
11 examples/example.rb
@@ -0,0 +1,11 @@
+class ExampleClass
+ define_method :foo do
+ 'bar'
+ end
+
+ def define_method(name, &block)
+
+ end
+end
+
+ExampleClass.new.foo # bar
View
2  lib/contract.rb
@@ -1,5 +1,7 @@
require "contract/version"
+autoload :DesignContracts, 'contract/design_contract'
+require 'contract/design_contract'
module Contract
# Your code goes here...
end
View
66 lib/contract/design_contract.rb
@@ -0,0 +1,66 @@
+
+ module Contract::DesignContracts
+ def define_contract_method (method, *args, &block)
+ config = init_config(method)
+ puts config.to_yaml
+ config.instance_eval &block
+
+
+ define_method method do |*inst_args|
+ config.setup_args(args, inst_args, self)
+ raise "Pre-condition not satisfied" unless config.preconditions.all? { |pre| config.instance_eval &pre }
+
+ config.instance_eval &config.execute if config.execute
+ self.send(method)
+ end
+
+
+ define_method "can_#{method}?" do |*inst_args|
+ config.setup_args(args, inst_args, self)
+ config.preconditions.all? { |pre| config.instance_eval &pre } && send(method, *inst_args)
+ self.send("super_can_#{method}?")
+ end
+ end
+
+ private
+
+ def init_config(method_name)
+ puts "here"
+ @methods ||= {}
+ return @methods[method_name] || @methods[method_name] = Contract::Config.new
+ end
+ end
+
+ class Contract::Config
+ attr_reader :preconditions
+ attr_reader :execute
+
+ def initialize
+ @preconditions = []
+ @execute = nil
+ end
+
+ def method_missing(method, *args)
+ @caller.send(method, *args)
+ end
+
+ def metaclass
+ class << self; self; end
+ end
+
+ def requires(&block)
+ @preconditions << block
+ end
+
+ def implementation(&block)
+ @execute = block
+ end
+
+ def setup_args(args, inst, caller)
+ @caller = caller
+
+ args.each_with_index do |a, i|
+ metaclass.send(:define_method, a) { inst[i] }
+ end
+ end
+ end
View
60 spec/example_spec.rb
@@ -0,0 +1,60 @@
+require 'spec_helper'
+
+class ExampleClass
+ extend Contract::DesignContracts
+
+ define_contract_method :divide, :num, :denominator do
+ requires { denominator > 0 }
+ implementation do
+ num / denominator
+ end
+ end
+
+end
+
+describe ExampleClass do
+ subject { ExampleClass }
+ it { should respond_to :define_contract_method }
+
+ describe "#divide" do
+ specify { ExampleClass.new.should respond_to :divide }
+
+ subject { ExampleClass.new.divide(numerator, denominator) }
+ let(:numerator) { 2 }
+
+ context "Denominator = 0" do
+ let(:denominator) { 0 }
+
+ specify { expect { subject }.to raise_error }
+ end
+
+ context "Denominator = -1" do
+ let(:denominator) { -1 }
+
+ specify { expect { subject }.to raise_error }
+ end
+
+ context "Denominator = 1" do
+ let(:denominator) { 1 }
+ it { should == 2 }
+ end
+ end
+
+
+ describe "#can_divide?" do
+ specify { ExampleClass.new.should respond_to :can_divide? }
+
+ subject { ExampleClass.new.can_divide?(numerator, denominator) }
+ let(:numerator) { 2 }
+
+ context "Denominator = 0" do
+ let(:denominator) { 0 }
+ it { should be_false }
+ end
+
+ context "Denominator = 1" do
+ let(:denominator) { 1 }
+ it { should be_true }
+ end
+ end
+end
View
54 spec/inheritance_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+class OpenExample
+ extend Contract::DesignContracts
+
+ attr_accessor :is_deleted
+
+ define_contract_method :delete_stuff do
+ implementation do
+ is_deleted = true
+ end
+ end
+end
+
+class SecuredExample < OpenExample
+ attr_accessor :password_provided
+
+ define_contract_method :delete_stuff do
+ requires { password_provided }
+ end
+end
+
+describe OpenExample do
+ describe "#can_delete_stuff?" do
+ specify { example_class.should respond_to :can_delete_stuff? }
+ let (:example_class) { OpenExample.new }
+ subject { example_class.can_delete_stuff? }
+
+ it { should be_true }
+ end
+end
+
+describe SecuredExample do
+ describe "#can_delete_stuff?" do
+ let (:example_class) { SecuredExample.new }
+
+ specify { example_class.should respond_to :can_delete_stuff? }
+ subject { example_class.can_delete_stuff? }
+
+ context "without password provided" do
+ before { example_class.password_provided = false }
+ it { should be_false }
+ end
+ context "with password provided" do
+ before { example_class.password_provided = true }
+ it { should be_true }
+ # check that we can actually call the method too (i.e. implementation wasn't wiped out)
+ specify {
+ example_class.delete_stuff
+ example_class.is_deleted.should == true
+ }
+ end
+ end
+end
View
34 spec/instance_variable_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+class ExampleAddClass
+ extend Contract::DesignContracts
+
+ attr_accessor :allow_add
+
+ define_contract_method :add, :num, :num2 do
+ requires { allow_add }
+ implementation do
+ num + num2
+ end
+ end
+
+end
+
+describe ExampleAddClass do
+
+ describe "#can_add?" do
+ specify { example_class.should respond_to :can_add? }
+ let (:example_class) { ExampleAddClass.new }
+ subject { example_class.can_add?(1,1) }
+
+ context "Don't allow add" do
+ before { example_class.allow_add = false }
+ it { should be_false }
+ end
+
+ context "Allow add" do
+ before { example_class.allow_add = true }
+ it { should be_true }
+ end
+ end
+end
View
46 spec/multiple_require_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+class ExampleAddPositivesClass
+ extend Contract::DesignContracts
+
+ define_contract_method :add_positives, :num, :num2 do
+ requires { num > 0 }
+ requires { num2 > 0 }
+
+ implementation do
+ num + num2
+ end
+ end
+
+end
+
+describe ExampleAddPositivesClass do
+
+ describe "#can_add?" do
+ specify { example_class.should respond_to :can_add_positives? }
+ let (:example_class) { ExampleAddPositivesClass.new }
+ let(:num1) { 1 }
+ let(:num2) { 1 }
+ subject { example_class.can_add_positives?(num1,num2) }
+
+ context "Num1 is negative" do
+ let(:num1) { -1 }
+ it { should be_false }
+ end
+
+ context "Num2 is negative" do
+ let(:num2) { -1 }
+ it { should be_false }
+ end
+
+ context "Both are negative" do
+ let(:num1) { -1 }
+ let(:num2) { -1 }
+ it { should be_false }
+ end
+
+ context "Both are positive" do
+ it { should be_true }
+ end
+ end
+end
View
9 spec/spec_helper.rb
@@ -0,0 +1,9 @@
+require 'bundler/setup'
+
+# require 'rspec'
+
+require 'contract'
+
+RSpec.configure do |config|
+
+end
Please sign in to comment.
Something went wrong with that request. Please try again.