module Collapsium::PrototypeMatch

Provides prototype matching for Hashes. See prototype_match

Constants

FAILURE

Large negative integer for failures we can't express otherwise in scoring.

Public Instance Methods

prototype_match(prototype, strict = false) click to toggle source

Given a prototype Hash, returns true if (recursively):

  • this hash contains all the prototype's keys, and

  • this hash contains all the prototype's values

Note that this is not the same as equality. If the prototype provides a nil value for any key, then any value in this Hash is considered to be valid. @param prototype (Hash) The prototype to match against. @param strict (Boolean) If true, this Hash may not contain keys that are

not present in the prototype.

@return (Boolean) True if matching succeeds, false otherwise.

# File lib/collapsium/prototype_match.rb, line 28
def prototype_match(prototype, strict = false)
  return prototype_match_score(prototype, strict) > 0
end
prototype_match_score(prototype, strict = false) click to toggle source

Calculates a matching score for matching the prototype. A score of 0 or less is not a match, and the higher the score, the better the match is.

@param prototype (Hash) The prototype to match against. @param strict (Boolean) If true, this Hash may not contain keys that are

not present in the prototype.

@return (Integer) Greater than zero for positive matches, equal to or

less than zero for mismatches.
# File lib/collapsium/prototype_match.rb, line 41
def prototype_match_score(prototype, strict = false)
  # The prototype contains keys that are not in the Hash. That's a failure,
  # and the level of failure is the number of missing keys.
  missing = (prototype.keys - keys).length
  if missing > 0
    return -missing
  end

  # In strict evaluation, the Hash may also not contain keys that are not
  # in the prototoype.
  if strict
    missing = (keys - prototype.keys).length
    if missing > 0
      return -missing
    end
  end

  # Now we have to examine the prototype's values.
  score = 0
  prototype.each do |key, value|
    # We can skip any nil values in the prototype. They exist only to ensure
    # the key is present. We do increase the score for a matched key, though!
    if value.nil?
      score += 1
      next
    end

    # If the prototype value is a Hash, then the Hash value also has to be,
    # and we have to recurse into this Hash.
    if value.is_a?(Hash)
      if not self[key].is_a?(Hash)
        return FAILURE
      end

      self[key].extend(PrototypeMatch)
      recurse_score = self[key].prototype_match_score(value)
      if recurse_score < 0
        return recurse_score
      end
      score += recurse_score

      next
    end

    # Otherwise the prototype value must be equal to the Hash's value
    if self[key] == value
      score += 1
    else
      score -= 1
    end
  end

  # Return score
  return score
end