fbomb 0.4.2

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/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
+