campfire-bot 0.1.0 → 1.0.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/.gitignore +1 -1
- data/Gemfile +6 -1
- data/README.textile +15 -5
- data/bin/campfire-bot +52 -6
- data/campfire-bot.gemspec +4 -7
- data/config.example.yml +3 -2
- data/lib/bot.rb +26 -26
- data/lib/version.rb +1 -1
- metadata +22 -96
- data/CHANGELOG.md +0 -10
- data/Gemfile.lock +0 -58
- data/plugins/accountability.rb +0 -45
- data/plugins/austin.rb +0 -29
- data/plugins/basecamp.rb +0 -48
- data/plugins/beer.rb +0 -214
- data/plugins/beijing_tally.rb +0 -30
- data/plugins/boop.rb +0 -127
- data/plugins/bruce.rb +0 -15
- data/plugins/bugzilla.rb +0 -198
- data/plugins/calvin.rb +0 -43
- data/plugins/chuck.rb +0 -23
- data/plugins/dilbert.rb +0 -51
- data/plugins/excuse.rb +0 -478
- data/plugins/fail.rb +0 -16
- data/plugins/figlet.rb +0 -10
- data/plugins/fun.rb +0 -95
- data/plugins/garfield.rb +0 -43
- data/plugins/generic_search.rb +0 -66
- data/plugins/help.rb +0 -13
- data/plugins/infobot.rb +0 -58
- data/plugins/insult.rb +0 -87
- data/plugins/jira.rb +0 -197
- data/plugins/lolcats.rb +0 -17
- data/plugins/our_quotes.rb +0 -195
- data/plugins/quote.rb +0 -31
- data/plugins/schneier.rb +0 -28
- data/plugins/seen.rb +0 -88
- data/plugins/signal_filter.rb +0 -9
- data/plugins/svn.rb +0 -167
- data/plugins/twitter_echo.rb +0 -54
- data/plugins/unfuddle.rb +0 -69
- data/plugins/weather.rb +0 -25
- data/plugins/xkcd.rb +0 -43
data/plugins/lolcats.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'open-uri'
|
2
|
-
require 'hpricot'
|
3
|
-
require 'tempfile'
|
4
|
-
|
5
|
-
class LolCats < CampfireBot::Plugin
|
6
|
-
on_command 'lolcat', :lolcats
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
@log = Logging.logger["CampfireBot::Plugin::Lolcat"]
|
10
|
-
end
|
11
|
-
|
12
|
-
def lolcats(msg)
|
13
|
-
# Scrape random lolcat
|
14
|
-
lolcat = (Hpricot(open('http://icanhascheezburger.com/?random#top'))/'div.entry img').first['src']
|
15
|
-
msg.speak(lolcat)
|
16
|
-
end
|
17
|
-
end
|
data/plugins/our_quotes.rb
DELETED
@@ -1,195 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
# Remember quotes and quips added upon request. Rather than pulling
|
4
|
-
# public quoes form the internet, the idea is that you can maintain
|
5
|
-
# your own list of quotes said by people at your campfire.
|
6
|
-
#
|
7
|
-
# Since this plugin maintains long-term persistent data, not just
|
8
|
-
# temporary state, its data file lives under var/ instead of tmp/.
|
9
|
-
#
|
10
|
-
# You can import from the eggdrop QuoteBot.log with this, which will
|
11
|
-
# overwrite any existing campfire-bot quotes:
|
12
|
-
#
|
13
|
-
# ruby -e '
|
14
|
-
# require "yaml"
|
15
|
-
# log = File.readlines("QuoteBot.log").collect { |l|
|
16
|
-
# action, scope, quoter, room, id, quote = l.split(" ", 6)
|
17
|
-
# quote.gsub!(/\x03\d\d/, "") # remove IRC color codes
|
18
|
-
# [action, quoter, room, id.sub(/^[(]#/, "").sub(/[)]$/, "").to_i,
|
19
|
-
# nil, quote]
|
20
|
-
# }
|
21
|
-
# File.open("var/quote-log.yml", "w") do |out|
|
22
|
-
# YAML.dump(log, out)
|
23
|
-
# end
|
24
|
-
# puts "wrote #{log.size} log entries"
|
25
|
-
# '
|
26
|
-
#
|
27
|
-
# Issues:
|
28
|
-
#
|
29
|
-
# * The entire log is rewritten after each add/del, which takes 1.2
|
30
|
-
# sec for my 3k quotes. It's the YAML.dump call that's slow. An
|
31
|
-
# alternative would be to store each log entry as a document and only
|
32
|
-
# append to the file. However, an incomplete write would corrupt the
|
33
|
-
# file. Maybe there's a way to discard the last, corrupt yaml
|
34
|
-
# document? For now, it's fast enough.
|
35
|
-
#
|
36
|
-
# * Would be nice when there are multiple matches to iterate through
|
37
|
-
# them when the same query is repeated.
|
38
|
-
#
|
39
|
-
# * There is another quote plugin in quote.rb whose model is to pull
|
40
|
-
# quotes from the internet. The upside is you have a list of quotes
|
41
|
-
# to start with. The downside is that it doesn't foster much sense
|
42
|
-
# of community nor develop common culture. To avoid a command name
|
43
|
-
# collision, the quote recall command of this plugin may be
|
44
|
-
# configured. The default commant is "!ourquote", but "!quote" is
|
45
|
-
# more natural.
|
46
|
-
#
|
47
|
-
class OurQuotes < CampfireBot::Plugin
|
48
|
-
on_command 'addquote', :addquote
|
49
|
-
on_command 'rmquote', :rmquote
|
50
|
-
# Configure with "our_quote_recall_command: quote"
|
51
|
-
#on_command 'quote', :quote
|
52
|
-
|
53
|
-
config_var :data_file, File.join(BOT_ROOT, 'var', 'quote-log.yml')
|
54
|
-
config_var :recall_command, "ourquote"
|
55
|
-
config_var :debug_enabled, false
|
56
|
-
|
57
|
-
attr_reader :use_htmlentities
|
58
|
-
|
59
|
-
def initialize()
|
60
|
-
super
|
61
|
-
|
62
|
-
self.class.on_command recall_command.to_s, :quote
|
63
|
-
|
64
|
-
# Put this in the constructor so we don't fail to find htmlentities
|
65
|
-
# every time we fetch a bug title.
|
66
|
-
begin
|
67
|
-
require 'htmlentities'
|
68
|
-
@use_htmlentities = true
|
69
|
-
rescue LoadError
|
70
|
-
debug "Falling back to 'cgi', install 'htmlentities' better unescaping"
|
71
|
-
require 'cgi'
|
72
|
-
end
|
73
|
-
|
74
|
-
@log = begin
|
75
|
-
YAML::load(File.read(@data_file))
|
76
|
-
rescue Errno::ENOENT => e
|
77
|
-
debug e
|
78
|
-
[]
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def debug(spew)
|
83
|
-
$stderr.puts "#{self.class.name}: #{spew}" if debug_enabled
|
84
|
-
end
|
85
|
-
|
86
|
-
def addquote(msg)
|
87
|
-
debug "Addquote requested: #{msg}"
|
88
|
-
if msg[:message].empty?
|
89
|
-
msg.speak "Please include the text of the quote and attribution."
|
90
|
-
return
|
91
|
-
end
|
92
|
-
append_add(msg[:person], msg[:room].name, msg[:message])
|
93
|
-
# Show the users quote numberes that start with 1 not 0
|
94
|
-
msg.speak "Added quote ##{quotes.length}."
|
95
|
-
end
|
96
|
-
|
97
|
-
def append_add(quoter, room, quote)
|
98
|
-
debug "ADD: #{quotes.length + 1} #{quote}"
|
99
|
-
@log.push ["ADD", quoter, room, quotes.length + 1, Time.now, decode(quote)]
|
100
|
-
write_log
|
101
|
-
end
|
102
|
-
|
103
|
-
def decode(str)
|
104
|
-
# Unicode decode: The "&" of "<" appear as "\\u0026".
|
105
|
-
html = str.gsub(/\\u([0-9a-f]{4})/i) { eval "0x#{$1}.chr" }
|
106
|
-
html_decode(html)
|
107
|
-
end
|
108
|
-
|
109
|
-
# Returns the non-HTML version of the given string using
|
110
|
-
# htmlentities if available, or else unescapeHTML
|
111
|
-
def html_decode(html)
|
112
|
-
if use_htmlentities
|
113
|
-
HTMLEntities.new.decode(html)
|
114
|
-
else
|
115
|
-
CGI.unescapeHTML(html)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def quote(msg)
|
120
|
-
q = msg[:message]
|
121
|
-
id = q.to_i
|
122
|
-
# If numeric
|
123
|
-
if id.to_s == q
|
124
|
-
msg.speak quotes[id - 1] ? format_quote(id) : "No quote ##{id}."
|
125
|
-
else
|
126
|
-
matches = select_quote_ids {|quote| quote.include?(q) }
|
127
|
-
msg.speak matches.empty? ?
|
128
|
-
"No matching quotes." :
|
129
|
-
format_quote(matches[rand(matches.length)]) +
|
130
|
-
(q == "" ? "" :
|
131
|
-
" (#{matches.size} match#{"es" if matches.size != 1})")
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def format_quote(id)
|
136
|
-
"##{id} #{quotes[id - 1]}"
|
137
|
-
end
|
138
|
-
|
139
|
-
def select_quote_ids
|
140
|
-
returning([]) {|ids|
|
141
|
-
quotes.each_with_index {|quote,idx|
|
142
|
-
if !quote.nil? && yield(quote)
|
143
|
-
ids.push(idx + 1)
|
144
|
-
end
|
145
|
-
}
|
146
|
-
}
|
147
|
-
end
|
148
|
-
|
149
|
-
def rmquote(msg)
|
150
|
-
q = msg[:message]
|
151
|
-
id = q.to_i
|
152
|
-
# If numeric
|
153
|
-
if id.to_s != q || !quotes[id - 1]
|
154
|
-
msg.speak "No quote ##{q}."
|
155
|
-
return
|
156
|
-
end
|
157
|
-
append_del(msg[:person], msg[:room].name, id)
|
158
|
-
msg.speak "Deleted quote ##{id}."
|
159
|
-
end
|
160
|
-
|
161
|
-
def append_del(rmer, room, id)
|
162
|
-
debug "DEL: #{quotes.length} #{id}"
|
163
|
-
@log.push ["DEL", rmer, room, id, Time.now, nil]
|
164
|
-
write_log
|
165
|
-
end
|
166
|
-
|
167
|
-
def quotes
|
168
|
-
return @quotes if @quotes
|
169
|
-
debug "Rebuilding @quotes from @log of length #{@log.size}"
|
170
|
-
@quotes = []
|
171
|
-
@log.each { |action, quoter, room, id, ts, quote|
|
172
|
-
case action
|
173
|
-
when "ADD" then
|
174
|
-
raise "Bad ID: #{id}" if id - 1 != @quotes.length
|
175
|
-
@quotes.push quote
|
176
|
-
when "DEL" then
|
177
|
-
@quotes[id - 1] = nil
|
178
|
-
# Allow any trailing IDs with nil quotes to be reused
|
179
|
-
@quotes.pop while @quotes.last.nil? && !@quotes.empty?
|
180
|
-
else raise "Unknown log action #{action}"
|
181
|
-
end
|
182
|
-
}
|
183
|
-
@quotes
|
184
|
-
end
|
185
|
-
|
186
|
-
def write_log
|
187
|
-
debug "Writing #{@log.length} log entries"
|
188
|
-
File.open("#{data_file}.tmp", 'w') do |out|
|
189
|
-
YAML.dump(@log, out)
|
190
|
-
end
|
191
|
-
debug "Renaming .tmp file to #{data_file}"
|
192
|
-
File.rename("#{data_file}.tmp", data_file)
|
193
|
-
@quotes = nil
|
194
|
-
end
|
195
|
-
end
|
data/plugins/quote.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'open-uri'
|
2
|
-
require 'hpricot'
|
3
|
-
|
4
|
-
class Quote < CampfireBot::Plugin
|
5
|
-
on_command 'quote', :quote
|
6
|
-
|
7
|
-
def quote(msg)
|
8
|
-
# Get our quotes from the web
|
9
|
-
url = "http://quotes4all.net/rss/000010110/quotes.xml"
|
10
|
-
response = ''
|
11
|
-
|
12
|
-
begin
|
13
|
-
# open-uri RDoc: http://stdlib.rubyonrails.org/libdoc/open-uri/rdoc/index.html
|
14
|
-
open(url, "User-Agent" => "Ruby/#{RUBY_VERSION}",
|
15
|
-
"From" => "Campfire") { |f|
|
16
|
-
|
17
|
-
# Save the response body
|
18
|
-
response = f.read
|
19
|
-
}
|
20
|
-
|
21
|
-
# HPricot RDoc: http://code.whytheluckystiff.net/hpricot/
|
22
|
-
doc = Hpricot(response)
|
23
|
-
|
24
|
-
msg.speak((doc/"*/item/description").inner_html.gsub(/<\/?[^>]*>/,"").gsub(/\s+/," ").gsub(/\"e;/,"'").gsub(/\&[\#|\w]\w+\;/,"").gsub(/\#39\;/,"'"))
|
25
|
-
msg.speak((doc/"*/item/title").inner_html)
|
26
|
-
|
27
|
-
rescue Exception => e
|
28
|
-
msg.speak(e, "\n")
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/plugins/schneier.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'open-uri'
|
2
|
-
require 'hpricot'
|
3
|
-
|
4
|
-
class Schneier < CampfireBot::Plugin
|
5
|
-
BASE_URL = 'http://geekz.co.uk/schneierfacts/'
|
6
|
-
|
7
|
-
on_command 'schneier', :schneier
|
8
|
-
|
9
|
-
def schneier(msg)
|
10
|
-
quote = case msg[:message].split(/\s+/)[0]
|
11
|
-
when 'latest'
|
12
|
-
fetch_quote(true)
|
13
|
-
when 'random'
|
14
|
-
fetch_quote
|
15
|
-
else
|
16
|
-
fetch_quote
|
17
|
-
end
|
18
|
-
msg.speak quote
|
19
|
-
rescue => e
|
20
|
-
msg.speak e
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def fetch_quote(latest = false)
|
26
|
-
CGI::unescapeHTML((Hpricot(open("#{BASE_URL}#{'fact/latest' if latest}"))).search('p .fact').html)
|
27
|
-
end
|
28
|
-
end
|
data/plugins/seen.rb
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
# Courtesy of joshwand (http://github.com/joshwand)
|
2
|
-
class Seen < CampfireBot::Plugin
|
3
|
-
ACTIVITY_REGEXP = /^(.*)$/
|
4
|
-
SEEN_REGEXP = /([^\?]+)(?=\?)*/
|
5
|
-
|
6
|
-
on_message Regexp.new("#{ACTIVITY_REGEXP.source}", Regexp::IGNORECASE), :update
|
7
|
-
on_command 'seen', :seen
|
8
|
-
on_command 'reload_seen', :reload
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@data_file = File.join(BOT_ROOT, 'tmp', "seen-#{BOT_ENVIRONMENT}.yml")
|
12
|
-
@seen = YAML::load(File.read(@data_file)) rescue {}
|
13
|
-
end
|
14
|
-
|
15
|
-
def update(msg)
|
16
|
-
left_room = (msg[:message] == "has left the room " ? true : false)
|
17
|
-
@seen[msg[:person]] = {:time => Time.now, :left => left_room}
|
18
|
-
|
19
|
-
File.open(@data_file, 'w') do |out|
|
20
|
-
YAML.dump(@seen, out)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def seen(msg)
|
25
|
-
found = false
|
26
|
-
puts msg[:message]
|
27
|
-
puts msg[:message] =~ SEEN_REGEXP
|
28
|
-
|
29
|
-
if !$1.nil?
|
30
|
-
first_name = $1.match("[A-Za-z]+")[0]
|
31
|
-
|
32
|
-
@seen.each do |person, seenat|
|
33
|
-
if person.downcase.include?(first_name.downcase)
|
34
|
-
time_ago = time_ago_in_words(seenat[:time])
|
35
|
-
left = seenat[:left] ? "leaving the room " : ""
|
36
|
-
msg.speak("#{person} was last seen #{left}#{time_ago} ago")
|
37
|
-
found = true
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
if !found
|
42
|
-
msg.speak("Sorry, I haven't seen #{first_name}.")
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def reload(msg)
|
49
|
-
@seen = {}
|
50
|
-
msg.speak("ok, reloaded seen db")
|
51
|
-
end
|
52
|
-
|
53
|
-
protected
|
54
|
-
|
55
|
-
def time_ago_in_words(from_time, include_seconds = false)
|
56
|
-
distance_of_time_in_words(from_time, Time.now, include_seconds)
|
57
|
-
end
|
58
|
-
|
59
|
-
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
|
60
|
-
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
61
|
-
to_time = to_time.to_time if to_time.respond_to?(:to_time)
|
62
|
-
distance_in_minutes = (((to_time - from_time).abs)/60).round
|
63
|
-
distance_in_seconds = ((to_time - from_time).abs).round
|
64
|
-
|
65
|
-
case distance_in_minutes
|
66
|
-
when 0..1
|
67
|
-
return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
|
68
|
-
case distance_in_seconds
|
69
|
-
when 0..4 then 'less than 5 seconds'
|
70
|
-
when 5..9 then 'less than 10 seconds'
|
71
|
-
when 10..19 then 'less than 20 seconds'
|
72
|
-
when 20..39 then 'half a minute'
|
73
|
-
when 40..59 then 'less than a minute'
|
74
|
-
else '1 minute'
|
75
|
-
end
|
76
|
-
|
77
|
-
when 2..44 then "#{distance_in_minutes} minutes"
|
78
|
-
when 45..89 then 'about 1 hour'
|
79
|
-
when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
|
80
|
-
when 1440..2879 then '1 day'
|
81
|
-
when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
|
82
|
-
when 43200..86399 then 'about 1 month'
|
83
|
-
when 86400..525599 then "#{(distance_in_minutes / 43200).round} months"
|
84
|
-
when 525600..1051199 then 'about 1 year'
|
85
|
-
else "over #{(distance_in_minutes / 525600).round} years"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
data/plugins/signal_filter.rb
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
class SignalFilter < CampfireBot::Plugin
|
2
|
-
on_message /^\[.*?\]/i, :echo_signal
|
3
|
-
|
4
|
-
def echo_signal(msg)
|
5
|
-
unless msg[:room] == bot.config['signal_target_room']
|
6
|
-
bot.rooms[bot.config['signal_target_room']].speak("#{msg[:person]} #{msg[:message]}")
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
data/plugins/svn.rb
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
require 'open-uri'
|
2
|
-
require 'hpricot'
|
3
|
-
require 'tempfile'
|
4
|
-
|
5
|
-
class Svn < CampfireBot::Plugin
|
6
|
-
|
7
|
-
at_interval 20.minutes, :check_svn
|
8
|
-
on_command 'svn', :checksvn_command
|
9
|
-
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
# log "initializing... "
|
13
|
-
@data_file = File.join(BOT_ROOT, 'tmp', "svn-#{BOT_ENVIRONMENT}-#{bot.config['room']}.yml")
|
14
|
-
@cached_revisions = YAML::load(File.read(@data_file)) rescue {}
|
15
|
-
@last_checked ||= 10.minutes.ago
|
16
|
-
@urls = bot.config['svn_urls']
|
17
|
-
@log = Logging.logger["CampfireBot::Plugin::Svn"]
|
18
|
-
end
|
19
|
-
|
20
|
-
# respond to checkjira command-- same as interval except we answer with 'no issues found' if
|
21
|
-
def checksvn_command(msg)
|
22
|
-
msg.speak "no new commits since I last checked #{@lastlast} ago" if !check_svn(msg)
|
23
|
-
end
|
24
|
-
|
25
|
-
def check_svn(msg)
|
26
|
-
|
27
|
-
saw_a_commit = false
|
28
|
-
old_cache = Marshal::load(Marshal.dump(@cached_revisions)) # since ruby doesn't have deep copy
|
29
|
-
|
30
|
-
@lastlast = time_ago_in_words(@last_checked)
|
31
|
-
commits = fetch_svn_urls
|
32
|
-
|
33
|
-
commits.each do |commit|
|
34
|
-
# p commit
|
35
|
-
if new?(commit, old_cache)
|
36
|
-
saw_an_issue = true
|
37
|
-
|
38
|
-
@cached_revisions = update_cache(commit, @cached_revisions)
|
39
|
-
flush_cache(@cached_revisions)
|
40
|
-
|
41
|
-
messagetext = "#{commit[:author]} committed revision #{commit[:revision]} #{time_ago_in_words(commit[:date])} ago on #{commit[:url]}:\n"
|
42
|
-
|
43
|
-
messagetext += "\n#{commit[:message]}\n"
|
44
|
-
messagetext += "----\n"
|
45
|
-
commit[:paths].each do |path|
|
46
|
-
messagetext += path[:action] + " " + path[:path] + "\n"
|
47
|
-
end
|
48
|
-
|
49
|
-
msg.paste(messagetext)
|
50
|
-
@log.info messagetext
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
@last_checked = Time.now
|
56
|
-
@log.info "no new commits." if !saw_a_commit
|
57
|
-
|
58
|
-
saw_a_commit
|
59
|
-
end
|
60
|
-
|
61
|
-
protected
|
62
|
-
|
63
|
-
# fetch jira url and return a list of commit Hashes
|
64
|
-
def fetch_svn_urls()
|
65
|
-
urls = bot.config['svn_urls']
|
66
|
-
commits = []
|
67
|
-
urls.each do |url|
|
68
|
-
begin
|
69
|
-
@log.info "checking #{url} for new commits..."
|
70
|
-
xmldata = `svn log --xml -v --limit 15 #{url}`
|
71
|
-
doc = REXML::Document.new(xmldata)
|
72
|
-
|
73
|
-
doc.elements.inject('log/logentry', commits) do |commits, element|
|
74
|
-
commits.push({:url => url}.merge(parse_entry_info(element)))
|
75
|
-
end
|
76
|
-
|
77
|
-
rescue Exception => e
|
78
|
-
@log.error "error connecting to svn: #{e.message}"
|
79
|
-
end
|
80
|
-
end
|
81
|
-
return commits
|
82
|
-
end
|
83
|
-
|
84
|
-
# extract commit hash from indivrevisionual xml element
|
85
|
-
def parse_entry_info(xml_element)
|
86
|
-
|
87
|
-
revision = xml_element.attributes['revision']
|
88
|
-
author = xml_element.elements['author'].text
|
89
|
-
date = DateTime.parse(xml_element.elements['date'].text)
|
90
|
-
message = xml_element.elements['msg'].text
|
91
|
-
|
92
|
-
paths = xml_element.elements.collect('paths/path') do |e|
|
93
|
-
{
|
94
|
-
:action => e.attributes['action'],
|
95
|
-
:path => e.text
|
96
|
-
}
|
97
|
-
end
|
98
|
-
|
99
|
-
return {
|
100
|
-
:revision => revision,
|
101
|
-
:author => author,
|
102
|
-
:message => message,
|
103
|
-
:date => date,
|
104
|
-
:paths => paths
|
105
|
-
}
|
106
|
-
end
|
107
|
-
|
108
|
-
# has this commit been seen before this run?
|
109
|
-
def new?(commit, old_cache)
|
110
|
-
!old_cache.key?(commit[:url]) or old_cache[commit[:url]] < commit[:revision].to_i
|
111
|
-
end
|
112
|
-
|
113
|
-
# only update the cached highest revision if it is in fact the highest revision
|
114
|
-
def update_cache(commit, cache)
|
115
|
-
cache[commit[:url]] = commit[:revision].to_i if new?(commit, cache)
|
116
|
-
cache
|
117
|
-
end
|
118
|
-
|
119
|
-
# write the cache to disk
|
120
|
-
def flush_cache(cache)
|
121
|
-
File.open(@data_file, 'w') do |out|
|
122
|
-
YAML.dump(cache, out)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
#
|
129
|
-
# time/utility functions
|
130
|
-
#
|
131
|
-
|
132
|
-
|
133
|
-
def time_ago_in_words(from_time, include_seconds = false)
|
134
|
-
distance_of_time_in_words(from_time, Time.now, include_seconds)
|
135
|
-
end
|
136
|
-
|
137
|
-
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
|
138
|
-
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
139
|
-
to_time = to_time.to_time if to_time.respond_to?(:to_time)
|
140
|
-
distance_in_minutes = (((to_time - from_time).abs)/60).round
|
141
|
-
distance_in_seconds = ((to_time - from_time).abs).round
|
142
|
-
|
143
|
-
case distance_in_minutes
|
144
|
-
when 0..1
|
145
|
-
return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
|
146
|
-
case distance_in_seconds
|
147
|
-
when 0..4 then 'less than 5 seconds'
|
148
|
-
when 5..9 then 'less than 10 seconds'
|
149
|
-
when 10..19 then 'less than 20 seconds'
|
150
|
-
when 20..39 then 'half a minute'
|
151
|
-
when 40..59 then 'less than a minute'
|
152
|
-
else '1 minute'
|
153
|
-
end
|
154
|
-
|
155
|
-
when 2..44 then "#{distance_in_minutes} minutes"
|
156
|
-
when 45..89 then 'about 1 hour'
|
157
|
-
when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
|
158
|
-
when 1440..2879 then '1 day'
|
159
|
-
when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
|
160
|
-
when 43200..86399 then 'about 1 month'
|
161
|
-
when 86400..525599 then "#{(distance_in_minutes / 43200).round} months"
|
162
|
-
when 525600..1051199 then 'about 1 year'
|
163
|
-
else "over #{(distance_in_minutes / 525600).round} years"
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
end
|