startat 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/History.txt +6 -0
- data/Manifest.txt +8 -0
- data/README.txt +68 -0
- data/Rakefile +12 -0
- data/examples/print-to-the-future.rb +70 -0
- data/examples/twitter-schedule-bot.rb +113 -0
- data/lib/startat.rb +121 -0
- data/test/test_startat.rb +142 -0
- metadata +106 -0
- metadata.gz.sig +3 -0
data.tar.gz.sig
ADDED
|
Binary file
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
= startat
|
|
2
|
+
|
|
3
|
+
* http://startat.rubyforge.org/
|
|
4
|
+
|
|
5
|
+
== DESCRIPTION:
|
|
6
|
+
|
|
7
|
+
StartAt is a simple class for future code execution. It is designed
|
|
8
|
+
to execute a block of code at a specific point in time in the future.
|
|
9
|
+
|
|
10
|
+
StartAt works by spawning a new thread, determining how long it must wait (in
|
|
11
|
+
seconds) until the future date and time is reached, calling sleep with the
|
|
12
|
+
exact number of seconds to wait, and then executing the code block.
|
|
13
|
+
|
|
14
|
+
StartAt was derived from a script written to post schedule information to
|
|
15
|
+
Twitter for a symposium. The schedule robot posted event details exactly
|
|
16
|
+
five minutes in advance of the event.
|
|
17
|
+
|
|
18
|
+
== FEATURES/PROBLEMS:
|
|
19
|
+
|
|
20
|
+
Issues:
|
|
21
|
+
* This is an alpha release. The developer is interested in feedback on the API.
|
|
22
|
+
* StartAt currently operates with whole seconds, not microseconds.
|
|
23
|
+
* A running (waiting) StartAt object can be interrupted early with SIGALARM.
|
|
24
|
+
* Thread safety issues have not been examined or addressed yet.
|
|
25
|
+
|
|
26
|
+
== SYNOPSIS:
|
|
27
|
+
|
|
28
|
+
require 'date'
|
|
29
|
+
require 'startat'
|
|
30
|
+
|
|
31
|
+
future_time = DateTime.parse("2010-03-24 03:34:45 PM EDT")
|
|
32
|
+
action = lambda { print "The time is now!" }
|
|
33
|
+
future_event = StartAt.new(future_time, &action)
|
|
34
|
+
future_event.start
|
|
35
|
+
future_event.join
|
|
36
|
+
|
|
37
|
+
== REQUIREMENTS:
|
|
38
|
+
|
|
39
|
+
* date
|
|
40
|
+
|
|
41
|
+
== INSTALL:
|
|
42
|
+
|
|
43
|
+
* sudo gem install startat
|
|
44
|
+
|
|
45
|
+
== LICENSE:
|
|
46
|
+
|
|
47
|
+
(The MIT License)
|
|
48
|
+
|
|
49
|
+
Copyright (c) 2009 Keith A. Watson <ikawnoclast@interocitry.com>
|
|
50
|
+
|
|
51
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
52
|
+
a copy of this software and associated documentation files (the
|
|
53
|
+
'Software'), to deal in the Software without restriction, including
|
|
54
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
55
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
56
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
57
|
+
the following conditions:
|
|
58
|
+
|
|
59
|
+
The above copyright notice and this permission notice shall be
|
|
60
|
+
included in all copies or substantial portions of the Software.
|
|
61
|
+
|
|
62
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
63
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
64
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
65
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
66
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
67
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
68
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# -*- ruby -*-
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'hoe'
|
|
5
|
+
|
|
6
|
+
Hoe.spec 'startat' do |p|
|
|
7
|
+
# self.rubyforge_name = 'startatx' # if different than 'startat'
|
|
8
|
+
p.developer('Keith Watson', 'ikawnoclast@interocitry.com')
|
|
9
|
+
p.remote_rdoc_dir = '' # Release to root
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# vim: syntax=ruby
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#! /usr/bin/env ruby -w
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# print-to-the-future.rb -- Schedules and prints messages in the future.
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2009 Keith A. Watson <ikawnoclast@interocitry.com>
|
|
7
|
+
#
|
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
9
|
+
# a copy of this software and associated documentation files (the
|
|
10
|
+
# 'Software'), to deal in the Software without restriction, including
|
|
11
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
12
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
13
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
14
|
+
# the following conditions:
|
|
15
|
+
#
|
|
16
|
+
# The above copyright notice and this permission notice shall be
|
|
17
|
+
# included in all copies or substantial portions of the Software.
|
|
18
|
+
#
|
|
19
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
20
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
21
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
22
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
23
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
24
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
25
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
26
|
+
#
|
|
27
|
+
|
|
28
|
+
require 'date'
|
|
29
|
+
require 'startat'
|
|
30
|
+
|
|
31
|
+
# The following is borrowed from the _Ruby Cookbook_, Lucas Carlson & Leonard
|
|
32
|
+
# Richardson, O'Reilly Press, page 111.
|
|
33
|
+
# Time.to_datetime exists -- it's private though.
|
|
34
|
+
class Time
|
|
35
|
+
def to_datetime
|
|
36
|
+
seconds = sec + Rational(usec, 10**6)
|
|
37
|
+
offset = Rational(utc_offset, 60 * 60 * 24)
|
|
38
|
+
DateTime.new(year, month, day, hour, min, seconds, offset)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
Time_format = "%b %e %H:%M:%S"
|
|
43
|
+
|
|
44
|
+
puts "Start time: #{DateTime.now.strftime(Time_format)}"
|
|
45
|
+
|
|
46
|
+
schedule = {
|
|
47
|
+
(Time.now + 5).to_datetime => "5 seconds later",
|
|
48
|
+
(Time.now + 10).to_datetime => "10 seconds later",
|
|
49
|
+
(Time.now + 33).to_datetime => "33 seconds later",
|
|
50
|
+
(Time.now + 1 * 60).to_datetime => "1 minute later",
|
|
51
|
+
(Time.now + 2 * 60).to_datetime => "2 minutes later and done."
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
scheduled_events = Array.new
|
|
55
|
+
|
|
56
|
+
schedule.each { | event_time, msg |
|
|
57
|
+
action = lambda {
|
|
58
|
+
puts "#{DateTime.now.strftime(Time_format)} #{msg}"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# create and start the scheduler for the future event
|
|
62
|
+
future_event = StartAt.new(event_time, &action)
|
|
63
|
+
future_event.start
|
|
64
|
+
|
|
65
|
+
# store the event
|
|
66
|
+
scheduled_events.push(future_event)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# wait out the longest thread
|
|
70
|
+
sleep 2 * 60 + 1
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/opt/local/bin/ruby -w
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# twitter-schedule-bot.rb -- A code example for using StartAt for posting
|
|
5
|
+
# a schedule of events for an event to Twitter.
|
|
6
|
+
#
|
|
7
|
+
# Copyright (c) 2009 Keith A. Watson <ikawnoclast@interocitry.com>
|
|
8
|
+
#
|
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
10
|
+
# a copy of this software and associated documentation files (the
|
|
11
|
+
# 'Software'), to deal in the Software without restriction, including
|
|
12
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
13
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
14
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
15
|
+
# the following conditions:
|
|
16
|
+
#
|
|
17
|
+
# The above copyright notice and this permission notice shall be
|
|
18
|
+
# included in all copies or substantial portions of the Software.
|
|
19
|
+
#
|
|
20
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
21
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
22
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
23
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
24
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
25
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
26
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
27
|
+
#
|
|
28
|
+
|
|
29
|
+
#
|
|
30
|
+
# NOTE: This is an updated version of the code CERIAS used to post the
|
|
31
|
+
# schedule of events for the 20009 CERIAS Information Security Symposium.
|
|
32
|
+
# This code is missing the Twitter account details (username and password)
|
|
33
|
+
# and the events have already elapsed. This is only an example, but is
|
|
34
|
+
# easily updated for your own events.
|
|
35
|
+
#
|
|
36
|
+
|
|
37
|
+
require 'rubygems'
|
|
38
|
+
require 'twitter'
|
|
39
|
+
require 'date'
|
|
40
|
+
require 'startat'
|
|
41
|
+
|
|
42
|
+
# message added to the beginning and end of the post
|
|
43
|
+
header="CERIAS Symposium Schedule:"
|
|
44
|
+
footer="#cerias"
|
|
45
|
+
|
|
46
|
+
# amount of time before the actual event to post info (in seconds)
|
|
47
|
+
leadTime = 5 * 60;
|
|
48
|
+
|
|
49
|
+
# Twitter account object creation
|
|
50
|
+
postService = Twitter::Base.new('myTwitterAccount', 'myTwitterPassword')
|
|
51
|
+
|
|
52
|
+
# schedule array containing event times and messages
|
|
53
|
+
schedule = {
|
|
54
|
+
DateTime.parse('2009-03-24 09:30:00 AM EDT') \
|
|
55
|
+
=> "Registration and Coffee in LWSN Commons",
|
|
56
|
+
DateTime.parse('2009-03-24 10:30:00 AM EDT') \
|
|
57
|
+
=> "Welcome in LWSN 1142",
|
|
58
|
+
DateTime.parse('2009-03-24 10:35:00 AM EDT') \
|
|
59
|
+
=> "Panel #1: Transitive Security & Standards Adoption in LWSN 1142",
|
|
60
|
+
DateTime.parse('2009-03-24 12:15:00 PM EDT') \
|
|
61
|
+
=> "Lunch in LWSN 1190",
|
|
62
|
+
DateTime.parse('2009-03-24 01:45:00 PM EDT') \
|
|
63
|
+
=> "Panel #2: Security in the Cloud in LWSN 1142",
|
|
64
|
+
DateTime.parse('2009-03-24 03:30:00 PM EDT') \
|
|
65
|
+
=> "Fireside Chat in LWSN 1142",
|
|
66
|
+
DateTime.parse('2009-03-24 07:00:00 PM EDT') \
|
|
67
|
+
=> "John Thompson, CEO Symantec in STEW Fowler Hall",
|
|
68
|
+
DateTime.parse('2009-03-25 08:00:00 AM EDT') \
|
|
69
|
+
=> "Registration and Coffee in LWSN Commons",
|
|
70
|
+
DateTime.parse('2009-03-25 08:30:00 AM EDT') \
|
|
71
|
+
=> "Morning Keynote Address: Dr. Ronald Ritchey in LWSN 1142",
|
|
72
|
+
DateTime.parse('2009-03-25 09:45:00 AM EDT') \
|
|
73
|
+
=> "Panel #3: Unsecured Economies in LWSN 1142",
|
|
74
|
+
DateTime.parse('2009-03-25 11:15:00 AM EDT') \
|
|
75
|
+
=> "Tech Talk Poster Preview in LWSN 1142",
|
|
76
|
+
DateTime.parse('2009-03-25 12:30:00 PM EDT') \
|
|
77
|
+
=> "Lunch and Awards in LWSN 1142",
|
|
78
|
+
DateTime.parse('2009-03-25 02:00:00 PM EDT') \
|
|
79
|
+
=> "Poster Session & CERIAS Anniversary Cake in LWSN Commons",
|
|
80
|
+
DateTime.parse('2009-03-25 04:30:00 PM EDT') \
|
|
81
|
+
=> "CERIAS Seminar in PFEN 241",
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
schedEvents = Array.new
|
|
85
|
+
|
|
86
|
+
schedule.keys.each { | event |
|
|
87
|
+
# cacluate the time to post the message before the actual event
|
|
88
|
+
postTime = StartAt.get_time_before(event, leadTime)
|
|
89
|
+
# create the action of posting a message; pasted to the scheduler
|
|
90
|
+
action = lambda {
|
|
91
|
+
msg = "#{header} #{schedule[event]} starts at #{event.strftime("%l:%M")} #{footer}"
|
|
92
|
+
puts "#{DateTime.now.strftime("%b %e %H:%M:%S")} Posting the following message: \"#{msg}\" (length=#{msg.length})"
|
|
93
|
+
puts postService.post(msg).inspect
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# create and start the scheduler for the future event
|
|
97
|
+
futureEvent = StartAt.new(postTime, &action)
|
|
98
|
+
futureEvent.start
|
|
99
|
+
|
|
100
|
+
# store the event
|
|
101
|
+
schedEvents.push(futureEvent)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# find the longest running thread and join it
|
|
105
|
+
longestEvent = StartAt.new(DateTime.now)
|
|
106
|
+
schedEvents.each { | eventPostTime |
|
|
107
|
+
if eventPostTime > longestEvent
|
|
108
|
+
longestEvent = eventPostTime
|
|
109
|
+
end
|
|
110
|
+
}
|
|
111
|
+
longestEvent.join
|
|
112
|
+
|
|
113
|
+
exit 0
|
data/lib/startat.rb
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# StartAt is class for executing code at a specific point in the future.
|
|
5
|
+
# The object is initialized with a #DateTime object with a point of time in the
|
|
6
|
+
# future and a code block to be executed. Calling #start will calculate the
|
|
7
|
+
# wait time (in seconds), initialize a #Thread that will then +sleep+ for the
|
|
8
|
+
# appropriate amount of time, and then the code block will be executed.
|
|
9
|
+
#
|
|
10
|
+
# For example:
|
|
11
|
+
#
|
|
12
|
+
# require 'date'
|
|
13
|
+
# require 'startat'
|
|
14
|
+
#
|
|
15
|
+
# bday = DateTime.parse("2009-08-20 08:30:00 AM EDT")
|
|
16
|
+
# action = lambda { puts "Happy Birthday, Dad!" }
|
|
17
|
+
# wait_for_it = StartAt.new(bday, &action)
|
|
18
|
+
# wait_for_it.start
|
|
19
|
+
# wait_for_it.join
|
|
20
|
+
#
|
|
21
|
+
#
|
|
22
|
+
# StartAt was originally written to post schedule information for a symposium to
|
|
23
|
+
# Twitter (see the examples directory).
|
|
24
|
+
#
|
|
25
|
+
class StartAt
|
|
26
|
+
VERSION = '0.1.0'
|
|
27
|
+
include Comparable
|
|
28
|
+
|
|
29
|
+
Seconds_per_day = 24 * 60 * 60 # :nodoc:
|
|
30
|
+
|
|
31
|
+
attr_reader :start_datetime
|
|
32
|
+
|
|
33
|
+
# Returns a new future action object that will execute the code block
|
|
34
|
+
# at a point in the future as defined by #start_datetime.
|
|
35
|
+
def initialize(start_datetime, &block)
|
|
36
|
+
@thread_started = false
|
|
37
|
+
if start_datetime.class == DateTime
|
|
38
|
+
@start_datetime = start_datetime
|
|
39
|
+
else
|
|
40
|
+
raise ArgumentError.new("must have a DateTime object")
|
|
41
|
+
end
|
|
42
|
+
if block
|
|
43
|
+
@action = block
|
|
44
|
+
elsif block_given?
|
|
45
|
+
@action = lambda { yield }
|
|
46
|
+
else
|
|
47
|
+
raise ArgumentError.new("missing a block")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Compares the start #DateTime of the current future action with the
|
|
52
|
+
# start time of the #other future action.
|
|
53
|
+
def <=> (other)
|
|
54
|
+
@start_datetime <=> other.start_datetime
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Starts the future action thread by determining the time needed to wait
|
|
58
|
+
# based on the start date and then executes the code block once the time
|
|
59
|
+
# has elapsed.
|
|
60
|
+
def start
|
|
61
|
+
if ! @thread_started
|
|
62
|
+
@sleeper = Thread.new do
|
|
63
|
+
wait = get_wait_time()
|
|
64
|
+
# Check that the wait time is positive, otherwise the future
|
|
65
|
+
# event time has already past. We skip it, since a warning
|
|
66
|
+
# message was produced in wait_time.
|
|
67
|
+
if wait > 0
|
|
68
|
+
sleep wait
|
|
69
|
+
@action.call
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
@thread_started = true
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Cancels a running future action object thread.
|
|
77
|
+
def cancel
|
|
78
|
+
if ! @thread_started
|
|
79
|
+
@sleeper.exit
|
|
80
|
+
@thread_started = false
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
alias kill cancel
|
|
85
|
+
|
|
86
|
+
# Returns the status of a future action object thread. See #Thread#status
|
|
87
|
+
def status
|
|
88
|
+
@sleeper.status
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Joins the current thread to the future action thread. See #Thread.join
|
|
92
|
+
def join
|
|
93
|
+
@sleeper.join
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Takes a future #DateTime object and returns a #DateTime object for the time
|
|
97
|
+
# before as specified in +time_before+ in seconds.
|
|
98
|
+
def self.get_time_before(future_datetime, time_before)
|
|
99
|
+
future_datetime - Rational(time_before, Seconds_per_day)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Takes a future #DateTime object and returns a #DateTime object for the time
|
|
103
|
+
# after as specified in +time_before+ in seconds.
|
|
104
|
+
def self.get_time_after(future_datetime, time_after)
|
|
105
|
+
future_datetime + Rational(time_after, Seconds_per_day)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def get_wait_time
|
|
111
|
+
# 1. Find the difference between the time now and the future time.
|
|
112
|
+
# 2. DateTime objects store time in whole seconds, so convert to the
|
|
113
|
+
# number of seconds in a day and return an interger.
|
|
114
|
+
wait_time = (((@start_datetime - DateTime.now) * Seconds_per_day) + 1).to_i
|
|
115
|
+
# send a warning message if the wait time is negative since the future
|
|
116
|
+
# time is no in the past.
|
|
117
|
+
warn "Specified date and time of #{@start_datetime.to_s} has already elapsed" if wait_time <= 0
|
|
118
|
+
return wait_time
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
require "test/unit"
|
|
2
|
+
require "date"
|
|
3
|
+
require "startat"
|
|
4
|
+
|
|
5
|
+
# The following is borrowed from the _Ruby Cookbook_, Lucas Carlson & Leonard
|
|
6
|
+
# Richardson, O'Reilly Press, page 111.
|
|
7
|
+
# Time.to_datetime exists -- it's private though.
|
|
8
|
+
class Time
|
|
9
|
+
def to_datetime
|
|
10
|
+
seconds = sec + Rational(usec, 10**6)
|
|
11
|
+
offset = Rational(utc_offset, 60 * 60 * 24)
|
|
12
|
+
DateTime.new(year, month, day, hour, min, seconds, offset)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Unit test suite
|
|
17
|
+
class TestStartat < Test::Unit::TestCase
|
|
18
|
+
def test_initialization1
|
|
19
|
+
action = lambda { val = true }
|
|
20
|
+
test = nil
|
|
21
|
+
start = DateTime.now
|
|
22
|
+
assert_nothing_raised(ArgumentError) {
|
|
23
|
+
test = StartAt.new(start, &action)
|
|
24
|
+
}
|
|
25
|
+
assert_not_nil test
|
|
26
|
+
assert_equal(start, test.start_datetime)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_initialization2
|
|
30
|
+
test = nil
|
|
31
|
+
start = DateTime.now
|
|
32
|
+
assert_nothing_raised(ArgumentError) {
|
|
33
|
+
test = StartAt.new(start) { val = true }
|
|
34
|
+
}
|
|
35
|
+
assert_not_nil test
|
|
36
|
+
assert_same(start, test.start_datetime)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_initialization3
|
|
40
|
+
test = StartAt
|
|
41
|
+
assert_raise(ArgumentError) {
|
|
42
|
+
test.new(DateTime.now)
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_initialization4
|
|
47
|
+
assert_raise(ArgumentError) {
|
|
48
|
+
test = StartAt.new(Time.now) { val = true }
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_initialization5
|
|
53
|
+
assert_raise(ArgumentError) {
|
|
54
|
+
test = StartAt.new("This should fail") { val = true }
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_start1
|
|
59
|
+
action = lambda { val = true }
|
|
60
|
+
test = StartAt.new((Time.now + 5).to_datetime, &action)
|
|
61
|
+
test.start
|
|
62
|
+
assert_equal("sleep", test.status)
|
|
63
|
+
test.cancel
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_stop1
|
|
67
|
+
action = lambda { val = true }
|
|
68
|
+
test = StartAt.new((Time.now + 5).to_datetime, &action)
|
|
69
|
+
test.start
|
|
70
|
+
test.cancel
|
|
71
|
+
assert(test.status)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def test_stop2
|
|
75
|
+
action = lambda { val = true }
|
|
76
|
+
test = StartAt.new((Time.now + 5).to_datetime, &action)
|
|
77
|
+
test.start
|
|
78
|
+
test.kill
|
|
79
|
+
assert(test.status)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def comparison1
|
|
83
|
+
test1 = StartAt
|
|
84
|
+
test2 = StartAt
|
|
85
|
+
test1.new((Time.now + 2).to_datetime) { val1 = true }
|
|
86
|
+
test2.new((Time.now + 3).to_datetime) { val2 = true }
|
|
87
|
+
assert_not_equal(test1, test2)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def comparison2
|
|
91
|
+
date_time = (Time.now + 2).to_datetime
|
|
92
|
+
test1 = StartAt.new(date_time) { val1 = true }
|
|
93
|
+
test2 = StartAt.new(date_time) { val2 = true }
|
|
94
|
+
assert_equal(test1, test2)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def comparison3
|
|
98
|
+
test1 = StartAt
|
|
99
|
+
test2 = StartAt
|
|
100
|
+
test1.new((Time.now + 2).to_datetime) { val1 = true }
|
|
101
|
+
test2.new((Time.now + 3).to_datetime) { val2 = true }
|
|
102
|
+
assert_operator(test1, :<, test2)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def test_invalid_time1
|
|
106
|
+
action = lambda { val = true }
|
|
107
|
+
test = StartAt.new((Time.now - 2).to_datetime, &action)
|
|
108
|
+
test.start
|
|
109
|
+
assert(!test.status)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def test_timing1
|
|
113
|
+
val = true
|
|
114
|
+
test = StartAt.new((Time.now + 2).to_datetime) { val = false }
|
|
115
|
+
test.start
|
|
116
|
+
assert(val)
|
|
117
|
+
sleep 1
|
|
118
|
+
assert(val)
|
|
119
|
+
sleep 2
|
|
120
|
+
assert(!val)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_get_time_before1
|
|
124
|
+
time_now = Time.now
|
|
125
|
+
datetime_now = time_now.to_datetime
|
|
126
|
+
lead_times = [ 5, 30, 120, 3600, 43200, 86400, 604800 ]
|
|
127
|
+
lead_times.each { | lead_time |
|
|
128
|
+
time_before = StartAt.get_time_before(datetime_now, lead_time)
|
|
129
|
+
assert_equal((time_now - lead_time).to_datetime, time_before)
|
|
130
|
+
}
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def test_get_time_after1
|
|
134
|
+
time_now = Time.now
|
|
135
|
+
datetime_now = time_now.to_datetime
|
|
136
|
+
lead_times = [ 5, 30, 120, 3600, 43200, 86400, 604800 ]
|
|
137
|
+
lead_times.each { | lead_time |
|
|
138
|
+
time_before = StartAt.get_time_after(datetime_now, lead_time)
|
|
139
|
+
assert_equal((time_now + lead_time).to_datetime, time_before)
|
|
140
|
+
}
|
|
141
|
+
end
|
|
142
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: startat
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Keith Watson
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain:
|
|
11
|
+
- |
|
|
12
|
+
-----BEGIN CERTIFICATE-----
|
|
13
|
+
MIIDRDCCAiygAwIBAgIBADANBgkqhkiG9w0BAQUFADBIMRQwEgYDVQQDDAtpa2F3
|
|
14
|
+
bm9jbGFzdDEbMBkGCgmSJomT8ixkARkWC2ludGVyb2NpdHJ5MRMwEQYKCZImiZPy
|
|
15
|
+
LGQBGRYDY29tMB4XDTA5MDcyOTEzNTcxOFoXDTEwMDcyOTEzNTcxOFowSDEUMBIG
|
|
16
|
+
A1UEAwwLaWthd25vY2xhc3QxGzAZBgoJkiaJk/IsZAEZFgtpbnRlcm9jaXRyeTET
|
|
17
|
+
MBEGCgmSJomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
|
18
|
+
ggEBAM6Pn7BiDNnNRWUQzmuPBr3vNgp9TIB1SrJ3a9c1iJY6sYaTZD4M+JUmMpfo
|
|
19
|
+
FzQGdAAASOY0aJpBaZdA13fEC7fCed7pr44sf5mxZv1cNsUrXJbw9ZNBQFHyouz6
|
|
20
|
+
YTvO7pd24F2/DmxngutwlgCZlXwvkB5mrEfNbqIof3UhYkvK7mHBEJ5AWlGQ1nft
|
|
21
|
+
K0x72nTi3ZIg0mufz2kMadWcwK8I7A74FuGdFbMcLmoXJb4DwxCKb3APnS8UzoYV
|
|
22
|
+
/y5ddiogWbSEi+coOY0t6BkkS0kAEPf1tW6UtWB8yI+/807kyP/BQ3sQ2IoBAi04
|
|
23
|
+
+khoWTEyqkYzWmH2zRYSuh5U7RMCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8E
|
|
24
|
+
BAMCBLAwHQYDVR0OBBYEFMSjxPX6jYn3js6kC8BqsQH1c3+VMA0GCSqGSIb3DQEB
|
|
25
|
+
BQUAA4IBAQCE9cS2qD2MGQ4mWHIQOeJk9y7mQle7L25Z3tuMVNG0tPwmnZlaXpeE
|
|
26
|
+
DSYDKVCCoJQCH6m0H5KX7Jns0Y3/4unzQzfGVEh1JNojay5f2sV4YwRO+33/Ymxd
|
|
27
|
+
hhqmbytCY5ie36XoOC0aayVulcqMaHfgUVAUPN3bBudPANpVdF79yqBhjuNuCl3R
|
|
28
|
+
AwTBaYaGwOoSCGMUpOh0F4ADlqFKlZZMlxr2WXQJD2cqfMnLuzKgoL5V/Hkes8OL
|
|
29
|
+
Wh0bTgBFH0mpCwLpypJgZiuM6xhz90YTH7WzLSz9itIx2Vhrvylvxq4ePPfuefPX
|
|
30
|
+
Ia165vMqyt5W7zBTANDsPWi6m1DiaDTD
|
|
31
|
+
-----END CERTIFICATE-----
|
|
32
|
+
|
|
33
|
+
date: 2009-07-29 00:00:00 -04:00
|
|
34
|
+
default_executable:
|
|
35
|
+
dependencies:
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: hoe
|
|
38
|
+
type: :development
|
|
39
|
+
version_requirement:
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
42
|
+
- - ">="
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: 2.3.2
|
|
45
|
+
version:
|
|
46
|
+
description: |-
|
|
47
|
+
StartAt is a simple class for future code execution. It is designed
|
|
48
|
+
to execute a block of code at a specific point in time in the future.
|
|
49
|
+
|
|
50
|
+
StartAt works by spawning a new thread, determining how long it must wait (in
|
|
51
|
+
seconds) until the future date and time is reached, calling sleep with the
|
|
52
|
+
exact number of seconds to wait, and then executing the code block.
|
|
53
|
+
|
|
54
|
+
StartAt was derived from a script written to post schedule information to
|
|
55
|
+
Twitter for a symposium. The schedule robot posted event details exactly
|
|
56
|
+
five minutes in advance of the event.
|
|
57
|
+
email:
|
|
58
|
+
- ikawnoclast@interocitry.com
|
|
59
|
+
executables: []
|
|
60
|
+
|
|
61
|
+
extensions: []
|
|
62
|
+
|
|
63
|
+
extra_rdoc_files:
|
|
64
|
+
- History.txt
|
|
65
|
+
- Manifest.txt
|
|
66
|
+
- README.txt
|
|
67
|
+
files:
|
|
68
|
+
- History.txt
|
|
69
|
+
- Manifest.txt
|
|
70
|
+
- README.txt
|
|
71
|
+
- Rakefile
|
|
72
|
+
- examples/print-to-the-future.rb
|
|
73
|
+
- examples/twitter-schedule-bot.rb
|
|
74
|
+
- lib/startat.rb
|
|
75
|
+
- test/test_startat.rb
|
|
76
|
+
has_rdoc: true
|
|
77
|
+
homepage: http://startat.rubyforge.org/
|
|
78
|
+
licenses: []
|
|
79
|
+
|
|
80
|
+
post_install_message:
|
|
81
|
+
rdoc_options:
|
|
82
|
+
- --main
|
|
83
|
+
- README.txt
|
|
84
|
+
require_paths:
|
|
85
|
+
- lib
|
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - ">="
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: "0"
|
|
91
|
+
version:
|
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: "0"
|
|
97
|
+
version:
|
|
98
|
+
requirements: []
|
|
99
|
+
|
|
100
|
+
rubyforge_project: startat
|
|
101
|
+
rubygems_version: 1.3.4
|
|
102
|
+
signing_key:
|
|
103
|
+
specification_version: 3
|
|
104
|
+
summary: StartAt is a simple class for future code execution
|
|
105
|
+
test_files:
|
|
106
|
+
- test/test_startat.rb
|
metadata.gz.sig
ADDED