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 a 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 a 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:



125
126
127
128
129
130
131
# File 'lib/reading/item/time_length.rb', line 125

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:



101
102
103
104
105
106
107
108
109
# File 'lib/reading/item/time_length.rb', line 101

def +(other)
  if other.is_a? 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 TimeLength."
  end
end

#-(other) ⇒ TimeLength

Parameters:

Returns:



113
114
115
116
117
118
119
120
121
# File 'lib/reading/item/time_length.rb', line 113

def -(other)
  if other.is_a? 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 TimeLength."
  end
end

#/(other) ⇒ TimeLength

Parameters:

Returns:



135
136
137
138
139
140
141
# File 'lib/reading/item/time_length.rb', line 135

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)


166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/reading/item/time_length.rb', line 166

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

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

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

  value <=> other.value
end

#coerce(other) ⇒ Object

Parameters:



156
157
158
159
160
161
162
# File 'lib/reading/item/time_length.rb', line 156

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)


183
184
185
# File 'lib/reading/item/time_length.rb', line 183

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

#hashInteger

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

Returns:

  • (Integer)


189
190
191
# File 'lib/reading/item/time_length.rb', line 189

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

#percentage_of(other) ⇒ TimeLength

For relativizing progress to a percentage of amount.

Parameters:

Returns:



146
147
148
149
150
151
152
# File 'lib/reading/item/time_length.rb', line 146

def percentage_of(other)
  if other.is_a? TimeLength
    value.to_f / other.value
  else
    raise TypeError, "TimeLength can't be percent-divided by #{other.class}."
  end
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:



89
90
91
92
93
94
95
96
97
# File 'lib/reading/item/time_length.rb', line 89

def to_i_if_whole
  if @value.is_a?(Float) && @value.nan?
    return self.class.new(0)
  else
    return self if @value.is_a?(Integer) || @value.to_i != @value

    self.class.new(@value.to_i)
  end
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
83
84
# File 'lib/reading/item/time_length.rb', line 76

def to_i_if_whole!
  if @value.is_a?(Float) && @value.nan?
    @value = 0
  elsif @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