Class: Friends::Friend

Inherits:
Object
  • Object
show all
Extended by:
Serializable
Defined in:
lib/friends/friend.rb

Constant Summary collapse

SERIALIZATION_PREFIX =
"- ".freeze
NICKNAME_PREFIX =
"a.k.a. ".freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Serializable

deserialize

Constructor Details

#initialize(name:, nickname_str: nil, location_name: nil, tags_str: nil) ⇒ Friend

Returns a new instance of Friend.

Parameters:

  • name (String)

    the name of the friend


30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/friends/friend.rb', line 30

def initialize(
  name:,
  nickname_str: nil,
  location_name: nil,
  tags_str: nil
)
  @name = name
  @nicknames = nickname_str &&
               nickname_str.split(" #{NICKNAME_PREFIX}") ||
               []
  @location_name = location_name
  @tags = tags_str && tags_str.split(/\s+/) || []
end

Instance Attribute Details

#likelihood_scoreObject


114
115
116
# File 'lib/friends/friend.rb', line 114

def likelihood_score
  defined?(@likelihood_score) ? @likelihood_score : 0
end

#location_nameObject

Returns the value of attribute location_name


45
46
47
# File 'lib/friends/friend.rb', line 45

def location_name
  @location_name
end

#n_activitiesObject


104
105
106
# File 'lib/friends/friend.rb', line 104

def n_activities
  defined?(@n_activities) ? @n_activities : 0
end

#nameObject

Returns the value of attribute name


44
45
46
# File 'lib/friends/friend.rb', line 44

def name
  @name
end

#tagsObject (readonly)

Returns the value of attribute tags


46
47
48
# File 'lib/friends/friend.rb', line 46

def tags
  @tags
end

Class Method Details

.deserialization_expectationRegexp

Returns the string of what we expected during deserialization.

Returns:

  • (Regexp)

    the string of what we expected during deserialization


25
26
27
# File 'lib/friends/friend.rb', line 25

def self.deserialization_expectation
  "[Friend Name]"
end

.deserialization_regexRegexp

Returns the regex for capturing groups in deserialization.

Returns:

  • (Regexp)

    the regex for capturing groups in deserialization


17
18
19
20
21
22
# File 'lib/friends/friend.rb', line 17

def self.deserialization_regex
  # Note: this regex must be on one line because whitespace is important
  # rubocop:disable Metrics/LineLength
  /(#{SERIALIZATION_PREFIX})?(?<name>[^\(\[@]*[^\(\[@\s])(\s+\(#{NICKNAME_PREFIX}(?<nickname_str>.+)\))?(\s+\[(?<location_name>[^\]]+)\])?(\s+(?<tags_str>(#{TAG_REGEX}\s*)+))?/
  # rubocop:enable Metrics/LineLength
end

Instance Method Details

#add_nickname(nickname) ⇒ Object

Adds a nickname, ignoring duplicates.

Parameters:

  • nickname (String)

    the nickname to add


86
87
88
89
# File 'lib/friends/friend.rb', line 86

def add_nickname(nickname)
  @nicknames << nickname
  @nicknames.uniq!
end

#add_tag(tag) ⇒ Object

Adds a tag, ignoring duplicates.

Parameters:

  • tag (String)

    the tag to add, of the format: “@tag”


72
73
74
75
# File 'lib/friends/friend.rb', line 72

def add_tag(tag)
  @tags << tag
  @tags.uniq!
end

#regexes_for_nameArray

NOTE: For now we only match on full names or first names.

Returns:

  • (Array)

    a list of all regexes to match the name in a string Example: [

    /Jacob\s+Morris\s+Evelyn/,
    /Jacob/
    

    ]


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/friends/friend.rb', line 124

def regexes_for_name
  # We generously allow any amount of whitespace between parts of a name.
  splitter = "\\s+"

  # Create the list of regexes and return it.
  chunks = name.split(Regexp.new(splitter))

  # We check nicknames before first names because nicknames may contain
  # first names, as in "Amazing Grace" being a nickname for Grace Hopper.
  [
    chunks, # Match a full name with the highest priority.
    *@nicknames.map { |n| [n] },

    # Match a first name followed by a last name initial, period, and then
    # (via lookahead) spacing followed by a lowercase letter. This matches
    # the "Jake E." part of something like "Jake E. and I went skiing." This
    # allows us to correctly count the period as part of the name when it's
    # in the middle of a sentence.
    ([chunks.first, "#{chunks.last[0]}\.(?=#{splitter}(?-i)[a-z])"] if chunks.size > 1),

    # If the above doesn't match, we check for just the first name and then
    # a last name initial. This matches the "Jake E" part of something like
    # "I went skiing with Jake E." This allows us to correctly exclude the
    # period from the name when it's at the end of a sentence.
    ([chunks.first, chunks.last[0]] if chunks.size > 1),

    *(1..chunks.size - 1).map { |i| chunks.take(i) }.reverse
  ].compact.map do |words|
    Friends::RegexBuilder.regex(words.join(splitter))
  end
end

#remove_nickname(nickname) ⇒ Object

Parameters:

  • nickname (String)

    the nickname to remove

Raises:

  • (FriendsError)

    if the friend does not have the given nickname


93
94
95
96
97
98
99
# File 'lib/friends/friend.rb', line 93

def remove_nickname(nickname)
  unless @nicknames.include? nickname
    raise FriendsError, "Nickname \"#{nickname}\" not found for \"#{name}\""
  end

  @nicknames.delete(nickname)
end

#remove_tag(tag) ⇒ Object

Parameters:

  • tag (String)

    the tag to remove, of the format: “@tag”

Raises:


78
79
80
81
82
# File 'lib/friends/friend.rb', line 78

def remove_tag(tag)
  raise FriendsError, "Tag \"#{tag}\" not found for \"#{name}\"" unless @tags.include? tag

  @tags.delete(tag)
end

#serializeString

Returns the file serialization text for the friend.

Returns:

  • (String)

    the file serialization text for the friend


49
50
51
52
# File 'lib/friends/friend.rb', line 49

def serialize
  # Remove terminal effects for serialization.
  Paint.unpaint("#{SERIALIZATION_PREFIX}#{self}")
end

#to_sString

Returns a string representing the friend's name and nicknames.

Returns:

  • (String)

    a string representing the friend's name and nicknames


55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/friends/friend.rb', line 55

def to_s
  unless @nicknames.empty?
    nickname_str = " (" +
                   @nicknames.map do |nickname|
                     "#{NICKNAME_PREFIX}#{Paint[nickname, :bold, :magenta]}"
                   end.join(" ") + ")"
  end

  location_str = " [#{Paint[@location_name, :bold, :yellow]}]" unless @location_name.nil?

  tag_str = " #{Paint[@tags.join(' '), :bold, :cyan]}" unless @tags.empty?

  "#{Paint[@name, :bold]}#{nickname_str}#{location_str}#{tag_str}"
end