Class: StableMatch::Candidate

Inherits:
Object
  • Object
show all
Defined in:
lib/stable_match/candidate.rb

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Candidate

Returns a new instance of Candidate.



29
30
31
32
33
34
35
# File 'lib/stable_match/candidate.rb', line 29

def initialize(*args)
  options      = Map.opts(args)
  @target      = options.target      rescue args.shift or raise ArgumentError.new( "No `target` provided!" )
  @preferences = options.preferences rescue args.shift or raise ArgumentError.new( "No `preferences` provided!" )

  @match_positions = options.match_positions if options.get( :match_positions )
end

Instance Method Details

#better_match?(other) ⇒ Boolean

Candidate#better_match?

Is the passed candidate a better match than any of the current matches?

ARG: ‘other` – another Candidate instance to check against the current set

Returns:

  • (Boolean)


43
44
45
46
47
48
# File 'lib/stable_match/candidate.rb', line 43

def better_match?( other )
  return true if prefers?( other ) && free?
  preference_index = preferences.index other
  match_preference_indexes = matches.map { | match | preferences.index match }
  preference_index and match_preference_indexes.any? { |i| i > preference_index }
end

#exhausted_preferences?Boolean

Candidate#exhausted_preferences?

Have all possible preferences been cycled through?

Returns:

  • (Boolean)


54
55
56
# File 'lib/stable_match/candidate.rb', line 54

def exhausted_preferences?
  preference_position >= preferences.size - 1
end

#free!Object

Candidate#free!

Delete the least-preferred candidate from the matches array



70
71
72
73
74
75
76
77
78
79
80
# File 'lib/stable_match/candidate.rb', line 70

def free!
  return false if matches.empty?
  match_preference_indexes = matches.map { | match | preferences.index match }
  max                      = match_preference_indexes.max # The index of the match with the lowest preference
  candidate_to_reject      = preferences[ max ]

## Delete from both sides
#
  candidate_to_reject.matches.delete self
  self.matches.delete candidate_to_reject
end

#free?Boolean

Candidate#free?

Is there available positions for more matches based on the defined ‘match_positions`?

Returns:

  • (Boolean)


62
63
64
# File 'lib/stable_match/candidate.rb', line 62

def free?
  matches.length < match_positions
end

#full?Boolean

Candidate#full?

Are there no remaining positions available for matches?

Returns:

  • (Boolean)


86
87
88
# File 'lib/stable_match/candidate.rb', line 86

def full?
  !free?
end

#inspectObject



90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/stable_match/candidate.rb', line 90

def inspect
  require "yaml"

  {
    :target              => target,
    :match_positions     => match_positions,
    :matches             => matches.map( &:target ),
    :preference_position => preference_position,
    :preferences         => preferences.map( &:target ),
    :proposals           => proposals.map( &:target )
  }.to_yaml
end

#match!(other) ⇒ Object

Candidate#match!

Match with another Candidate

ARG: ‘other` – another Candidate instance to match with



109
110
111
112
113
# File 'lib/stable_match/candidate.rb', line 109

def match!( other )
  return false unless prefers?( other ) && !matched?( other )
  matches       << other
  other.matches << self
end

#match_positionsObject

The number of matches the candidate is able to make



9
# File 'lib/stable_match/candidate.rb', line 9

fattr( :match_positions ){ 1 }

#matched?(other = nil) ⇒ Boolean

Candidate#matched?

If no argument is passed: Do we have at least as many matches as available ‘match_positions`? If another Candidate is passed: Is that candidate included in the matches?

ARG: ‘other` [optional] – another Candidate instance

Returns:

  • (Boolean)


122
123
124
125
# File 'lib/stable_match/candidate.rb', line 122

def matched?( other = nil )
  return full? if other.nil?
  matches.include? other
end

#matchesObject

The matches this candidate has attained



5
# File 'lib/stable_match/candidate.rb', line 5

fattr( :matches ){ [] }

#next_preference!Object

Candidate#next_preference!

Increment ‘preference_position` and return the preference at that position



131
132
133
134
# File 'lib/stable_match/candidate.rb', line 131

def next_preference!
  self.preference_position += 1
  preferences.fetch preference_position
end

#preference_positionObject

The tracked position for preferences that have been attempted for matches



13
# File 'lib/stable_match/candidate.rb', line 13

fattr( :preference_position ){ -1 }

#preferencesObject

An ordered array of candidates where, the lower the index, the higher the preference

WARNING – this may be instantiated with targets at first that get converted to Candidates



19
# File 'lib/stable_match/candidate.rb', line 19

fattr( :preferences ){ [] }

#prefers?(other) ⇒ Boolean

Candidate#prefers?

Is there a preference for the passed Candidate?

ARG: ‘other` – another Candidate instance

Returns:

  • (Boolean)


142
143
144
# File 'lib/stable_match/candidate.rb', line 142

def prefers?( other )
  preferences.include? other
end

#proposalsObject

The array to track proposals that have already been made



23
# File 'lib/stable_match/candidate.rb', line 23

fattr( :proposals ){ [] }

#propose_to(other) ⇒ Object

Candidate#propose_to

Track that a proposal was made then ask the other Candidate to respond to a proposal

ARG: ‘other` – another Candidate instance



152
153
154
155
# File 'lib/stable_match/candidate.rb', line 152

def propose_to( other )
  proposals << other
  other.respond_to_proposal_from self
end

#propose_to_next_preferenceObject

Candidate#propose_to_next_preference

Send a proposal to the next tracked preference



161
162
163
# File 'lib/stable_match/candidate.rb', line 161

def propose_to_next_preference
  propose_to next_preference!
end

#respond_to_proposal_from(other) ⇒ Object

Candidate#respond_to_proposal_from

Given another candidate, respond properly based on current state

ARG: ‘other` – another Candidate instance



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/stable_match/candidate.rb', line 171

def respond_to_proposal_from( other )
  case
  ## Is there a preference for the candidate?
  #
    when !prefers?( other )
      false

  ## Are there available positions for more matches?
  #
    when free?
      match! other

  ## Is the passed Candidate a better match than any other match?
  #
    when better_match?( other )
      free!
      match! other

    else
      false
  end
end

#targetObject

The object that the candidate represents



27
# File 'lib/stable_match/candidate.rb', line 27

fattr :target