forked from ryanbrunner/ruby-contract
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
ryanbrunner
committed
Feb 7, 2012
1 parent
a9704d7
commit 262659e
Showing
9 changed files
with
283 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
class ExampleClass | ||
define_method :foo do | ||
'bar' | ||
end | ||
|
||
def define_method(name, &block) | ||
|
||
end | ||
end | ||
|
||
ExampleClass.new.foo # bar |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
require "contract/version" | ||
|
||
autoload :DesignContracts, 'contract/design_contract' | ||
require 'contract/design_contract' | ||
module Contract | ||
# Your code goes here... | ||
end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require 'bundler/setup' | ||
|
||
# require 'rspec' | ||
|
||
require 'contract' | ||
|
||
RSpec.configure do |config| | ||
|
||
end |