entitlements 0.1.8 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/bin/deploy-entitlements +10 -1
- data/lib/contracts-ruby2/CHANGELOG.markdown +115 -0
- data/lib/contracts-ruby2/Gemfile +17 -0
- data/lib/contracts-ruby2/LICENSE +23 -0
- data/lib/contracts-ruby2/README.md +108 -0
- data/lib/contracts-ruby2/Rakefile +8 -0
- data/lib/contracts-ruby2/TODO.markdown +6 -0
- data/lib/contracts-ruby2/TUTORIAL.md +773 -0
- data/lib/contracts-ruby2/benchmarks/bench.rb +67 -0
- data/lib/contracts-ruby2/benchmarks/hash.rb +69 -0
- data/lib/contracts-ruby2/benchmarks/invariants.rb +91 -0
- data/lib/contracts-ruby2/benchmarks/io.rb +62 -0
- data/lib/contracts-ruby2/benchmarks/wrap_test.rb +57 -0
- data/lib/contracts-ruby2/contracts.gemspec +17 -0
- data/lib/contracts-ruby2/cucumber.yml +1 -0
- data/lib/contracts-ruby2/dependabot.yml +20 -0
- data/lib/contracts-ruby2/features/README.md +17 -0
- data/lib/contracts-ruby2/features/basics/functype.feature +71 -0
- data/lib/contracts-ruby2/features/basics/pretty-print.feature +241 -0
- data/lib/contracts-ruby2/features/basics/simple_example.feature +210 -0
- data/lib/contracts-ruby2/features/builtin_contracts/README.md +22 -0
- data/lib/contracts-ruby2/features/builtin_contracts/and.feature +103 -0
- data/lib/contracts-ruby2/features/builtin_contracts/any.feature +44 -0
- data/lib/contracts-ruby2/features/builtin_contracts/args.feature +80 -0
- data/lib/contracts-ruby2/features/builtin_contracts/array_of.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/bool.feature +64 -0
- data/lib/contracts-ruby2/features/builtin_contracts/enum.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/eq.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/exactly.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/func.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/hash_of.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/int.feature +93 -0
- data/lib/contracts-ruby2/features/builtin_contracts/keyword_args.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/maybe.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/nat.feature +115 -0
- data/lib/contracts-ruby2/features/builtin_contracts/nat_pos.feature +119 -0
- data/lib/contracts-ruby2/features/builtin_contracts/neg.feature +115 -0
- data/lib/contracts-ruby2/features/builtin_contracts/none.feature +145 -0
- data/lib/contracts-ruby2/features/builtin_contracts/not.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/num.feature +64 -0
- data/lib/contracts-ruby2/features/builtin_contracts/or.feature +83 -0
- data/lib/contracts-ruby2/features/builtin_contracts/pos.feature +116 -0
- data/lib/contracts-ruby2/features/builtin_contracts/range_of.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/respond_to.feature +78 -0
- data/lib/contracts-ruby2/features/builtin_contracts/send.feature +147 -0
- data/lib/contracts-ruby2/features/builtin_contracts/set_of.feature +1 -0
- data/lib/contracts-ruby2/features/builtin_contracts/xor.feature +99 -0
- data/lib/contracts-ruby2/features/support/env.rb +6 -0
- data/lib/contracts-ruby2/lib/contracts/attrs.rb +24 -0
- data/lib/contracts-ruby2/lib/contracts/builtin_contracts.rb +542 -0
- data/lib/contracts-ruby2/lib/contracts/call_with.rb +108 -0
- data/lib/contracts-ruby2/lib/contracts/core.rb +52 -0
- data/lib/contracts-ruby2/lib/contracts/decorators.rb +47 -0
- data/lib/contracts-ruby2/lib/contracts/engine/base.rb +136 -0
- data/lib/contracts-ruby2/lib/contracts/engine/eigenclass.rb +50 -0
- data/lib/contracts-ruby2/lib/contracts/engine/target.rb +70 -0
- data/lib/contracts-ruby2/lib/contracts/engine.rb +26 -0
- data/lib/contracts-ruby2/lib/contracts/errors.rb +71 -0
- data/lib/contracts-ruby2/lib/contracts/formatters.rb +136 -0
- data/lib/contracts-ruby2/lib/contracts/invariants.rb +68 -0
- data/lib/contracts-ruby2/lib/contracts/method_handler.rb +187 -0
- data/lib/contracts-ruby2/lib/contracts/method_reference.rb +100 -0
- data/lib/contracts-ruby2/lib/contracts/support.rb +61 -0
- data/lib/contracts-ruby2/lib/contracts/validators.rb +139 -0
- data/lib/contracts-ruby2/lib/contracts/version.rb +3 -0
- data/lib/contracts-ruby2/lib/contracts.rb +281 -0
- data/lib/contracts-ruby2/script/docs-release +3 -0
- data/lib/contracts-ruby2/script/docs-staging +3 -0
- data/lib/contracts-ruby2/script/rubocop.rb +5 -0
- data/lib/contracts-ruby2/spec/attrs_spec.rb +119 -0
- data/lib/contracts-ruby2/spec/builtin_contracts_spec.rb +461 -0
- data/lib/contracts-ruby2/spec/contracts_spec.rb +770 -0
- data/lib/contracts-ruby2/spec/fixtures/fixtures.rb +730 -0
- data/lib/contracts-ruby2/spec/invariants_spec.rb +17 -0
- data/lib/contracts-ruby2/spec/methods_spec.rb +54 -0
- data/lib/contracts-ruby2/spec/module_spec.rb +18 -0
- data/lib/contracts-ruby2/spec/override_validators_spec.rb +162 -0
- data/lib/contracts-ruby2/spec/ruby_version_specific/contracts_spec_1.9.rb +24 -0
- data/lib/contracts-ruby2/spec/ruby_version_specific/contracts_spec_2.0.rb +55 -0
- data/lib/contracts-ruby2/spec/ruby_version_specific/contracts_spec_2.1.rb +63 -0
- data/lib/contracts-ruby2/spec/spec_helper.rb +102 -0
- data/lib/contracts-ruby2/spec/support.rb +10 -0
- data/lib/contracts-ruby2/spec/support_spec.rb +21 -0
- data/lib/contracts-ruby2/spec/validators_spec.rb +47 -0
- data/lib/contracts-ruby3/CHANGELOG.markdown +117 -0
- data/lib/contracts-ruby3/Gemfile +21 -0
- data/lib/contracts-ruby3/LICENSE +23 -0
- data/lib/contracts-ruby3/README.md +114 -0
- data/lib/contracts-ruby3/Rakefile +10 -0
- data/lib/contracts-ruby3/TODO.markdown +6 -0
- data/lib/contracts-ruby3/TUTORIAL.md +773 -0
- data/lib/contracts-ruby3/benchmarks/bench.rb +67 -0
- data/lib/contracts-ruby3/benchmarks/hash.rb +69 -0
- data/lib/contracts-ruby3/benchmarks/invariants.rb +91 -0
- data/lib/contracts-ruby3/benchmarks/io.rb +62 -0
- data/lib/contracts-ruby3/benchmarks/wrap_test.rb +57 -0
- data/lib/contracts-ruby3/contracts.gemspec +20 -0
- data/lib/contracts-ruby3/cucumber.yml +1 -0
- data/lib/contracts-ruby3/dependabot.yml +20 -0
- data/lib/contracts-ruby3/features/README.md +17 -0
- data/lib/contracts-ruby3/features/basics/functype.feature +71 -0
- data/lib/contracts-ruby3/features/basics/pretty-print.feature +241 -0
- data/lib/contracts-ruby3/features/basics/simple_example.feature +210 -0
- data/lib/contracts-ruby3/features/builtin_contracts/README.md +22 -0
- data/lib/contracts-ruby3/features/builtin_contracts/and.feature +103 -0
- data/lib/contracts-ruby3/features/builtin_contracts/any.feature +44 -0
- data/lib/contracts-ruby3/features/builtin_contracts/args.feature +80 -0
- data/lib/contracts-ruby3/features/builtin_contracts/array_of.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/bool.feature +64 -0
- data/lib/contracts-ruby3/features/builtin_contracts/enum.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/eq.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/exactly.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/func.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/hash_of.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/int.feature +93 -0
- data/lib/contracts-ruby3/features/builtin_contracts/keyword_args.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/maybe.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/nat.feature +115 -0
- data/lib/contracts-ruby3/features/builtin_contracts/nat_pos.feature +119 -0
- data/lib/contracts-ruby3/features/builtin_contracts/neg.feature +115 -0
- data/lib/contracts-ruby3/features/builtin_contracts/none.feature +145 -0
- data/lib/contracts-ruby3/features/builtin_contracts/not.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/num.feature +64 -0
- data/lib/contracts-ruby3/features/builtin_contracts/or.feature +83 -0
- data/lib/contracts-ruby3/features/builtin_contracts/pos.feature +116 -0
- data/lib/contracts-ruby3/features/builtin_contracts/range_of.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/respond_to.feature +78 -0
- data/lib/contracts-ruby3/features/builtin_contracts/send.feature +147 -0
- data/lib/contracts-ruby3/features/builtin_contracts/set_of.feature +1 -0
- data/lib/contracts-ruby3/features/builtin_contracts/xor.feature +99 -0
- data/lib/contracts-ruby3/features/support/env.rb +8 -0
- data/lib/contracts-ruby3/lib/contracts/attrs.rb +26 -0
- data/lib/contracts-ruby3/lib/contracts/builtin_contracts.rb +575 -0
- data/lib/contracts-ruby3/lib/contracts/call_with.rb +119 -0
- data/lib/contracts-ruby3/lib/contracts/core.rb +54 -0
- data/lib/contracts-ruby3/lib/contracts/decorators.rb +50 -0
- data/lib/contracts-ruby3/lib/contracts/engine/base.rb +137 -0
- data/lib/contracts-ruby3/lib/contracts/engine/eigenclass.rb +51 -0
- data/lib/contracts-ruby3/lib/contracts/engine/target.rb +72 -0
- data/lib/contracts-ruby3/lib/contracts/engine.rb +28 -0
- data/lib/contracts-ruby3/lib/contracts/errors.rb +74 -0
- data/lib/contracts-ruby3/lib/contracts/formatters.rb +140 -0
- data/lib/contracts-ruby3/lib/contracts/invariants.rb +72 -0
- data/lib/contracts-ruby3/lib/contracts/method_handler.rb +197 -0
- data/lib/contracts-ruby3/lib/contracts/method_reference.rb +102 -0
- data/lib/contracts-ruby3/lib/contracts/support.rb +63 -0
- data/lib/contracts-ruby3/lib/contracts/validators.rb +143 -0
- data/lib/contracts-ruby3/lib/contracts/version.rb +5 -0
- data/lib/contracts-ruby3/lib/contracts.rb +290 -0
- data/lib/contracts-ruby3/script/docs-release +3 -0
- data/lib/contracts-ruby3/script/docs-staging +3 -0
- data/lib/contracts-ruby3/script/rubocop.rb +5 -0
- data/lib/contracts-ruby3/spec/attrs_spec.rb +119 -0
- data/lib/contracts-ruby3/spec/builtin_contracts_spec.rb +457 -0
- data/lib/contracts-ruby3/spec/contracts_spec.rb +773 -0
- data/lib/contracts-ruby3/spec/fixtures/fixtures.rb +725 -0
- data/lib/contracts-ruby3/spec/invariants_spec.rb +17 -0
- data/lib/contracts-ruby3/spec/methods_spec.rb +54 -0
- data/lib/contracts-ruby3/spec/module_spec.rb +18 -0
- data/lib/contracts-ruby3/spec/override_validators_spec.rb +162 -0
- data/lib/contracts-ruby3/spec/ruby_version_specific/contracts_spec_1.9.rb +24 -0
- data/lib/contracts-ruby3/spec/ruby_version_specific/contracts_spec_2.0.rb +55 -0
- data/lib/contracts-ruby3/spec/ruby_version_specific/contracts_spec_2.1.rb +63 -0
- data/lib/contracts-ruby3/spec/spec_helper.rb +102 -0
- data/lib/contracts-ruby3/spec/support.rb +10 -0
- data/lib/contracts-ruby3/spec/support_spec.rb +21 -0
- data/lib/contracts-ruby3/spec/validators_spec.rb +47 -0
- data/lib/entitlements/data/groups/calculated/yaml.rb +7 -1
- data/lib/entitlements/data/people/yaml.rb +9 -1
- data/lib/entitlements/extras/ldap_group/rules/ldap_group.rb +5 -1
- data/lib/entitlements/extras/orgchart/person_methods.rb +7 -1
- data/lib/entitlements.rb +13 -2
- data/lib/ruby_version_check.rb +17 -0
- metadata +209 -14
@@ -0,0 +1,281 @@
|
|
1
|
+
require "contracts/attrs"
|
2
|
+
require "contracts/builtin_contracts"
|
3
|
+
require "contracts/decorators"
|
4
|
+
require "contracts/errors"
|
5
|
+
require "contracts/formatters"
|
6
|
+
require "contracts/invariants"
|
7
|
+
require "contracts/method_reference"
|
8
|
+
require "contracts/support"
|
9
|
+
require "contracts/engine"
|
10
|
+
require "contracts/method_handler"
|
11
|
+
require "contracts/validators"
|
12
|
+
require "contracts/call_with"
|
13
|
+
require "contracts/core"
|
14
|
+
|
15
|
+
module Contracts
|
16
|
+
def self.included(base)
|
17
|
+
base.send(:include, Core)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.extended(base)
|
21
|
+
base.send(:extend, Core)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# This is the main Contract class. When you write a new contract, you'll
|
26
|
+
# write it as:
|
27
|
+
#
|
28
|
+
# Contract [contract names] => return_value
|
29
|
+
#
|
30
|
+
# This class also provides useful callbacks and a validation method.
|
31
|
+
#
|
32
|
+
# For #make_validator and related logic see file
|
33
|
+
# lib/contracts/validators.rb
|
34
|
+
# For #call_with and related logic see file
|
35
|
+
# lib/contracts/call_with.rb
|
36
|
+
class Contract < Contracts::Decorator
|
37
|
+
extend Contracts::Validators
|
38
|
+
include Contracts::CallWith
|
39
|
+
|
40
|
+
# Default implementation of failure_callback. Provided as a block to be able
|
41
|
+
# to monkey patch #failure_callback only temporary and then switch it back.
|
42
|
+
# First important usage - for specs.
|
43
|
+
DEFAULT_FAILURE_CALLBACK = proc do |data|
|
44
|
+
if data[:return_value]
|
45
|
+
# this failed on the return contract
|
46
|
+
fail ReturnContractError.new(failure_msg(data), data)
|
47
|
+
else
|
48
|
+
# this failed for a param contract
|
49
|
+
fail data[:contracts].failure_exception.new(failure_msg(data), data)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
attr_reader :args_contracts, :ret_contract, :klass, :method
|
54
|
+
def initialize(klass, method, *contracts)
|
55
|
+
unless contracts.last.is_a?(Hash)
|
56
|
+
unless contracts.one?
|
57
|
+
fail %{
|
58
|
+
It looks like your contract for #{method.name} doesn't have a return
|
59
|
+
value. A contract should be written as `Contract arg1, arg2 =>
|
60
|
+
return_value`.
|
61
|
+
}.strip
|
62
|
+
end
|
63
|
+
contracts = [nil => contracts[-1]]
|
64
|
+
end
|
65
|
+
|
66
|
+
# internally we just convert that return value syntax back to an array
|
67
|
+
@args_contracts = contracts[0, contracts.size - 1] + contracts[-1].keys
|
68
|
+
|
69
|
+
@ret_contract = contracts[-1].values[0]
|
70
|
+
|
71
|
+
@args_validators = args_contracts.map do |contract|
|
72
|
+
Contract.make_validator(contract)
|
73
|
+
end
|
74
|
+
|
75
|
+
@args_contract_index = args_contracts.index do |contract|
|
76
|
+
contract.is_a? Contracts::Args
|
77
|
+
end
|
78
|
+
|
79
|
+
@ret_validator = Contract.make_validator(ret_contract)
|
80
|
+
|
81
|
+
@pattern_match = false
|
82
|
+
|
83
|
+
# == @has_proc_contract
|
84
|
+
last_contract = args_contracts.last
|
85
|
+
is_a_proc = last_contract.is_a?(Class) && (last_contract <= Proc || last_contract <= Method)
|
86
|
+
maybe_a_proc = last_contract.is_a?(Contracts::Maybe) && last_contract.include_proc?
|
87
|
+
|
88
|
+
@has_proc_contract = is_a_proc || maybe_a_proc || last_contract.is_a?(Contracts::Func)
|
89
|
+
|
90
|
+
# ====
|
91
|
+
|
92
|
+
# == @has_options_contract
|
93
|
+
last_contract = args_contracts.last
|
94
|
+
penultimate_contract = args_contracts[-2]
|
95
|
+
@has_options_contract = if @has_proc_contract
|
96
|
+
penultimate_contract.is_a?(Hash) || penultimate_contract.is_a?(Contracts::Builtin::KeywordArgs)
|
97
|
+
else
|
98
|
+
last_contract.is_a?(Hash) || last_contract.is_a?(Contracts::Builtin::KeywordArgs)
|
99
|
+
end
|
100
|
+
# ===
|
101
|
+
|
102
|
+
@klass, @method = klass, method
|
103
|
+
end
|
104
|
+
|
105
|
+
def pretty_contract c
|
106
|
+
c.is_a?(Class) ? c.name : c.class.name
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_s
|
110
|
+
args = args_contracts.map { |c| pretty_contract(c) }.join(", ")
|
111
|
+
ret = pretty_contract(ret_contract)
|
112
|
+
("#{args} => #{ret}").gsub("Contracts::Builtin::", "")
|
113
|
+
end
|
114
|
+
|
115
|
+
# Given a hash, prints out a failure message.
|
116
|
+
# This function is used by the default #failure_callback method
|
117
|
+
# and uses the hash passed into the failure_callback method.
|
118
|
+
def self.failure_msg(data)
|
119
|
+
indent_amount = 8
|
120
|
+
method_name = Contracts::Support.method_name(data[:method])
|
121
|
+
|
122
|
+
# Header
|
123
|
+
header = if data[:return_value]
|
124
|
+
"Contract violation for return value:"
|
125
|
+
else
|
126
|
+
"Contract violation for argument #{data[:arg_pos]} of #{data[:total_args]}:"
|
127
|
+
end
|
128
|
+
|
129
|
+
# Expected
|
130
|
+
expected_prefix = "Expected: "
|
131
|
+
expected_value = Contracts::Support.indent_string(
|
132
|
+
Contracts::Formatters::Expected.new(data[:contract]).contract.pretty_inspect,
|
133
|
+
expected_prefix.length
|
134
|
+
).strip
|
135
|
+
expected_line = expected_prefix + expected_value + ","
|
136
|
+
|
137
|
+
# Actual
|
138
|
+
actual_prefix = "Actual: "
|
139
|
+
actual_value = Contracts::Support.indent_string(
|
140
|
+
data[:arg].pretty_inspect,
|
141
|
+
actual_prefix.length
|
142
|
+
).strip
|
143
|
+
actual_line = actual_prefix + actual_value
|
144
|
+
|
145
|
+
# Value guarded in
|
146
|
+
value_prefix = "Value guarded in: "
|
147
|
+
value_value = "#{data[:class]}::#{method_name}"
|
148
|
+
value_line = value_prefix + value_value
|
149
|
+
|
150
|
+
# Contract
|
151
|
+
contract_prefix = "With Contract: "
|
152
|
+
contract_value = data[:contracts].to_s
|
153
|
+
contract_line = contract_prefix + contract_value
|
154
|
+
|
155
|
+
# Position
|
156
|
+
position_prefix = "At: "
|
157
|
+
position_value = Contracts::Support.method_position(data[:method])
|
158
|
+
position_line = position_prefix + position_value
|
159
|
+
|
160
|
+
header +
|
161
|
+
"\n" +
|
162
|
+
Contracts::Support.indent_string(
|
163
|
+
[expected_line,
|
164
|
+
actual_line,
|
165
|
+
value_line,
|
166
|
+
contract_line,
|
167
|
+
position_line].join("\n"),
|
168
|
+
indent_amount
|
169
|
+
)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Callback for when a contract fails. By default it raises
|
173
|
+
# an error and prints detailed info about the contract that
|
174
|
+
# failed. You can also monkeypatch this callback to do whatever
|
175
|
+
# you want...log the error, send you an email, print an error
|
176
|
+
# message, etc.
|
177
|
+
#
|
178
|
+
# Example of monkeypatching:
|
179
|
+
#
|
180
|
+
# def Contract.failure_callback(data)
|
181
|
+
# puts "You had an error!"
|
182
|
+
# puts failure_msg(data)
|
183
|
+
# exit
|
184
|
+
# end
|
185
|
+
def self.failure_callback(data, use_pattern_matching = true)
|
186
|
+
if data[:contracts].pattern_match? && use_pattern_matching
|
187
|
+
return DEFAULT_FAILURE_CALLBACK.call(data)
|
188
|
+
end
|
189
|
+
|
190
|
+
fetch_failure_callback.call(data)
|
191
|
+
end
|
192
|
+
|
193
|
+
# Used to override failure_callback without monkeypatching.
|
194
|
+
#
|
195
|
+
# Takes: block parameter, that should accept one argument - data.
|
196
|
+
#
|
197
|
+
# Example usage:
|
198
|
+
#
|
199
|
+
# Contract.override_failure_callback do |data|
|
200
|
+
# puts "You had an error"
|
201
|
+
# puts failure_msg(data)
|
202
|
+
# exit
|
203
|
+
# end
|
204
|
+
def self.override_failure_callback(&blk)
|
205
|
+
@failure_callback = blk
|
206
|
+
end
|
207
|
+
|
208
|
+
# Used to restore default failure callback
|
209
|
+
def self.restore_failure_callback
|
210
|
+
@failure_callback = DEFAULT_FAILURE_CALLBACK
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.fetch_failure_callback
|
214
|
+
@failure_callback ||= DEFAULT_FAILURE_CALLBACK
|
215
|
+
end
|
216
|
+
|
217
|
+
# Used to verify if an argument satisfies a contract.
|
218
|
+
#
|
219
|
+
# Takes: an argument and a contract.
|
220
|
+
#
|
221
|
+
# Returns: a tuple: [Boolean, metadata]. The boolean indicates
|
222
|
+
# whether the contract was valid or not. If it wasn't, metadata
|
223
|
+
# contains some useful information about the failure.
|
224
|
+
def self.valid?(arg, contract)
|
225
|
+
make_validator(contract)[arg]
|
226
|
+
end
|
227
|
+
|
228
|
+
def [](*args, &blk)
|
229
|
+
call(*args, &blk)
|
230
|
+
end
|
231
|
+
|
232
|
+
def call(*args, &blk)
|
233
|
+
call_with(nil, *args, &blk)
|
234
|
+
end
|
235
|
+
|
236
|
+
# if we specified a proc in the contract but didn't pass one in,
|
237
|
+
# it's possible we are going to pass in a block instead. So lets
|
238
|
+
# append a nil to the list of args just so it doesn't fail.
|
239
|
+
|
240
|
+
# a better way to handle this might be to take this into account
|
241
|
+
# before throwing a "mismatched # of args" error.
|
242
|
+
# returns true if it appended nil
|
243
|
+
def maybe_append_block! args, blk
|
244
|
+
return false unless @has_proc_contract && !blk &&
|
245
|
+
(@args_contract_index || args.size < args_contracts.size)
|
246
|
+
args << nil
|
247
|
+
true
|
248
|
+
end
|
249
|
+
|
250
|
+
# Same thing for when we have named params but didn't pass any in.
|
251
|
+
# returns true if it appended nil
|
252
|
+
def maybe_append_options! args, blk
|
253
|
+
return false unless @has_options_contract
|
254
|
+
if @has_proc_contract && (args_contracts[-2].is_a?(Hash) || args_contracts[-2].is_a?(Contracts::Builtin::KeywordArgs)) && !args[-2].is_a?(Hash)
|
255
|
+
args.insert(-2, {})
|
256
|
+
elsif (args_contracts[-1].is_a?(Hash) || args_contracts[-1].is_a?(Contracts::Builtin::KeywordArgs)) && !args[-1].is_a?(Hash)
|
257
|
+
args << {}
|
258
|
+
end
|
259
|
+
true
|
260
|
+
end
|
261
|
+
|
262
|
+
# Used to determine type of failure exception this contract should raise in case of failure
|
263
|
+
def failure_exception
|
264
|
+
if pattern_match?
|
265
|
+
PatternMatchingError
|
266
|
+
else
|
267
|
+
ParamContractError
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# @private
|
272
|
+
# Used internally to mark contract as pattern matching contract
|
273
|
+
def pattern_match!
|
274
|
+
@pattern_match = true
|
275
|
+
end
|
276
|
+
|
277
|
+
# Used to determine if contract is a pattern matching contract
|
278
|
+
def pattern_match?
|
279
|
+
@pattern_match == true
|
280
|
+
end
|
281
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
RSpec.describe "Contracts:" do
|
2
|
+
describe "Attrs:" do
|
3
|
+
class Person
|
4
|
+
include Contracts::Core
|
5
|
+
include Contracts::Attrs
|
6
|
+
include Contracts::Builtin
|
7
|
+
|
8
|
+
def initialize(name)
|
9
|
+
@name_r = name
|
10
|
+
@name_w = name
|
11
|
+
@name_rw = name
|
12
|
+
|
13
|
+
@name_r_2 = name
|
14
|
+
@name_w_2 = name
|
15
|
+
@name_rw_2 = name
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader_with_contract :name_r, :name_r_2, String
|
19
|
+
attr_writer_with_contract :name_w, :name_w_2, String
|
20
|
+
attr_accessor_with_contract :name_rw, :name_rw_2, String
|
21
|
+
end
|
22
|
+
|
23
|
+
context "attr_reader_with_contract" do
|
24
|
+
it "getting valid type" do
|
25
|
+
expect(Person.new("bob").name_r)
|
26
|
+
.to(eq("bob"))
|
27
|
+
end
|
28
|
+
|
29
|
+
it "getting invalid type" do
|
30
|
+
expect { Person.new(1.3).name_r }
|
31
|
+
.to(raise_error(ReturnContractError))
|
32
|
+
end
|
33
|
+
|
34
|
+
it "getting valid type for second val" do
|
35
|
+
expect(Person.new("bob").name_r_2)
|
36
|
+
.to(eq("bob"))
|
37
|
+
end
|
38
|
+
|
39
|
+
it "getting invalid type for second val" do
|
40
|
+
expect { Person.new(1.3).name_r_2 }
|
41
|
+
.to(raise_error(ReturnContractError))
|
42
|
+
end
|
43
|
+
|
44
|
+
it "setting" do
|
45
|
+
expect { Person.new("bob").name_r = "alice" }
|
46
|
+
.to(raise_error(NoMethodError))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "attr_writer_with_contract" do
|
51
|
+
it "getting" do
|
52
|
+
expect { Person.new("bob").name_w }
|
53
|
+
.to(raise_error(NoMethodError))
|
54
|
+
end
|
55
|
+
|
56
|
+
it "setting valid type" do
|
57
|
+
expect(Person.new("bob").name_w = "alice")
|
58
|
+
.to(eq("alice"))
|
59
|
+
end
|
60
|
+
|
61
|
+
it "setting invalid type" do
|
62
|
+
expect { Person.new("bob").name_w = 1.2 }
|
63
|
+
.to(raise_error(ParamContractError))
|
64
|
+
end
|
65
|
+
|
66
|
+
it "setting valid type for second val" do
|
67
|
+
expect(Person.new("bob").name_w_2 = "alice")
|
68
|
+
.to(eq("alice"))
|
69
|
+
end
|
70
|
+
|
71
|
+
it "setting invalid type for second val" do
|
72
|
+
expect { Person.new("bob").name_w_2 = 1.2 }
|
73
|
+
.to(raise_error(ParamContractError))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "attr_accessor_with_contract" do
|
78
|
+
it "getting valid type" do
|
79
|
+
expect(Person.new("bob").name_rw)
|
80
|
+
.to(eq("bob"))
|
81
|
+
end
|
82
|
+
|
83
|
+
it "getting invalid type" do
|
84
|
+
expect { Person.new(1.2).name_rw }
|
85
|
+
.to(raise_error(ReturnContractError))
|
86
|
+
end
|
87
|
+
|
88
|
+
it "setting valid type" do
|
89
|
+
expect(Person.new("bob").name_rw = "alice")
|
90
|
+
.to(eq("alice"))
|
91
|
+
end
|
92
|
+
|
93
|
+
it "setting invalid type" do
|
94
|
+
expect { Person.new("bob").name_rw = 1.2 }
|
95
|
+
.to(raise_error(ParamContractError))
|
96
|
+
end
|
97
|
+
|
98
|
+
it "getting valid type for second val" do
|
99
|
+
expect(Person.new("bob").name_rw_2)
|
100
|
+
.to(eq("bob"))
|
101
|
+
end
|
102
|
+
|
103
|
+
it "getting invalid type for second val" do
|
104
|
+
expect { Person.new(1.2).name_rw_2 }
|
105
|
+
.to(raise_error(ReturnContractError))
|
106
|
+
end
|
107
|
+
|
108
|
+
it "setting valid type for second val" do
|
109
|
+
expect(Person.new("bob").name_rw_2 = "alice")
|
110
|
+
.to(eq("alice"))
|
111
|
+
end
|
112
|
+
|
113
|
+
it "setting invalid type for second val" do
|
114
|
+
expect { Person.new("bob").name_rw_2 = 1.2 }
|
115
|
+
.to(raise_error(ParamContractError))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|