Class: Reading::Item::TimeLength

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/reading/item/time_length.rb

Overview

The length of an item when it is a time, as opposed to pages. (Pages are represented simply with an Integer or Float.)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value) ⇒ TimeLength

Returns a new instance of TimeLength.

Parameters:

  • value (Numeric)

    the total minutes



11
12
13
# File 'lib/reading/item/time_length.rb', line 11

def initialize(value)
  @value = value
end

Instance Attribute Details

#valueObject (readonly)

in total minutes



8
9
10
# File 'lib/reading/item/time_length.rb', line 8

def value
  @value
end

Class Method Details

.from_pages(pages) ⇒ TimeLength

Builds an Item::TimeLength based on a page count.

Parameters:

  • pages (Integer, Float)

Returns:



28
29
30
# File 'lib/reading/item/time_length.rb', line 28

def self.from_pages(pages)
  new(pages_to_minutes(pages))
end

.pages_to_minutes(pages) ⇒ Integer

Converts a page count to minutes.

Parameters:

  • pages (Integer, Float)

Returns:

  • (Integer)


35
36
37
# File 'lib/reading/item/time_length.rb', line 35

def self.pages_to_minutes(pages)
  (pages.to_f / Config.hash.fetch(:pages_per_hour) * 60)
end

.parse(string) ⇒ TimeLength?

Builds an Item::TimeLength from a string.

Parameters:

  • string (String)

    a time duration in “h:mm” format.

Returns:



18
19
20
21
22
23
# File 'lib/reading/item/time_length.rb', line 18

def self.parse(string)
  return nil unless string.match? /\A\d+:\d\d\z/

  hours, minutes = string.split(':').map(&:to_i)
  new((hours * 60) + minutes)
end

Instance Method Details

#*(other) ⇒ TimeLength

Parameters:

Returns:



119
120
121
122
123
124
125
# File 'lib/reading/item/time_length.rb', line 119

def *(other)
  if other.is_a? Numeric
    self.class.new(value * other).to_i_if_whole!
  else
    raise TypeError, "TimeLength can't be multiplied by #{other.class}."
  end
end

#+(other) ⇒ TimeLength

Parameters:

Returns:



95
96
97
98
99
100
101
102
103
# File 'lib/reading/item/time_length.rb', line 95

def +(other)
  if other.is_a? Item::TimeLength
    self.class.new(value + other.value)
  elsif other.is_a? Numeric
    self.class.new(value + self.class.pages_to_minutes(other))
  else
    raise TypeError, "#{other.class} can't be added to Item::TimeLength."
  end
end

#-(other) ⇒ TimeLength

Parameters:

Returns:



107
108
109
110
111
112
113
114
115
# File 'lib/reading/item/time_length.rb', line 107

def -(other)
  if other.is_a? Item::TimeLength
    self.class.new(value - other.value)
  elsif other.is_a? Numeric
    self.class.new(value - self.class.pages_to_minutes(other))
  else
    raise TypeError, "#{other.class} can't be subtracted from Item::TimeLength."
  end
end

#/(other) ⇒ TimeLength

Parameters:

Returns:



129
130
131
132
133
134
135
# File 'lib/reading/item/time_length.rb', line 129

def /(other)
  if other.is_a? Numeric
    self.class.new(value / other).to_i_if_whole!
  else
    raise TypeError, "TimeLength can't be divided by #{other.class}."
  end
end

#<=>(other) ⇒ Integer

Parameters:

Returns:

  • (Integer)


149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/reading/item/time_length.rb', line 149

def <=>(other)
  return 1 if other.nil?

  if other.is_a? Numeric
    other = self.class.from_pages(other)
  end

  unless other.is_a? Item::TimeLength
    raise TypeError, "TimeLength can't be compared to #{other.class} #{other}."
  end

  value <=> other.value
end

#coerce(other) ⇒ Object

Parameters:



139
140
141
142
143
144
145
# File 'lib/reading/item/time_length.rb', line 139

def coerce(other)
  if other.is_a? Numeric
    [self.class.from_pages(other), self]
  else
    raise TypeError, "#{other.class} can't be coerced into a TimeLength."
  end
end

#eql?(other) ⇒ Boolean

Must be implemented for hash key equality checks.

Parameters:

Returns:

  • (Boolean)


166
167
168
# File 'lib/reading/item/time_length.rb', line 166

def eql?(other)
  hash == other.hash
end

#hashInteger

Must be implemented along with #eql? for hash key equality checks.

Returns:

  • (Integer)


172
173
174
# File 'lib/reading/item/time_length.rb', line 172

def hash
  value
end

#hoursNumeric

Only the hours, e.g. the “h” value in “h:mm”.

Returns:



41
42
43
# File 'lib/reading/item/time_length.rb', line 41

def hours
  value.to_i / 60
end

#minutesNumeric

Only the hours, e.g. the “mm” value in “h:mm”.

Returns:



47
48
49
# File 'lib/reading/item/time_length.rb', line 47

def minutes
  value % 60
end

#roundTimeLength

A copy of self with a rounded @value.

Returns:



70
71
72
# File 'lib/reading/item/time_length.rb', line 70

def round
  self.class.new(@value.round)
end

#to_iInteger

To pages.

Returns:

  • (Integer)


59
60
61
# File 'lib/reading/item/time_length.rb', line 59

def to_i
  ((value / 60.0) * Config.hash.fetch(:pages_per_hour)).to_i
end

#to_i_if_wholeTimeLength

A non-mutating version of #to_i_if_whole! for compatibility with the refinement Numeric#to_i_if_whole.

Returns:



87
88
89
90
91
# File 'lib/reading/item/time_length.rb', line 87

def to_i_if_whole
  return self if @value.is_a?(Integer) || @value.to_i != @value

  self.class.new(@value.to_i)
end

#to_i_if_whole!TimeLength

Converts @value to an Integer if it’s a whole number, and returns self.

Returns:



76
77
78
79
80
81
82
# File 'lib/reading/item/time_length.rb', line 76

def to_i_if_whole!
  if @value.to_i == @value
    @value = @value.to_i
  end

  self
end

#to_sString

A string in “h:mm” format.

Returns:



53
54
55
# File 'lib/reading/item/time_length.rb', line 53

def to_s
  "#{hours}:#{minutes.round.to_s.rjust(2, '0')} or #{(value / 60.0 * Config.hash.fetch(:pages_per_hour)).round} pages"
end

#zero?Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/reading/item/time_length.rb', line 64

def zero?
  value.zero?
end