Class: Contract
- Inherits:
-
Object
- Object
- Contract
- Defined in:
- lib/obvious/contract.rb
Constant Summary collapse
- @@disable_override =
false
Class Method Summary collapse
-
.contract_for(method, contract) ⇒ Object
Public: Defines a contract for a method.
-
.contract_list ⇒ Object
Provides a default empty array for method_added Overriden by self.contracts.
-
.contracts(*contracts) ⇒ Object
Public: Sets the contracts.
-
.method_added(name) ⇒ Object
This method will move methods defined in @contracts into new methods.
Instance Method Summary collapse
-
#call_method(method, input, input_shape, output_shape) ⇒ Object
This method is used as a shorthand to mak the contract method calling pattern more DRY It starts by checking if you are sending in input and if so will check the input shape for errors.
Class Method Details
.contract_for(method, contract) ⇒ Object
Public: Defines a contract for a method
method - a symbol representing the method name contract - a hash with the keys :input and :output holding the respective shapes.
Examples
class FooJackContract < Contract
contract_for :save, {
:input => Foo.shape,
:output => Foo.shape,
}
end
44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/obvious/contract.rb', line 44 def self.contract_for method, contract method_alias = "#{method}_alias".to_sym method_contract = "#{method}_contract".to_sym define_method method_contract do |*args| input = args[0] call_method method_alias, input, contract[:input], contract[:output] end contracts( *contract_list, method ) end |
.contract_list ⇒ Object
Provides a default empty array for method_added Overriden by self.contracts
6 7 8 |
# File 'lib/obvious/contract.rb', line 6 def self.contract_list [] end |
.contracts(*contracts) ⇒ Object
Public: Sets the contracts
contracts - a list of contracts, as String or as Symbols.
Examples
class FooJackContract < Contract
contracts :save, :get, :list
end
Returns Nothing.
22 23 24 25 26 |
# File 'lib/obvious/contract.rb', line 22 def self.contracts *contracts singleton_class.send :define_method, :contract_list do contracts end end |
.method_added(name) ⇒ Object
This method will move methods defined in @contracts into new methods. Each entry in @contracts will cause the method with the same name to become method_name_alias and for the original method to point to method_name_contract.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/obvious/contract.rb', line 60 def self.method_added name unless @@disable_override self.contract_list.each do |method| if name == method.to_sym method_alias = "#{method}_alias".to_sym method_contract = "#{method}_contract".to_sym @@disable_override = true # to stop the new build method self.send :alias_method, method_alias, name self.send :remove_method, name self.send :alias_method, name, method_contract @@disable_override = false else # puts self.inspect # puts "defining other method #{name}" end end end end |
Instance Method Details
#call_method(method, input, input_shape, output_shape) ⇒ Object
This method is used as a shorthand to mak the contract method calling pattern more DRY It starts by checking if you are sending in input and if so will check the input shape for errors. If no errors are found it calls the method via the passed in symbol(method).
Output checking is more complicated because of the types of output we check for. Nil is never valid output. If we pass in the output shape of true, that means we are looking for result to be the object True. If the output shape is an array, that is actually a shorthand for telling our output check to look at the output as an array and compare it to the shape stored in output_shape. If we pass in the symbol :true_false it means we are looking for the result to be either true or false. The default case will just check if result has the shape of the output_shape.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/obvious/contract.rb', line 92 def call_method method, input, input_shape, output_shape if input != nil && input_shape != nil has_shape, error_field = input.has_shape? input_shape, true unless has_shape raise ContractInputError, "incorrect input data format field #{error_field}" end result = self.send method, input else result = self.send method end # check output # output should never be nil if result == nil raise ContractOutputError, 'incorrect output data format' end if result === {} raise DataNotFoundError, 'data was not found' end # we are looking for result to be a True object if output_shape === true if output_shape == result return result else raise ContractOutputError, 'incorrect output data format' end end # we want to check the shape of each item in the result array if output_shape.class == Array if result.class == Array inner_shape = output_shape[0] result.each do |item| has_shape, error_field = item.has_shape? inner_shape, true unless has_shape raise ContractOutputError, "incorrect output data format field #{error_field}" end end return result end raise ContractOutputError, 'incorrect output data format' end # we want result to be true or false if output_shape == :true_false unless result == true || result == false raise ContractOutputError, 'incorrect output data format' end return result end # we want result to be output_shape's shape has_shape, error_field = result.has_shape? output_shape, true unless has_shape raise ContractOutputError, "incorrect output data format field #{error_field}" end result end |