Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first commit

  • Loading branch information...
commit 4a0b6049a48496e3f23ceb858691f72d5abddf3e 0 parents
@ahoward authored
20 README
@@ -0,0 +1,20 @@
+NAME
+ fbomb
+
+SYNOPSIS
+ fbomb is the dangerous campfire bot
+
+USAGE
+ 1) get going
+ ./bin/fbomb setup
+
+ 2) try out some commands
+ ./bin/fbomb /help
+ ./bin/fbomb /chucknorris
+ ./bin/fbomb /fukung canada
+
+ 3) devestate your campfire room
+ ./bin/fbomb run
+
+CUSOMIZE
+ see lib/fbomb/commands/*
392 Rakefile
@@ -0,0 +1,392 @@
+This.rubyforge_project = 'codeforpeople'
+This.author = "Ara T. Howard"
+This.email = "ara.t.howard@gmail.com"
+This.homepage = "https://github.com/ahoward/#{ This.lib }"
+
+
+task :default do
+ puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
+end
+
+task :test do
+ run_tests!
+end
+
+namespace :test do
+ task(:unit){ run_tests!(:unit) }
+ task(:functional){ run_tests!(:functional) }
+ task(:integration){ run_tests!(:integration) }
+end
+
+def run_tests!(which = nil)
+ which ||= '**'
+ test_dir = File.join(This.dir, "test")
+ test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
+ test_rbs = Dir.glob(test_glob).sort
+
+ div = ('=' * 119)
+ line = ('-' * 119)
+
+ test_rbs.each_with_index do |test_rb, index|
+ testno = index + 1
+ command = "#{ This.ruby } -I ./lib -I ./test/lib #{ test_rb }"
+
+ puts
+ say(div, :color => :cyan, :bold => true)
+ say("@#{ testno } => ", :bold => true, :method => :print)
+ say(command, :color => :cyan, :bold => true)
+ say(line, :color => :cyan, :bold => true)
+
+ system(command)
+
+ say(line, :color => :cyan, :bold => true)
+
+ status = $?.exitstatus
+
+ if status.zero?
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
+ say("SUCCESS", :color => :green, :bold => true)
+ else
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
+ say("FAILURE", :color => :red, :bold => true)
+ end
+ say(line, :color => :cyan, :bold => true)
+
+ exit(status) unless status.zero?
+ end
+end
+
+
+task :gemspec do
+ ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
+ ignore_directories = ['pkg']
+ ignore_files = ['test/log', 'a.rb'] + Dir['db/*'] + %w'db'
+
+ shiteless =
+ lambda do |list|
+ list.delete_if do |entry|
+ next unless test(?e, entry)
+ extension = File.basename(entry).split(%r/[.]/).last
+ ignore_extensions.any?{|ext| ext === extension}
+ end
+ list.delete_if do |entry|
+ next unless test(?d, entry)
+ dirname = File.expand_path(entry)
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
+ end
+ list.delete_if do |entry|
+ next unless test(?f, entry)
+ filename = File.expand_path(entry)
+ ignore_files.any?{|file| File.expand_path(file) == filename}
+ end
+ end
+
+ lib = This.lib
+ object = This.object
+ version = This.version
+ files = shiteless[Dir::glob("**/**")]
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
+ #has_rdoc = true #File.exist?('doc')
+ test_files = test(?e, "test/#{ lib }.rb") ? "test/#{ lib }.rb" : nil
+ summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
+ description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
+
+ if This.extensions.nil?
+ This.extensions = []
+ extensions = This.extensions
+ %w( Makefile configure extconf.rb ).each do |ext|
+ extensions << ext if File.exists?(ext)
+ end
+ end
+ extensions = [extensions].flatten.compact
+
+# TODO
+ if This.dependencies.nil?
+ dependencies = []
+ else
+ case This.dependencies
+ when Hash
+ dependencies = This.dependencies.values
+ when Array
+ dependencies = This.dependencies
+ end
+ end
+
+ template =
+ if test(?e, 'gemspec.erb')
+ Template{ IO.read('gemspec.erb') }
+ else
+ Template {
+ <<-__
+ ## <%= lib %>.gemspec
+ #
+
+ Gem::Specification::new do |spec|
+ spec.name = <%= lib.inspect %>
+ spec.version = <%= version.inspect %>
+ spec.platform = Gem::Platform::RUBY
+ spec.summary = <%= lib.inspect %>
+ spec.description = <%= description.inspect %>
+
+ spec.files =\n<%= files.sort.pretty_inspect %>
+ spec.executables = <%= executables.inspect %>
+
+ spec.require_path = "lib"
+
+ spec.test_files = <%= test_files.inspect %>
+
+ <% dependencies.each do |lib_version| %>
+ spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>)
+ <% end %>
+
+ spec.extensions.push(*<%= extensions.inspect %>)
+
+ spec.rubyforge_project = <%= This.rubyforge_project.inspect %>
+ spec.author = <%= This.author.inspect %>
+ spec.email = <%= This.email.inspect %>
+ spec.homepage = <%= This.homepage.inspect %>
+ end
+ __
+ }
+ end
+
+ Fu.mkdir_p(This.pkgdir)
+ gemspec = "#{ lib }.gemspec"
+ open(gemspec, "w"){|fd| fd.puts(template)}
+ This.gemspec = gemspec
+end
+
+task :gem => [:clean, :gemspec] do
+ Fu.mkdir_p(This.pkgdir)
+ before = Dir['*.gem']
+ cmd = "gem build #{ This.gemspec }"
+ `#{ cmd }`
+ after = Dir['*.gem']
+ gem = ((after - before).first || after.first) or abort('no gem!')
+ Fu.mv(gem, This.pkgdir)
+ This.gem = File.join(This.pkgdir, File.basename(gem))
+end
+
+task :readme do
+ samples = ''
+ prompt = '~ > '
+ lib = This.lib
+ version = This.version
+
+ Dir['sample*/*'].sort.each do |sample|
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
+
+ cmd = "cat #{ sample }"
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
+ samples << Util.indent(`#{ cmd }`, 4) << "\n"
+
+ cmd = "ruby #{ sample }"
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
+
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
+ samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
+ end
+
+ template =
+ if test(?e, 'readme.erb')
+ Template{ IO.read('readme.erb') }
+ else
+ Template {
+ <<-__
+ NAME
+ #{ lib }
+
+ DESCRIPTION
+
+ INSTALL
+ gem install #{ lib }
+
+ SAMPLES
+ #{ samples }
+ __
+ }
+ end
+
+ open("README", "w"){|fd| fd.puts template}
+end
+
+
+task :clean do
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
+end
+
+
+task :release => [:clean, :gemspec, :gem] do
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
+ raise "which one? : #{ gems.inspect }" if gems.size > 1
+ raise "no gems?" if gems.size < 1
+
+ cmd = "gem push #{ This.gem }"
+ puts cmd
+ puts
+ system(cmd)
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
+
+ cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
+ puts cmd
+ puts
+ system(cmd)
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
+end
+
+
+
+
+
+BEGIN {
+# support for this rakefile
+#
+ $VERBOSE = nil
+
+ require 'ostruct'
+ require 'erb'
+ require 'fileutils'
+ require 'rbconfig'
+ require 'pp'
+
+# fu shortcut
+#
+ Fu = FileUtils
+
+# cache a bunch of stuff about this rakefile/environment
+#
+ This = OpenStruct.new
+
+ This.file = File.expand_path(__FILE__)
+ This.dir = File.dirname(This.file)
+ This.pkgdir = File.join(This.dir, 'pkg')
+
+# grok lib
+#
+ lib = ENV['LIB']
+ unless lib
+ lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
+ end
+ This.lib = lib
+
+# grok version
+#
+ version = ENV['VERSION']
+ unless version
+ require "./lib/#{ This.lib }"
+ This.name = lib.capitalize
+ const = Object.constants.detect{|const| const =~ /\A#{ This.name }\Z/i}
+ abort("no module exported for #{ This.name }") unless const
+ This.object = eval(const)
+ version = This.object.send(:version)
+ end
+ This.version = version
+
+# see if dependencies are export by the module
+#
+ if This.object.respond_to?(:dependencies)
+ This.dependencies = This.object.dependencies
+ end
+
+# we need to know the name of the lib an it's version
+#
+ abort('no lib') unless This.lib
+ abort('no version') unless This.version
+
+# discover full path to this ruby executable
+#
+ c = Config::CONFIG
+ bindir = c["bindir"] || c['BINDIR']
+ ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
+ ruby_ext = c['EXEEXT'] || ''
+ ruby = File.join(bindir, (ruby_install_name + ruby_ext))
+ This.ruby = ruby
+
+# some utils
+#
+ module Util
+ def indent(s, n = 2)
+ s = unindent(s)
+ ws = ' ' * n
+ s.gsub(%r/^/, ws)
+ end
+
+ def unindent(s)
+ indent = nil
+ s.each_line do |line|
+ next if line =~ %r/^\s*$/
+ indent = line[%r/^\s*/] and break
+ end
+ indent ? s.gsub(%r/^#{ indent }/, "") : s
+ end
+ extend self
+ end
+
+# template support
+#
+ class Template
+ def initialize(&block)
+ @block = block
+ @template = block.call.to_s
+ end
+ def expand(b=nil)
+ ERB.new(Util.unindent(@template)).result((b||@block).binding)
+ end
+ alias_method 'to_s', 'expand'
+ end
+ def Template(*args, &block) Template.new(*args, &block) end
+
+# colored console output support
+#
+ This.ansi = {
+ :clear => "\e[0m",
+ :reset => "\e[0m",
+ :erase_line => "\e[K",
+ :erase_char => "\e[P",
+ :bold => "\e[1m",
+ :dark => "\e[2m",
+ :underline => "\e[4m",
+ :underscore => "\e[4m",
+ :blink => "\e[5m",
+ :reverse => "\e[7m",
+ :concealed => "\e[8m",
+ :black => "\e[30m",
+ :red => "\e[31m",
+ :green => "\e[32m",
+ :yellow => "\e[33m",
+ :blue => "\e[34m",
+ :magenta => "\e[35m",
+ :cyan => "\e[36m",
+ :white => "\e[37m",
+ :on_black => "\e[40m",
+ :on_red => "\e[41m",
+ :on_green => "\e[42m",
+ :on_yellow => "\e[43m",
+ :on_blue => "\e[44m",
+ :on_magenta => "\e[45m",
+ :on_cyan => "\e[46m",
+ :on_white => "\e[47m"
+ }
+ def say(phrase, *args)
+ options = args.last.is_a?(Hash) ? args.pop : {}
+ options[:color] = args.shift.to_s.to_sym unless args.empty?
+ keys = options.keys
+ keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
+
+ color = options[:color]
+ bold = options.has_key?(:bold)
+
+ parts = [phrase]
+ parts.unshift(This.ansi[color]) if color
+ parts.unshift(This.ansi[:bold]) if bold
+ parts.push(This.ansi[:clear]) if parts.size > 1
+
+ method = options[:method] || :puts
+
+ Kernel.send(method, parts.join)
+ end
+
+# always run out of the project dir
+#
+ Dir.chdir(This.dir)
+}
109 bin/fbomb
@@ -0,0 +1,109 @@
+#! /usr/bin/env ruby
+
+Main {
+##
+#
+ edit_config_file! <<-__
+ campfire:
+ domain: YOUR_CAMPFIRE_DOMAIN
+ token: YOUR_CAMPFIRE_API_TOKEN
+ room: YOUR_CAMPFIRE_ROOM_NAME
+
+ commands:
+ - system
+ - builtin
+ __
+
+##
+#
+ def run
+ load_commands!
+ end
+
+ def load_commands!
+ @commands = FBomb::Command.load(config[:commands])
+ run_command! if argv.first =~ %r|^/| unless argv.empty?
+ end
+
+ def run_command!
+ path, args = argv
+ commands = FBomb::Command.table
+ command = commands[path] or abort("no such command #{ path }")
+ command.call(*args)
+ exit
+ end
+
+##
+#
+ mode(:run) do
+ def run
+ load_commands!
+ drop_fbombs!
+ end
+
+ def drop_fbombs!
+ domain, token, room = config[:campfire].slice(:domain, :token, :room).values
+ campfire = FBomb::Campfire.new(domain, :token => token)
+ room = campfire.room_for(room)
+ room.join
+ id = room.id
+
+ FBomb::Command.room = room
+ url = URI.parse("http://#{ token }:x@streaming.campfirenow.com//room/#{ id }/live.json")
+
+ trap('INT'){ exit! }
+
+ loop do
+ logging_errors do
+ Yajl::HttpStream.get(url) do |message|
+ case message['type'].to_s
+ when 'TextMessage'
+ body = message['body'].to_s
+ tokens = body.scan(%r/[^\s]+/)
+ arg, *args = tokens
+
+ if arg =~ %r|^\s*/|
+ path = arg.strip
+ command = @commands[path]
+ if command
+ logging_errors do
+ command.call(*args)
+ end
+ end
+ end
+ end
+ end
+
+ sleep(rand(42))
+ end
+ end
+ end
+ end
+
+##
+#
+ mode(:setup) do
+ def run
+ puts self.class.config_path
+ end
+ end
+
+##
+#
+ def logging_errors(&block)
+ begin
+ block.call()
+ rescue Object => e
+ m, c, b = e.message, e.class, Array(e.backtrace).join("\n")
+ logger.error("#{ m }(#{ c })\n#{ b }")
+ end
+ end
+}
+
+BEGIN{
+ bindir = File.expand_path(File.dirname(__FILE__))
+ srcdir = File.dirname(bindir)
+ libdir = File.join(srcdir, 'lib')
+ lib = File.join(libdir, 'fbomb.rb')
+ require(test(?s, lib) ? lib : 'fbomb')
+}
32 fbomb.gemspec
@@ -0,0 +1,32 @@
+## fbomb.gemspec
+#
+
+Gem::Specification::new do |spec|
+ spec.name = "fbomb"
+ spec.version = "0.4.2"
+ spec.platform = Gem::Platform::RUBY
+ spec.summary = "fbomb"
+ spec.description = "description: fbomb kicks the ass"
+
+ spec.files =
+["Rakefile", "fbomb.gemspec", "lib", "lib/fbomb.rb"]
+
+ spec.executables = []
+
+ spec.require_path = "lib"
+
+ spec.test_files = nil
+
+
+ spec.add_dependency(*["tinder", "~> 1.4.3"])
+
+ spec.add_dependency(*["main", "~> 4.7.3"])
+
+
+ spec.extensions.push(*[])
+
+ spec.rubyforge_project = "codeforpeople"
+ spec.author = "Ara T. Howard"
+ spec.email = "ara.t.howard@gmail.com"
+ spec.homepage = "https://github.com/ahoward/fbomb"
+end
86 lib/fbomb.rb
@@ -0,0 +1,86 @@
+# built-ins
+#
+ require 'thread'
+ require "uri"
+ require 'net/http'
+ require 'net/https'
+ require 'open-uri'
+
+# libs
+#
+ module FBomb
+ Version = '0.4.2' unless defined?(Version)
+
+ def version
+ FBomb::Version
+ end
+
+ def dependencies
+ {
+ 'tinder' => [ 'tinder' , '~> 1.4.3' ] ,
+ 'twitter/json_stream' => [ 'twitter-stream' , '~> 0.1.14' ] ,
+ 'yajl' => [ 'yajl-ruby' , '~> 0.8.3' ] ,
+ 'fukung' => [ 'fukung' , '~> 1.1.0' ] ,
+ 'main' => [ 'main' , '~> 4.7.6' ]
+ }
+ end
+
+ def libdir(*args, &block)
+ @libdir ||= File.expand_path(__FILE__).sub(/\.rb$/,'')
+ args.empty? ? @libdir : File.join(@libdir, *args)
+ ensure
+ if block
+ begin
+ $LOAD_PATH.unshift(@libdir)
+ block.call()
+ ensure
+ $LOAD_PATH.shift()
+ end
+ end
+ end
+
+ def load(*libs)
+ libs = libs.join(' ').scan(/[^\s+]+/)
+ FBomb.libdir{ libs.each{|lib| Kernel.load(lib) } }
+ end
+
+ extend(FBomb)
+ end
+
+# gems
+#
+ begin
+ require 'rubygems'
+ rescue LoadError
+ nil
+ end
+
+ if defined?(gem)
+ FBomb.dependencies.each do |lib, dependency|
+ gem(*dependency)
+ require(lib)
+ end
+ end
+
+ require "yajl/json_gem" ### this *replaces* any other JSON.parse !
+ require "yajl/http_stream" ### we really do need this
+
+ FBomb.load %w[
+ util.rb
+ campfire.rb
+ command.rb
+ ]
+
+## openssl - STFU!
+#
+ class Net::HTTP
+ def warn(msg)
+ Kernel.warn(msg) unless msg == "warning: peer certificate won't be verified in this SSL session"
+ end
+ end
+
+## global DSL hook
+#
+ def FBomb(*args, &block)
+ FBomb::Command::DSL.evaluate(*args, &block)
+ end
71 lib/fbomb/campfire.rb
@@ -0,0 +1,71 @@
+module FBomb
+ class Campfire < ::Tinder::Campfire
+ module SearchExtension
+ def search(term)
+ room = self
+ term = CGI.escape(term.to_s)
+ return_to_room_id = CGI.escape(room.id.to_s)
+ messages = connection.get("/search?term=#{ term }&return_to_room_id=#{ return_to_room_id }")
+ if messages and messages.is_a?(Hash)
+ messages = messages['messages']
+ end
+ messages.each do |message|
+ message['created_at_time'] = Time.parse(message['created_at'])
+ end
+ messages.replace(messages.sort_by{|message| message['created_at_time']})
+ messages
+ end
+ end
+
+ module UserExtension
+ Cached = {}
+
+ def user(id)
+ user = Cached[id]
+ return user if user
+
+ if id
+ user = users.detect{|u| u[:id] == id}
+ unless user
+ user_data = connection.get("/users/#{ id }.json")
+ user = user_data && user_data['user']
+ end
+ user['created_at'] = Time.parse(user['created_at'])
+ Cached[id] = user
+ end
+ end
+ end
+
+ module StreamExtension
+ def stream
+ @stream ||= (
+ room = self
+ Twitter::JSONStream.connect(
+ :path => "/room/#{ room.id }/live.json",
+ :host => 'streaming.campfirenow.com',
+ :auth => "#{ connection.token }:x"
+ )
+ )
+ end
+
+ def streaming(&block)
+ steam.instance_eval(&block)
+ end
+ end
+
+ def Campfire.new(*args, &block)
+ allocate.tap do |instance|
+ instance.send(:initialize, *args, &block)
+ end
+ end
+
+ def room_for(name)
+ name = name.to_s
+ room = rooms.detect{|_| _.name == name}
+ room.extend(SearchExtension)
+ room.extend(UserExtension)
+ room.extend(StreamExtension)
+ room
+ end
+ end
+end
144 lib/fbomb/command.rb
@@ -0,0 +1,144 @@
+module FBomb
+## class_methods
+#
+ class Command
+ class Table < ::Map
+ def help
+ map = Map.new
+ each do |path, command|
+ map[path] = command.description
+ end
+ map
+ end
+ end
+
+ class << Command
+ fattr(:table){ Table.new }
+ fattr(:dir){ File.join(File.expand_path(File.dirname(__FILE__)), 'commands') }
+ fattr(:room)
+
+ def load(*args)
+ args.flatten.uniq.each do |arg|
+ case arg.to_s
+ when %r|^/|
+ load_absolute_path(arg)
+ when %r|://|
+ load_uri(arg)
+ else
+ load_relative_path(arg)
+ end
+ end
+ setup
+ table
+ end
+
+ def commands
+ table.values
+ end
+
+ def setup
+ commands.each do |command|
+ if command.setup and command.setup.respond_to?(:call)
+ command.setup.call()
+ command.setup = true
+ end
+ end
+ end
+
+ def load_uri(arg)
+ uri = arg.to_s
+ open(uri) do |fd|
+ open(path){|fd| load_string(fd.read)}
+ end
+ end
+
+ def load_relative_path(arg)
+ basename = arg.to_s
+ basename += '.rb' unless basename =~ /\.rb\Z/
+ load_absolute_path(File.join(Command.dir, basename))
+ end
+
+ def load_absolute_path(arg)
+ path = File.expand_path(arg.to_s)
+ path += '.rb' unless path =~ /\.rb\Z/
+ open(path){|fd| load_string(fd.read)}
+ end
+
+ def load_string(string, dangerous = true)
+ Thread.new(string, dangerous) do |string, dangerous|
+ Thread.current.abort_on_exception = true
+ $SAFE = 12 unless dangerous
+ Kernel.eval(string)
+ end.value
+ end
+ end
+
+## instance methods
+#
+ fattr(:room){ self.class.room }
+ fattr(:path)
+ fattr(:help)
+ fattr(:setup)
+
+ def initialize
+ @call = proc{}
+ end
+
+ def call(*args, &block)
+ block ? @call=call : instance_exec(*args, &@call)
+ end
+
+ def call=(call)
+ @call = call
+ end
+
+ %w( speak paste ).each do |method|
+ module_eval <<-__, __FILE__, __LINE__
+ def #{ method }(*args, &block)
+ room ? room.#{ method }(*args, &block) : puts(*args, &block)
+ end
+ __
+ end
+
+## dsl
+#
+ class DSL
+ instance_methods.each{|m| undef_method(m) unless m.to_s =~ /(^__)|object_id/}
+
+ def DSL.evaluate(*args, &block)
+ dsl = new
+ dsl.evaluate(*args, &block)
+ dsl
+ end
+
+ def initialize
+ @commands = Command.table
+ end
+
+ def evaluate(*args, &block)
+ Object.instance_method(:instance_eval).bind(self).call(&block)
+ end
+
+ def command(*args, &block)
+ return @command if(args.empty? and block.nil?)
+ @command = Command.new
+ @command.path = Util.absolute_path_for(args.shift)
+ @commands[@command.path] ||= @command
+ evaluate(&block)
+ end
+ alias_method('Command', 'command')
+
+ def help(*args)
+ @command.help = args.join("\n")
+ end
+
+ def setup(&block)
+ @command.setup = block
+ end
+
+ def call(&block)
+ @command.call = block
+ end
+ end
+ end
+end
90 lib/fbomb/commands/builtin.rb
@@ -0,0 +1,90 @@
+FBomb {
+
+##
+#
+ command(:rhymeswith) {
+ help 'show ryhming words'
+
+ setup{ require 'cgi' }
+
+ call do |*args|
+ args.each do |arg|
+ word = CGI.escape(arg.strip)
+ url = "http://www.zachblume.com/apis/rhyme.php?format=xml&word=#{ word }"
+ data = `curl --silent #{ url.inspect }`
+ words = data.scan(%r|<word>([^<]*)</word>|).flatten
+ msg = words.join(" ")
+ speak(msg)
+ end
+ end
+ }
+
+##
+#
+ command(:chucknorris) {
+ call do |*args|
+ data = JSON.parse(`curl --silent 'http://api.icndb.com/jokes/random'`)
+ msg = data['value']['joke']
+ speak(msg) unless msg.strip.empty?
+ end
+ }
+
+##
+#
+ command(:fukung) {
+ call do |*args|
+ tags = args.join(' ').strip.downcase
+ msg = Fukung.tag(tags).sort_by{ rand }.first(3).join("\n")
+ speak(msg) unless msg.strip.empty?
+ end
+ }
+
+##
+#
+ command(:google) {
+ setup{ require "google-search" }
+
+ call do |*args|
+ type = args.first
+ msg = ""
+ case type
+ when /image|img|i/i
+ args.shift
+ query = args.join(' ')
+ Google::Search::Image.new(:query => query, :image_size => :icon).each do |result|
+ msg << "#{ result.uri }\n"
+ end
+ else
+ query = args.join(' ')
+ Google::Search::Web.new(:query => query).each do |result|
+ msg << "#{ result.uri }\n"
+ end
+ end
+ speak(msg) unless msg.empty?
+ end
+ }
+
+##
+#
+ command(:gist) {
+ call do |*args|
+ url = args.join(' ').strip
+
+ id = url.scan(/\d+/).first
+ gist_url = "https://gist.github.com/#{ id }"
+ speak(gist_url)
+
+ gist_html = `curl --silent #{ gist_url.inspect }`
+ re = %r| <a\s+href\s*=\s*" (/raw[^">]+) "\s*>\s*raw\s*</a> |iox
+ match, raw_path = re.match(gist_html).to_a
+
+ if match
+ raw_url = "https://gist.github.com#{ raw_path }"
+ raw_html = `curl --silent --location #{ raw_url.inspect }`
+ paste(raw_html)
+ end
+ end
+ }
+
+}
+
23 lib/fbomb/commands/system.rb
@@ -0,0 +1,23 @@
+FBomb {
+ command(:help) {
+ call do |*args|
+ sections = []
+ Command.table.each do |path, command|
+ next if path == '/help'
+ help = command.help || path
+ chunk = [path, Util.indent(help) + "\n"]
+ sections.push(chunk)
+ end
+ sections.sort!{|a, b| a.first <=> b.first}
+ sections.push(["/help", Util.indent("this message") + "\n"])
+ msg = sections.join("\n")
+ paste(msg) unless msg.strip.empty?
+ end
+ }
+
+ command(:fbomb) {
+ call {
+ speak('http://s3.amazonaws.com/drawohara.com.mp3/tom_jones_sex_bomb_dance_remix.mp3')
+ }
+ }
+}
93 lib/fbomb/util.rb
@@ -0,0 +1,93 @@
+module Util
+ def paths_for(*args)
+ path = args.flatten.compact.join('/')
+ path.gsub!(%r|[.]+/|, '/')
+ path.squeeze!('/')
+ path.sub!(%r|^/|, '')
+ path.sub!(%r|/$|, '')
+ paths = path.split('/')
+ end
+
+ def absolute_path_for(*args)
+ ('/' + paths_for(*args).join('/')).squeeze('/')
+ end
+
+ def absolute_prefix_for(*args)
+ absolute_path_for(*args) + '/'
+ end
+
+ def path_for(*args)
+ paths_for(*args).join('/').squeeze('/')
+ end
+
+ def prefix_for(*args)
+ path_for(*args) + '/'
+ end
+
+ def normalize_path(arg, *args)
+ absolute_path_for(arg, *args)
+ end
+
+ def indent(chunk, n = 2)
+ lines = chunk.split %r/\n/
+ re = nil
+ s = ' ' * n
+ lines.map! do |line|
+ unless re
+ margin = line[%r/^\s*/]
+ re = %r/^#{ margin }/
+ end
+ line.gsub re, s
+ end.join("\n")
+ end
+
+ def unindent(chunk)
+ lines = chunk.split %r/\n/
+ indent = nil
+ re = %r/^/
+ lines.map! do |line|
+ unless indent
+ indent = line[%r/^\s*/]
+ re = %r/^#{ indent }/
+ end
+ line.gsub re, ''
+ end.join("\n")
+ end
+
+ def columnize(buf, opts = {})
+ width = Util.getopt 'width', opts, 80
+ indent = Util.getopt 'indent', opts
+ indent = Fixnum === indent ? (' ' * indent) : "#{ indent }"
+ column = []
+ words = buf.split %r/\s+/o
+ row = "#{ indent }"
+ while((word = words.shift))
+ if((row.size + word.size) < (width - 1))
+ row << word
+ else
+ column << row
+ row = "#{ indent }"
+ row << word
+ end
+ row << ' ' unless row.size == (width - 1)
+ end
+ column << row unless row.strip.empty?
+ column.join "\n"
+ end
+
+ def getopt(opt, hash, default = nil)
+ keys = opt.respond_to?('each') ? opt : [opt]
+
+ keys.each do |key|
+ return hash[key] if hash.has_key? key
+ key = "#{ key }"
+ return hash[key] if hash.has_key? key
+ key = key.intern
+ return hash[key] if hash.has_key? key
+ end
+
+ return default
+ end
+
+ extend(Util)
+end
Please sign in to comment.
Something went wrong with that request. Please try again.