crazydoll 0.0.1
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.md +26 -0
- data/bin/crazy_doll +12 -0
- data/lib/crazy_doll.rb +15 -0
- data/lib/crazy_doll/bot.rb +25 -0
- data/lib/crazy_doll/config.rb +131 -0
- data/lib/crazy_doll/config_backend/yaml.rb +69 -0
- data/lib/crazy_doll/core.rb +14 -0
- data/lib/crazy_doll/events.rb +49 -0
- data/lib/crazy_doll/fixes.rb +72 -0
- data/lib/crazy_doll/irc.rb +52 -0
- data/lib/crazy_doll/message.rb +102 -0
- data/lib/crazy_doll/plugin_manager.rb +286 -0
- data/lib/crazy_doll/plugins/join_plugin.rb +30 -0
- data/lib/crazy_doll/plugins/nick_plugin.rb +77 -0
- data/lib/crazy_doll/plugins/search_plugin.rb +15 -0
- data/lib/crazy_doll/plugins/show_url_info_plugin.rb +34 -0
- data/lib/crazy_doll/plugins/welcome_plugin.rb +33 -0
- data/lib/crazy_doll/welcome_plugin.rb +15 -0
- data/lib/crazy_doll/wizard.rb +45 -0
- metadata +106 -0
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# CrazyDoll
|
2
|
+
|
3
|
+
## Whats?
|
4
|
+
CrazyDoll is a simple IRC bot that aim flexibility.
|
5
|
+
With CrazyDoll you can:
|
6
|
+
|
7
|
+
* Use a different backend for config like MySQL, PostgreSQL, FireBird
|
8
|
+
or any other ruby supported backend(currently only using YAML)
|
9
|
+
* Run multiple bots on same ruby process.
|
10
|
+
* Bots do not share the plugins. You can can have join and nick plugin
|
11
|
+
to Bot A and nick and search plugin to Bot B
|
12
|
+
* Use a different IRC library
|
13
|
+
* More coming soon...
|
14
|
+
|
15
|
+
|
16
|
+
## How I install?
|
17
|
+
Only run `gem install crazydoll`
|
18
|
+
|
19
|
+
## How I use it?
|
20
|
+
Given that the path of bin folder is in your $PATH variable, only run `crazy_doll`
|
21
|
+
In first time it will run a wizard to add basic info
|
22
|
+
If you want to re-run this wizard, only delete `~/.crazy_doll/database.yaml`
|
23
|
+
|
24
|
+
## License
|
25
|
+
This project is licensed under MIT license.
|
26
|
+
See MIT-LICENSE file for more details.
|
data/bin/crazy_doll
ADDED
data/lib/crazy_doll.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
$LOAD_PATH << File.dirname(File.expand_path(__FILE__))
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'net/irc'
|
5
|
+
require 'httparty'
|
6
|
+
require 'crazy_doll/core'
|
7
|
+
require 'crazy_doll/fixes'
|
8
|
+
require 'crazy_doll/config'
|
9
|
+
require 'crazy_doll/config_backend/yaml'
|
10
|
+
require 'crazy_doll/events'
|
11
|
+
require 'crazy_doll/irc'
|
12
|
+
require 'crazy_doll/plugin_manager'
|
13
|
+
require 'crazy_doll/message'
|
14
|
+
require 'crazy_doll/bot'
|
15
|
+
require 'crazy_doll/wizard'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class CrazyDoll::Bot
|
2
|
+
|
3
|
+
|
4
|
+
attr_reader :irc, :event_manager, :plugin_manager, :config
|
5
|
+
def initialize(config=nil)
|
6
|
+
@config = config || CrazyDoll::Config.new('yaml', File.join(ENV['HOME'], '.crazy_doll','database.yaml'))
|
7
|
+
core_config = @config.config_of 'Core'
|
8
|
+
@irc = CrazyDoll::IRC.new(core_config.server, core_config.port)
|
9
|
+
@event_manager = CrazyDoll::EventManager.new(@irc)
|
10
|
+
@plugin_manager = CrazyDoll::PluginManager
|
11
|
+
@plugin_manager.load_plugins
|
12
|
+
@plugin_manager.find_usable_errors
|
13
|
+
@plugin_manager.register_plugins(@event_manager, @config)
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
@config.start_use
|
18
|
+
begin
|
19
|
+
@irc.start
|
20
|
+
ensure
|
21
|
+
@config.end_use
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module CrazyDoll::Config
|
4
|
+
|
5
|
+
def self.new(type, *args)
|
6
|
+
case type
|
7
|
+
when /yaml/i then Backend::YAML.new(*args)
|
8
|
+
else raise ArgumentError, "no config backend #{type.inspect}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.parse(owner, key, description, value)
|
13
|
+
out = setup_class(value.class) unless value.respond_to?(:crazy_doll_setuped?) and value.to_yaml('class_setuped?') == 'YES SIR !'
|
14
|
+
return value if value.crazy_doll_setuped?
|
15
|
+
value.owner = owner
|
16
|
+
value.key = key
|
17
|
+
value.description = description
|
18
|
+
value
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.setup_class(klass)
|
22
|
+
klass.class_eval do
|
23
|
+
def crazy_doll_setuped?
|
24
|
+
@owner and @key and @description ? true : false
|
25
|
+
end
|
26
|
+
|
27
|
+
alias :crazy_doll_setuped :crazy_doll_setuped?
|
28
|
+
|
29
|
+
[['owner', 'to_s'], ['key', 'to_sym'], ['description', 'to_s']].each do |name,m|
|
30
|
+
class_eval <<-EVAL
|
31
|
+
def #{name}
|
32
|
+
@#{name} || nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def #{name}=(value)
|
36
|
+
raise ArgumentError, "can't redefine #{name}" if defined?(@#{name})
|
37
|
+
@#{name} = value.#{m}
|
38
|
+
end
|
39
|
+
EVAL
|
40
|
+
end
|
41
|
+
|
42
|
+
alias :__to_yaml :to_yaml
|
43
|
+
|
44
|
+
def _to_yaml(opts = {})
|
45
|
+
return __to_yaml(opts) unless crazy_doll_setuped?
|
46
|
+
a, b, c = @owner, @key, @description
|
47
|
+
['@owner', '@key', '@description'].each { |x| remove_instance_variable(x) }
|
48
|
+
begin
|
49
|
+
return __to_yaml(opts)
|
50
|
+
ensure
|
51
|
+
@owner, @key, @description = a, b, c
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_yaml( opts = {} )
|
56
|
+
return 'YES SIR !' if opts == 'class_setuped?'
|
57
|
+
return _to_yaml(opts) unless crazy_doll_setuped?
|
58
|
+
YAML.quick_emit( self.object_id, opts ) do |out|
|
59
|
+
out.map( "tag:crazydoll.org,2010:ConfigVar", "crazydoll.org,2010/ConfigVar" ) do |map|
|
60
|
+
map.add('owner', self.owner )
|
61
|
+
map.add('key', self.key )
|
62
|
+
map.add('description', self.description)
|
63
|
+
map.add('value', self._to_yaml )
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class Instance
|
71
|
+
|
72
|
+
attr_reader :config, :owner
|
73
|
+
def initialize(owner, config={})
|
74
|
+
@config = config.empty? ? {} : config
|
75
|
+
@owner = owner
|
76
|
+
@config.keys.each { |k| create_key(k) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def register(owner, key, description, value)
|
80
|
+
k = key.to_sym
|
81
|
+
return false if @config[k]
|
82
|
+
@config[k] = CrazyDoll::Config.parse(@owner, key, description, value)
|
83
|
+
create_key(k)
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
def create_key(name)
|
88
|
+
self.instance_eval <<-EVAL
|
89
|
+
def #{name}
|
90
|
+
@config[:#{name}]
|
91
|
+
end
|
92
|
+
|
93
|
+
def #{name}=(val)
|
94
|
+
c = @config[:#{name}]
|
95
|
+
key = c.key
|
96
|
+
desc = c.description
|
97
|
+
@config[:#{name}] = CrazyDoll::Config.parse(@owner, key, desc, val)
|
98
|
+
end
|
99
|
+
EVAL
|
100
|
+
end
|
101
|
+
|
102
|
+
def method_missing(name, *args, &block)
|
103
|
+
if name.to_s.match(/=$/) and args.size == 1
|
104
|
+
key = name.to_s.gsub(/=$/,'').to_sym
|
105
|
+
puts "!!! key #{key} missing, but creating !!!"
|
106
|
+
@config[key] = CrazyDoll::Config.parse(@owner, key, 'created by method_missing', args[0])
|
107
|
+
create_key(key)
|
108
|
+
@config[key]
|
109
|
+
elsif name.to_s.match(/\?$/) and self.respond_to?((k=name.to_s.gsub(/\?$/,'')))
|
110
|
+
puts "!!! method #{name} missing, creating it !!!"
|
111
|
+
self.instance_eval <<-EVAL
|
112
|
+
def #{name}
|
113
|
+
@config[:#{k}]
|
114
|
+
end
|
115
|
+
EVAL
|
116
|
+
send(name)
|
117
|
+
else
|
118
|
+
puts "!!! method #{name} missing !!!"
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
CrazyDoll::Config.setup_class(Object)
|
128
|
+
|
129
|
+
YAML.add_domain_type('crazydoll.org,2010', 'ConfigVar') do |type,val|
|
130
|
+
CrazyDoll::Config.parse(val['owner'], val['key'], val['description'], YAML.load(val['value']))
|
131
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module CrazyDoll::Config::Backend
|
5
|
+
|
6
|
+
class YAML
|
7
|
+
|
8
|
+
attr_reader :instances
|
9
|
+
def initialize(file)
|
10
|
+
@file = file
|
11
|
+
self.load
|
12
|
+
end
|
13
|
+
|
14
|
+
def start_use
|
15
|
+
@thread = Thread.new(self) do |b|
|
16
|
+
loop do
|
17
|
+
sleep 60
|
18
|
+
b.save
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def end_use
|
24
|
+
@thread.kill if @thread and @thread.alive?
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup_table_if_needed
|
28
|
+
FileUtis.mkdir_p(File.dirname(@file)) unless FileTest.directory?(File.dirname(@file))
|
29
|
+
File.open(@file, "w+") { |f| f.write(::YAML.dump({})) } unless FileTest.file?(@file)
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_instances(data=nil)
|
33
|
+
return false unless data.is_a?(Hash)
|
34
|
+
@instances ||= {}
|
35
|
+
keys = data.keys
|
36
|
+
keys.each do |k|
|
37
|
+
key = real_key(k)
|
38
|
+
@instances[key] = CrazyDoll::Config::Instance.new(key, data[k])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def load
|
43
|
+
setup_table_if_needed
|
44
|
+
create_instances(::YAML.load_file(@file))
|
45
|
+
end
|
46
|
+
|
47
|
+
def save
|
48
|
+
setup_table_if_needed
|
49
|
+
d = {}
|
50
|
+
@instances.each { |k,v| d[k] = v.config }
|
51
|
+
File.open(@file, 'w+') { |f| f.write(::YAML.dump(d)) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def config_of(key)
|
55
|
+
key = real_key(key)
|
56
|
+
@instances[key] ||= CrazyDoll::Config::Instance.new(key, {})
|
57
|
+
end
|
58
|
+
|
59
|
+
def real_key(k)
|
60
|
+
[String, Symbol].include?(k.class) ? k.to_s : k.class.to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
def [](key)
|
64
|
+
@instances[key]
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module CrazyDoll
|
2
|
+
|
3
|
+
VERSION = '0.0.1'.freeze
|
4
|
+
|
5
|
+
def self.init
|
6
|
+
config_file = File.join(ENV['HOME'], '.crazy_doll', 'database.yaml')
|
7
|
+
config_instance = CrazyDoll::Config.new('yaml', config_file)
|
8
|
+
config = config_instance.config_of 'Core'
|
9
|
+
CrazyDoll::Wizard.new(config)
|
10
|
+
config_instance.save
|
11
|
+
CrazyDoll::Bot.new(config_instance).start
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class CrazyDoll::Event
|
2
|
+
|
3
|
+
attr_reader :klass, :real_method_name, :method_name
|
4
|
+
def initialize(klass, opts = {})
|
5
|
+
@klass = klass
|
6
|
+
verify(opts)
|
7
|
+
@real_method_name, @method_name = opts[:real_method_name], opts[:method_name]
|
8
|
+
end
|
9
|
+
|
10
|
+
def verify(opts)
|
11
|
+
errors = []
|
12
|
+
errors << 'need a real method name' unless @klass.respond_to?(opts[:real_method_name])
|
13
|
+
errors << 'need a method name' unless opts[:method_name]
|
14
|
+
return true if errors.empty?
|
15
|
+
raise ArgumentError, errors.join(', ')
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(opts, line='')
|
19
|
+
@klass.opts = opts
|
20
|
+
@klass.line = line
|
21
|
+
@klass.send(@real_method_name) rescue nil
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class CrazyDoll::EventManager
|
27
|
+
|
28
|
+
attr_reader :irc, :events, :config
|
29
|
+
def initialize(irc)
|
30
|
+
@irc = irc
|
31
|
+
@irc.event_manager = self
|
32
|
+
@events = { :sys => {}, :get => {}, :put => {} }
|
33
|
+
end
|
34
|
+
|
35
|
+
def fire(type, name, opts = {}, line = '')
|
36
|
+
type, name = type.to_sym, name.to_sym
|
37
|
+
return false unless [:sys, :get, :put].include?(type)
|
38
|
+
@events[type][name] ||= []
|
39
|
+
@events[type][name].each { |x| x.call(opts, line) }
|
40
|
+
fire(type, :command_message, opts, line) if opts.is_a?(CrazyDoll::Message) and opts.command == 'PRIVMSG' and name != :command_message
|
41
|
+
end
|
42
|
+
|
43
|
+
def register(type, klass, opts)
|
44
|
+
type, name = type.to_sym, opts[:method_name].to_sym
|
45
|
+
@events[type][name] ||= []
|
46
|
+
@events[type][name] << CrazyDoll::Event.new(klass, opts)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
def +(other_hash)
|
4
|
+
raise ArgumentError, 'hash + hash only' unless other_hash.class == Hash
|
5
|
+
new_hash = self.clone
|
6
|
+
for key in other_hash.keys
|
7
|
+
new_hash[key] = other_hash[key]
|
8
|
+
end
|
9
|
+
return new_hash
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
module YAML
|
15
|
+
|
16
|
+
def load_file(f)
|
17
|
+
return false unless FileTest.file?(f)
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
class String
|
24
|
+
|
25
|
+
def to_crazy_doll_regexp
|
26
|
+
x=(' ' << self).gsub(/([^\\])::(\S+)/, '\1(\S+)').gsub(/([^\\])\*\*(\S+)/, '\1(.*)').gsub(/#{0.chr}[^#{1.chr}]+#{1.chr}([^#{2.chr}]+)#{2.chr}/, '\1')
|
27
|
+
x[0] = ''
|
28
|
+
Regexp.new("^#{x}$")
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class MatchData
|
34
|
+
|
35
|
+
def to_crazy_doll_params(line)
|
36
|
+
out = {}
|
37
|
+
params = (' ' << line).scan(/[^\\](::|\*\*)(\S+)|#{0.chr}([^#{1.chr}]+)#{1.chr}[^#{2.chr}]+#{2.chr}/).flatten.
|
38
|
+
map { |x| ['::', '**'].include?(x) ? nil : x }.compact
|
39
|
+
params.each_with_index do |key,idx|
|
40
|
+
out[key.to_sym] = self[idx+1]
|
41
|
+
end
|
42
|
+
OpenStruct.new(out)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
Numeric.class_eval do
|
48
|
+
HUMAN_SIZES = [
|
49
|
+
[1024.0, 'K'],
|
50
|
+
[1048576.0, 'M'],
|
51
|
+
[1073741824.0, 'G'],
|
52
|
+
[1099511627776.0, 'P']
|
53
|
+
]
|
54
|
+
|
55
|
+
def to_human_readable_size
|
56
|
+
return self if self < HUMAN_SIZES[0][0]
|
57
|
+
fsize, fletter = nil, nil
|
58
|
+
|
59
|
+
for size, letter in HUMAN_SIZES
|
60
|
+
t = self/size
|
61
|
+
if t <= 1024
|
62
|
+
fsize, fletter = size, letter
|
63
|
+
break
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
fsize, fletter = HUMAN_SIZES.last if fsize.nil?
|
68
|
+
|
69
|
+
return "%.03f %s" % [self/fsize, fletter]
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class CrazyDoll::IRC < Net::IRC::Client
|
2
|
+
|
3
|
+
attr_accessor :event_manager
|
4
|
+
|
5
|
+
def start
|
6
|
+
# reset config
|
7
|
+
@server_config = Message::ServerConfig.new
|
8
|
+
@socket = TCPSocket.open(@host, @port)
|
9
|
+
@event_manager.fire(:sys, :socket_start)
|
10
|
+
while l = @socket.gets
|
11
|
+
begin
|
12
|
+
@log.debug "RECEIVE: #{l.chomp}"
|
13
|
+
m = Message.parse(l)
|
14
|
+
name = real_name((COMMANDS[m.command.upcase] || m.command).downcase, m)
|
15
|
+
@log.debug "TYPE: get_#{name}"
|
16
|
+
@event_manager.fire(:get, name, CrazyDoll::Message.parse(l.chomp), l.chomp)
|
17
|
+
#next if on_message(m) === true
|
18
|
+
#name = "on_#{(COMMANDS[m.command.upcase] || m.command).downcase}"
|
19
|
+
#send(name, m) if respond_to?(name)
|
20
|
+
rescue Exception => e
|
21
|
+
warn e
|
22
|
+
warn e.backtrace.join("\r\t")
|
23
|
+
raise
|
24
|
+
rescue Message::InvalidMessage
|
25
|
+
@log.error "MessageParse: " + l.inspect
|
26
|
+
end
|
27
|
+
end
|
28
|
+
rescue IOError
|
29
|
+
ensure
|
30
|
+
finish
|
31
|
+
end
|
32
|
+
|
33
|
+
public :post
|
34
|
+
|
35
|
+
def finish
|
36
|
+
super
|
37
|
+
@event_manager.fire(:sys, :socket_stop)
|
38
|
+
end
|
39
|
+
|
40
|
+
def real_name(n,m)
|
41
|
+
$msg = [n, m]
|
42
|
+
o = if n == 'privmsg'
|
43
|
+
if m[0][0].chr == '#'
|
44
|
+
'chanmsg'
|
45
|
+
elsif m[1] == "\x01VERSION \x01"
|
46
|
+
'version'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
o.nil? ? n : o
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
class CrazyDoll::Message < OpenStruct
|
2
|
+
|
3
|
+
def self.parse_from(args)
|
4
|
+
return '' if args.nil?
|
5
|
+
if args.class == MatchData
|
6
|
+
new({ :nick => args[1], :user => args[2], :host => args[3] })
|
7
|
+
else
|
8
|
+
new({ :nick => args[0], :user => args[1], :host => args[2] })
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def self.parse(line)
|
14
|
+
|
15
|
+
new case line
|
16
|
+
when /\A:([^!]+)!([^@]+)@(\S+) PRIVMSG (\S+) :(.*)\z/ then
|
17
|
+
{
|
18
|
+
:from => parse_from($~),
|
19
|
+
:command => "PRIVMSG",
|
20
|
+
:to => $~[4],
|
21
|
+
:message => $~[5]
|
22
|
+
}
|
23
|
+
when /\APING :(.*)$/ then
|
24
|
+
{
|
25
|
+
:from => $~[1],
|
26
|
+
:to => $~[1],
|
27
|
+
:command => "PING"
|
28
|
+
}
|
29
|
+
when /\A:([^!]+)!([^@]+)@(\S+) NOTICE (\S+) :(.*)\z/ then
|
30
|
+
{
|
31
|
+
:from => parse_from($~),
|
32
|
+
:to => $~[4],
|
33
|
+
:message => $~[5],
|
34
|
+
:command => "NOTICE"
|
35
|
+
}
|
36
|
+
when /\A:([^!]+)!([^@]+)@(\S+) JOIN :(.*)\z/ then
|
37
|
+
{
|
38
|
+
:from => parse_from($~),
|
39
|
+
:user => $~[1],
|
40
|
+
:channel => $~[4],
|
41
|
+
:command => "JOIN"
|
42
|
+
}
|
43
|
+
when /\A:(\S+) 353 (\S+) = (\S+) :(.*)\z/ then
|
44
|
+
{
|
45
|
+
:from => $~[1],
|
46
|
+
:me => $~[2],
|
47
|
+
:channel => $~[3],
|
48
|
+
:users => $~[4].split(" "),
|
49
|
+
:command => 353
|
50
|
+
}
|
51
|
+
when /\A:([^!]+)!([^@]+)@(\S+) NICK :(.*)\z/ then
|
52
|
+
{
|
53
|
+
:from => parse_from($~),
|
54
|
+
:command => "NICK",
|
55
|
+
:new_nick => $~[4]
|
56
|
+
}
|
57
|
+
when /\A:([^!]+)!([^@]+)@(\S+) (\S+) (\S+) :(.*)\z/ then
|
58
|
+
{
|
59
|
+
:from => parse_from($~),
|
60
|
+
:command => $~[4],
|
61
|
+
:to => $~[5],
|
62
|
+
:message => $~[6]
|
63
|
+
}
|
64
|
+
when /\A:([^!]+)!([^@]+)@(\S+) (\S+) :(.*)\z/ then
|
65
|
+
{
|
66
|
+
:from => parse_from($~),
|
67
|
+
:command => $~[4],
|
68
|
+
:to => $~[1],
|
69
|
+
:message => $~[5]
|
70
|
+
}
|
71
|
+
when /\A:(\S+) (\S+) (\S+) (\S+) :(.*)\z/ then
|
72
|
+
{
|
73
|
+
:from => $~[1],
|
74
|
+
:command => $~[2],
|
75
|
+
:to => $~[3],
|
76
|
+
:extra => $~[4],
|
77
|
+
:message => $~[5]
|
78
|
+
}
|
79
|
+
when /\A:(\S+) (\S+) (\S+) :(.*)\z/
|
80
|
+
{
|
81
|
+
:from => $~[1],
|
82
|
+
:command => $~[2],
|
83
|
+
:to => $~[3],
|
84
|
+
:message => $~[4]
|
85
|
+
}
|
86
|
+
when /\A:(\S+) (\S+) (\S+) ([^:]+) :(.*)\z/ then
|
87
|
+
{
|
88
|
+
:from => $~[1],
|
89
|
+
:command => $~[2],
|
90
|
+
:to => $~[3],
|
91
|
+
:extras => $~[4].split(' '),
|
92
|
+
:message => $~[5]
|
93
|
+
}
|
94
|
+
else
|
95
|
+
{
|
96
|
+
:extras => line.split(' ')
|
97
|
+
}
|
98
|
+
end.update({ :source => line })
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,286 @@
|
|
1
|
+
module CrazyDoll::PluginManager
|
2
|
+
|
3
|
+
@path =
|
4
|
+
[
|
5
|
+
File.join(ENV['HOME'], '.crazy_doll', 'plugins'),
|
6
|
+
File.join(File.expand_path(File.dirname(__FILE__)), 'plugins')
|
7
|
+
]
|
8
|
+
@plugins = { :success => {}, :error => {}, :not_usable => {} }
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def path
|
13
|
+
@path
|
14
|
+
end
|
15
|
+
|
16
|
+
def plugins
|
17
|
+
@plugins
|
18
|
+
end
|
19
|
+
|
20
|
+
def register_plugins(event_manager, config, plugins=:all)
|
21
|
+
plugins = @plugins[:success].map { |k,v| k.to_sym } if plugins == :all
|
22
|
+
registered = []
|
23
|
+
for plugin in plugins
|
24
|
+
if @plugins[:success][plugin]
|
25
|
+
@plugins[:success][plugin][:class].new(event_manager, config)
|
26
|
+
registered << plugin
|
27
|
+
end
|
28
|
+
end
|
29
|
+
registered
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_plugins
|
33
|
+
for path in @path
|
34
|
+
next unless FileTest.directory?(path)
|
35
|
+
for e in Dir.entries(path) - ['.','..']
|
36
|
+
entrie = File.join(path, e)
|
37
|
+
if entrie.match(/_plugin(\.rb)?$/)
|
38
|
+
if FileTest.file?(entrie)
|
39
|
+
load_plugin(entrie)
|
40
|
+
elsif FileTest.directory?(entrie) and FileTest.file?(File.join(entrie, 'plugin.rb'))
|
41
|
+
load_plugin(File.join(entrie, 'plugin.rb'), File.basename(entrie))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def unload_plugins
|
49
|
+
for plugin,info in @plugins[:success]
|
50
|
+
unload_plugin(plugin)
|
51
|
+
end
|
52
|
+
@plugins = { :success => {}, :error => {} }
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
|
56
|
+
def reload_plugins
|
57
|
+
unload_plugins
|
58
|
+
load_plugins
|
59
|
+
end
|
60
|
+
|
61
|
+
def unload_plugin(name)
|
62
|
+
Object.send(:remove_const, name) rescue false
|
63
|
+
end
|
64
|
+
|
65
|
+
def load_plugin(path, file_name=nil)
|
66
|
+
file_name ||= File.basename(path)
|
67
|
+
name = file_name.gsub(/\.rb$/,'').split('_').map { |x| x.capitalize }.join
|
68
|
+
begin
|
69
|
+
load path
|
70
|
+
klass = eval(name)
|
71
|
+
@plugins[:success][name.to_sym] = { :path => path, :class => klass }
|
72
|
+
rescue => e
|
73
|
+
@plugins[:error][name.to_sym] = { :path => path, :error => e }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def find_usable_errors
|
78
|
+
for name, opts in @plugins[:success]
|
79
|
+
config = opts[:class].config
|
80
|
+
_plugins = config.plugins
|
81
|
+
_gems = config.gems
|
82
|
+
p = problem_with_plugins?(_plugins)
|
83
|
+
g = problem_with_gems?(_gems)
|
84
|
+
next if p == false and g == false
|
85
|
+
plugin_failed(name, p, g)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def problem_with_plugins?(plugins)
|
90
|
+
return false
|
91
|
+
# errors = []
|
92
|
+
# for plugin in plugins
|
93
|
+
# end
|
94
|
+
end
|
95
|
+
|
96
|
+
def problem_with_gems?(gems)
|
97
|
+
errors = {}
|
98
|
+
for g,opts in gems
|
99
|
+
begin
|
100
|
+
gem g.to_s, opts[:version] || '>= 0'
|
101
|
+
require opts[:lib] || g.to_s
|
102
|
+
rescue Gem::LoadError => e
|
103
|
+
errors[g] = e
|
104
|
+
end
|
105
|
+
end
|
106
|
+
return false if errors.empty?
|
107
|
+
errors
|
108
|
+
end
|
109
|
+
|
110
|
+
def plugin_failed(name, p, g)
|
111
|
+
@plugins[:not_usable][name] = @plugins[:success].delete(name).update({:plugins => p, :gems => g })
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
class Config
|
117
|
+
|
118
|
+
attr_reader :gems, :plugins, :keys, :custom_messages
|
119
|
+
def initialize(klass)
|
120
|
+
@klass = klass
|
121
|
+
@gems, @plugins, @keys, @custom_messages = {}, {}, {}, []
|
122
|
+
end
|
123
|
+
|
124
|
+
def gem(name, opts = {})
|
125
|
+
@gems[name.to_sym] = opts
|
126
|
+
end
|
127
|
+
|
128
|
+
def plugin(name, opts = {})
|
129
|
+
@plugins[name.to_sym] = opts
|
130
|
+
end
|
131
|
+
|
132
|
+
def key(name, value, description='')
|
133
|
+
@keys[name.to_sym] = [description, value]
|
134
|
+
end
|
135
|
+
|
136
|
+
def register(name, line, method, where=[:chan, :priv], regexp=nil)
|
137
|
+
line = '' unless line.is_a?(String)
|
138
|
+
line = "#{name}#{line.empty? ? '' : ' ' + line}"
|
139
|
+
@custom_messages << [regexp || line.to_crazy_doll_regexp, line, method, [where].flatten]
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
class CrazyDoll::Plugin
|
147
|
+
|
148
|
+
include Net::IRC::Constants
|
149
|
+
|
150
|
+
attr_accessor :opts, :line
|
151
|
+
attr_reader :params
|
152
|
+
def initialize(manager, config)
|
153
|
+
@manager = manager
|
154
|
+
@irc = manager.irc
|
155
|
+
@my_config = config.config_of self.class.to_s
|
156
|
+
@master_config = config.config_of 'Core'
|
157
|
+
@config = config
|
158
|
+
@opts, @line, @params = {}, '', {}
|
159
|
+
register_keys
|
160
|
+
register_events
|
161
|
+
init if respond_to?(:init)
|
162
|
+
end
|
163
|
+
|
164
|
+
def register_events
|
165
|
+
for method in methods.grep(/^(sys|get|put)_/)
|
166
|
+
type, name = method.split('_', 2)
|
167
|
+
@manager.register(type, self, { :method_name => name, :real_method_name => method })
|
168
|
+
end
|
169
|
+
@manager.register(:get, self, { :method_name => :chanmsg, :real_method_name => :custom_messages_chan })
|
170
|
+
@manager.register(:get, self, { :method_name => :privmsg, :real_method_name => :custom_messages_priv })
|
171
|
+
end
|
172
|
+
|
173
|
+
def register_keys
|
174
|
+
for key,opts in self.class.config.keys
|
175
|
+
c.register(self, key, opts[0], opts[1])
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def custom_messages(prefix='!', type=:priv)
|
180
|
+
reg = Regexp.new("^#{prefix}")
|
181
|
+
return unless opts.message =~ reg
|
182
|
+
message = opts.message.gsub(reg, '')
|
183
|
+
|
184
|
+
for regexp, original_line, method, where in self.class.config.custom_messages
|
185
|
+
if where.include?(type) and message =~ regexp
|
186
|
+
@params = $~.to_crazy_doll_params(original_line)
|
187
|
+
send(method)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def custom_messages_chan
|
193
|
+
custom_messages('!', :chan)
|
194
|
+
end
|
195
|
+
|
196
|
+
def custom_messages_priv
|
197
|
+
custom_messages('', :priv)
|
198
|
+
end
|
199
|
+
|
200
|
+
def post(*args)
|
201
|
+
@irc.post(*args)
|
202
|
+
end
|
203
|
+
|
204
|
+
def config
|
205
|
+
@master_config
|
206
|
+
end
|
207
|
+
|
208
|
+
def c
|
209
|
+
@my_config
|
210
|
+
end
|
211
|
+
|
212
|
+
def current_nick
|
213
|
+
config.nick.name
|
214
|
+
end
|
215
|
+
|
216
|
+
def reply_to
|
217
|
+
case opts.command
|
218
|
+
when 'PRIVMSG' then opts.to.match(/^#/) ? opts.to : opts.from.nick
|
219
|
+
when 'JOIN' then opts.from.nick
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def current_channel
|
224
|
+
if opts.respond_to?(:channel)
|
225
|
+
opts.channel
|
226
|
+
elsif opts.respond_to?(:to) and opts.to =~ /^#/
|
227
|
+
opts.to
|
228
|
+
else
|
229
|
+
raise ArgumentError, "opts don't respond to :channel and :to isn't a channel"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def join(chan, pass=nil)
|
234
|
+
post JOIN, chan, pass
|
235
|
+
end
|
236
|
+
|
237
|
+
def say(to, message)
|
238
|
+
post PRIVMSG, to, message
|
239
|
+
end
|
240
|
+
|
241
|
+
def reply(message, with_nick=true)
|
242
|
+
message = parse_message(message)
|
243
|
+
case opts.command
|
244
|
+
when 'PRIVMSG' then say reply_to, message
|
245
|
+
when 'JOIN' then say current_channel, message
|
246
|
+
else
|
247
|
+
p opts
|
248
|
+
raise ArgumentError, "can't reply"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def get(url)
|
253
|
+
HTTParty.get(url)
|
254
|
+
end
|
255
|
+
|
256
|
+
def parse_message(message)
|
257
|
+
message.
|
258
|
+
gsub('{{me}}', current_nick).
|
259
|
+
gsub('{{to}}', reply_to).
|
260
|
+
gsub('{{channel}}', reply_to_a_channel? ? current_channel : '')
|
261
|
+
end
|
262
|
+
|
263
|
+
def reply_to_a_channel?
|
264
|
+
(reply_to || '') =~ /^#/
|
265
|
+
end
|
266
|
+
|
267
|
+
alias :reply_to_a_channel :reply_to_a_channel?
|
268
|
+
|
269
|
+
def talked_with_me?
|
270
|
+
return false unless opts.message
|
271
|
+
opts.message.downcase.include?(current_nick.downcase)
|
272
|
+
end
|
273
|
+
|
274
|
+
alias :talked_with_me :talked_with_me?
|
275
|
+
|
276
|
+
class << self
|
277
|
+
|
278
|
+
def config(&block)
|
279
|
+
@config ||= CrazyDoll::PluginManager::Config.new(self)
|
280
|
+
return @config unless block_given?
|
281
|
+
block.call(@config)
|
282
|
+
end
|
283
|
+
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class JoinPlugin < CrazyDoll::Plugin
|
2
|
+
|
3
|
+
config do |c|
|
4
|
+
c.key :channels, [], 'Channels'
|
5
|
+
c.register 'join', '::channel', :join_channel
|
6
|
+
end
|
7
|
+
|
8
|
+
def init
|
9
|
+
c.channels = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def join_all
|
13
|
+
for channel,password in config.channels - c.channels
|
14
|
+
join(channel, password)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_rpl_welcome
|
19
|
+
join_all
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_join
|
23
|
+
(c.channels << opts.channel).uniq!
|
24
|
+
end
|
25
|
+
|
26
|
+
def join_channel
|
27
|
+
join(@params.channel)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
class NickPlugin < CrazyDoll::Plugin
|
2
|
+
|
3
|
+
config do |c|
|
4
|
+
c.key :nick, {}, 'Current Bot Nick'
|
5
|
+
c.key :random_nick, true, 'Using a Random Nick?'
|
6
|
+
c.key :identified, false, 'Nick are identified?'
|
7
|
+
c.register 'nick', '', :change_nick
|
8
|
+
end
|
9
|
+
|
10
|
+
def init
|
11
|
+
c.identified = false
|
12
|
+
c.random_nick = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_current_nick
|
16
|
+
if c.random_nick?
|
17
|
+
c.nick = config.nick
|
18
|
+
c.random_nick = false
|
19
|
+
else
|
20
|
+
c.nick = gen_random_nick
|
21
|
+
c.random_nick = true
|
22
|
+
end
|
23
|
+
send_nick
|
24
|
+
send_user
|
25
|
+
end
|
26
|
+
|
27
|
+
def send_nick(nick=nil)
|
28
|
+
post NICK, nick || c.nick.name
|
29
|
+
end
|
30
|
+
|
31
|
+
def send_user(user=nil, real_name=nil)
|
32
|
+
post USER, user||c.nick.user, "0", "*", real_name||c.nick.real_name
|
33
|
+
end
|
34
|
+
|
35
|
+
def gen_random_nick
|
36
|
+
letters = [*97..122].map { |x| x.chr }
|
37
|
+
OpenStruct.new({ :name => 8.times.map { letters.shuffle[0] }.join, :user => 'CrazyDoll', :real_name => 'CrazyDoll Bot' })
|
38
|
+
end
|
39
|
+
|
40
|
+
def identify(pass=nil)
|
41
|
+
say 'NickServ', "IDENTIFY #{pass||c.nick.password}" if pass or (not c.random_nick and c.nick.password)
|
42
|
+
end
|
43
|
+
|
44
|
+
def sys_socket_start
|
45
|
+
set_current_nick
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_err_unavailresource
|
49
|
+
if opts.extra == c.nick.name
|
50
|
+
set_current_nick
|
51
|
+
identify
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_rpl_welcome
|
56
|
+
identify
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_ping
|
60
|
+
post PONG, opts.from
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_nick
|
64
|
+
c.nick.name = opts.new_nick
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_version
|
68
|
+
post NOTICE, opts.from.nick, "\x01VERSION CrazyDoll IRC Bot v.#{CrazyDoll::VERSION}\x01"
|
69
|
+
end
|
70
|
+
|
71
|
+
def change_nick
|
72
|
+
return reply "I'm already using my correct nick." if current_nick == config.nick.name
|
73
|
+
set_current_nick
|
74
|
+
identify
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class SearchPlugin < CrazyDoll::Plugin
|
2
|
+
|
3
|
+
config do |c|
|
4
|
+
c.gem 'ruby-web-search'
|
5
|
+
c.key :number_of_results, 3, 'Number of results to be displayed'
|
6
|
+
c.register 'g', '**query', :google, [:chan, :priv]
|
7
|
+
end
|
8
|
+
|
9
|
+
def google
|
10
|
+
return if c.number_of_results <= 0
|
11
|
+
reply RubyWebSearch::Google.search(:query => @params.query).results[0..(c.number_of_results-1)].map { |x|
|
12
|
+
"#{CGI.unescapeHTML(x[:title])} - #{x[:url]}" }.join(" | ")
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class ShowUrlInfoPlugin < CrazyDoll::Plugin
|
2
|
+
|
3
|
+
config do |c|
|
4
|
+
c.gem 'nokogiri'
|
5
|
+
c.gem 'httparty'
|
6
|
+
c.key :show_info, true, 'Should show info of urls?'
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_privmsg
|
10
|
+
return unless c.show_info
|
11
|
+
for url in URI::extract(opts.message, ['http','https'])
|
12
|
+
reply url_info(url), false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
alias :get_chanmsg :get_privmsg
|
17
|
+
|
18
|
+
def url_info(url)
|
19
|
+
resp = HTTParty::Request.new(Net::HTTP::Head, url)
|
20
|
+
resp.perform
|
21
|
+
lr = resp.last_response
|
22
|
+
if lr['content-type'].include?('text/html')
|
23
|
+
title = (Nokogiri::HTML(get(url))/'title').text
|
24
|
+
title = 'No title' if title.empty?
|
25
|
+
"[Site] #{title}"
|
26
|
+
else
|
27
|
+
file = File.basename(resp.uri.path).gsub(/\?.*/,'')
|
28
|
+
file = 'unknown' if file.empty?
|
29
|
+
"[file] #{file.inspect}, content-type: #{lr['content-type'].inspect}, content-length: #{lr['content-length'].to_i.to_human_readable_size}, " +
|
30
|
+
"last-modified: #{lr['last-modified'].inspect}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class WelcomePlugin < CrazyDoll::Plugin
|
2
|
+
|
3
|
+
config do |c|
|
4
|
+
c.key :messages, {}, 'Channels and messages'
|
5
|
+
c.register 'welcome', 'ignore ::user', :add_ignore, :chan
|
6
|
+
c.register 'welcome', 'message **message', :change_message, :chan
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_join
|
10
|
+
chan = opts.channel
|
11
|
+
setup_chan(chan)
|
12
|
+
reply c.messages[chan][:message] if opts.user != current_nick and not c.messages[chan][:ignore].include?(opts.user) and c.messages[chan][:message]
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_ignore
|
16
|
+
setup_chan(opts.to)
|
17
|
+
return reply "I'm already ignoring #{@params.user}." if c.messages[opts.to][:ignore].include?(@params.user)
|
18
|
+
c.messages[opts.to][:ignore] << @params.user
|
19
|
+
reply "I've started to ignore #{@params.user}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def setup_chan(chan)
|
23
|
+
c.messages[chan] ||= {}
|
24
|
+
c.messages[chan][:ignore] ||= []
|
25
|
+
end
|
26
|
+
|
27
|
+
def change_message
|
28
|
+
setup_chan(opts.to)
|
29
|
+
c.messages[opts.to][:message] = @params.message
|
30
|
+
reply 'Message updated!'
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class WellcomePlugin < CrazyDoll::Plugin
|
2
|
+
|
3
|
+
config do |c|
|
4
|
+
c.key :messages,
|
5
|
+
{ '#funrer' => 'Seja bem vindo ao #funrer', '#ubuntugames' => 'Seja bem vindo ao UbuntuGames, o seu canal de jogos :)' },
|
6
|
+
'Canais e mensagens a serem mostradas aos visitantes'
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_join
|
10
|
+
channel = opts.message
|
11
|
+
post PRIVMSG, channel, "#{opts.from.nick}, #{config[:messages][channel]}" if
|
12
|
+
config[:messages][channel] and opts.from.nick != @config[:nick][:current_nick][0]
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class CrazyDoll::Wizard
|
2
|
+
|
3
|
+
def initialize(config)
|
4
|
+
@config = config
|
5
|
+
run
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
@config.register(self,
|
10
|
+
:server,
|
11
|
+
'Address of IRC server',
|
12
|
+
get("Type the address of server(i.e. irc.freenode.net):", 'irc.freenode.net')) unless @config.respond_to?(:server) and @config.server.is_a?(String)
|
13
|
+
@config.register(self,
|
14
|
+
:port,
|
15
|
+
'The port of IRC server',
|
16
|
+
get("Type the port of server(default 6667):", 6667){|x| Integer(x) rescue 6667 }) unless @config.respond_to?(:port) and @config.port.is_a?(Integer)
|
17
|
+
|
18
|
+
unless @config.respond_to?(:nick) and @config.nick.is_a?(OpenStruct) and @config.nick.name and not @config.nick.name.empty?
|
19
|
+
@config.register(self, :nick, 'Info(nick, user, name, password) of bot', OpenStruct.new({
|
20
|
+
:name => get("Type the nick of bot(default CrazyDoll):", 'CrazyDoll') { |x| x.empty? ? 'CrazyDoll' : x },
|
21
|
+
:user => get("Type the user of bot(default CrazyBot):", 'CrazyBot') { |x| x.empty? ? 'CrazyBot' : x },
|
22
|
+
:real_name => get("Type the 'real name' of bot(default CrazyDoll #{CrazyDoll::VERSION}):",
|
23
|
+
"CrazyDoll #{CrazyDoll::VERSION}") { |x| x.empty? ? "CrazyDoll #{CrazyDoll::VERSION}" : x },
|
24
|
+
:password => get("Type the password of bot(default not use):", nil) { |x| x.empty? ? nil : x }
|
25
|
+
}))
|
26
|
+
end
|
27
|
+
|
28
|
+
@config.register(self,
|
29
|
+
:channels,
|
30
|
+
'Channels to join',
|
31
|
+
get("Type the channels to enter separed by comma(i.e. #crazydoll,#ubuntugames):", "#crazydoll") { |chans|
|
32
|
+
chans.gsub(' ','').split(',') }) unless @config.respond_to?(:channels) and @config.channels.is_a?(Array) and not @config.channels.empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
def get(string, default=nil, &block)
|
36
|
+
print string << " "
|
37
|
+
g = gets.chomp
|
38
|
+
g = default if g.empty?
|
39
|
+
if g and block_given?
|
40
|
+
return yield g
|
41
|
+
end
|
42
|
+
g
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: crazydoll
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Renan Fernandes
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-02-27 00:00:00 -04:00
|
18
|
+
default_executable: crazy_doll
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: net-irc
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 0
|
30
|
+
- 9
|
31
|
+
version: 0.0.9
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: httparty
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
- 5
|
44
|
+
- 2
|
45
|
+
version: 0.5.2
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
description: A plugin oriented IRC bot
|
49
|
+
email: renan@kauamanga.com.br
|
50
|
+
executables:
|
51
|
+
- crazy_doll
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files:
|
55
|
+
- README.md
|
56
|
+
files:
|
57
|
+
- lib/crazy_doll.rb
|
58
|
+
- lib/crazy_doll/bot.rb
|
59
|
+
- lib/crazy_doll/config.rb
|
60
|
+
- lib/crazy_doll/config_backend/yaml.rb
|
61
|
+
- lib/crazy_doll/core.rb
|
62
|
+
- lib/crazy_doll/events.rb
|
63
|
+
- lib/crazy_doll/fixes.rb
|
64
|
+
- lib/crazy_doll/irc.rb
|
65
|
+
- lib/crazy_doll/message.rb
|
66
|
+
- lib/crazy_doll/plugin_manager.rb
|
67
|
+
- lib/crazy_doll/plugins/join_plugin.rb
|
68
|
+
- lib/crazy_doll/plugins/nick_plugin.rb
|
69
|
+
- lib/crazy_doll/plugins/search_plugin.rb
|
70
|
+
- lib/crazy_doll/plugins/show_url_info_plugin.rb
|
71
|
+
- lib/crazy_doll/plugins/welcome_plugin.rb
|
72
|
+
- lib/crazy_doll/welcome_plugin.rb
|
73
|
+
- lib/crazy_doll/wizard.rb
|
74
|
+
- README.md
|
75
|
+
has_rdoc: true
|
76
|
+
homepage: http://github.com/ShadowBelmolve/crazydoll
|
77
|
+
licenses: []
|
78
|
+
|
79
|
+
post_install_message: "\n =================================================================\n Thanks for installing CrazyDoll\n If you want to use the 'show_url_info' plugin you'll need to\n install nokogiri gem\n\n gem install nokogiri \n\n =================================================================\n "
|
80
|
+
rdoc_options:
|
81
|
+
- --charset=UTF-8
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
segments:
|
89
|
+
- 0
|
90
|
+
version: "0"
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
98
|
+
requirements: []
|
99
|
+
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 1.3.6
|
102
|
+
signing_key:
|
103
|
+
specification_version: 3
|
104
|
+
summary: A IRC bot
|
105
|
+
test_files: []
|
106
|
+
|