fbomb 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,20 @@
1
+ NAME
2
+ fbomb
3
+
4
+ SYNOPSIS
5
+ fbomb is the dangerous campfire bot
6
+
7
+ USAGE
8
+ 1) get going
9
+ ./bin/fbomb setup
10
+
11
+ 2) try out some commands
12
+ ./bin/fbomb /help
13
+ ./bin/fbomb /chucknorris
14
+ ./bin/fbomb /fukung canada
15
+
16
+ 3) devestate your campfire room
17
+ ./bin/fbomb run
18
+
19
+ CUSTOMIZE
20
+ see lib/fbomb/commands/*
data/Rakefile ADDED
@@ -0,0 +1,392 @@
1
+ This.rubyforge_project = 'codeforpeople'
2
+ This.author = "Ara T. Howard"
3
+ This.email = "ara.t.howard@gmail.com"
4
+ This.homepage = "https://github.com/ahoward/#{ This.lib }"
5
+
6
+
7
+ task :default do
8
+ puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
9
+ end
10
+
11
+ task :test do
12
+ run_tests!
13
+ end
14
+
15
+ namespace :test do
16
+ task(:unit){ run_tests!(:unit) }
17
+ task(:functional){ run_tests!(:functional) }
18
+ task(:integration){ run_tests!(:integration) }
19
+ end
20
+
21
+ def run_tests!(which = nil)
22
+ which ||= '**'
23
+ test_dir = File.join(This.dir, "test")
24
+ test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
25
+ test_rbs = Dir.glob(test_glob).sort
26
+
27
+ div = ('=' * 119)
28
+ line = ('-' * 119)
29
+
30
+ test_rbs.each_with_index do |test_rb, index|
31
+ testno = index + 1
32
+ command = "#{ This.ruby } -I ./lib -I ./test/lib #{ test_rb }"
33
+
34
+ puts
35
+ say(div, :color => :cyan, :bold => true)
36
+ say("@#{ testno } => ", :bold => true, :method => :print)
37
+ say(command, :color => :cyan, :bold => true)
38
+ say(line, :color => :cyan, :bold => true)
39
+
40
+ system(command)
41
+
42
+ say(line, :color => :cyan, :bold => true)
43
+
44
+ status = $?.exitstatus
45
+
46
+ if status.zero?
47
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
48
+ say("SUCCESS", :color => :green, :bold => true)
49
+ else
50
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
51
+ say("FAILURE", :color => :red, :bold => true)
52
+ end
53
+ say(line, :color => :cyan, :bold => true)
54
+
55
+ exit(status) unless status.zero?
56
+ end
57
+ end
58
+
59
+
60
+ task :gemspec do
61
+ ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
62
+ ignore_directories = ['pkg']
63
+ ignore_files = ['test/log', 'a.rb'] + Dir['db/*'] + %w'db'
64
+
65
+ shiteless =
66
+ lambda do |list|
67
+ list.delete_if do |entry|
68
+ next unless test(?e, entry)
69
+ extension = File.basename(entry).split(%r/[.]/).last
70
+ ignore_extensions.any?{|ext| ext === extension}
71
+ end
72
+ list.delete_if do |entry|
73
+ next unless test(?d, entry)
74
+ dirname = File.expand_path(entry)
75
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
76
+ end
77
+ list.delete_if do |entry|
78
+ next unless test(?f, entry)
79
+ filename = File.expand_path(entry)
80
+ ignore_files.any?{|file| File.expand_path(file) == filename}
81
+ end
82
+ end
83
+
84
+ lib = This.lib
85
+ object = This.object
86
+ version = This.version
87
+ files = shiteless[Dir::glob("**/**")]
88
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
89
+ #has_rdoc = true #File.exist?('doc')
90
+ test_files = test(?e, "test/#{ lib }.rb") ? "test/#{ lib }.rb" : nil
91
+ summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
92
+ description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
93
+
94
+ if This.extensions.nil?
95
+ This.extensions = []
96
+ extensions = This.extensions
97
+ %w( Makefile configure extconf.rb ).each do |ext|
98
+ extensions << ext if File.exists?(ext)
99
+ end
100
+ end
101
+ extensions = [extensions].flatten.compact
102
+
103
+ # TODO
104
+ if This.dependencies.nil?
105
+ dependencies = []
106
+ else
107
+ case This.dependencies
108
+ when Hash
109
+ dependencies = This.dependencies.values
110
+ when Array
111
+ dependencies = This.dependencies
112
+ end
113
+ end
114
+
115
+ template =
116
+ if test(?e, 'gemspec.erb')
117
+ Template{ IO.read('gemspec.erb') }
118
+ else
119
+ Template {
120
+ <<-__
121
+ ## <%= lib %>.gemspec
122
+ #
123
+
124
+ Gem::Specification::new do |spec|
125
+ spec.name = <%= lib.inspect %>
126
+ spec.version = <%= version.inspect %>
127
+ spec.platform = Gem::Platform::RUBY
128
+ spec.summary = <%= lib.inspect %>
129
+ spec.description = <%= description.inspect %>
130
+
131
+ spec.files =\n<%= files.sort.pretty_inspect %>
132
+ spec.executables = <%= executables.inspect %>
133
+
134
+ spec.require_path = "lib"
135
+
136
+ spec.test_files = <%= test_files.inspect %>
137
+
138
+ <% dependencies.each do |lib_version| %>
139
+ spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>)
140
+ <% end %>
141
+
142
+ spec.extensions.push(*<%= extensions.inspect %>)
143
+
144
+ spec.rubyforge_project = <%= This.rubyforge_project.inspect %>
145
+ spec.author = <%= This.author.inspect %>
146
+ spec.email = <%= This.email.inspect %>
147
+ spec.homepage = <%= This.homepage.inspect %>
148
+ end
149
+ __
150
+ }
151
+ end
152
+
153
+ Fu.mkdir_p(This.pkgdir)
154
+ gemspec = "#{ lib }.gemspec"
155
+ open(gemspec, "w"){|fd| fd.puts(template)}
156
+ This.gemspec = gemspec
157
+ end
158
+
159
+ task :gem => [:clean, :gemspec] do
160
+ Fu.mkdir_p(This.pkgdir)
161
+ before = Dir['*.gem']
162
+ cmd = "gem build #{ This.gemspec }"
163
+ `#{ cmd }`
164
+ after = Dir['*.gem']
165
+ gem = ((after - before).first || after.first) or abort('no gem!')
166
+ Fu.mv(gem, This.pkgdir)
167
+ This.gem = File.join(This.pkgdir, File.basename(gem))
168
+ end
169
+
170
+ task :readme do
171
+ samples = ''
172
+ prompt = '~ > '
173
+ lib = This.lib
174
+ version = This.version
175
+
176
+ Dir['sample*/*'].sort.each do |sample|
177
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
178
+
179
+ cmd = "cat #{ sample }"
180
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
181
+ samples << Util.indent(`#{ cmd }`, 4) << "\n"
182
+
183
+ cmd = "ruby #{ sample }"
184
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
185
+
186
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
187
+ samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
188
+ end
189
+
190
+ template =
191
+ if test(?e, 'readme.erb')
192
+ Template{ IO.read('readme.erb') }
193
+ else
194
+ Template {
195
+ <<-__
196
+ NAME
197
+ #{ lib }
198
+
199
+ DESCRIPTION
200
+
201
+ INSTALL
202
+ gem install #{ lib }
203
+
204
+ SAMPLES
205
+ #{ samples }
206
+ __
207
+ }
208
+ end
209
+
210
+ open("README", "w"){|fd| fd.puts template}
211
+ end
212
+
213
+
214
+ task :clean do
215
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
216
+ end
217
+
218
+
219
+ task :release => [:clean, :gemspec, :gem] do
220
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
221
+ raise "which one? : #{ gems.inspect }" if gems.size > 1
222
+ raise "no gems?" if gems.size < 1
223
+
224
+ cmd = "gem push #{ This.gem }"
225
+ puts cmd
226
+ puts
227
+ system(cmd)
228
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
229
+
230
+ cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
231
+ puts cmd
232
+ puts
233
+ system(cmd)
234
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
235
+ end
236
+
237
+
238
+
239
+
240
+
241
+ BEGIN {
242
+ # support for this rakefile
243
+ #
244
+ $VERBOSE = nil
245
+
246
+ require 'ostruct'
247
+ require 'erb'
248
+ require 'fileutils'
249
+ require 'rbconfig'
250
+ require 'pp'
251
+
252
+ # fu shortcut
253
+ #
254
+ Fu = FileUtils
255
+
256
+ # cache a bunch of stuff about this rakefile/environment
257
+ #
258
+ This = OpenStruct.new
259
+
260
+ This.file = File.expand_path(__FILE__)
261
+ This.dir = File.dirname(This.file)
262
+ This.pkgdir = File.join(This.dir, 'pkg')
263
+
264
+ # grok lib
265
+ #
266
+ lib = ENV['LIB']
267
+ unless lib
268
+ lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
269
+ end
270
+ This.lib = lib
271
+
272
+ # grok version
273
+ #
274
+ version = ENV['VERSION']
275
+ unless version
276
+ require "./lib/#{ This.lib }"
277
+ This.name = lib.capitalize
278
+ const = Object.constants.detect{|const| const =~ /\A#{ This.name }\Z/i}
279
+ abort("no module exported for #{ This.name }") unless const
280
+ This.object = eval(const)
281
+ version = This.object.send(:version)
282
+ end
283
+ This.version = version
284
+
285
+ # see if dependencies are export by the module
286
+ #
287
+ if This.object.respond_to?(:dependencies)
288
+ This.dependencies = This.object.dependencies
289
+ end
290
+
291
+ # we need to know the name of the lib an it's version
292
+ #
293
+ abort('no lib') unless This.lib
294
+ abort('no version') unless This.version
295
+
296
+ # discover full path to this ruby executable
297
+ #
298
+ c = Config::CONFIG
299
+ bindir = c["bindir"] || c['BINDIR']
300
+ ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
301
+ ruby_ext = c['EXEEXT'] || ''
302
+ ruby = File.join(bindir, (ruby_install_name + ruby_ext))
303
+ This.ruby = ruby
304
+
305
+ # some utils
306
+ #
307
+ module Util
308
+ def indent(s, n = 2)
309
+ s = unindent(s)
310
+ ws = ' ' * n
311
+ s.gsub(%r/^/, ws)
312
+ end
313
+
314
+ def unindent(s)
315
+ indent = nil
316
+ s.each_line do |line|
317
+ next if line =~ %r/^\s*$/
318
+ indent = line[%r/^\s*/] and break
319
+ end
320
+ indent ? s.gsub(%r/^#{ indent }/, "") : s
321
+ end
322
+ extend self
323
+ end
324
+
325
+ # template support
326
+ #
327
+ class Template
328
+ def initialize(&block)
329
+ @block = block
330
+ @template = block.call.to_s
331
+ end
332
+ def expand(b=nil)
333
+ ERB.new(Util.unindent(@template)).result((b||@block).binding)
334
+ end
335
+ alias_method 'to_s', 'expand'
336
+ end
337
+ def Template(*args, &block) Template.new(*args, &block) end
338
+
339
+ # colored console output support
340
+ #
341
+ This.ansi = {
342
+ :clear => "\e[0m",
343
+ :reset => "\e[0m",
344
+ :erase_line => "\e[K",
345
+ :erase_char => "\e[P",
346
+ :bold => "\e[1m",
347
+ :dark => "\e[2m",
348
+ :underline => "\e[4m",
349
+ :underscore => "\e[4m",
350
+ :blink => "\e[5m",
351
+ :reverse => "\e[7m",
352
+ :concealed => "\e[8m",
353
+ :black => "\e[30m",
354
+ :red => "\e[31m",
355
+ :green => "\e[32m",
356
+ :yellow => "\e[33m",
357
+ :blue => "\e[34m",
358
+ :magenta => "\e[35m",
359
+ :cyan => "\e[36m",
360
+ :white => "\e[37m",
361
+ :on_black => "\e[40m",
362
+ :on_red => "\e[41m",
363
+ :on_green => "\e[42m",
364
+ :on_yellow => "\e[43m",
365
+ :on_blue => "\e[44m",
366
+ :on_magenta => "\e[45m",
367
+ :on_cyan => "\e[46m",
368
+ :on_white => "\e[47m"
369
+ }
370
+ def say(phrase, *args)
371
+ options = args.last.is_a?(Hash) ? args.pop : {}
372
+ options[:color] = args.shift.to_s.to_sym unless args.empty?
373
+ keys = options.keys
374
+ keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
375
+
376
+ color = options[:color]
377
+ bold = options.has_key?(:bold)
378
+
379
+ parts = [phrase]
380
+ parts.unshift(This.ansi[color]) if color
381
+ parts.unshift(This.ansi[:bold]) if bold
382
+ parts.push(This.ansi[:clear]) if parts.size > 1
383
+
384
+ method = options[:method] || :puts
385
+
386
+ Kernel.send(method, parts.join)
387
+ end
388
+
389
+ # always run out of the project dir
390
+ #
391
+ Dir.chdir(This.dir)
392
+ }
data/bin/fbomb ADDED
@@ -0,0 +1,109 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ Main {
4
+ ##
5
+ #
6
+ edit_config_file! <<-__
7
+ campfire:
8
+ domain: YOUR_CAMPFIRE_DOMAIN
9
+ token: YOUR_CAMPFIRE_API_TOKEN
10
+ room: YOUR_CAMPFIRE_ROOM_NAME
11
+
12
+ commands:
13
+ - system
14
+ - builtin
15
+ __
16
+
17
+ ##
18
+ #
19
+ def run
20
+ load_commands!
21
+ end
22
+
23
+ def load_commands!
24
+ @commands = FBomb::Command.load(config[:commands])
25
+ run_command! if argv.first =~ %r|^/| unless argv.empty?
26
+ end
27
+
28
+ def run_command!
29
+ path, args = argv
30
+ commands = FBomb::Command.table
31
+ command = commands[path] or abort("no such command #{ path }")
32
+ command.call(*args)
33
+ exit
34
+ end
35
+
36
+ ##
37
+ #
38
+ mode(:run) do
39
+ def run
40
+ load_commands!
41
+ drop_fbombs!
42
+ end
43
+
44
+ def drop_fbombs!
45
+ domain, token, room = config[:campfire].slice(:domain, :token, :room).values
46
+ campfire = FBomb::Campfire.new(domain, :token => token)
47
+ room = campfire.room_for(room)
48
+ room.join
49
+ id = room.id
50
+
51
+ FBomb::Command.room = room
52
+ url = URI.parse("http://#{ token }:x@streaming.campfirenow.com//room/#{ id }/live.json")
53
+
54
+ trap('INT'){ exit! }
55
+
56
+ loop do
57
+ logging_errors do
58
+ Yajl::HttpStream.get(url) do |message|
59
+ case message['type'].to_s
60
+ when 'TextMessage'
61
+ body = message['body'].to_s
62
+ tokens = body.scan(%r/[^\s]+/)
63
+ arg, *args = tokens
64
+
65
+ if arg =~ %r|^\s*/|
66
+ path = arg.strip
67
+ command = @commands[path]
68
+ if command
69
+ logging_errors do
70
+ command.call(*args)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ sleep(rand(42))
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ ##
84
+ #
85
+ mode(:setup) do
86
+ def run
87
+ puts self.class.config_path
88
+ end
89
+ end
90
+
91
+ ##
92
+ #
93
+ def logging_errors(&block)
94
+ begin
95
+ block.call()
96
+ rescue Object => e
97
+ m, c, b = e.message, e.class, Array(e.backtrace).join("\n")
98
+ logger.error("#{ m }(#{ c })\n#{ b }")
99
+ end
100
+ end
101
+ }
102
+
103
+ BEGIN{
104
+ bindir = File.expand_path(File.dirname(__FILE__))
105
+ srcdir = File.dirname(bindir)
106
+ libdir = File.join(srcdir, 'lib')
107
+ lib = File.join(libdir, 'fbomb.rb')
108
+ require(test(?s, lib) ? lib : 'fbomb')
109
+ }
data/fbomb.gemspec ADDED
@@ -0,0 +1,51 @@
1
+ ## fbomb.gemspec
2
+ #
3
+
4
+ Gem::Specification::new do |spec|
5
+ spec.name = "fbomb"
6
+ spec.version = "0.4.2"
7
+ spec.platform = Gem::Platform::RUBY
8
+ spec.summary = "fbomb"
9
+ spec.description = "description: fbomb kicks the ass"
10
+
11
+ spec.files =
12
+ ["README",
13
+ "Rakefile",
14
+ "bin",
15
+ "bin/fbomb",
16
+ "fbomb.gemspec",
17
+ "lib",
18
+ "lib/fbomb",
19
+ "lib/fbomb.rb",
20
+ "lib/fbomb/campfire.rb",
21
+ "lib/fbomb/command.rb",
22
+ "lib/fbomb/commands",
23
+ "lib/fbomb/commands/builtin.rb",
24
+ "lib/fbomb/commands/system.rb",
25
+ "lib/fbomb/util.rb"]
26
+
27
+ spec.executables = ["fbomb"]
28
+
29
+ spec.require_path = "lib"
30
+
31
+ spec.test_files = nil
32
+
33
+
34
+ spec.add_dependency(*["tinder", "~> 1.4.3"])
35
+
36
+ spec.add_dependency(*["main", "~> 4.7.6"])
37
+
38
+ spec.add_dependency(*["fukung", "~> 1.1.0"])
39
+
40
+ spec.add_dependency(*["twitter-stream", "~> 0.1.14"])
41
+
42
+ spec.add_dependency(*["yajl-ruby", "~> 0.8.3"])
43
+
44
+
45
+ spec.extensions.push(*[])
46
+
47
+ spec.rubyforge_project = "codeforpeople"
48
+ spec.author = "Ara T. Howard"
49
+ spec.email = "ara.t.howard@gmail.com"
50
+ spec.homepage = "https://github.com/ahoward/fbomb"
51
+ end
@@ -0,0 +1,71 @@
1
+ module FBomb
2
+ class Campfire < ::Tinder::Campfire
3
+ module SearchExtension
4
+ def search(term)
5
+ room = self
6
+ term = CGI.escape(term.to_s)
7
+ return_to_room_id = CGI.escape(room.id.to_s)
8
+ messages = connection.get("/search?term=#{ term }&return_to_room_id=#{ return_to_room_id }")
9
+ if messages and messages.is_a?(Hash)
10
+ messages = messages['messages']
11
+ end
12
+ messages.each do |message|
13
+ message['created_at_time'] = Time.parse(message['created_at'])
14
+ end
15
+ messages.replace(messages.sort_by{|message| message['created_at_time']})
16
+ messages
17
+ end
18
+ end
19
+
20
+ module UserExtension
21
+ Cached = {}
22
+
23
+ def user(id)
24
+ user = Cached[id]
25
+ return user if user
26
+
27
+ if id
28
+ user = users.detect{|u| u[:id] == id}
29
+ unless user
30
+ user_data = connection.get("/users/#{ id }.json")
31
+ user = user_data && user_data['user']
32
+ end
33
+ user['created_at'] = Time.parse(user['created_at'])
34
+ Cached[id] = user
35
+ end
36
+ end
37
+ end
38
+
39
+ module StreamExtension
40
+ def stream
41
+ @stream ||= (
42
+ room = self
43
+ Twitter::JSONStream.connect(
44
+ :path => "/room/#{ room.id }/live.json",
45
+ :host => 'streaming.campfirenow.com',
46
+ :auth => "#{ connection.token }:x"
47
+ )
48
+ )
49
+ end
50
+
51
+ def streaming(&block)
52
+ steam.instance_eval(&block)
53
+ end
54
+ end
55
+
56
+ def Campfire.new(*args, &block)
57
+ allocate.tap do |instance|
58
+ instance.send(:initialize, *args, &block)
59
+ end
60
+ end
61
+
62
+ def room_for(name)
63
+ name = name.to_s
64
+ room = rooms.detect{|_| _.name == name}
65
+ room.extend(SearchExtension)
66
+ room.extend(UserExtension)
67
+ room.extend(StreamExtension)
68
+ room
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,144 @@
1
+ module FBomb
2
+ ## class_methods
3
+ #
4
+ class Command
5
+ class Table < ::Map
6
+ def help
7
+ map = Map.new
8
+ each do |path, command|
9
+ map[path] = command.description
10
+ end
11
+ map
12
+ end
13
+ end
14
+
15
+ class << Command
16
+ fattr(:table){ Table.new }
17
+ fattr(:dir){ File.join(File.expand_path(File.dirname(__FILE__)), 'commands') }
18
+ fattr(:room)
19
+
20
+ def load(*args)
21
+ args.flatten.uniq.each do |arg|
22
+ case arg.to_s
23
+ when %r|^/|
24
+ load_absolute_path(arg)
25
+ when %r|://|
26
+ load_uri(arg)
27
+ else
28
+ load_relative_path(arg)
29
+ end
30
+ end
31
+ setup
32
+ table
33
+ end
34
+
35
+ def commands
36
+ table.values
37
+ end
38
+
39
+ def setup
40
+ commands.each do |command|
41
+ if command.setup and command.setup.respond_to?(:call)
42
+ command.setup.call()
43
+ command.setup = true
44
+ end
45
+ end
46
+ end
47
+
48
+ def load_uri(arg)
49
+ uri = arg.to_s
50
+ open(uri) do |fd|
51
+ open(path){|fd| load_string(fd.read)}
52
+ end
53
+ end
54
+
55
+ def load_relative_path(arg)
56
+ basename = arg.to_s
57
+ basename += '.rb' unless basename =~ /\.rb\Z/
58
+ load_absolute_path(File.join(Command.dir, basename))
59
+ end
60
+
61
+ def load_absolute_path(arg)
62
+ path = File.expand_path(arg.to_s)
63
+ path += '.rb' unless path =~ /\.rb\Z/
64
+ open(path){|fd| load_string(fd.read)}
65
+ end
66
+
67
+ def load_string(string, dangerous = true)
68
+ Thread.new(string, dangerous) do |string, dangerous|
69
+ Thread.current.abort_on_exception = true
70
+ $SAFE = 12 unless dangerous
71
+ Kernel.eval(string)
72
+ end.value
73
+ end
74
+ end
75
+
76
+ ## instance methods
77
+ #
78
+ fattr(:room){ self.class.room }
79
+ fattr(:path)
80
+ fattr(:help)
81
+ fattr(:setup)
82
+
83
+ def initialize
84
+ @call = proc{}
85
+ end
86
+
87
+ def call(*args, &block)
88
+ block ? @call=call : instance_exec(*args, &@call)
89
+ end
90
+
91
+ def call=(call)
92
+ @call = call
93
+ end
94
+
95
+ %w( speak paste ).each do |method|
96
+ module_eval <<-__, __FILE__, __LINE__
97
+ def #{ method }(*args, &block)
98
+ room ? room.#{ method }(*args, &block) : puts(*args, &block)
99
+ end
100
+ __
101
+ end
102
+
103
+ ## dsl
104
+ #
105
+ class DSL
106
+ instance_methods.each{|m| undef_method(m) unless m.to_s =~ /(^__)|object_id/}
107
+
108
+ def DSL.evaluate(*args, &block)
109
+ dsl = new
110
+ dsl.evaluate(*args, &block)
111
+ dsl
112
+ end
113
+
114
+ def initialize
115
+ @commands = Command.table
116
+ end
117
+
118
+ def evaluate(*args, &block)
119
+ Object.instance_method(:instance_eval).bind(self).call(&block)
120
+ end
121
+
122
+ def command(*args, &block)
123
+ return @command if(args.empty? and block.nil?)
124
+ @command = Command.new
125
+ @command.path = Util.absolute_path_for(args.shift)
126
+ @commands[@command.path] ||= @command
127
+ evaluate(&block)
128
+ end
129
+ alias_method('Command', 'command')
130
+
131
+ def help(*args)
132
+ @command.help = args.join("\n")
133
+ end
134
+
135
+ def setup(&block)
136
+ @command.setup = block
137
+ end
138
+
139
+ def call(&block)
140
+ @command.call = block
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,90 @@
1
+ FBomb {
2
+
3
+ ##
4
+ #
5
+ command(:rhymeswith) {
6
+ help 'show ryhming words'
7
+
8
+ setup{ require 'cgi' }
9
+
10
+ call do |*args|
11
+ args.each do |arg|
12
+ word = CGI.escape(arg.strip)
13
+ url = "http://www.zachblume.com/apis/rhyme.php?format=xml&word=#{ word }"
14
+ data = `curl --silent #{ url.inspect }`
15
+ words = data.scan(%r|<word>([^<]*)</word>|).flatten
16
+ msg = words.join(" ")
17
+ speak(msg)
18
+ end
19
+ end
20
+ }
21
+
22
+ ##
23
+ #
24
+ command(:chucknorris) {
25
+ call do |*args|
26
+ data = JSON.parse(`curl --silent 'http://api.icndb.com/jokes/random'`)
27
+ msg = data['value']['joke']
28
+ speak(msg) unless msg.strip.empty?
29
+ end
30
+ }
31
+
32
+ ##
33
+ #
34
+ command(:fukung) {
35
+ call do |*args|
36
+ tags = args.join(' ').strip.downcase
37
+ msg = Fukung.tag(tags).sort_by{ rand }.first(3).join("\n")
38
+ speak(msg) unless msg.strip.empty?
39
+ end
40
+ }
41
+
42
+ ##
43
+ #
44
+ command(:google) {
45
+ setup{ require "google-search" }
46
+
47
+ call do |*args|
48
+ type = args.first
49
+ msg = ""
50
+ case type
51
+ when /image|img|i/i
52
+ args.shift
53
+ query = args.join(' ')
54
+ Google::Search::Image.new(:query => query, :image_size => :icon).each do |result|
55
+ msg << "#{ result.uri }\n"
56
+ end
57
+ else
58
+ query = args.join(' ')
59
+ Google::Search::Web.new(:query => query).each do |result|
60
+ msg << "#{ result.uri }\n"
61
+ end
62
+ end
63
+ speak(msg) unless msg.empty?
64
+ end
65
+ }
66
+
67
+ ##
68
+ #
69
+ command(:gist) {
70
+ call do |*args|
71
+ url = args.join(' ').strip
72
+
73
+ id = url.scan(/\d+/).first
74
+ gist_url = "https://gist.github.com/#{ id }"
75
+ speak(gist_url)
76
+
77
+ gist_html = `curl --silent #{ gist_url.inspect }`
78
+ re = %r| <a\s+href\s*=\s*" (/raw[^">]+) "\s*>\s*raw\s*</a> |iox
79
+ match, raw_path = re.match(gist_html).to_a
80
+
81
+ if match
82
+ raw_url = "https://gist.github.com#{ raw_path }"
83
+ raw_html = `curl --silent --location #{ raw_url.inspect }`
84
+ paste(raw_html)
85
+ end
86
+ end
87
+ }
88
+
89
+ }
90
+
@@ -0,0 +1,28 @@
1
+ FBomb {
2
+ command(:help) {
3
+ call do |*args|
4
+ sections = []
5
+ Command.table.each do |path, command|
6
+ next if path == '/help'
7
+ help = command.help || path
8
+ chunk = [path, Util.indent(help) + "\n"]
9
+ sections.push(chunk)
10
+ end
11
+ sections.sort!{|a, b| a.first <=> b.first}
12
+ sections.push(["/help", Util.indent("this message") + "\n"])
13
+ msg = sections.join("\n")
14
+ paste(msg) unless msg.strip.empty?
15
+ end
16
+ }
17
+
18
+ command(:fbomb) {
19
+ call {
20
+ urls = %w(
21
+ http://s3.amazonaws.com/drawohara.com.mp3/tom_jones_sex_bomb_dance_remix.mp3
22
+ http://4.bp.blogspot.com/-K7nKv-g9WyQ/Thb7Jqw-YoI/AAAAAAAABeo/e0AWFySD_GY/s1600/Tom+Jones+2.jpg
23
+ http://www.fitceleb.com/files/tom_jones.jpg
24
+ )
25
+ speak(urls.sort_by{ rand }.first)
26
+ }
27
+ }
28
+ }
data/lib/fbomb/util.rb ADDED
@@ -0,0 +1,93 @@
1
+ module Util
2
+ def paths_for(*args)
3
+ path = args.flatten.compact.join('/')
4
+ path.gsub!(%r|[.]+/|, '/')
5
+ path.squeeze!('/')
6
+ path.sub!(%r|^/|, '')
7
+ path.sub!(%r|/$|, '')
8
+ paths = path.split('/')
9
+ end
10
+
11
+ def absolute_path_for(*args)
12
+ ('/' + paths_for(*args).join('/')).squeeze('/')
13
+ end
14
+
15
+ def absolute_prefix_for(*args)
16
+ absolute_path_for(*args) + '/'
17
+ end
18
+
19
+ def path_for(*args)
20
+ paths_for(*args).join('/').squeeze('/')
21
+ end
22
+
23
+ def prefix_for(*args)
24
+ path_for(*args) + '/'
25
+ end
26
+
27
+ def normalize_path(arg, *args)
28
+ absolute_path_for(arg, *args)
29
+ end
30
+
31
+ def indent(chunk, n = 2)
32
+ lines = chunk.split %r/\n/
33
+ re = nil
34
+ s = ' ' * n
35
+ lines.map! do |line|
36
+ unless re
37
+ margin = line[%r/^\s*/]
38
+ re = %r/^#{ margin }/
39
+ end
40
+ line.gsub re, s
41
+ end.join("\n")
42
+ end
43
+
44
+ def unindent(chunk)
45
+ lines = chunk.split %r/\n/
46
+ indent = nil
47
+ re = %r/^/
48
+ lines.map! do |line|
49
+ unless indent
50
+ indent = line[%r/^\s*/]
51
+ re = %r/^#{ indent }/
52
+ end
53
+ line.gsub re, ''
54
+ end.join("\n")
55
+ end
56
+
57
+ def columnize(buf, opts = {})
58
+ width = Util.getopt 'width', opts, 80
59
+ indent = Util.getopt 'indent', opts
60
+ indent = Fixnum === indent ? (' ' * indent) : "#{ indent }"
61
+ column = []
62
+ words = buf.split %r/\s+/o
63
+ row = "#{ indent }"
64
+ while((word = words.shift))
65
+ if((row.size + word.size) < (width - 1))
66
+ row << word
67
+ else
68
+ column << row
69
+ row = "#{ indent }"
70
+ row << word
71
+ end
72
+ row << ' ' unless row.size == (width - 1)
73
+ end
74
+ column << row unless row.strip.empty?
75
+ column.join "\n"
76
+ end
77
+
78
+ def getopt(opt, hash, default = nil)
79
+ keys = opt.respond_to?('each') ? opt : [opt]
80
+
81
+ keys.each do |key|
82
+ return hash[key] if hash.has_key? key
83
+ key = "#{ key }"
84
+ return hash[key] if hash.has_key? key
85
+ key = key.intern
86
+ return hash[key] if hash.has_key? key
87
+ end
88
+
89
+ return default
90
+ end
91
+
92
+ extend(Util)
93
+ end
data/lib/fbomb.rb ADDED
@@ -0,0 +1,86 @@
1
+ # built-ins
2
+ #
3
+ require 'thread'
4
+ require "uri"
5
+ require 'net/http'
6
+ require 'net/https'
7
+ require 'open-uri'
8
+
9
+ # libs
10
+ #
11
+ module FBomb
12
+ Version = '0.4.2' unless defined?(Version)
13
+
14
+ def version
15
+ FBomb::Version
16
+ end
17
+
18
+ def dependencies
19
+ {
20
+ 'tinder' => [ 'tinder' , '~> 1.4.3' ] ,
21
+ 'twitter/json_stream' => [ 'twitter-stream' , '~> 0.1.14' ] ,
22
+ 'yajl' => [ 'yajl-ruby' , '~> 0.8.3' ] ,
23
+ 'fukung' => [ 'fukung' , '~> 1.1.0' ] ,
24
+ 'main' => [ 'main' , '~> 4.7.6' ]
25
+ }
26
+ end
27
+
28
+ def libdir(*args, &block)
29
+ @libdir ||= File.expand_path(__FILE__).sub(/\.rb$/,'')
30
+ args.empty? ? @libdir : File.join(@libdir, *args)
31
+ ensure
32
+ if block
33
+ begin
34
+ $LOAD_PATH.unshift(@libdir)
35
+ block.call()
36
+ ensure
37
+ $LOAD_PATH.shift()
38
+ end
39
+ end
40
+ end
41
+
42
+ def load(*libs)
43
+ libs = libs.join(' ').scan(/[^\s+]+/)
44
+ FBomb.libdir{ libs.each{|lib| Kernel.load(lib) } }
45
+ end
46
+
47
+ extend(FBomb)
48
+ end
49
+
50
+ # gems
51
+ #
52
+ begin
53
+ require 'rubygems'
54
+ rescue LoadError
55
+ nil
56
+ end
57
+
58
+ if defined?(gem)
59
+ FBomb.dependencies.each do |lib, dependency|
60
+ gem(*dependency)
61
+ require(lib)
62
+ end
63
+ end
64
+
65
+ require "yajl/json_gem" ### this *replaces* any other JSON.parse !
66
+ require "yajl/http_stream" ### we really do need this
67
+
68
+ FBomb.load %w[
69
+ util.rb
70
+ campfire.rb
71
+ command.rb
72
+ ]
73
+
74
+ ## openssl - STFU!
75
+ #
76
+ class Net::HTTP
77
+ def warn(msg)
78
+ Kernel.warn(msg) unless msg == "warning: peer certificate won't be verified in this SSL session"
79
+ end
80
+ end
81
+
82
+ ## global DSL hook
83
+ #
84
+ def FBomb(*args, &block)
85
+ FBomb::Command::DSL.evaluate(*args, &block)
86
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fbomb
3
+ version: !ruby/object:Gem::Version
4
+ hash: 11
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 4
9
+ - 2
10
+ version: 0.4.2
11
+ platform: ruby
12
+ authors:
13
+ - Ara T. Howard
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-09-18 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: tinder
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 1
29
+ segments:
30
+ - 1
31
+ - 4
32
+ - 3
33
+ version: 1.4.3
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: main
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 47
45
+ segments:
46
+ - 4
47
+ - 7
48
+ - 6
49
+ version: 4.7.6
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: fukung
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 19
61
+ segments:
62
+ - 1
63
+ - 1
64
+ - 0
65
+ version: 1.1.0
66
+ type: :runtime
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: twitter-stream
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ hash: 7
77
+ segments:
78
+ - 0
79
+ - 1
80
+ - 14
81
+ version: 0.1.14
82
+ type: :runtime
83
+ version_requirements: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ name: yajl-ruby
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ~>
91
+ - !ruby/object:Gem::Version
92
+ hash: 57
93
+ segments:
94
+ - 0
95
+ - 8
96
+ - 3
97
+ version: 0.8.3
98
+ type: :runtime
99
+ version_requirements: *id005
100
+ description: "description: fbomb kicks the ass"
101
+ email: ara.t.howard@gmail.com
102
+ executables:
103
+ - fbomb
104
+ extensions: []
105
+
106
+ extra_rdoc_files: []
107
+
108
+ files:
109
+ - README
110
+ - Rakefile
111
+ - bin/fbomb
112
+ - fbomb.gemspec
113
+ - lib/fbomb.rb
114
+ - lib/fbomb/campfire.rb
115
+ - lib/fbomb/command.rb
116
+ - lib/fbomb/commands/builtin.rb
117
+ - lib/fbomb/commands/system.rb
118
+ - lib/fbomb/util.rb
119
+ homepage: https://github.com/ahoward/fbomb
120
+ licenses: []
121
+
122
+ metadata: {}
123
+
124
+ post_install_message:
125
+ rdoc_options: []
126
+
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ hash: 3
135
+ segments:
136
+ - 0
137
+ version: "0"
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ hash: 3
144
+ segments:
145
+ - 0
146
+ version: "0"
147
+ requirements: []
148
+
149
+ rubyforge_project: codeforpeople
150
+ rubygems_version: 1.8.10
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: fbomb
154
+ test_files: []
155
+