campfire-bot 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|