Module: Collapsium::PrototypeMatch

Included in:
UberHash
Defined in:
lib/collapsium/prototype_match.rb

Overview

Provides prototype matching for Hashes. See #prototype_match

Constant Summary collapse

FAILURE =

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

-2147483648

Instance Method Summary collapse

Instance Method Details

#prototype_match(prototype, strict = false) ⇒ Boolean

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.

Parameters:

  • prototype (Hash)

    The prototype to match against.

  • strict (Boolean) (defaults to: false)

    If true, this Hash may not contain keys that are not present in the prototype.

Returns:

  • (Boolean)

    True if matching succeeds, false otherwise.



28
29
30
# 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) ⇒ Integer

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.

Parameters:

  • prototype (Hash)

    The prototype to match against.

  • strict (Boolean) (defaults to: false)

    If true, this Hash may not contain keys that are not present in the prototype.

Returns:

  • (Integer)

    Greater than zero for positive matches, equal to or less than zero for mismatches.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# 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