class Stannum::Contracts::ParametersContract

A Parameters defines constraints on the parameters for a block or method.

The ParametersContract requires that the actual object matched be a Hash with the following keys: :arguments, with an Array value; :keywords, with a Hash value; and :block, with a value of either a Proc or nil.

For the arguments constraints, the contract verifies that the correct number of arguments are given and that each argument matches the type or constraint specified. If the contract has a variadic arguments constraint, then each variadic (or “splatted”) argument is checked against the type or constraint.

For the keywords constraints, the contract verifies that the expected keywords are given and that each keyword value matches the type or constraint specified. If the contract has a variadic keywords constraint, then each variadic keyword value is checked against the type or constraint.

For the block constraint, the contract specifies that the block is present, the block is absent, or the block matches the given constraint.

@example Defining A Parameters Contract With Arguments

contract = Stannum::Contracts::ParametersContract.new do
  argument :name, String
  argument :size, String, default: true
end

contract.matches?(
  { arguments: [], keywords: {}, block: nil }
)
#=> false

contract.matches?(
  { arguments: [:a_symbol], keywords: {}, block: nil }
)
#=> false

contract.matches?(
  { arguments: ['Widget', 'Small', :extra], keywords: {}, block: nil }
)
#=> false

contract.matches?(
  { arguments: ['Widget', 'Small', :extra], keywords: {}, block: nil }
)
#=> false

contract.matches?(
  { arguments: ['Widget'], keywords: {}, block: nil }
)
#=> true

contract.matches?(
  { arguments: ['Widget', nil], keywords: {}, block: nil }
)
#=> false

contract.matches?(
  { arguments: ['Widget', 'Small'], keywords: {}, block: nil }
)
#=> true

@example Defining A Parameters Contract With Keywords

contract = Stannum::Contracts::ParametersContract.new do
  keyword :price,    String
  keyword :quantity, Integer, optional: true
end

contract.matches?(
  { arguments: [], keywords: {}, block: nil }
)
#=> false

contract.matches?(
  arguments: [],
  keywords:  {
    price: 1_000_000,
  },
  block: nil
)
#=> false

contract.matches?(
  arguments: [],
  keywords:  {
    currency: 'USD',
    price:    '$1_000_000',
  },
  block: nil
)
#=> false

contract.matches?(
  arguments: [],
  keywords:  {
    price: '$1_000_000',
  },
  block: nil
)

#=> true
contract.matches?(
  arguments: [],
  keywords:  {
    price:    '$1_000_000',
    quantity: 50,
  },
  block: nil
)
#=> true

@example Defining A Parameters Contract With Variadic Arguments

contract = Stannum::Contracts::ParametersContract.new do
  arguments :words, String
end

contract.matches?(
  { arguments: [1, 2, 3], keywords: {}, block: nil }
)
#=> false

contract.matches?(
  { arguments: [], keywords: {}, block: nil }
)
#=> true

contract.matches?(
  { arguments: ['foo', 'bar', 'baz'], keywords: {}, block: nil }
)
#=> true

@example Defining A Parameters Contract With Variadic Keywords

contract = Stannum::Contracts::ParametersContract.new do
  keywords :options, Symbol
end

contract.matches?(
  arguments: [],
  keywords:  {
    price: 1_000_000,
  },
  block: nil
)
#=> false

contract.matches?(
  arguments: [],
  keywords:  {},
  block: nil
)
#=> true

contract.matches?(
  arguments: [],
  keywords:  {
    color: :red,
    shape: :triangle
  },
  block: nil
)
#=> true

@example Defining A Parameters Contract With A Block Constraint

contract = Stannum::Contracts::ParametersContract.new do
  block true
end

contract.matches?(
  { arguments: [], keywords: {}, block: nil }
)
#=> false

contract.matches?(
  { arguments: [], keywords: {}, block: Proc.new }
)
#=> true

Attributes

block_constraint[R]

Public Instance Methods

add_argument_constraint(index, type, **options) click to toggle source

Adds an argument constraint to the contract.

Generates an argument constraint based on the given type. If the type is a constraint, then the given constraint will be copied with the given options and added for the argument at the index. If the type is a Class or a Module, then a Stannum::Constraints::Type constraint will be created with the given type and options and added for the argument.

If the index is specified, then the constraint will be added for the argument at the specified index. If the index is not given, then the constraint will be applied to the next unconstrained argument. For example, the first argument constraint will be added for the argument at index 0, the second constraint for the argument at index 1, and so on.

@param index [Integer, nil] The index of the argument. If not given, then

the next argument will be constrained with the type.

@param type [Class, Module, Stannum::Constraints:Base] The expected type

of the argument.

@param options [Hash<Symbol, Object>] Configuration options for the

constraint. Defaults to an empty Hash.

@return [Stannum::Contracts::ParametersContract] the contract.

# File lib/stannum/contracts/parameters_contract.rb, line 398
def add_argument_constraint(index, type, **options)
  arguments_contract.add_argument_constraint(index, type, **options)

  self
end
add_keyword_constraint(keyword, type, **options) click to toggle source

Adds a keyword constraint to the contract.

Generates a keyword constraint based on the given type. If the type is a constraint, then the given constraint will be copied with the given options and added for the given keyword. If the type is a Class or a Module, then a Stannum::Constraints::Type constraint will be created with the given type and options and added for the keyword.

@param keyword [Symbol] The keyword to constrain. @param type [Class, Module, Stannum::Constraints:Base] The expected type

of the argument.

@param options [Hash<Symbol, Object>] Configuration options for the

constraint. Defaults to an empty Hash.

@return [Stannum::Contracts::ParametersContract] the contract.

# File lib/stannum/contracts/parameters_contract.rb, line 419
def add_keyword_constraint(keyword, type, **options)
  keywords_contract.add_keyword_constraint(keyword, type, **options)

  self
end
set_arguments_item_constraint(name, type) click to toggle source

Sets the variadic arguments constraint for the contract.

If the parameters includes variadic (or “splatted”) arguments, then each item in the variadic arguments array must match the given type or constraint. If the type is a constraint, then the given constraint will be copied with the given options. If the type is a Class or a Module, then a Stannum::Constraints::Type constraint will be created with the given type.

@param name [String, Symbol] a human-readable name for the variadic

arguments; used in generating error messages.

@param type [Class, Module, Stannum::Constraints:Base] The expected type

of the variadic arguments items.

@return [Stannum::Contracts::ParametersContract] the contract.

@raise [RuntimeError] if there is already a variadic arguments constraint

defined for the contract.
# File lib/stannum/contracts/parameters_contract.rb, line 442
def set_arguments_item_constraint(name, type)
  arguments_contract.set_variadic_item_constraint(type, as: name)

  self
end
set_block_constraint(present) click to toggle source

Sets the block parameter constraint for the contract.

If the expected presence is true, a block must be given as part of the parameters. If the expected presence is false, a block must not be given. If the presence is a constraint, then the block must match the constraint.

@param present [true, false, Stannum::Constraint] The expected presence of

the block.

@return [Stannum::Contracts::ParametersContract] the contract.

@raise [RuntimeError] if there is already a block constraint defined for

the contract.
# File lib/stannum/contracts/parameters_contract.rb, line 461
def set_block_constraint(present) # rubocop:disable Naming/AccessorMethodName
  raise 'block constraint is already set' if @block_constraint

  @block_constraint = build_block_constraint(present)

  add_key_constraint(:block, @block_constraint)
end
set_keywords_value_constraint(name, type) click to toggle source

Sets the variadic keywords constraint for the contract.

If the parameters includes variadic (or “splatted”) keywords, then each value in the variadic keywords hash must match the given type or constraint. If the type is a constraint, then the given constraint will be copied with the given options. If the type is a Class or a Module, then a Stannum::Constraints::Type constraint will be created with the given type.

@param name [String, Symbol] a human-readable name for the variadic

keywords; used in generating error messages.

@param type [Class, Module, Stannum::Constraints:Base] The expected type

of the variadic keywords values.

@return [Stannum::Contracts::ParametersContract] the contract.

@raise [RuntimeError] if there is already a variadic keywords constraint

defined for the contract.
# File lib/stannum/contracts/parameters_contract.rb, line 486
def set_keywords_value_constraint(name, type)
  keywords_contract.set_variadic_value_constraint(type, as: name)

  self
end

Private Instance Methods

add_extra_keys_constraint() click to toggle source
# File lib/stannum/contracts/parameters_contract.rb, line 496
def add_extra_keys_constraint; end
add_type_constraint() click to toggle source
# File lib/stannum/contracts/parameters_contract.rb, line 498
def add_type_constraint
  add_constraint \
    Stannum::Contracts::Parameters::SignatureContract.new,
    sanity: true
end
arguments_contract() click to toggle source
# File lib/stannum/contracts/parameters_contract.rb, line 504
def arguments_contract
  @arguments_contract ||=
    Stannum::Contracts::Parameters::ArgumentsContract.new
end
build_block_constraint(value) click to toggle source
# File lib/stannum/contracts/parameters_contract.rb, line 509
def build_block_constraint(value)
  Stannum::Support::Coercion.presence_constraint(value) \
  do |present, **options|
    next Stannum::Constraints::Types::ProcType.new(**options) if present

    Stannum::Constraints::Types::NilType.new(**options)
  end
end
define_constraints(&block) click to toggle source
# File lib/stannum/contracts/parameters_contract.rb, line 518
def define_constraints(&block)
  super(&block)

  add_key_constraint :arguments, arguments_contract
  add_key_constraint :keywords,  keywords_contract
end
keywords_contract() click to toggle source
# File lib/stannum/contracts/parameters_contract.rb, line 525
def keywords_contract
  @keywords_contract ||=
    Stannum::Contracts::Parameters::KeywordsContract.new
end