Class: Duration

Inherits:
Object show all
Defined in:
lib/days_and_times/duration.rb

Direct Known Subclasses

Days, Hours, Minutes, Seconds, Weeks

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(count = 0, unit = 1, start_time = nil, auto_klass = {}) ⇒ Duration

Returns a new instance of Duration.



8
9
10
11
12
13
14
15
16
17
18
# File 'lib/days_and_times/duration.rb', line 8

def initialize(count=0,unit=1,start_time=nil,auto_klass={})
  if unit.is_a?(Time) || unit.is_a?(DateTime)
    start_time = unit
    unit = 1
  end
  options = {:count => count || 0, :unit => unit || 1, :start_time => start_time}.merge(count.is_a?(Hash) ? count : {})

  @unit = options[:unit]
  @length = (@unit * options[:count].to_f).round
  @start_time = options[:start_time]
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args) ⇒ Object

                                                    • *



272
273
274
275
276
# File 'lib/days_and_times/duration.rb', line 272

def method_missing(method_name, *args)
  # Delegate any missing methods to the start_time Time object, if we have a start_time and the method exists there.
  return self.start_time.send(method_name, *args) if self.anchored? && self.start_time.respond_to?(method_name)
  super
end

Instance Attribute Details

#lengthObject

Length is the length of the time span, in seconds Unit is a length of time (in seconds) to use in collection methods StartTime is an optional attribute that can ‘anchor’ a duration

to a specific real time.


7
8
9
# File 'lib/days_and_times/duration.rb', line 7

def length
  @length
end

#start_timeObject

Length is the length of the time span, in seconds Unit is a length of time (in seconds) to use in collection methods StartTime is an optional attribute that can ‘anchor’ a duration

to a specific real time.


7
8
9
# File 'lib/days_and_times/duration.rb', line 7

def start_time
  @start_time
end

#unitObject

Length is the length of the time span, in seconds Unit is a length of time (in seconds) to use in collection methods StartTime is an optional attribute that can ‘anchor’ a duration

to a specific real time.


7
8
9
# File 'lib/days_and_times/duration.rb', line 7

def unit
  @unit
end

Class Method Details

.create_find_within_method_for(other, method_name, other_method_name) ⇒ Object



267
268
269
# File 'lib/days_and_times/duration.rb', line 267

def self.create_find_within_method_for(other, method_name, other_method_name)
  self.bind_class_object_method(other, method_name, other_method_name, [[], ['self.start_time', 'self.end_time']])
end

.lengthObject



27
28
29
# File 'lib/days_and_times/duration.rb', line 27

def self.length
  1
end

.new(*args) ⇒ Object



19
20
21
22
23
24
25
26
# File 'lib/days_and_times/duration.rb', line 19

def self.new(*args)
  a = super
  if self.name == 'Duration' && (args.last.is_a?(Hash) ? args.last[:auto_class] == true : true)
    a.send(:auto_class)
  else
    a
  end
end

Instance Method Details

#*(value) ⇒ Object



109
110
111
112
113
114
115
116
117
# File 'lib/days_and_times/duration.rb', line 109

def *(value)
  if value.is_a?(Duration)
    @length * value.length * value.unit
  elsif value.respond_to?(:to_i)
    auto_class(Duration.new(@length * value))
  else
    raise TypeError, "Can't convert #{value.class.name} to an integer."
  end
end

#+(value) ⇒ Object



102
103
104
105
106
107
108
# File 'lib/days_and_times/duration.rb', line 102

def +(value)
  if value.respond_to?(:to_i)
    auto_class(Duration.new(@length + value.to_i))
  else
    raise TypeError, "Can't convert #{value.class.name} to an integer."
  end
end

#-(value) ⇒ Object



95
96
97
98
99
100
101
# File 'lib/days_and_times/duration.rb', line 95

def -(value)
  if value.respond_to?(:to_i)
    auto_class(Duration.new(@length - value.to_i))
  else
    raise TypeError, "Can't convert #{value.class.name} to an integer."
  end
end

#/(value) ⇒ Object



118
119
120
121
122
123
124
125
126
# File 'lib/days_and_times/duration.rb', line 118

def /(value)
  if value.is_a?(Duration)
    @length / (value.length * value.unit)
  elsif value.respond_to?(:to_i)
    auto_class(Duration.new(@length / value))
  else
    raise TypeError, "Can't convert #{value.class.name} to an integer."
  end
end

#===(other) ⇒ Object



76
77
78
# File 'lib/days_and_times/duration.rb', line 76

def ===(other)
  self.to_f == other.to_f
end

#abs_lengthObject



54
55
56
# File 'lib/days_and_times/duration.rb', line 54

def abs_length
  @length
end

#abs_length=(value) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/days_and_times/duration.rb', line 47

def abs_length=(value)
  if value.respond_to?(:to_i)
    @length = value.to_i
  else
    raise TypeError, "Can't set a Duration's length to a #{value.class.name} object."
  end
end

#agoObject



200
201
202
# File 'lib/days_and_times/duration.rb', line 200

def ago
  self.before(Time.now)
end

#anchored?Boolean

Returns:

  • (Boolean)


184
185
186
# File 'lib/days_and_times/duration.rb', line 184

def anchored?
  !self.start_time.nil?
end

#before(time) ⇒ Object



194
195
196
# File 'lib/days_and_times/duration.rb', line 194

def before(time)
  time - @length
end

#coerce(*args) ⇒ Object



72
73
74
# File 'lib/days_and_times/duration.rb', line 72

def coerce(*args)
  to_f.coerce(*args)
end

#collect(use_unit = self.class.length, &block) ⇒ Object



230
231
232
233
234
235
236
# File 'lib/days_and_times/duration.rb', line 230

def collect(use_unit=self.class.length,&block)
  ary = []
  self.each(use_unit) do |x|
    ary << (block_given? ? yield(x) : x)
  end
  ary
end

#create_find_within_method_for(other, method_name, other_method_name) ⇒ Object

                                                    • *

Through some ingenious metacoding (see ‘def bind_object_method’) below, it is possible to create a new method on a Duration object to a method on another object, in order to gather information based on the duration mentioned.



264
265
266
# File 'lib/days_and_times/duration.rb', line 264

def create_find_within_method_for(other, method_name, other_method_name)
  self.bind_object_method(other, method_name, other_method_name, [[], ['self.start_time', 'self.end_time']])
end

#daysObject



150
151
152
# File 'lib/days_and_times/duration.rb', line 150

def days
  @length.to_f / Day.length
end

#each(use_unit = self.class.length) ⇒ Object



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/days_and_times/duration.rb', line 237

def each(use_unit=self.class.length)
  remainder = @length.to_f % use_unit
  ret = []
  if self.start_time.nil?
    (@length.to_f / use_unit).to_i.times do |i|
      ret << Duration.new(1, use_unit)
      yield(ret[-1])
    end
  else
    (@length.to_f / use_unit).to_i.times do |i|
      ret << Duration.new(1, use_unit, (self.start_time + (use_unit * i)))
      yield(ret[-1])
    end
  end
  if remainder > 0
    ret << (self.start_time.nil? ? Duration.new(remainder, 1) : Duration.new(remainder, 1, (self.start_time + @length - remainder)))
    yield(ret[-1])
  end
  ret
end

#each_day(&block) ⇒ Object



218
219
220
# File 'lib/days_and_times/duration.rb', line 218

def each_day(&block)
  self.each(Day.length,&block)
end

#each_hour(&block) ⇒ Object



221
222
223
# File 'lib/days_and_times/duration.rb', line 221

def each_hour(&block)
  self.each(Hour.length,&block)
end

#each_minute(&block) ⇒ Object



224
225
226
# File 'lib/days_and_times/duration.rb', line 224

def each_minute(&block)
  self.each(Minute.length,&block)
end

#each_second(&block) ⇒ Object



227
228
229
# File 'lib/days_and_times/duration.rb', line 227

def each_second(&block)
  self.each(Second.length,&block)
end

#each_week(&block) ⇒ Object

                                                    • *

A Duration can be treated as a ‘collection’ of units



215
216
217
# File 'lib/days_and_times/duration.rb', line 215

def each_week(&block)
  self.each(Week.length,&block)
end

#end_timeObject



181
182
183
# File 'lib/days_and_times/duration.rb', line 181

def end_time
  @start_time + self
end

#end_time=(value) ⇒ Object



174
175
176
177
178
179
180
# File 'lib/days_and_times/duration.rb', line 174

def end_time=(value)
  if value.is_a?(Time) || value.is_a?(DateTime)
    @start_time = value.to_time - self #Subtracts this duration from the end_time to get the start_time
  else
    raise TypeError, "A Duration's end_time must be a Time or DateTime object."
  end
end

#ending(time) ⇒ Object



207
208
209
210
# File 'lib/days_and_times/duration.rb', line 207

def ending(time)
  self.end_time = time
  self
end

#from(time) ⇒ Object

                                              • *

Calculations using Duration as an intermediate



191
192
193
# File 'lib/days_and_times/duration.rb', line 191

def from(time)
  time + @length
end

#from_nowObject



197
198
199
# File 'lib/days_and_times/duration.rb', line 197

def from_now
  self.from(Time.now)
end

#hoursObject



153
154
155
# File 'lib/days_and_times/duration.rb', line 153

def hours
  @length.to_f / Hour.length
end

#in_daysObject



131
132
133
134
# File 'lib/days_and_times/duration.rb', line 131

def in_days
  self.unit = Day.length
  auto_class(self)
end

#in_hoursObject



135
136
137
138
# File 'lib/days_and_times/duration.rb', line 135

def in_hours
  self.unit = Hour.length
  auto_class(self)
end

#in_minutesObject



139
140
141
142
# File 'lib/days_and_times/duration.rb', line 139

def in_minutes
  self.unit = Minute.length
  auto_class(self)
end

#in_secondsObject



143
144
145
146
# File 'lib/days_and_times/duration.rb', line 143

def in_seconds
  self.unit = Second.length
  auto_class(self)
end

#in_weeksObject



127
128
129
130
# File 'lib/days_and_times/duration.rb', line 127

def in_weeks
  self.unit = Week.length
  auto_class(self)
end

#inspectObject



79
80
81
# File 'lib/days_and_times/duration.rb', line 79

def inspect
  "#<#{self.class.name}:#{self.object_id} (length=#{self.length.inspect}) #{self.instance_variables.reject {|d| d=='@length' || self.instance_variable_get(d).nil?}.collect {|iv| "#{iv}=#{self.instance_variable_get(iv).inspect}"}.join(' ')}>"
end

#minutesObject



156
157
158
# File 'lib/days_and_times/duration.rb', line 156

def minutes
  @length.to_f / Minute.length
end

#secondsObject



159
160
161
# File 'lib/days_and_times/duration.rb', line 159

def seconds
  @length.to_f / Second.length
end

#starting(time) ⇒ Object



203
204
205
206
# File 'lib/days_and_times/duration.rb', line 203

def starting(time)
  self.start_time = time
  self
end

#to_aObject



57
58
59
60
61
62
# File 'lib/days_and_times/duration.rb', line 57

def to_a
  hrs = hours.to_i
  mins = (self - hrs.hours).minutes.to_i
  secs = (self - hrs.hours - mins.minutes).seconds.to_i
  [hrs, mins, secs]
end

#to_fObject



66
67
68
# File 'lib/days_and_times/duration.rb', line 66

def to_f
  self.abs_length.to_f
end

#to_iObject



63
64
65
# File 'lib/days_and_times/duration.rb', line 63

def to_i
  self.abs_length.to_i
end

#to_sObject



69
70
71
# File 'lib/days_and_times/duration.rb', line 69

def to_s
  "#{self.length} #{self.class.name}"
end

#weeksObject



147
148
149
# File 'lib/days_and_times/duration.rb', line 147

def weeks
  @length.to_f / Week.length
end