Class: Friends::Event

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

Direct Known Subclasses

Activity, Note

Constant Summary collapse

SERIALIZATION_PREFIX =
"- "
DATE_PARTITION =
": "

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Serializable

deserialize

Constructor Details

#initialize(str: "") ⇒ Activity

Returns the new activity.

Parameters:

  • str (String) (defaults to: "")

    the text of the activity, of one of the formats: “<date>: <description>” “<date>” (Program will prompt for description.) “<description>” (The current date will be used by default.)



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/friends/event.rb', line 30

def initialize(str: "")
  # Partition lets us parse "Today" and "Today: I awoke." identically.
  date_s, _, description = str.partition(DATE_PARTITION)

  time = if date_s =~ /^\d{4}-\d{2}-\d{2}$/
           Time.parse(date_s)
         else
           # If the user inputed a non YYYY-MM-DD format, asssume
           # it is in the past.
           past_time = Chronic.parse(date_s, context: :past)

           # If there's no year, Chronic will sometimes parse the date
           # as being the next occurrence of that date in the future.
           # Instead, we want to subtract one year to make it the last
           # occurrence of the date in the past.
           # NOTE: This is a hacky workaround for the fact that
           # Chronic's `context: :past` doesn't actually work. We should
           # remove this when that behavior is fixed.
           if past_time && past_time > Time.now
             Time.local(past_time.year - 1, past_time.month, past_time.day)
           else
             past_time
           end
         end

  if time
    @date = time.to_date
    @description = description
  else
    # If the user didn't input a date, we fall back to the current date.
    @date = Date.today
    @description = str # Use str in case DATE_PARTITION occurred naturally.
  end
end

Instance Attribute Details

#dateObject (readonly)

Returns the value of attribute date.



65
66
67
# File 'lib/friends/event.rb', line 65

def date
  @date
end

#descriptionObject

Returns the value of attribute description.



66
67
68
# File 'lib/friends/event.rb', line 66

def description
  @description
end

#implicit_location=(value) ⇒ Object (writeonly)

Sets the attribute implicit_location

Parameters:

  • value

    the value to set the attribute implicit_location to.



67
68
69
# File 'lib/friends/event.rb', line 67

def implicit_location=(value)
  @implicit_location = value
end

Class Method Details

.deserialization_regexRegexp

Returns the regex for capturing groups in deserialization.

Returns:

  • (Regexp)

    the regex for capturing groups in deserialization



21
22
23
# File 'lib/friends/event.rb', line 21

def self.deserialization_regex
  /(#{SERIALIZATION_PREFIX})?(?<str>.+)?/
end

Instance Method Details

#default_locationObject



141
142
143
# File 'lib/friends/event.rb', line 141

def default_location
  @default_location ||= @description[/(?<=to _)\w[^_]*(?=_)/]
end

#description_location_namesArray

Find the names of all locations in this description.

Returns:

  • (Array)

    list of all location names in the description



170
171
172
# File 'lib/friends/event.rb', line 170

def description_location_names
  @description.scan(/(?<=_)\w[^_]*(?=_)/).uniq
end

#friend_namesArray

Find the names of all friends in this description.

Returns:

  • (Array)

    list of all friend names in the description



164
165
166
# File 'lib/friends/event.rb', line 164

def friend_names
  @description.scan(/(?<=\*\*)\w[^\*]*(?=\*\*)/).uniq
end

#highlight_description(introvert:) ⇒ Object

Modify the description to turn inputted friend names (e.g. “Jacob” or “Jacob Evelyn”) into full asterisk’d names (e.g. “**Jacob Evelyn**”) and inputted location names (e.g. “Atlantis”) into full underscore’d names (e.g. “Atlantis”).

Parameters:

  • introvert (Introvert)

    used to access internal data structures to perform object matching



106
107
108
109
# File 'lib/friends/event.rb', line 106

def highlight_description(introvert:)
  highlight_locations(introvert: introvert)
  highlight_friends(introvert: introvert)
end

#includes_friend?(friend) ⇒ Boolean

Returns true iff this activity includes the given friend.

Parameters:

  • friend (Friend)

    the friend to test

Returns:

  • (Boolean)

    true iff this activity includes the given friend



147
148
149
# File 'lib/friends/event.rb', line 147

def includes_friend?(friend)
  friend_names.include? friend.name
end

#includes_location?(location) ⇒ Boolean

Returns true if activity has location in description or it equals implicit location.

Parameters:

  • location (Location)

    the location to test

Returns:

  • (Boolean)

    true if activity has location in description or it equals implicit location



137
138
139
# File 'lib/friends/event.rb', line 137

def includes_location?(location)
  location_in_description?(location) || location_is_implicit?(location)
end

#includes_tag?(tag) ⇒ Boolean

Returns true iff this activity includes the given tag.

Parameters:

  • tag (String)

    the tag to test, of the form “@tag”

Returns:

  • (Boolean)

    true iff this activity includes the given tag



153
154
155
# File 'lib/friends/event.rb', line 153

def includes_tag?(tag)
  tags.include? tag.downcase
end

#location_namesArray

Returns list of all location names in either description or implicit_location.

Returns:

  • (Array)

    list of all location names in either description or implicit_location



175
176
177
# File 'lib/friends/event.rb', line 175

def location_names
  @implicit_location ? [@implicit_location] : description_location_names
end

#serializeString

Returns the file serialization text for the activity.

Returns:

  • (String)

    the file serialization text for the activity



96
97
98
# File 'lib/friends/event.rb', line 96

def serialize
  "#{SERIALIZATION_PREFIX}#{date}: #{description}"
end

#tagsSet

Returns all tags in this activity (including the “@”).

Returns:

  • (Set)

    all tags in this activity (including the “@”)



158
159
160
# File 'lib/friends/event.rb', line 158

def tags
  Set.new(@description.scan(TAG_REGEX).map(&:downcase))
end

#to_sString

Returns the command-line display text for the activity.

Returns:

  • (String)

    the command-line display text for the activity



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/friends/event.rb', line 70

def to_s
  date_s = Paint[date, :bold]
  description_s = description.to_s
  # rubocop:disable Lint/AssignmentInCondition
  while match = description_s.match(/\*\*([^\*]+)\*\*/)
    # rubocop:enable Lint/AssignmentInCondition
    description_s = "#{match.pre_match}"\
                    "#{Paint[match[1], :bold, :magenta]}"\
                    "#{match.post_match}"
  end

  # rubocop:disable Lint/AssignmentInCondition
  while match = description_s.match(/_([^_]+)_/)
    # rubocop:enable Lint/AssignmentInCondition
    description_s = "#{match.pre_match}"\
                    "#{Paint[match[1], :bold, :yellow]}"\
                    "#{match.post_match}"
  end

  description_s = description_s.
                  gsub(TAG_REGEX, Paint['\0', :bold, :cyan])

  "#{date_s}: #{description_s}"
end

#update_friend_name(old_name:, new_name:) ⇒ String?

Updates a friend’s old_name to their new_name

Parameters:

  • old_name (String)
  • new_name (String)

Returns:

  • (String)

    if name found in description

  • (nil)

    if no change was made



116
117
118
119
120
121
# File 'lib/friends/event.rb', line 116

def update_friend_name(old_name:, new_name:)
  @description = @description.gsub(
    Regexp.new("(?<=\\*\\*)#{old_name}(?=\\*\\*)"),
    new_name
  )
end

#update_location_name(old_name:, new_name:) ⇒ String?

Updates a location’s old_name to their new_name

Parameters:

  • old_name (String)
  • new_name (String)

Returns:

  • (String)

    if name found in description

  • (nil)

    if no change was made



128
129
130
131
132
133
# File 'lib/friends/event.rb', line 128

def update_location_name(old_name:, new_name:)
  @description = @description.gsub(
    Regexp.new("(?<=_)#{old_name}(?=_)"),
    new_name
  )
end