summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Vazgenovich Shakaryan <dvshakaryan@gmail.com>2014-08-17 23:31:45 -0700
committerDavid Vazgenovich Shakaryan <dvshakaryan@gmail.com>2014-08-17 23:31:45 -0700
commite633d656e00fdac51f077eff827518848235e916 (patch)
tree0b40a60f95b219545d40fe709e11583ab9e3df6b
downloadbocelli-e633d656e00fdac51f077eff827518848235e916.tar.gz
bocelli-e633d656e00fdac51f077eff827518848235e916.tar.xz
Initial commit.
-rw-r--r--bocelli.rb2
-rw-r--r--bocelli/base.rb83
-rw-r--r--bocelli/core/irc.rb53
-rw-r--r--bocelli/module/base.rb25
-rw-r--r--example.rb45
5 files changed, 208 insertions, 0 deletions
diff --git a/bocelli.rb b/bocelli.rb
new file mode 100644
index 0000000..eaa28e0
--- /dev/null
+++ b/bocelli.rb
@@ -0,0 +1,2 @@
+require_relative 'bocelli/base'
+require_relative 'bocelli/module/base'
diff --git a/bocelli/base.rb b/bocelli/base.rb
new file mode 100644
index 0000000..dfb7875
--- /dev/null
+++ b/bocelli/base.rb
@@ -0,0 +1,83 @@
+require_relative 'core/irc'
+
+module Bocelli
+ class Base
+ def initialize(str, route, block, metadata)
+ @bocelli = {
+ str: str,
+ route: route,
+ block: block,
+ metadata: metadata
+ }
+ end
+
+ def execute
+ instance_eval(&@bocelli[:block])
+ end
+
+ def out(message)
+ self.class.privmsg(@bocelli[:metadata][:channel], message)
+ end
+
+ class << self
+ include Bocelli::Core::IRC
+
+ def setup
+ @routes = {}
+ @modules = {}
+ end
+
+ def inherited(subclass)
+ super
+
+ subclass.setup
+ end
+
+ def on(route, &block)
+ name = "route #{route.inspect}"
+
+ @routes[route] = block
+ end
+
+ def register(mod)
+ @modules[mod.name[/[^:]+$/].downcase.intern] ||= mod
+ end
+
+ def match(str, route)
+ case route
+ when Regexp
+ str =~ route
+ when String
+ str == route
+ end
+ end
+
+ def process(str)
+ routes = @modules.inject([]) { |m, (_, v)| m.push(*v.routes) }
+ routes.push(*@routes)
+
+ if str =~ /(\S+) PRIVMSG (\S+) :?(.*)/
+ metadata = {
+ user: $1,
+ channel: $2,
+ message: $3
+ }
+
+ if (match = routes.detect { |k, _| match(metadata[:message], k) })
+ route, block = match
+
+ new(str, route, block, metadata).execute
+ end
+ end
+ end
+
+ def run
+ while (str = sgets)
+ pong($1) if str =~ /\APING (.*)\z/
+
+ process(str)
+ end
+ end
+ end
+ end
+end
diff --git a/bocelli/core/irc.rb b/bocelli/core/irc.rb
new file mode 100644
index 0000000..4264e2d
--- /dev/null
+++ b/bocelli/core/irc.rb
@@ -0,0 +1,53 @@
+require 'socket'
+
+module Bocelli
+ module Core
+ module IRC
+ def configure(host, port, nick, pass = nil)
+ @host = host
+ @port = port
+ @nick = nick
+ @pass = pass
+
+ @socket = nil
+ end
+
+ def connect(&block)
+ @socket = TCPSocket.new(@host, @port)
+
+ sputs("PASS #{@pass}") if @pass
+ sputs("NICK #{@nick}")
+ sputs("USER #{@nick} 0 * :#{@nick}")
+
+ instance_eval(&block) if block_given?
+ end
+
+ def sgets
+ str = @socket.gets
+ str.chomp! unless str.nil?
+
+ puts '<< ' + str.inspect
+
+ str
+ end
+
+ def sputs(str)
+ puts '>> ' + str.inspect
+
+ @socket.puts(str)
+ end
+
+ def pong(message)
+ sputs("PONG #{message}")
+ end
+
+ def join(channel)
+ sputs("JOIN #{channel}")
+ end
+
+ def privmsg(channel, message)
+ sputs("PRIVMSG #{channel} :#{message}")
+ end
+ end
+ end
+end
diff --git a/bocelli/module/base.rb b/bocelli/module/base.rb
new file mode 100644
index 0000000..1306830
--- /dev/null
+++ b/bocelli/module/base.rb
@@ -0,0 +1,25 @@
+module Bocelli
+ module Module
+ module Base
+ attr_reader :routes
+
+ def setup
+ @routes = {}
+ end
+
+ def on(route, &block)
+ raise 'no block given' if block.nil?
+
+ @routes[route] = block
+ end
+
+ class << self
+ def extended(mod)
+ super
+
+ mod.setup
+ end
+ end
+ end
+ end
+end
diff --git a/example.rb b/example.rb
new file mode 100644
index 0000000..cd09859
--- /dev/null
+++ b/example.rb
@@ -0,0 +1,45 @@
+require_relative 'bocelli'
+
+module Bocelli::Module::Foo
+ extend Bocelli::Module::Base
+
+ on 'test' do
+ out 'this is a test!'
+ end
+
+ on /^foo/ do
+ out 'foo' * (rand(5) + 1)
+ end
+end
+
+module Bocelli::Module::Bar
+ extend Bocelli::Module::Base
+
+ on /^bar+$/ do
+ out 'bar' * (rand(5) + 1)
+ end
+
+ on /^baz+$/i do
+ out 'baz' * (rand(5) + 1)
+ end
+end
+
+class TestBot < Bocelli::Base
+ register Bocelli::Module::Foo
+ register Bocelli::Module::Bar
+
+ on 'rand' do
+ out rand(100)
+ end
+
+ on 'current' do
+ out '%s %s' % [@bocelli[:str].inspect, @bocelli[:route].inspect]
+ end
+end
+
+TestBot.configure('chat.freenode.net', 6667, 'bocelli%03d' % rand(1000))
+TestBot.connect do
+ join '##omp'
+end
+
+TestBot.run