Module: Contracts::ClassMethods
- Defined in:
- lib/contracts.rb
Instance Method Summary collapse
- #contract(name = nil, **options, &block) ⇒ Object
- #declare_contract(name, type, options, source_location: caller_locations(2, 1).first, &block) ⇒ Object
- #invariant(description = "invariant", &block) ⇒ Object
- #merge_parent_contract!(contract) ⇒ Object
- #method_added(name) ⇒ Object
- #snapshot(&block) ⇒ Object
- #wrap_contract(name, contract) ⇒ Object
- #wrap_initialize_for_invariants ⇒ Object
Instance Method Details
#contract(name = nil, **options, &block) ⇒ Object
917 918 919 920 921 922 |
# File 'lib/contracts.rb', line 917 def contract(name = nil, **, &block) if name.nil? then @__contracts_pending = [, block, caller_locations(1, 1).first] return end declare_contract(name, :instance, , &block) end |
#declare_contract(name, type, options, source_location: caller_locations(2, 1).first, &block) ⇒ Object
956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 |
# File 'lib/contracts.rb', line 956 def declare_contract(name, type, , source_location: caller_locations(2, 1).first, &block) contract = Contract.new(owner: self, method_name: name, method_type: type, source_location: source_location, options: ) ContractBuilder.new(contract).instance_eval(&block) if block merge_parent_contract!(contract) unless Contracts.configuration.inheritance_mode == :independent if contract.snapshot_block.nil? && @__contracts_snapshot contract.instance_variable_set(:@snapshot_block, @__contracts_snapshot) end Contracts.registry.register(contract) wrap_contract(name, contract) if method_defined?(name, false) || private_method_defined?(name, false) || protected_method_defined?( name, false ) contract end |
#invariant(description = "invariant", &block) ⇒ Object
924 925 926 927 928 929 930 931 932 933 934 935 936 |
# File 'lib/contracts.rb', line 924 def invariant(description = "invariant", &block) location = caller_locations(1, 1).first contract = Contracts.registry.find(self, :__invariant__) || Contract.new(owner: self, method_name: :__invariant__, source_location: location) contract.invariants << Invariant.new(id: "#{name || object_id}:#{caller_locations(1, 1).first.lineno}", owner: self, description: description, predicate: block, source_location: caller_locations(1, 1).first, options: {}) Contracts.registry.register(contract) @__contracts_has_invariants = true wrap_initialize_for_invariants if method_defined?(:initialize, false) || private_method_defined?(:initialize, false) end |
#merge_parent_contract!(contract) ⇒ Object
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 |
# File 'lib/contracts.rb', line 975 def merge_parent_contract!(contract) parent = ancestors.drop(1).lazy.map do |ancestor| Contracts.registry.for_class(ancestor).find do |candidate| candidate.method_name == contract.method_name && candidate.method_type == contract.method_type end end.find(&:itself) return unless parent if Contracts.configuration.inheritance_mode == :strict parent.parameters.each do |name, constraint| child = contract.parameters[name] if child && child.description != constraint.description raise InheritanceViolation.new(owner: self, method_name: contract.method_name, contract_type: :inheritance, description: "parameter #{name} changes parent constraint #{constraint.description}") end end end contract.parameters = parent.parameters.merge(contract.parameters) unless parent.parameters.empty? contract.positionals = parent.positionals if contract.positionals.empty? contract.preconditions.unshift(*parent.preconditions) contract.postconditions.unshift(*parent.postconditions) contract.return_constraint = parent.return_constraint unless contract.return_constraint contract.allowed_exceptions.unshift(*parent.allowed_exceptions) contract.observed.unshift(*parent.observed.reject do |observation| contract.observed.any? do |own| own.name == observation.name end end) end |
#method_added(name) ⇒ Object
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 |
# File 'lib/contracts.rb', line 940 def method_added(name) return if @__contracts_hook if (pending = @__contracts_pending) @__contracts_pending = nil declare_contract(name, :instance, pending[0], source_location: pending[2], &pending[1]) elsif (contract = Contracts.registry.find(self, name, method_type: :instance)) && contract.owner == self wrap_contract(name, contract) elsif (contract = Contracts.registry.find(self, name, method_type: :singleton)) && contract.owner == self wrap_contract(name, contract) end wrap_initialize_for_invariants if name == :initialize && @__contracts_has_invariants super end |
#snapshot(&block) ⇒ Object
938 |
# File 'lib/contracts.rb', line 938 def snapshot(&block) = (@__contracts_snapshot = block) |
#wrap_contract(name, contract) ⇒ Object
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 |
# File 'lib/contracts.rb', line 1005 def wrap_contract(name, contract) return if contract.instance_variable_defined?(:@wrapped) original = instance_method(name) contract.method_source_location = original.source_location visibility = if private_method_defined?(name) :private else protected_method_defined?(name) ? :protected : :public end @__contracts_hook = true define_method(name) do |*args, **kwargs, &block| Contracts.invoke(self, contract, args, kwargs, block) do original.bind_call(self, *args, **kwargs, &block) end end send(visibility, name) contract.instance_variable_set(:@wrapped, true) ensure @__contracts_hook = false end |
#wrap_initialize_for_invariants ⇒ Object
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 |
# File 'lib/contracts.rb', line 1028 def wrap_initialize_for_invariants return if @__contracts_initialize_wrapped original = instance_method(:initialize) @__contracts_hook = true define_method(:initialize) do |*args, **kwargs, &block| original.bind_call(self, *args, **kwargs, &block).tap do Contracts.check_invariants!(self) if Contracts.configuration.check_invariants_after_initialize && Contracts.configuration.invariant_checking != :disabled end end private :initialize @__contracts_initialize_wrapped = true ensure @__contracts_hook = false end |