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
825 826 827 828 829 830 |
# File 'lib/contracts.rb', line 825 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
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 |
# File 'lib/contracts.rb', line 864 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
832 833 834 835 836 837 838 839 840 841 842 843 844 |
# File 'lib/contracts.rb', line 832 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
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 |
# File 'lib/contracts.rb', line 883 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
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 |
# File 'lib/contracts.rb', line 848 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
846 |
# File 'lib/contracts.rb', line 846 def snapshot(&block) = (@__contracts_snapshot = block) |
#wrap_contract(name, contract) ⇒ Object
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 |
# File 'lib/contracts.rb', line 913 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
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 |
# File 'lib/contracts.rb', line 936 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 |