contracts 0.9 → 0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.markdown +5 -2
 - data/TUTORIAL.md +136 -21
 - data/benchmarks/hash.rb +69 -0
 - data/lib/contracts.rb +20 -156
 - data/lib/contracts/builtin_contracts.rb +100 -3
 - data/lib/contracts/call_with.rb +96 -0
 - data/lib/contracts/decorators.rb +4 -194
 - data/lib/contracts/engine.rb +26 -0
 - data/lib/contracts/engine/base.rb +136 -0
 - data/lib/contracts/engine/eigenclass.rb +46 -0
 - data/lib/contracts/engine/target.rb +68 -0
 - data/lib/contracts/method_handler.rb +195 -0
 - data/lib/contracts/support.rb +45 -30
 - data/lib/contracts/validators.rb +127 -0
 - data/lib/contracts/version.rb +1 -1
 - data/spec/builtin_contracts_spec.rb +78 -2
 - data/spec/contracts_spec.rb +64 -1
 - data/spec/fixtures/fixtures.rb +77 -5
 - data/spec/override_validators_spec.rb +162 -0
 - data/spec/ruby_version_specific/contracts_spec_2.1.rb +10 -2
 - metadata +12 -6
 - data/lib/contracts/eigenclass.rb +0 -38
 - data/lib/contracts/modules.rb +0 -17
 
    
        data/lib/contracts/support.rb
    CHANGED
    
    | 
         @@ -1,44 +1,59 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Contracts
         
     | 
| 
       2 
2 
     | 
    
         
             
              module Support
         
     | 
| 
       3 
     | 
    
         
            -
                 
     | 
| 
       4 
     | 
    
         
            -
                   
     | 
| 
      
 3 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def method_position(method)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    return method.method_position if method.is_a?(MethodReference)
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
      
 7 
     | 
    
         
            +
                    if RUBY_VERSION =~ /^1\.8/
         
     | 
| 
      
 8 
     | 
    
         
            +
                      if method.respond_to?(:__file__)
         
     | 
| 
      
 9 
     | 
    
         
            +
                        method.__file__ + ":" + method.__line__.to_s
         
     | 
| 
      
 10 
     | 
    
         
            +
                      else
         
     | 
| 
      
 11 
     | 
    
         
            +
                        method.inspect
         
     | 
| 
      
 12 
     | 
    
         
            +
                      end
         
     | 
| 
       9 
13 
     | 
    
         
             
                    else
         
     | 
| 
       10 
     | 
    
         
            -
                      method. 
     | 
| 
      
 14 
     | 
    
         
            +
                      file, line = method.source_location
         
     | 
| 
      
 15 
     | 
    
         
            +
                      file + ":" + line.to_s
         
     | 
| 
       11 
16 
     | 
    
         
             
                    end
         
     | 
| 
       12 
     | 
    
         
            -
                  else
         
     | 
| 
       13 
     | 
    
         
            -
                    file, line = method.source_location
         
     | 
| 
       14 
     | 
    
         
            -
                    file + ":" + line.to_s
         
     | 
| 
       15 
17 
     | 
    
         
             
                  end
         
     | 
| 
       16 
     | 
    
         
            -
                end
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def method_name(method)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    method.is_a?(Proc) ? "Proc" : method.name
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
       21 
22 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 23 
     | 
    
         
            +
                  # Generates unique id, which can be used as a part of identifier
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #
         
     | 
| 
      
 25 
     | 
    
         
            +
                  # Example:
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #    Contracts::Support.unique_id   # => "i53u6tiw5hbo"
         
     | 
| 
      
 27 
     | 
    
         
            +
                  def unique_id
         
     | 
| 
      
 28 
     | 
    
         
            +
                    # Consider using SecureRandom.hex here, and benchmark which one is better
         
     | 
| 
      
 29 
     | 
    
         
            +
                    (Time.now.to_f * 1000).to_i.to_s(36) + rand(1_000_000).to_s(36)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
       30 
31 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
                   
     | 
| 
       34 
     | 
    
         
            -
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
                  def contract_id(contract)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    contract.object_id
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
      
 36 
     | 
    
         
            +
                  def eigenclass_hierarchy_supported?
         
     | 
| 
      
 37 
     | 
    
         
            +
                    return false if RUBY_PLATFORM == "java" && RUBY_VERSION.to_f < 2.0
         
     | 
| 
      
 38 
     | 
    
         
            +
                    RUBY_VERSION.to_f > 1.8
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def eigenclass_of(target)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    class << target; self; end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
       39 
44 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def eigenclass?(target)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    module_eigenclass?(target) ||
         
     | 
| 
      
 47 
     | 
    
         
            +
                      target <= eigenclass_of(Object)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  private
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  # Module eigenclass can be detected by its ancestor chain
         
     | 
| 
      
 53 
     | 
    
         
            +
                  # containing a Module
         
     | 
| 
      
 54 
     | 
    
         
            +
                  def module_eigenclass?(target)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    target < Module
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
       42 
57 
     | 
    
         
             
                end
         
     | 
| 
       43 
58 
     | 
    
         
             
              end
         
     | 
| 
       44 
59 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,127 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Contracts
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Validators
         
     | 
| 
      
 3 
     | 
    
         
            +
                DEFAULT_VALIDATOR_STRATEGIES = {
         
     | 
| 
      
 4 
     | 
    
         
            +
                  # e.g. lambda {true}
         
     | 
| 
      
 5 
     | 
    
         
            +
                  Proc => lambda { |contract| contract },
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  # e.g. [Num, String]
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # TODO: account for these errors too
         
     | 
| 
      
 9 
     | 
    
         
            +
                  Array => lambda do |contract|
         
     | 
| 
      
 10 
     | 
    
         
            +
                    lambda do |arg|
         
     | 
| 
      
 11 
     | 
    
         
            +
                      return false unless arg.is_a?(Array) && arg.length == contract.length
         
     | 
| 
      
 12 
     | 
    
         
            +
                      arg.zip(contract).all? do |_arg, _contract|
         
     | 
| 
      
 13 
     | 
    
         
            +
                        Contract.valid?(_arg, _contract)
         
     | 
| 
      
 14 
     | 
    
         
            +
                      end
         
     | 
| 
      
 15 
     | 
    
         
            +
                    end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end,
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  # e.g. { :a => Num, :b => String }
         
     | 
| 
      
 19 
     | 
    
         
            +
                  Hash => lambda do |contract|
         
     | 
| 
      
 20 
     | 
    
         
            +
                    lambda do |arg|
         
     | 
| 
      
 21 
     | 
    
         
            +
                      return false unless arg.is_a?(Hash)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      contract.keys.all? do |k|
         
     | 
| 
      
 23 
     | 
    
         
            +
                        Contract.valid?(arg[k], contract[k])
         
     | 
| 
      
 24 
     | 
    
         
            +
                      end
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end,
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  Contracts::Args => lambda do |contract|
         
     | 
| 
      
 29 
     | 
    
         
            +
                    lambda do |arg|
         
     | 
| 
      
 30 
     | 
    
         
            +
                      Contract.valid?(arg, contract.contract)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end,
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  Contracts::Func => lambda do |_|
         
     | 
| 
      
 35 
     | 
    
         
            +
                    lambda do |arg|
         
     | 
| 
      
 36 
     | 
    
         
            +
                      arg.is_a?(Method) || arg.is_a?(Proc)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end,
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  :valid => lambda do |contract|
         
     | 
| 
      
 41 
     | 
    
         
            +
                    lambda { |arg| contract.valid?(arg) }
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end,
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  :class => lambda do |contract|
         
     | 
| 
      
 45 
     | 
    
         
            +
                    lambda { |arg| arg.is_a?(contract) }
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end,
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  :default => lambda do |contract|
         
     | 
| 
      
 49 
     | 
    
         
            +
                    lambda { |arg| contract == arg }
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                }.freeze
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                # Allows to override validator with custom one.
         
     | 
| 
      
 54 
     | 
    
         
            +
                # Example:
         
     | 
| 
      
 55 
     | 
    
         
            +
                #   Contract.override_validator(Array) do |contract|
         
     | 
| 
      
 56 
     | 
    
         
            +
                #     lambda do |arg|
         
     | 
| 
      
 57 
     | 
    
         
            +
                #       # .. implementation for Array contract ..
         
     | 
| 
      
 58 
     | 
    
         
            +
                #     end
         
     | 
| 
      
 59 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 60 
     | 
    
         
            +
                #
         
     | 
| 
      
 61 
     | 
    
         
            +
                #   Contract.override_validator(:class) do |contract|
         
     | 
| 
      
 62 
     | 
    
         
            +
                #     lambda do |arg|
         
     | 
| 
      
 63 
     | 
    
         
            +
                #       arg.is_a?(contract) || arg.is_a?(RSpec::Mocks::Double)
         
     | 
| 
      
 64 
     | 
    
         
            +
                #     end
         
     | 
| 
      
 65 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 66 
     | 
    
         
            +
                def override_validator(name, &block)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  validator_strategies[name] = block
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                # This is a little weird. For each contract
         
     | 
| 
      
 71 
     | 
    
         
            +
                # we pre-make a proc to validate it so we
         
     | 
| 
      
 72 
     | 
    
         
            +
                # don't have to go through this decision tree every time.
         
     | 
| 
      
 73 
     | 
    
         
            +
                # Seems silly but it saves us a bunch of time (4.3sec vs 5.2sec)
         
     | 
| 
      
 74 
     | 
    
         
            +
                def make_validator!(contract)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  klass = contract.class
         
     | 
| 
      
 76 
     | 
    
         
            +
                  key = if validator_strategies.key?(klass)
         
     | 
| 
      
 77 
     | 
    
         
            +
                          klass
         
     | 
| 
      
 78 
     | 
    
         
            +
                        else
         
     | 
| 
      
 79 
     | 
    
         
            +
                          if contract.respond_to? :valid?
         
     | 
| 
      
 80 
     | 
    
         
            +
                            :valid
         
     | 
| 
      
 81 
     | 
    
         
            +
                          elsif klass == Class || klass == Module
         
     | 
| 
      
 82 
     | 
    
         
            +
                            :class
         
     | 
| 
      
 83 
     | 
    
         
            +
                          else
         
     | 
| 
      
 84 
     | 
    
         
            +
                            :default
         
     | 
| 
      
 85 
     | 
    
         
            +
                          end
         
     | 
| 
      
 86 
     | 
    
         
            +
                        end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  validator_strategies[key].call(contract)
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                def make_validator(contract)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  contract_id = Support.contract_id(contract)
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  if memoized_validators.key?(contract_id)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    return memoized_validators[contract_id]
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  memoized_validators[contract_id] = make_validator!(contract)
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 102 
     | 
    
         
            +
                def reset_validators
         
     | 
| 
      
 103 
     | 
    
         
            +
                  clean_memoized_validators
         
     | 
| 
      
 104 
     | 
    
         
            +
                  restore_validators
         
     | 
| 
      
 105 
     | 
    
         
            +
                end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 108 
     | 
    
         
            +
                def validator_strategies
         
     | 
| 
      
 109 
     | 
    
         
            +
                  @_validator_strategies ||= restore_validators
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 113 
     | 
    
         
            +
                def restore_validators
         
     | 
| 
      
 114 
     | 
    
         
            +
                  @_validator_strategies = DEFAULT_VALIDATOR_STRATEGIES.dup
         
     | 
| 
      
 115 
     | 
    
         
            +
                end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 118 
     | 
    
         
            +
                def memoized_validators
         
     | 
| 
      
 119 
     | 
    
         
            +
                  @_memoized_validators ||= clean_memoized_validators
         
     | 
| 
      
 120 
     | 
    
         
            +
                end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 123 
     | 
    
         
            +
                def clean_memoized_validators
         
     | 
| 
      
 124 
     | 
    
         
            +
                  @_memoized_validators = {}
         
     | 
| 
      
 125 
     | 
    
         
            +
                end
         
     | 
| 
      
 126 
     | 
    
         
            +
              end
         
     | 
| 
      
 127 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/contracts/version.rb
    CHANGED
    
    
| 
         @@ -12,14 +12,18 @@ RSpec.describe "Contracts:" do 
     | 
|
| 
       12 
12 
     | 
    
         
             
                  expect { @o.double(2.2) }.to_not raise_error
         
     | 
| 
       13 
13 
     | 
    
         
             
                end
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
                it "should fail for  
     | 
| 
       16 
     | 
    
         
            -
                  expect { @o.double( 
     | 
| 
      
 15 
     | 
    
         
            +
                it "should fail for nil and other data types" do
         
     | 
| 
      
 16 
     | 
    
         
            +
                  expect { @o.double(nil) }.to raise_error(ContractError)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  expect { @o.double(:x)  }.to raise_error(ContractError)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  expect { @o.double("x") }.to raise_error(ContractError)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  expect { @o.double(/x/) }.to raise_error(ContractError)
         
     | 
| 
       17 
20 
     | 
    
         
             
                end
         
     | 
| 
       18 
21 
     | 
    
         
             
              end
         
     | 
| 
       19 
22 
     | 
    
         | 
| 
       20 
23 
     | 
    
         
             
              describe "Pos:" do
         
     | 
| 
       21 
24 
     | 
    
         
             
                it "should pass for positive numbers" do
         
     | 
| 
       22 
25 
     | 
    
         
             
                  expect { @o.pos_test(1) }.to_not raise_error
         
     | 
| 
      
 26 
     | 
    
         
            +
                  expect { @o.pos_test(1.6) }.to_not raise_error
         
     | 
| 
       23 
27 
     | 
    
         
             
                end
         
     | 
| 
       24 
28 
     | 
    
         | 
| 
       25 
29 
     | 
    
         
             
                it "should fail for 0" do
         
     | 
| 
         @@ -28,12 +32,21 @@ RSpec.describe "Contracts:" do 
     | 
|
| 
       28 
32 
     | 
    
         | 
| 
       29 
33 
     | 
    
         
             
                it "should fail for negative numbers" do
         
     | 
| 
       30 
34 
     | 
    
         
             
                  expect { @o.pos_test(-1) }.to raise_error(ContractError)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  expect { @o.pos_test(-1.6) }.to raise_error(ContractError)
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                it "should fail for nil and other data types" do
         
     | 
| 
      
 39 
     | 
    
         
            +
                  expect { @o.pos_test(nil) }.to raise_error(ContractError)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  expect { @o.pos_test(:x)  }.to raise_error(ContractError)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  expect { @o.pos_test("x") }.to raise_error(ContractError)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  expect { @o.pos_test(/x/) }.to raise_error(ContractError)
         
     | 
| 
       31 
43 
     | 
    
         
             
                end
         
     | 
| 
       32 
44 
     | 
    
         
             
              end
         
     | 
| 
       33 
45 
     | 
    
         | 
| 
       34 
46 
     | 
    
         
             
              describe "Neg:" do
         
     | 
| 
       35 
47 
     | 
    
         
             
                it "should pass for negative numbers" do
         
     | 
| 
       36 
48 
     | 
    
         
             
                  expect { @o.neg_test(-1) }.to_not raise_error
         
     | 
| 
      
 49 
     | 
    
         
            +
                  expect { @o.neg_test(-1.6) }.to_not raise_error
         
     | 
| 
       37 
50 
     | 
    
         
             
                end
         
     | 
| 
       38 
51 
     | 
    
         | 
| 
       39 
52 
     | 
    
         
             
                it "should fail for 0" do
         
     | 
| 
         @@ -42,6 +55,14 @@ RSpec.describe "Contracts:" do 
     | 
|
| 
       42 
55 
     | 
    
         | 
| 
       43 
56 
     | 
    
         
             
                it "should fail for positive numbers" do
         
     | 
| 
       44 
57 
     | 
    
         
             
                  expect { @o.neg_test(1) }.to raise_error(ContractError)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  expect { @o.neg_test(1.6) }.to raise_error(ContractError)
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                it "should fail for nil and other data types" do
         
     | 
| 
      
 62 
     | 
    
         
            +
                  expect { @o.neg_test(nil) }.to raise_error(ContractError)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  expect { @o.neg_test(:x)  }.to raise_error(ContractError)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  expect { @o.neg_test("x") }.to raise_error(ContractError)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  expect { @o.neg_test(/x/) }.to raise_error(ContractError)
         
     | 
| 
       45 
66 
     | 
    
         
             
                end
         
     | 
| 
       46 
67 
     | 
    
         
             
              end
         
     | 
| 
       47 
68 
     | 
    
         | 
| 
         @@ -60,6 +81,14 @@ RSpec.describe "Contracts:" do 
     | 
|
| 
       60 
81 
     | 
    
         | 
| 
       61 
82 
     | 
    
         
             
                it "should fail for negative numbers" do
         
     | 
| 
       62 
83 
     | 
    
         
             
                  expect { @o.nat_test(-1) }.to raise_error(ContractError)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  expect { @o.nat_test(-1.6) }.to raise_error(ContractError)
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                it "should fail for nil and other data types" do
         
     | 
| 
      
 88 
     | 
    
         
            +
                  expect { @o.nat_test(nil) }.to raise_error(ContractError)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  expect { @o.nat_test(:x)  }.to raise_error(ContractError)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  expect { @o.nat_test("x") }.to raise_error(ContractError)
         
     | 
| 
      
 91 
     | 
    
         
            +
                  expect { @o.nat_test(/x/) }.to raise_error(ContractError)
         
     | 
| 
       63 
92 
     | 
    
         
             
                end
         
     | 
| 
       64 
93 
     | 
    
         
             
              end
         
     | 
| 
       65 
94 
     | 
    
         | 
| 
         @@ -215,6 +244,45 @@ RSpec.describe "Contracts:" do 
     | 
|
| 
       215 
244 
     | 
    
         
             
                end
         
     | 
| 
       216 
245 
     | 
    
         
             
              end
         
     | 
| 
       217 
246 
     | 
    
         | 
| 
      
 247 
     | 
    
         
            +
              describe "RangeOf:" do
         
     | 
| 
      
 248 
     | 
    
         
            +
                require "date"
         
     | 
| 
      
 249 
     | 
    
         
            +
                it "should pass for a range of nums" do
         
     | 
| 
      
 250 
     | 
    
         
            +
                  expect { @o.first_in_range_num(3..10) }.to_not raise_error
         
     | 
| 
      
 251 
     | 
    
         
            +
                end
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
                it "should pass for a range of dates" do
         
     | 
| 
      
 254 
     | 
    
         
            +
                  d1 = Date.today
         
     | 
| 
      
 255 
     | 
    
         
            +
                  d2 = d1 + 18
         
     | 
| 
      
 256 
     | 
    
         
            +
                  expect { @o.first_in_range_date(d1..d2) }.to_not raise_error
         
     | 
| 
      
 257 
     | 
    
         
            +
                end
         
     | 
| 
      
 258 
     | 
    
         
            +
             
     | 
| 
      
 259 
     | 
    
         
            +
                it "should fail for a non-range" do
         
     | 
| 
      
 260 
     | 
    
         
            +
                  expect { @o.first_in_range_num("foo") }.to raise_error(ContractError)
         
     | 
| 
      
 261 
     | 
    
         
            +
                  expect { @o.first_in_range_num(:foo) }.to raise_error(ContractError)
         
     | 
| 
      
 262 
     | 
    
         
            +
                  expect { @o.first_in_range_num(5) }.to raise_error(ContractError)
         
     | 
| 
      
 263 
     | 
    
         
            +
                  expect { @o.first_in_range_num(nil) }.to raise_error(ContractError)
         
     | 
| 
      
 264 
     | 
    
         
            +
                end
         
     | 
| 
      
 265 
     | 
    
         
            +
             
     | 
| 
      
 266 
     | 
    
         
            +
                it "should fail for a range with incorrect data type" do
         
     | 
| 
      
 267 
     | 
    
         
            +
                  expect { @o.first_in_range_num("a".."z") }.to raise_error(ContractError)
         
     | 
| 
      
 268 
     | 
    
         
            +
                end
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
                it "should fail for a badly-defined range" do
         
     | 
| 
      
 271 
     | 
    
         
            +
                  # For some reason, Ruby 2.0.0 allows (date .. number) as a range.
         
     | 
| 
      
 272 
     | 
    
         
            +
                  # Perhaps other Ruby versions do too.
         
     | 
| 
      
 273 
     | 
    
         
            +
                  # Note that (date .. string) gives ArgumentError.
         
     | 
| 
      
 274 
     | 
    
         
            +
                  # This test guards against ranges with inconsistent data types.
         
     | 
| 
      
 275 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 276 
     | 
    
         
            +
                    d1 = Date.today
         
     | 
| 
      
 277 
     | 
    
         
            +
                    expect { @o.first_in_range_date(d1..10).to raise_error(ContractError) }
         
     | 
| 
      
 278 
     | 
    
         
            +
                    expect { @o.first_in_range_num(d1..10).to raise_error(ContractError) }
         
     | 
| 
      
 279 
     | 
    
         
            +
                  rescue ArgumentError
         
     | 
| 
      
 280 
     | 
    
         
            +
                    # If Ruby doesn't like the range, we ignore the test.
         
     | 
| 
      
 281 
     | 
    
         
            +
                    :nop
         
     | 
| 
      
 282 
     | 
    
         
            +
                  end
         
     | 
| 
      
 283 
     | 
    
         
            +
                end
         
     | 
| 
      
 284 
     | 
    
         
            +
              end
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
       218 
286 
     | 
    
         
             
              describe "SetOf:" do
         
     | 
| 
       219 
287 
     | 
    
         
             
                it "should pass for a set of nums" do
         
     | 
| 
       220 
288 
     | 
    
         
             
                  expect { @o.product_from_set(Set.new([1, 2, 3])) }.to_not raise_error
         
     | 
| 
         @@ -254,6 +322,14 @@ RSpec.describe "Contracts:" do 
     | 
|
| 
       254 
322 
     | 
    
         
             
                end
         
     | 
| 
       255 
323 
     | 
    
         
             
              end
         
     | 
| 
       256 
324 
     | 
    
         | 
| 
      
 325 
     | 
    
         
            +
              describe "Optional:" do
         
     | 
| 
      
 326 
     | 
    
         
            +
                it "can't be used outside of KeywordArgs" do
         
     | 
| 
      
 327 
     | 
    
         
            +
                  expect do
         
     | 
| 
      
 328 
     | 
    
         
            +
                    BareOptionalContractUsed.new.something(3, 5)
         
     | 
| 
      
 329 
     | 
    
         
            +
                  end.to raise_error(ArgumentError, Contracts::Optional::UNABLE_TO_USE_OUTSIDE_OF_OPT_HASH)
         
     | 
| 
      
 330 
     | 
    
         
            +
                end
         
     | 
| 
      
 331 
     | 
    
         
            +
              end
         
     | 
| 
      
 332 
     | 
    
         
            +
             
     | 
| 
       257 
333 
     | 
    
         
             
              describe "HashOf:" do
         
     | 
| 
       258 
334 
     | 
    
         
             
                it "doesn't allow to specify multiple key-value pairs with pretty syntax" do
         
     | 
| 
       259 
335 
     | 
    
         
             
                  expect do
         
     | 
    
        data/spec/contracts_spec.rb
    CHANGED
    
    | 
         @@ -250,7 +250,6 @@ RSpec.describe "Contracts:" do 
     | 
|
| 
       250 
250 
     | 
    
         
             
                let(:mod) do
         
     | 
| 
       251 
251 
     | 
    
         
             
                  Module.new do
         
     | 
| 
       252 
252 
     | 
    
         
             
                    include Contracts
         
     | 
| 
       253 
     | 
    
         
            -
                    include Contracts::Modules
         
     | 
| 
       254 
253 
     | 
    
         | 
| 
       255 
254 
     | 
    
         
             
                    Contract String => String
         
     | 
| 
       256 
255 
     | 
    
         
             
                    def greeting(name)
         
     | 
| 
         @@ -404,6 +403,26 @@ RSpec.describe "Contracts:" do 
     | 
|
| 
       404 
403 
     | 
    
         
             
                    @o.double_with_proc(4)
         
     | 
| 
       405 
404 
     | 
    
         
             
                  end.to raise_error(ContractError, /Actual: nil/)
         
     | 
| 
       406 
405 
     | 
    
         
             
                end
         
     | 
| 
      
 406 
     | 
    
         
            +
             
     | 
| 
      
 407 
     | 
    
         
            +
                it "should succeed for maybe proc with no proc" do
         
     | 
| 
      
 408 
     | 
    
         
            +
                  expect do
         
     | 
| 
      
 409 
     | 
    
         
            +
                    @o.maybe_call(5)
         
     | 
| 
      
 410 
     | 
    
         
            +
                  end.to_not raise_error
         
     | 
| 
      
 411 
     | 
    
         
            +
                end
         
     | 
| 
      
 412 
     | 
    
         
            +
             
     | 
| 
      
 413 
     | 
    
         
            +
                it "should succeed for maybe proc with proc" do
         
     | 
| 
      
 414 
     | 
    
         
            +
                  expect do
         
     | 
| 
      
 415 
     | 
    
         
            +
                    @o.maybe_call(5) do
         
     | 
| 
      
 416 
     | 
    
         
            +
                      2 + 2
         
     | 
| 
      
 417 
     | 
    
         
            +
                    end
         
     | 
| 
      
 418 
     | 
    
         
            +
                  end.to_not raise_error
         
     | 
| 
      
 419 
     | 
    
         
            +
                end
         
     | 
| 
      
 420 
     | 
    
         
            +
             
     | 
| 
      
 421 
     | 
    
         
            +
                it "should fail for maybe proc with invalid input" do
         
     | 
| 
      
 422 
     | 
    
         
            +
                  expect do
         
     | 
| 
      
 423 
     | 
    
         
            +
                    @o.maybe_call("bad")
         
     | 
| 
      
 424 
     | 
    
         
            +
                  end.to raise_error(ContractError)
         
     | 
| 
      
 425 
     | 
    
         
            +
                end
         
     | 
| 
       407 
426 
     | 
    
         
             
              end
         
     | 
| 
       408 
427 
     | 
    
         | 
| 
       409 
428 
     | 
    
         
             
              describe "varargs" do
         
     | 
| 
         @@ -489,6 +508,18 @@ RSpec.describe "Contracts:" do 
     | 
|
| 
       489 
508 
     | 
    
         
             
                it "should fail for a function that doesn't pass the contract with weak other args" do
         
     | 
| 
       490 
509 
     | 
    
         
             
                  expect { @o.map_plain(["hello", "joe"], lambda { |_| nil }) }.to raise_error(ContractError)
         
     | 
| 
       491 
510 
     | 
    
         
             
                end
         
     | 
| 
      
 511 
     | 
    
         
            +
             
     | 
| 
      
 512 
     | 
    
         
            +
                it "should fail for a returned function that doesn't pass the contract" do
         
     | 
| 
      
 513 
     | 
    
         
            +
                  expect { @o.lambda_with_wrong_return.call("hello") }.to raise_error(ContractError)
         
     | 
| 
      
 514 
     | 
    
         
            +
                end
         
     | 
| 
      
 515 
     | 
    
         
            +
             
     | 
| 
      
 516 
     | 
    
         
            +
                it "should fail for a returned function that receives the wrong argument type" do
         
     | 
| 
      
 517 
     | 
    
         
            +
                  expect { @o.lambda_with_correct_return.call(123) }.to raise_error(ContractError)
         
     | 
| 
      
 518 
     | 
    
         
            +
                end
         
     | 
| 
      
 519 
     | 
    
         
            +
             
     | 
| 
      
 520 
     | 
    
         
            +
                it "should not fail for a returned function that passes the contract" do
         
     | 
| 
      
 521 
     | 
    
         
            +
                  expect { @o.lambda_with_correct_return.call("hello") }.to_not raise_error
         
     | 
| 
      
 522 
     | 
    
         
            +
                end
         
     | 
| 
       492 
523 
     | 
    
         
             
              end
         
     | 
| 
       493 
524 
     | 
    
         | 
| 
       494 
525 
     | 
    
         
             
              describe "default args to functions" do
         
     | 
| 
         @@ -536,6 +567,38 @@ RSpec.describe "Contracts:" do 
     | 
|
| 
       536 
567 
     | 
    
         
             
                end
         
     | 
| 
       537 
568 
     | 
    
         
             
              end
         
     | 
| 
       538 
569 
     | 
    
         | 
| 
      
 570 
     | 
    
         
            +
              describe "module contracts" do
         
     | 
| 
      
 571 
     | 
    
         
            +
                it "passes for instance of class including module" do
         
     | 
| 
      
 572 
     | 
    
         
            +
                  expect(
         
     | 
| 
      
 573 
     | 
    
         
            +
                    ModuleContractExample.hello(ModuleContractExample::AClassWithModule.new)
         
     | 
| 
      
 574 
     | 
    
         
            +
                  ).to eq(:world)
         
     | 
| 
      
 575 
     | 
    
         
            +
                end
         
     | 
| 
      
 576 
     | 
    
         
            +
             
     | 
| 
      
 577 
     | 
    
         
            +
                it "passes for instance of class including inherited module" do
         
     | 
| 
      
 578 
     | 
    
         
            +
                  expect(
         
     | 
| 
      
 579 
     | 
    
         
            +
                    ModuleContractExample.hello(ModuleContractExample::AClassWithInheritedModule.new)
         
     | 
| 
      
 580 
     | 
    
         
            +
                  ).to eq(:world)
         
     | 
| 
      
 581 
     | 
    
         
            +
                end
         
     | 
| 
      
 582 
     | 
    
         
            +
             
     | 
| 
      
 583 
     | 
    
         
            +
                it "does not pass for instance of class not including module" do
         
     | 
| 
      
 584 
     | 
    
         
            +
                  expect do
         
     | 
| 
      
 585 
     | 
    
         
            +
                    ModuleContractExample.hello(ModuleContractExample::AClassWithoutModule.new)
         
     | 
| 
      
 586 
     | 
    
         
            +
                  end.to raise_error(ContractError, /Expected: ModuleContractExample::AModule/)
         
     | 
| 
      
 587 
     | 
    
         
            +
                end
         
     | 
| 
      
 588 
     | 
    
         
            +
             
     | 
| 
      
 589 
     | 
    
         
            +
                it "does not pass for instance of class including another module" do
         
     | 
| 
      
 590 
     | 
    
         
            +
                  expect do
         
     | 
| 
      
 591 
     | 
    
         
            +
                    ModuleContractExample.hello(ModuleContractExample::AClassWithAnotherModule.new)
         
     | 
| 
      
 592 
     | 
    
         
            +
                  end.to raise_error(ContractError, /Expected: ModuleContractExample::AModule/)
         
     | 
| 
      
 593 
     | 
    
         
            +
                end
         
     | 
| 
      
 594 
     | 
    
         
            +
             
     | 
| 
      
 595 
     | 
    
         
            +
                it "passes for instance of class including both modules" do
         
     | 
| 
      
 596 
     | 
    
         
            +
                  expect(
         
     | 
| 
      
 597 
     | 
    
         
            +
                    ModuleContractExample.hello(ModuleContractExample::AClassWithBothModules.new)
         
     | 
| 
      
 598 
     | 
    
         
            +
                  ).to eq(:world)
         
     | 
| 
      
 599 
     | 
    
         
            +
                end
         
     | 
| 
      
 600 
     | 
    
         
            +
              end
         
     | 
| 
      
 601 
     | 
    
         
            +
             
     | 
| 
       539 
602 
     | 
    
         
             
              describe "Contracts to_s formatting in expected" do
         
     | 
| 
       540 
603 
     | 
    
         
             
                def not_s(match)
         
     | 
| 
       541 
604 
     | 
    
         
             
                  Regexp.new "[^\"\']#{match}[^\"\']"
         
     | 
    
        data/spec/fixtures/fixtures.rb
    CHANGED
    
    | 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "date"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            class A
         
     | 
| 
       2 
4 
     | 
    
         
             
              include Contracts
         
     | 
| 
       3 
5 
     | 
    
         | 
| 
         @@ -120,8 +122,13 @@ class GenericExample 
     | 
|
| 
       120 
122 
     | 
    
         
             
              end
         
     | 
| 
       121 
123 
     | 
    
         | 
| 
       122 
124 
     | 
    
         
             
              Contract Proc => Any
         
     | 
| 
       123 
     | 
    
         
            -
              def do_call(& 
     | 
| 
       124 
     | 
    
         
            -
                 
     | 
| 
      
 125 
     | 
    
         
            +
              def do_call(&block)
         
     | 
| 
      
 126 
     | 
    
         
            +
                block.call
         
     | 
| 
      
 127 
     | 
    
         
            +
              end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
              Contract Args[Num], Maybe[Proc] => Any
         
     | 
| 
      
 130 
     | 
    
         
            +
              def maybe_call(*vals, &block)
         
     | 
| 
      
 131 
     | 
    
         
            +
                block.call if block
         
     | 
| 
       125 
132 
     | 
    
         
             
              end
         
     | 
| 
       126 
133 
     | 
    
         | 
| 
       127 
134 
     | 
    
         
             
              Contract Args[Num] => Num
         
     | 
| 
         @@ -219,6 +226,16 @@ class GenericExample 
     | 
|
| 
       219 
226 
     | 
    
         
             
                end
         
     | 
| 
       220 
227 
     | 
    
         
             
              end
         
     | 
| 
       221 
228 
     | 
    
         | 
| 
      
 229 
     | 
    
         
            +
              Contract RangeOf[Num] => Num
         
     | 
| 
      
 230 
     | 
    
         
            +
              def first_in_range_num(r)
         
     | 
| 
      
 231 
     | 
    
         
            +
                r.first
         
     | 
| 
      
 232 
     | 
    
         
            +
              end
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
              Contract RangeOf[Date] => Date
         
     | 
| 
      
 235 
     | 
    
         
            +
              def first_in_range_date(r)
         
     | 
| 
      
 236 
     | 
    
         
            +
                r.first
         
     | 
| 
      
 237 
     | 
    
         
            +
              end
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
       222 
239 
     | 
    
         
             
              Contract Bool => nil
         
     | 
| 
       223 
240 
     | 
    
         
             
              def bool_test(x)
         
     | 
| 
       224 
241 
     | 
    
         
             
              end
         
     | 
| 
         @@ -262,6 +279,16 @@ class GenericExample 
     | 
|
| 
       262 
279 
     | 
    
         
             
                end
         
     | 
| 
       263 
280 
     | 
    
         
             
              end
         
     | 
| 
       264 
281 
     | 
    
         | 
| 
      
 282 
     | 
    
         
            +
              Contract None => Func[String => Num]
         
     | 
| 
      
 283 
     | 
    
         
            +
              def lambda_with_wrong_return
         
     | 
| 
      
 284 
     | 
    
         
            +
                lambda { |x| x }
         
     | 
| 
      
 285 
     | 
    
         
            +
              end
         
     | 
| 
      
 286 
     | 
    
         
            +
             
     | 
| 
      
 287 
     | 
    
         
            +
              Contract None => Func[String => Num]
         
     | 
| 
      
 288 
     | 
    
         
            +
              def lambda_with_correct_return
         
     | 
| 
      
 289 
     | 
    
         
            +
                lambda { |x| x.length }
         
     | 
| 
      
 290 
     | 
    
         
            +
              end
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
       265 
292 
     | 
    
         
             
              Contract Num => Num
         
     | 
| 
       266 
293 
     | 
    
         
             
              def default_args(x = 1)
         
     | 
| 
       267 
294 
     | 
    
         
             
                2
         
     | 
| 
         @@ -528,10 +555,7 @@ with_enabled_no_contracts do 
     | 
|
| 
       528 
555 
     | 
    
         
             
            end
         
     | 
| 
       529 
556 
     | 
    
         | 
| 
       530 
557 
     | 
    
         
             
            module ModuleExample
         
     | 
| 
       531 
     | 
    
         
            -
              # This inclusion is required to actually override `method_added`
         
     | 
| 
       532 
     | 
    
         
            -
              # hooks for module.
         
     | 
| 
       533 
558 
     | 
    
         
             
              include Contracts
         
     | 
| 
       534 
     | 
    
         
            -
              include Contracts::Modules
         
     | 
| 
       535 
559 
     | 
    
         | 
| 
       536 
560 
     | 
    
         
             
              Contract Num, Num => Num
         
     | 
| 
       537 
561 
     | 
    
         
             
              def plus(a, b)
         
     | 
| 
         @@ -567,3 +591,51 @@ end 
     | 
|
| 
       567 
591 
     | 
    
         | 
| 
       568 
592 
     | 
    
         
             
            class SingletonInheritanceExampleSubclass < SingletonInheritanceExample
         
     | 
| 
       569 
593 
     | 
    
         
             
            end
         
     | 
| 
      
 594 
     | 
    
         
            +
             
     | 
| 
      
 595 
     | 
    
         
            +
            class BareOptionalContractUsed
         
     | 
| 
      
 596 
     | 
    
         
            +
              include Contracts
         
     | 
| 
      
 597 
     | 
    
         
            +
             
     | 
| 
      
 598 
     | 
    
         
            +
              Contract Num, Optional[Num] => nil
         
     | 
| 
      
 599 
     | 
    
         
            +
              def something(a, b)
         
     | 
| 
      
 600 
     | 
    
         
            +
                nil
         
     | 
| 
      
 601 
     | 
    
         
            +
              end
         
     | 
| 
      
 602 
     | 
    
         
            +
            end
         
     | 
| 
      
 603 
     | 
    
         
            +
             
     | 
| 
      
 604 
     | 
    
         
            +
            module ModuleContractExample
         
     | 
| 
      
 605 
     | 
    
         
            +
              include Contracts
         
     | 
| 
      
 606 
     | 
    
         
            +
             
     | 
| 
      
 607 
     | 
    
         
            +
              module AModule
         
     | 
| 
      
 608 
     | 
    
         
            +
              end
         
     | 
| 
      
 609 
     | 
    
         
            +
             
     | 
| 
      
 610 
     | 
    
         
            +
              module AnotherModule
         
     | 
| 
      
 611 
     | 
    
         
            +
              end
         
     | 
| 
      
 612 
     | 
    
         
            +
             
     | 
| 
      
 613 
     | 
    
         
            +
              module InheritedModule
         
     | 
| 
      
 614 
     | 
    
         
            +
                include AModule
         
     | 
| 
      
 615 
     | 
    
         
            +
              end
         
     | 
| 
      
 616 
     | 
    
         
            +
             
     | 
| 
      
 617 
     | 
    
         
            +
              class AClassWithModule
         
     | 
| 
      
 618 
     | 
    
         
            +
                include AModule
         
     | 
| 
      
 619 
     | 
    
         
            +
              end
         
     | 
| 
      
 620 
     | 
    
         
            +
             
     | 
| 
      
 621 
     | 
    
         
            +
              class AClassWithoutModule
         
     | 
| 
      
 622 
     | 
    
         
            +
              end
         
     | 
| 
      
 623 
     | 
    
         
            +
             
     | 
| 
      
 624 
     | 
    
         
            +
              class AClassWithAnotherModule
         
     | 
| 
      
 625 
     | 
    
         
            +
                include AnotherModule
         
     | 
| 
      
 626 
     | 
    
         
            +
              end
         
     | 
| 
      
 627 
     | 
    
         
            +
             
     | 
| 
      
 628 
     | 
    
         
            +
              class AClassWithInheritedModule
         
     | 
| 
      
 629 
     | 
    
         
            +
                include InheritedModule
         
     | 
| 
      
 630 
     | 
    
         
            +
              end
         
     | 
| 
      
 631 
     | 
    
         
            +
             
     | 
| 
      
 632 
     | 
    
         
            +
              class AClassWithBothModules
         
     | 
| 
      
 633 
     | 
    
         
            +
                include AModule
         
     | 
| 
      
 634 
     | 
    
         
            +
                include AnotherModule
         
     | 
| 
      
 635 
     | 
    
         
            +
              end
         
     | 
| 
      
 636 
     | 
    
         
            +
             
     | 
| 
      
 637 
     | 
    
         
            +
              Contract AModule => Symbol
         
     | 
| 
      
 638 
     | 
    
         
            +
              def self.hello(thing)
         
     | 
| 
      
 639 
     | 
    
         
            +
                :world
         
     | 
| 
      
 640 
     | 
    
         
            +
              end
         
     | 
| 
      
 641 
     | 
    
         
            +
            end
         
     |