bitbckt-botbckt 0.3.0 → 0.4.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/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :patch: 0
3
3
  :major: 0
4
- :minor: 3
4
+ :minor: 4
data/bin/botbckt ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'pathname'
5
+ local_lib = Pathname.new(__FILE__).expand_path.dirname.join('..', 'lib', 'botbckt.rb')
6
+ if local_lib.file?
7
+ require local_lib
8
+ else
9
+ require 'botbckt'
10
+ end
11
+ rescue LoadError
12
+ require 'rubygems'
13
+ require 'botbckt'
14
+ end
15
+
16
+ Botbckt::Cmd.run(ARGV)
data/lib/botbckt/bot.rb CHANGED
@@ -3,12 +3,14 @@ module Botbckt #:nodoc:
3
3
  # Create a new IRC bot. See Bot.start to get started.
4
4
  #
5
5
  class Bot
6
+ include Singleton
7
+ include ActiveSupport::BufferedLogger::Severity
6
8
 
7
9
  AFFIRMATIVE = ["'Sea, mhuise.", "In Ordnung", "Ik begrijp", "Alles klar", "Ok.", "Roger.", "You don't have to tell me twice.", "Ack. Ack.", "C'est bon!"]
8
10
  NEGATIVE = ["Titim gan éirí ort.", "Gabh mo leithscéal?", "No entiendo", "excusez-moi", "Excuse me?", "Huh?", "I don't understand.", "Pardon?", "It's greek to me."]
9
-
10
- cattr_accessor :commands
11
- @@commands = { }
11
+
12
+ attr_accessor :logger
13
+ attr_accessor :store
12
14
 
13
15
  # ==== Parameters
14
16
  # options<Hash{Symbol => String,Integer}>
@@ -21,22 +23,90 @@ module Botbckt #:nodoc:
21
23
  # :channels<Array[String]>:: An array of channels to join. Channel names should *not* include the '#' prefix. Required.
22
24
  # :log<String>:: The name of a log file. Defaults to 'botbckt.log'.
23
25
  # :log_level<Integer>:: The minimum severity level to log. Defaults to 1 (INFO).
26
+ # :pid<String>:: The name of a file to drop the PID. Defaults to 'botbckt.pid'.
27
+ # :daemonize<Boolean>:: Fork and background the process. Defaults to true.
28
+ # :backend_host<String>:: The hostname of a Redis store. Optional.
29
+ # :backend_port<Integer>:: The port used by the Redis store. Optional.
24
30
  #
25
31
  def self.start(options)
26
- EventMachine::run do
27
- Botbckt::IRC.connect(options)
32
+
33
+ self.instance.logger = ActiveSupport::BufferedLogger.new options.delete(:log) || 'botbckt.log',
34
+ options.delete(:log_level) || INFO
35
+
36
+ host, port = options.delete(:backend_host), options.delete(:backend_port)
37
+ daemonize = options.delete(:daemonize)
38
+ pid = options.delete(:pid) || 'botbckt.pid'
39
+
40
+ if daemonize || daemonize.nil?
41
+ EventMachine::fork_reactor do
42
+ Botbckt::IRC.connect(options)
43
+
44
+ if host && port
45
+ self.instance.store = Store.new(host, port)
46
+ end
47
+
48
+ if pid
49
+ File.open(pid, 'w'){ |f| f.write("#{Process.pid}") }
50
+ at_exit { File.delete(pid) if File.exist?(pid) }
51
+ end
52
+
53
+ end
54
+ else
55
+ EventMachine::run do
56
+ Botbckt::IRC.connect(options)
57
+ end
28
58
  end
29
59
  end
30
60
 
61
+ # Registers a new command.
62
+ #
63
+ # ==== Parameters
64
+ # command<~to_sym>:: Trigger to register. Required.
65
+ # callable<~call>:: Callback or class with #call to execute. Required.
66
+ #
67
+ def register(command, callable)
68
+ @commands ||= { }
69
+ @commands[command.to_sym] = callable
70
+ end
71
+
72
+ # Returns currently registered commands.
73
+ #
74
+ def commands
75
+ @commands
76
+ end
77
+
78
+ #--
79
+ # TODO: Forwardable?
80
+ #++
81
+ def set(key, value, &block)
82
+ self.store && self.store.set(key, value, &block)
83
+ end
84
+
85
+ #--
86
+ # TODO: Forwardable?
87
+ #++
88
+ def get(key, &block)
89
+ self.store && self.store.get(key, &block)
90
+ end
91
+
92
+ #--
93
+ # TODO: Forwardable?
94
+ #++
95
+ def increment!(key, &block)
96
+ self.store && self.store.increment!(key, &block)
97
+ end
98
+
31
99
  # ==== Parameters
32
100
  # command<Symbol>:: The name of a registered command to run. Required.
101
+ # sender<String>:: The sender (incl. hostmask) of the trigger. Required.
102
+ # channel<String>:: The channel on which the command was triggered. Required.
33
103
  # *args:: Arguments to be passed to the command. Optional.
34
104
  #
35
105
  #--
36
106
  # TODO: Before/after callbacks?
37
107
  #++
38
- def self.run(command, sender, channel, *args)
39
- callable = self.commands[command.to_sym]
108
+ def run(command, sender, channel, *args)
109
+ callable = commands[command.to_sym]
40
110
 
41
111
  if callable.is_a?(Class)
42
112
  # Callables are Singletons; we use #create! as a convention to give
@@ -44,7 +114,10 @@ module Botbckt #:nodoc:
44
114
  callable = callable.create!(sender, channel, *args)
45
115
  end
46
116
 
47
- callable.respond_to?(:call) ? callable.call(sender, channel, *args) : say(befuddled, channel)
117
+ callable.respond_to?(:call) ? callable.call(sender, channel, *args) : say(Bot.befuddled, channel)
118
+ # TODO: Log me.
119
+ rescue StandardError => e
120
+ say Bot.befuddled, channel
48
121
  end
49
122
 
50
123
  # Returns a random "affirmative" message. Use to acknowledge user input.
@@ -70,10 +143,14 @@ module Botbckt #:nodoc:
70
143
  # msg<String>:: A message to send to the channel
71
144
  # channel<String>:: The channel to send the message. Required.
72
145
  #
73
- def self.say(msg, channel)
146
+ def say(msg, channel)
74
147
  Botbckt::IRC.connection.say msg, channel
75
148
  end
149
+
150
+ def log(msg, level = INFO) #:nodoc:
151
+ self.logger.add(level, msg)
152
+ end
76
153
 
77
154
  end
78
155
 
79
- end
156
+ end
@@ -0,0 +1,86 @@
1
+ module Botbckt #:nodoc:
2
+
3
+ class Cmd
4
+
5
+ SEVERITY = %w{0 1 2 3 4 5}
6
+ SEVERITY_ALIASES = { "DEBUG" => 0, "INFO" => 1, "WARN" => 2, "ERROR" => 3, "FATAL" => 4, "UNKNOWN" => 5}
7
+
8
+ def self.run(args)
9
+ Botbckt::Bot.start parse(args)
10
+ end
11
+
12
+ def self.parse(args)
13
+ options = {}
14
+ options[:user] = 'botbckt'
15
+ options[:port] = 6667
16
+ options[:channels] = []
17
+ options[:backend_port] = 6379
18
+
19
+ opts = OptionParser.new do |opts|
20
+ opts.banner = 'Usage: botbckt [options]'
21
+
22
+ opts.separator ''
23
+ opts.separator 'Options:'
24
+
25
+ opts.on('-u', '--user [USER]', 'Username to identify as. (default: botbckt)') do |user|
26
+ options[:user] = user
27
+ end
28
+
29
+ opts.on('-p', '--password [PASSWORD]', 'Password to authenticate with.') do |pass|
30
+ options[:password] = pass
31
+ end
32
+
33
+ opts.on('-s', '--server SERVER', 'Address of the IRC server.') do |server|
34
+ options[:server] = server
35
+ end
36
+
37
+ opts.on('-P', '--port [PORT]', Integer, 'Port of the IRC server. (default: 6667)') do |port|
38
+ options[:port] = port
39
+ end
40
+
41
+ opts.on('-c', '--channels [x,y,z]', Array,
42
+ 'Comma-separated list of channels to JOIN. Do not include the # prefix.') do |channels|
43
+ options[:channels] = channels
44
+ end
45
+
46
+ opts.on('-l', '--logfile [FILE]', 'Log file. (default botbckt.log)') do |log|
47
+ options[:log] = log
48
+ end
49
+
50
+ severities = SEVERITY_ALIASES.keys.join(', ')
51
+ opts.on('-V', '--verbosity [LEVEL]', SEVERITY, SEVERITY_ALIASES, Integer,
52
+ "Minimum severity level to log.Accepted values are: #{severities}. (default: INFO)") do |level|
53
+ options[:log_level] = level
54
+ end
55
+
56
+ opts.on('-b', '--backend-host [SERVER]', 'Address of a Redis server.') do |backend|
57
+ options[:backend_host] = backend
58
+ end
59
+
60
+ opts.on('-B', '--backend-port [PORT]', Integer, 'Port of a Redis server. (default: 6379)') do |port|
61
+ options[:backend_port] = port
62
+ end
63
+
64
+ opts.on('-D', '--[no-]daemonize', 'Fork and run in the background. (default: true)') do |daemon|
65
+ options[:daemonize] = daemon
66
+ end
67
+
68
+ opts.on('-i', '--pid FILE', 'File to store PID (default: botbckt.pid)') do |file|
69
+ options[:pid] = file
70
+ end
71
+
72
+ opts.on_tail('-h', '--help', 'Show this message.') do |help|
73
+ puts opts
74
+ exit
75
+ end
76
+ end
77
+
78
+ opts.parse!(args)
79
+ options
80
+ rescue OptionParser::ParseError
81
+ puts opts
82
+ exit
83
+ end
84
+
85
+ end
86
+ end
@@ -1,11 +1,10 @@
1
- require 'singleton'
2
-
3
1
  module Botbckt #:nodoc:
4
2
 
5
- # This acts as a kind of abstract class for Botbckt commands. Extend your
6
- # command class with this module to define new bot commands.
3
+ # This acts as a kind of abstract class for Botbckt commands. Subclass
4
+ # this class to define new bot commands.
7
5
  #
8
- # Command subclasses must (re-)define initialize and call.
6
+ # Command subclasses must (re-)define call. If any setup is needed, override
7
+ # create! and return self.instance.
9
8
  #
10
9
  class Command
11
10
  include Utilities
@@ -39,9 +38,10 @@ module Botbckt #:nodoc:
39
38
  #
40
39
  # ==== Parameters
41
40
  # command<Symbol>:: In-channel trigger for the command. Required.
41
+ # &block:: An optional block to execute, in lieu of call.
42
42
  #
43
43
  def self.trigger(command, &block)
44
- Botbckt::Bot.commands[command.to_sym] = block_given? ? block : self
44
+ Botbckt::Bot.instance.register(command, block_given? ? block : self)
45
45
  end
46
46
 
47
47
  # ==== Parameters
@@ -49,7 +49,7 @@ module Botbckt #:nodoc:
49
49
  # channel<String>:: The channel to send the message. Required.
50
50
  #
51
51
  def self.say(msg, channel)
52
- Botbckt::Bot.say(msg, channel) if msg
52
+ Botbckt::Bot.instance.say(msg, channel) if msg
53
53
  end
54
54
 
55
55
  # Proxy for Command.say
@@ -58,6 +58,18 @@ module Botbckt #:nodoc:
58
58
  self.class.say(msg, channel)
59
59
  end
60
60
 
61
+ def set(key, value, &block)
62
+ Botbckt::Bot.instance.set(key, value, &block)
63
+ end
64
+
65
+ def get(key, &block)
66
+ Botbckt::Bot.instance.get(key, &block)
67
+ end
68
+
69
+ def increment!(key, &block)
70
+ Botbckt::Bot.instance.increment!(key, &block)
71
+ end
72
+
61
73
  end
62
74
 
63
75
  end
@@ -0,0 +1,114 @@
1
+ module Botbckt #:nodoc:
2
+
3
+ # Sends text repeatedly to Google Translate via the JSON API
4
+ # to garble the output. Translation starts and ends with
5
+ # MAIN_LANGUAGE unless a language option is passed in. If
6
+ # an option is present it is used as the starting language.
7
+ #
8
+ #
9
+ # < user> ~gooble We the People of the United States, in Order to form a more perfect Union
10
+ # < botbckt> Popular in the United States to create the completed
11
+ #
12
+ # With language option:
13
+ #
14
+ # < user> ~gooble --german Guten tag
15
+ # < botbckt> Good day
16
+ #
17
+ # or the short version
18
+ #
19
+ # < user> ~gooble -de Guten tag
20
+ # < botbckt> Good day
21
+
22
+ class Gooble < Command
23
+
24
+ MAIN_LANGUAGE = "en"
25
+ TRANSLATE_ATTEMPTS = 4
26
+ # Yeah this is wordy but it's self documenting.
27
+ LANGUAGES =
28
+ {
29
+ "Albanian" => "sq",
30
+ "Arabic" => "ar",
31
+ "Bulgarian" => "bg",
32
+ "Catalan" => "ca",
33
+ "Chinese" => "zh-CN",
34
+ "Croatian" => "hr",
35
+ "Czech" => "cs",
36
+ "Danish" => "da",
37
+ "Dutch" => "nl",
38
+ "English" => "en",
39
+ "Estonian" => "et",
40
+ "Filipino" => "tl",
41
+ "Finnish" => "fi",
42
+ "French" => "fr",
43
+ "Galician" => "gl",
44
+ "German" => "de",
45
+ "Greek" => "el",
46
+ "Hebrew" => "iw",
47
+ "Hindi" => "hi",
48
+ "Hungarian" => "hu",
49
+ "Indonesian" => "id",
50
+ "Italian" => "it",
51
+ "Japanese" => "ja",
52
+ "Korean" => "ko",
53
+ "Latvian" => "lv",
54
+ "Lithuanian" => "lt",
55
+ "Maltese" => "mt",
56
+ "Norwegian" => "no",
57
+ "Polish" => "pl",
58
+ "Portuguese" => "pt",
59
+ "Romanian" => "ro",
60
+ "Russian" => "ru",
61
+ "Serbian" => "sr",
62
+ "Slovak" => "sk",
63
+ "Slovenian" => "sl",
64
+ "Spanish" => "es",
65
+ "Swedish" => "sv",
66
+ "Thai" => "th",
67
+ "Turkish" => "tr",
68
+ "Ukrainian" => "uk",
69
+ "Vietnamese" => "vi"
70
+ }
71
+
72
+ trigger :gooble do |sender, channel, gooble_string|
73
+ # start with english unless asked for something else
74
+ gooble_string =~ /(-\w{2}|--\w+)?(.*)/i
75
+ option, text = $1, $2
76
+ clean_option = option.gsub(/-/,'') if option
77
+
78
+ start_language = case option
79
+ when /^--/ then
80
+ LANGUAGES[clean_option.capitalize!] || MAIN_LANGUAGE
81
+ when /^-/ then
82
+ LANGUAGES.value?(clean_option) ? clean_option : MAIN_LANGUAGE
83
+ else
84
+ MAIN_LANGUAGE
85
+ end
86
+
87
+ # languages to use for the goobling
88
+ languages = [start_language]
89
+ languages << LANGUAGES.values.sort_by{ rand }.slice(0...TRANSLATE_ATTEMPTS)
90
+ languages << MAIN_LANGUAGE # always end with main
91
+
92
+ result = gooble(text, languages.flatten)
93
+ say result, channel
94
+ end
95
+
96
+ private
97
+
98
+ # args
99
+ # text<String>: text to translate
100
+ # langs<Array>: languages to translate from/to
101
+ def self.gooble(text, languages) #:nodoc:
102
+ if languages.length >= 2
103
+ pair = "#{languages[0]}|#{languages[1]}"
104
+ json = open("http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=#{CGI.escape(text)}&langpair=#{CGI.escape(pair)}")
105
+ response = JSON.parse(json.read) # could check for failed response with response['responseStatus'] != 200
106
+ languages.shift
107
+ gooble(response['responseData']['translatedText'], languages)
108
+ else
109
+ text
110
+ end
111
+ end
112
+
113
+ end
114
+ end
@@ -7,6 +7,10 @@ module Botbckt #:nodoc:
7
7
  # ... five minutes
8
8
  # < botbckt> user: message
9
9
  #
10
+ # < user> ~remind at 10:30 with message
11
+ # ... at 10:30
12
+ # < botbckt> user: message
13
+ #
10
14
  class Remind < Command
11
15
 
12
16
  SCALES = %w{ minute minutes second seconds hour hours }
@@ -14,20 +18,52 @@ module Botbckt #:nodoc:
14
18
  trigger :remind
15
19
 
16
20
  def call(user, channel, reminder_string)
21
+
22
+ case reminder_string
23
+ when /^in/i
24
+ msg, time = *relative_reminder(reminder_string)
25
+ when /^at/i
26
+ msg, time = *absolute_reminder(reminder_string)
27
+ else
28
+ say Botbckt::Bot.befuddled, channel
29
+ return
30
+ end
31
+
32
+ if msg && time
33
+ remind(freenode_split(user).first, channel, msg, time)
34
+ else
35
+ say Botbckt::Bot.befuddled, channel
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def relative_reminder(str) #:nodoc:
17
42
  # Somewhat faster than #match...
18
- reminder_string =~ /in (\d+) (\w+) with (.*)/i
43
+ str =~ /in (\d+) (\w+) with (.*)/i
19
44
  num, scale, msg = $1, $2, $3
20
45
 
21
46
  if SCALES.include?(scale)
22
47
  time = num.to_i.send(scale.to_sym).seconds
23
-
24
- remind(freenode_split(user).first, channel, msg, time)
48
+ [ msg, time ]
25
49
  else
26
- say Botbckt::Bot.befuddled, channel
50
+ [ ]
27
51
  end
28
52
  end
29
53
 
30
- private
54
+ def absolute_reminder(str) #:nodoc:
55
+ # Somewhat faster than #match...
56
+ str =~ /at (.*) with (.*)/i
57
+ time, msg = $1, $2
58
+
59
+ time = Time.parse(time) - Time.now
60
+
61
+ [ msg, time ]
62
+ # TODO: Log me.
63
+ rescue ArgumentError => e
64
+ # raised by Time.parse; do nothing, for now...
65
+ [ ]
66
+ end
31
67
 
32
68
  def remind(user, channel, msg, seconds) #:nodoc:
33
69
  EventMachine::Timer.new(seconds) do
@@ -13,22 +13,14 @@ module Botbckt #:nodoc:
13
13
  class StarJar < Command
14
14
 
15
15
  trigger :star
16
-
17
- attr_accessor :jar
18
-
19
- def self.create!(*args) #:nodoc:
20
- self.instance.jar ||= { }
21
- self.instance
22
- end
23
16
 
24
17
  # Adds a star to the jar for the user
25
18
  #
26
19
  # ==== Parameters
27
20
  # user<String>:: The user receiving a star. Required.
28
21
  #
29
- def push(user)
30
- @jar[user] ||= 0
31
- @jar[user] += 1
22
+ def push(user, &block)
23
+ increment! "starjar-#{user}", &block
32
24
  end
33
25
 
34
26
  # Removes a star from the jar for the user
@@ -36,21 +28,23 @@ module Botbckt #:nodoc:
36
28
  # ==== Parameters
37
29
  # user<String>:: The user being docked a star. Required.
38
30
  #
39
- def pop(user)
40
- @jar[user] ||= 0
31
+ def pop(user, &block)
32
+ get "starjar-#{user}" do |stars|
41
33
 
42
- if @jar[user] == 0
43
- return 0
44
- else
45
- @jar[user] -= 1
34
+ if stars
35
+ set "starjar-#{user}", stars - 1, &block
36
+ else
37
+ set "starjar-#{user}", 0, &block
38
+ end
46
39
  end
47
40
  end
48
41
 
49
42
  def call(giver, channel, receiver)
50
43
  receiver.split(' ').each do |rcv|
51
44
  if rcv != freenode_split(giver).first
52
- total = push(rcv)
53
- say "#{rcv}: Gold star for you! (#{total})", channel
45
+ push(rcv) do |total|
46
+ say "#{rcv}: Gold star for you! (#{total})", channel
47
+ end
54
48
  else
55
49
  say "#{rcv}: No star for you!", channel
56
50
  end
@@ -6,7 +6,6 @@ module Botbckt #:nodoc:
6
6
  # < botbckt> Today's Forecast: 90F/65F (Sunny)
7
7
  #
8
8
  # < user> ~conditions Los Angeles, CA
9
- # < botbckt> Conditions -
10
9
  # < botbckt> Today: Areas of low clouds in the morning then mostly sunny. Highs in the upper 60s to mid 70s. West winds 10 to 20 mph in the afternoon.
11
10
  # < botbckt> Tonight: Mostly clear. Lows in the mid to upper 50s. West winds 10 to 20 mph in the evening.
12
11
  #
@@ -37,7 +36,7 @@ module Botbckt #:nodoc:
37
36
  daytime = (xml/'forecastday[1]')
38
37
  evening = (xml/'forecastday[2]')
39
38
 
40
- "Conditions -\nToday: #{(daytime/'fcttext').inner_html}\nTonight: #{(evening/'fcttext').inner_html}"
39
+ "Today: #{(daytime/'fcttext').inner_html}\nTonight: #{(evening/'fcttext').inner_html}"
41
40
  end
42
41
 
43
42
  def self.forecast(query) #:nodoc:
data/lib/botbckt/irc.rb CHANGED
@@ -4,7 +4,6 @@ module Botbckt #:nodoc:
4
4
  #
5
5
  class IRC < EventMachine::Connection
6
6
  include EventMachine::Protocols::LineText2
7
- include ActiveSupport::BufferedLogger::Severity
8
7
 
9
8
  attr_accessor :config
10
9
  cattr_accessor :connection
@@ -20,8 +19,6 @@ module Botbckt #:nodoc:
20
19
  # :server<String>:: The FQDN of the IRC server. Required.
21
20
  # :port<~to_i>:: The port number of the IRC server. Required.
22
21
  # :channels<Array[String]>:: An array of channels to join. Channel names should *not* include the '#' prefix. Required.
23
- # :log<String>:: The name of a log file. Defaults to 'botbckt.log'.
24
- # :log_level<Integer>:: The minimum severity level to log. Defaults to 1 (INFO).
25
22
  #
26
23
  def self.connect(options)
27
24
  self.connection = EM.connect(options[:server], options[:port].to_i, self, options)
@@ -34,9 +31,6 @@ module Botbckt #:nodoc:
34
31
  #++
35
32
  def initialize(options) #:nodoc:
36
33
  self.config = OpenStruct.new(options)
37
-
38
- @logger = ActiveSupport::BufferedLogger.new self.config.log || 'botbckt.log',
39
- self.config.log_level || INFO
40
34
  end
41
35
 
42
36
  # ==== Parameters
@@ -66,7 +60,7 @@ module Botbckt #:nodoc:
66
60
  args << $5.squish if $5
67
61
 
68
62
  # run args: command, sender, channel, optional args
69
- Botbckt::Bot.run($4, *args)
63
+ Botbckt::Bot.instance.run($4, *args)
70
64
  else
71
65
  log line
72
66
  end
@@ -81,8 +75,8 @@ module Botbckt #:nodoc:
81
75
 
82
76
  private
83
77
 
84
- def log(msg, level = INFO) #:nodoc:
85
- @logger.add(level, msg)
78
+ def log(msg, level = Botbckt::Bot::INFO) #:nodoc:
79
+ Botbckt::Bot.instance.log msg, level
86
80
  end
87
81
 
88
82
  def command(*cmd) #:nodoc:
@@ -0,0 +1,33 @@
1
+ require 'em-redis'
2
+
3
+ module Botbckt #:nodoc:
4
+
5
+ # Implements a basic key/value store API for cross-session state storage.
6
+ #
7
+ # Currently, this class is Redis-backed, but any key/value store could be
8
+ # supported, in theory.
9
+ #
10
+ class Store
11
+
12
+ attr_accessor :backend
13
+
14
+ def initialize(host, port)
15
+ self.backend = EventMachine::Protocols::Redis.connect(host, port)
16
+ end
17
+
18
+ def set(key, value, &block)
19
+ backend.set(key, value, &block)
20
+ end
21
+
22
+ def get(key, &block)
23
+ backend.get(key, &block)
24
+ end
25
+
26
+ def increment!(key, &block)
27
+ backend.incr(key, &block)
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
data/lib/botbckt.rb CHANGED
@@ -1,3 +1,3 @@
1
- %w{ rubygems eventmachine activesupport ostruct json open-uri cgi hpricot }.each { |lib| require lib }
2
- %w{ irc bot utilities command }.each { |lib| require File.dirname(__FILE__) + "/botbckt/#{ lib }" }
1
+ %w{ rubygems eventmachine activesupport ostruct json open-uri cgi hpricot singleton optparse }.each { |lib| require lib }
2
+ %w{ irc store bot utilities command cmd }.each { |lib| require File.dirname(__FILE__) + "/botbckt/#{ lib }" }
3
3
  Dir[File.dirname(__FILE__) + '/botbckt/commands/*'].each { |lib| require lib }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitbckt-botbckt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Mitchell
@@ -9,14 +9,14 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-04 00:00:00 -07:00
13
- default_executable:
12
+ date: 2009-06-23 00:00:00 -07:00
13
+ default_executable: botbckt
14
14
  dependencies: []
15
15
 
16
16
  description: Boredom strikes on Sunday mornings.
17
17
  email: brandon@systemisdown.net
18
- executables: []
19
-
18
+ executables:
19
+ - botbckt
20
20
  extensions: []
21
21
 
22
22
  extra_rdoc_files:
@@ -24,9 +24,12 @@ extra_rdoc_files:
24
24
  files:
25
25
  - Rakefile
26
26
  - VERSION.yml
27
+ - bin/botbckt
27
28
  - lib/botbckt.rb
28
29
  - lib/botbckt/bot.rb
30
+ - lib/botbckt/cmd.rb
29
31
  - lib/botbckt/command.rb
32
+ - lib/botbckt/commands/gooble.rb
30
33
  - lib/botbckt/commands/google.rb
31
34
  - lib/botbckt/commands/meme.rb
32
35
  - lib/botbckt/commands/ping.rb
@@ -36,6 +39,7 @@ files:
36
39
  - lib/botbckt/commands/ticker.rb
37
40
  - lib/botbckt/commands/weather.rb
38
41
  - lib/botbckt/irc.rb
42
+ - lib/botbckt/store.rb
39
43
  - lib/botbckt/utilities.rb
40
44
  - README
41
45
  has_rdoc: true