cinch 0.1 → 0.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.rdoc +24 -1
- data/examples/hello.rb +13 -0
- data/examples/join_part.rb +26 -0
- data/examples/msg.rb +14 -0
- data/examples/named-param-types.rb +19 -0
- data/examples/seen.rb +41 -0
- data/lib/cinch.rb +2 -1
- data/lib/cinch/base.rb +83 -47
- data/lib/cinch/irc/parser.rb +1 -1
- data/lib/cinch/irc/socket.rb +5 -2
- data/lib/cinch/rules.rb +161 -0
- data/spec/base_spec.rb +107 -0
- data/spec/rules_spec.rb +109 -0
- metadata +11 -3
data/README.rdoc
CHANGED
@@ -10,7 +10,11 @@ plugin, defining a rule, and watching your profits flourish.
|
|
10
10
|
Cinch will do all of the hard work for you, so you can spend time creating cool plugins
|
11
11
|
and extensions to wow your internet peers.
|
12
12
|
|
13
|
+
Cinch is not a fully fledged IRC framework, its base is extremely small. If you're looking
|
14
|
+
for a more controlled library check out {silverplatter-irc}[http://github.com/apeiros/silverplatter-irc].
|
15
|
+
|
13
16
|
== Installation
|
17
|
+
The latest version of Cinch is 0.2
|
14
18
|
|
15
19
|
=== RubyGems
|
16
20
|
You can install the latest version of Cinch using RubyGems
|
@@ -95,9 +99,28 @@ the rules given, for example if we want to reply only if the nick sending the me
|
|
95
99
|
could pass the 'nick' option to the hash.
|
96
100
|
|
97
101
|
bot.plugin("join :channel", :nick => 'injekt') do |m|
|
98
|
-
|
102
|
+
bot.join #{m.args[:channel]}
|
103
|
+
end
|
104
|
+
|
105
|
+
== Named Parameter Types
|
106
|
+
Since version 0.2, Cinch supports named parameter types. Although at the moment you're constrained
|
107
|
+
to the <i>digit</i>, <i>string</i> and <i>word</i> types. It means stuff like the this works:
|
108
|
+
|
109
|
+
bot.plugin("say :n-digit :text") do |m|
|
110
|
+
m.args[:n].to_i.times {
|
111
|
+
m.reply m.args[:text]
|
112
|
+
end
|
99
113
|
end
|
100
114
|
|
115
|
+
This would provide the following output on IRC
|
116
|
+
|
117
|
+
injekt> !say foo bar
|
118
|
+
injekt> !say 2 foo bar
|
119
|
+
Cinch> foo bar
|
120
|
+
Cinch> foo bar
|
121
|
+
|
122
|
+
* See Cinch::Base#compile for more information
|
123
|
+
|
101
124
|
== Authors
|
102
125
|
Just me at the moment, sad poor lonely me...
|
103
126
|
* {Lee Jarvis}[http://blog.injekt.net]
|
data/examples/hello.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'cinch'
|
2
|
+
|
3
|
+
bot = Cinch.setup do
|
4
|
+
server "irc.freenode.org"
|
5
|
+
nick "CinchBot"
|
6
|
+
channels %w( #cinch )
|
7
|
+
end
|
8
|
+
|
9
|
+
# Who should be able to access these plugins
|
10
|
+
admin = 'injekt'
|
11
|
+
|
12
|
+
bot.plugin "join :channel", :nick => admin do |m|
|
13
|
+
bot.join m.args[:channel]
|
14
|
+
end
|
15
|
+
|
16
|
+
bot.plugin "part :channel", :nick => admin do |m|
|
17
|
+
bot.part m.args[:channel]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Part current channel if none is given
|
21
|
+
bot.plugin "part", :nick => admin do |m|
|
22
|
+
bot.part m.channel
|
23
|
+
end
|
24
|
+
|
25
|
+
bot.run
|
26
|
+
|
data/examples/msg.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'cinch'
|
2
|
+
|
3
|
+
bot = Cinch.setup do
|
4
|
+
server "irc.freenode.org"
|
5
|
+
channels %w( #cinch )
|
6
|
+
end
|
7
|
+
|
8
|
+
bot.plugin("say :n-digit :text") do |m|
|
9
|
+
m.args[:n].to_i.times {
|
10
|
+
m.reply m.args[:text]
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
bot.plugin("say :text-word :rest") do |m|
|
15
|
+
stuff = [m.args[:text], m.args[:rest]].join(' ')
|
16
|
+
m.reply stuff
|
17
|
+
end
|
18
|
+
|
19
|
+
bot.run
|
data/examples/seen.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'cinch'
|
2
|
+
|
3
|
+
users = {}
|
4
|
+
|
5
|
+
class Seen < Struct.new(:who, :where, :what, :time)
|
6
|
+
def to_s
|
7
|
+
"[#{time.asctime}] #{who} was seen in #{where} saying #{what}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
bot = Cinch.setup(
|
12
|
+
:server => 'irc.freenode.org',
|
13
|
+
:channels => ['#cinch'],
|
14
|
+
:prefix => '!',
|
15
|
+
:verbose => true,
|
16
|
+
)
|
17
|
+
|
18
|
+
# Only log a PRIVMSG
|
19
|
+
bot.on :privmsg do |m|
|
20
|
+
# Dont record a private message
|
21
|
+
unless m.private?
|
22
|
+
users[m.nick] = Seen.new(m.nick, m.channel, m.text, Time.new)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
bot.plugin("seen :nick foo") do |m|
|
27
|
+
nick = m.args[:nick]
|
28
|
+
|
29
|
+
if nick == bot.nick
|
30
|
+
m.reply "That's me!"
|
31
|
+
elsif nick == m.nick
|
32
|
+
m.reply "That's you!"
|
33
|
+
elsif users.key?(nick)
|
34
|
+
m.reply users[nick].to_s
|
35
|
+
else
|
36
|
+
m.reply "I haven't seen #{nick}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
bot.run
|
41
|
+
|
data/lib/cinch.rb
CHANGED
@@ -5,10 +5,11 @@ require 'ostruct'
|
|
5
5
|
require 'optparse'
|
6
6
|
|
7
7
|
require 'cinch/irc'
|
8
|
+
require 'cinch/rules'
|
8
9
|
require 'cinch/base'
|
9
10
|
|
10
11
|
module Cinch
|
11
|
-
VERSION = '0.
|
12
|
+
VERSION = '0.2'
|
12
13
|
|
13
14
|
# Setup bot options and return a new Cinch::Base instance
|
14
15
|
def self.setup(ops={}, &blk)
|
data/lib/cinch/base.rb
CHANGED
@@ -60,7 +60,7 @@ module Cinch
|
|
60
60
|
options = DEFAULTS.merge(ops).merge(Options.new(&blk))
|
61
61
|
@options = OpenStruct.new(options.merge(cli_ops))
|
62
62
|
|
63
|
-
@rules =
|
63
|
+
@rules = Rules.new
|
64
64
|
@listeners = {}
|
65
65
|
|
66
66
|
@irc = IRC::Socket.new(options[:server], options[:port])
|
@@ -85,12 +85,15 @@ module Cinch
|
|
85
85
|
op.on("-n nick") {|v| options[:nick] = v }
|
86
86
|
op.on("-c command_prefix") {|v| options[:prefix] = v }
|
87
87
|
op.on("-v", "--verbose", "Enable verbose mode") {|v| options[:verbose] = true }
|
88
|
-
op.on("-
|
88
|
+
op.on("-C", "--channels x,y,z", Array, "Autojoin channels") {|v|
|
89
89
|
options[:channels] = v.map {|c| %w(# + &).include?(c[0].chr) ? c : c.insert(0, '#') }
|
90
90
|
}
|
91
91
|
end.parse(ARGV)
|
92
92
|
rescue OptionParser::MissingArgument => err
|
93
|
-
|
93
|
+
warn "Missing values for options: #{err.args.join(', ')}\nFalling back to default"
|
94
|
+
rescue OptionParser::InvalidOption => err
|
95
|
+
warn err.message
|
96
|
+
exit
|
94
97
|
end
|
95
98
|
end
|
96
99
|
options
|
@@ -104,7 +107,13 @@ module Cinch
|
|
104
107
|
# end
|
105
108
|
def plugin(rule, options={}, &blk)
|
106
109
|
rule, keys = compile(rule)
|
107
|
-
|
110
|
+
|
111
|
+
if @rules.has_rule?(rule)
|
112
|
+
@rules.add_callback(rule, blk)
|
113
|
+
@rules.merge_options(rule, options)
|
114
|
+
else
|
115
|
+
@rules.add_rule(rule, keys, options, blk)
|
116
|
+
end
|
108
117
|
end
|
109
118
|
|
110
119
|
# Add new listeners
|
@@ -123,35 +132,80 @@ module Cinch
|
|
123
132
|
end
|
124
133
|
end
|
125
134
|
|
126
|
-
#
|
135
|
+
# This method builds a regular expression from your rule
|
136
|
+
# and defines all named parameters, as well as dealing with
|
137
|
+
# types.
|
138
|
+
#
|
139
|
+
# So far 3 types are supported:
|
140
|
+
#
|
141
|
+
# * word - matches [a-zA-Z]+
|
142
|
+
# * string - matches \w+
|
143
|
+
# * digit - matches \d+
|
144
|
+
#
|
145
|
+
# == Examples
|
146
|
+
# For capturing individual words
|
147
|
+
# bot.plugin("say :text-word")
|
148
|
+
# * Does match !say foo
|
149
|
+
# * Does not match !say foo bar baz
|
150
|
+
#
|
151
|
+
# For capturing digits
|
152
|
+
# bot.plugin("say :text-digit")
|
153
|
+
# * Does match !say 3
|
154
|
+
# * Does not match !say 3 4
|
155
|
+
# * Does not match !say foo
|
156
|
+
#
|
157
|
+
# For both
|
158
|
+
# bot.plugin("say :n-digit :text-word")
|
159
|
+
# * Does match !say 3 foo
|
160
|
+
# * Does not match !say 3 foo bar
|
161
|
+
#
|
162
|
+
# For capturing until the end of the line
|
163
|
+
# bot.plugin("say :text")
|
164
|
+
# * Does match !say foo
|
165
|
+
# * Does match !say foo bar
|
166
|
+
#
|
167
|
+
# Or mix them all
|
168
|
+
# bot.plugin("say :n-digit :who-word :text")
|
169
|
+
#
|
170
|
+
# Using "!say 3 injekt some text here" would provide
|
171
|
+
# the following attributes
|
172
|
+
# m.args[:n] => 3
|
173
|
+
# m.args[:who] => injekt
|
174
|
+
# m.args[:text] => some text here
|
127
175
|
def compile(rule)
|
128
|
-
return [rule []] if rule.is_a?(Regexp)
|
176
|
+
return [rule, []] if rule.is_a?(Regexp)
|
129
177
|
keys = []
|
130
178
|
special_chars = %w{. + ( )}
|
131
179
|
|
132
|
-
pattern = rule.to_s.gsub(/((
|
180
|
+
pattern = rule.to_s.gsub(/((:[\w\-]+)|[\*#{special_chars.join}])/) do |match|
|
133
181
|
case match
|
134
182
|
when *special_chars
|
135
183
|
Regexp.escape(match)
|
136
184
|
else
|
137
|
-
|
138
|
-
|
185
|
+
k = $2
|
186
|
+
if k =~ /\-(\w+)$/
|
187
|
+
key, type = k.split('-')
|
188
|
+
keys << key[1..-1]
|
189
|
+
|
190
|
+
case type
|
191
|
+
when 'digit'; "(\\d+?)"
|
192
|
+
when 'word'; "([a-zA-Z]+?)"
|
193
|
+
when 'string'; "(\\w+?)"
|
194
|
+
else
|
195
|
+
"([^\x00\r\n]+?)"
|
196
|
+
end
|
197
|
+
else
|
198
|
+
keys << k[1..-1]
|
199
|
+
"([^\x00\r\n]+?)"
|
200
|
+
end
|
139
201
|
end
|
140
202
|
end
|
141
203
|
["^#{pattern}$", keys]
|
142
204
|
end
|
143
205
|
|
144
|
-
# Add a new rule, or add to an existing one if it
|
145
|
-
# already exists
|
146
|
-
def add_rule(rule, keys, options={}, &blk)
|
147
|
-
unless @rules.key?(rule)
|
148
|
-
@rules[rule] = [rule, keys, options, blk]
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
206
|
# Run run run
|
153
|
-
def run
|
154
|
-
@irc.connect
|
207
|
+
def run
|
208
|
+
@irc.connect options.server, options.port
|
155
209
|
@irc.nick options.nick
|
156
210
|
@irc.user options.username, options.usermode, '*', options.realname
|
157
211
|
|
@@ -166,6 +220,7 @@ module Cinch
|
|
166
220
|
|
167
221
|
# Process the next line read from the server
|
168
222
|
def process(line)
|
223
|
+
return unless line
|
169
224
|
message = @parser.parse(line)
|
170
225
|
message.irc = @irc
|
171
226
|
puts message if options.verbose
|
@@ -175,40 +230,21 @@ module Cinch
|
|
175
230
|
end
|
176
231
|
|
177
232
|
if [:privmsg].include?(message.symbol)
|
178
|
-
rules.
|
179
|
-
rule
|
180
|
-
|
181
|
-
|
182
|
-
unless ops.has_key?(:prefix) || options.prefix == false
|
183
|
-
rule.insert(1, options.prefix) unless rule[1].chr == options.prefix
|
233
|
+
rules.each do |rule|
|
234
|
+
unless rule.options.key?(:prefix) || options.prefix == false
|
235
|
+
rule.to_s.insert(1, options.prefix) unless rule.to_s[1].chr == options.prefix
|
184
236
|
end
|
185
237
|
|
186
|
-
if message.text && mdata = message.text.match(Regexp.new(rule))
|
187
|
-
unless keys.empty? || mdata.captures.empty?
|
188
|
-
args = Hash[keys.map {|k| k.to_sym}.zip(mdata.captures)]
|
238
|
+
if message.text && mdata = message.text.match(Regexp.new(rule.to_s))
|
239
|
+
unless rule.keys.empty? || mdata.captures.empty?
|
240
|
+
args = Hash[rule.keys.map {|k| k.to_sym}.zip(mdata.captures)]
|
189
241
|
message.args = args
|
190
|
-
end
|
191
|
-
|
192
|
-
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
# Execute a rule
|
198
|
-
def execute_rule(message, ops, blk)
|
199
|
-
ops.keys.each do |k|
|
200
|
-
case k
|
201
|
-
when :nick; return unless ops[:nick] == message.nick
|
202
|
-
when :user; return unless ops[:user] == message.user
|
203
|
-
when :host; return unless ops[:host] == message.host
|
204
|
-
when :channel
|
205
|
-
if message.channel
|
206
|
-
return unless ops[:channel] == message.channel
|
242
|
+
end
|
243
|
+
# execute rule
|
244
|
+
rule.execute(message)
|
207
245
|
end
|
208
246
|
end
|
209
247
|
end
|
210
|
-
|
211
|
-
blk.call(message)
|
212
248
|
end
|
213
249
|
|
214
250
|
# Catch methods
|
data/lib/cinch/irc/parser.rb
CHANGED
@@ -80,7 +80,7 @@ module Cinch
|
|
80
80
|
# Parse the incoming raw IRC string and return
|
81
81
|
# a nicely formatted IRC::Message
|
82
82
|
def parse_servermessage(raw)
|
83
|
-
raise ArgumentError, raw unless matches = raw.match(pattern(:message))
|
83
|
+
raise ArgumentError, raw unless raw && matches = raw.match(pattern(:message))
|
84
84
|
|
85
85
|
prefix, command, parameters = matches.captures
|
86
86
|
|
data/lib/cinch/irc/socket.rb
CHANGED
@@ -87,8 +87,11 @@ module Cinch
|
|
87
87
|
|
88
88
|
# Connect to an IRC server, returns true on a successful connection, or
|
89
89
|
# raises otherwise
|
90
|
-
def connect
|
91
|
-
@
|
90
|
+
def connect(server=nil, port=nil)
|
91
|
+
@server = server if server
|
92
|
+
@port = port if port
|
93
|
+
|
94
|
+
@socket = TCPSocket.new(@server, @port)
|
92
95
|
rescue Interrupt
|
93
96
|
raise
|
94
97
|
rescue Exception
|
data/lib/cinch/rules.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
module Cinch
|
2
|
+
|
3
|
+
# == Author
|
4
|
+
# * Lee Jarvis - ljjarvis@gmail.com
|
5
|
+
#
|
6
|
+
# == Description
|
7
|
+
# Every rule defined through the Cinch::Base#plugin method becomes an instance
|
8
|
+
# of this class. Each rule consists of keys used for named parameters, a hash
|
9
|
+
# of options, and an Array of callbacks.
|
10
|
+
#
|
11
|
+
# When a rule matches an IRC message, all options with be checked, then all
|
12
|
+
# callbacks will be invoked.
|
13
|
+
class Rule < Struct.new(:rule, :keys, :options, :callbacks)
|
14
|
+
def initialize(rule, keys, options, callback)
|
15
|
+
callbacks = [callback]
|
16
|
+
super(rule, keys, options, callbacks)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Execute all callbacks, passing an Cinch::IRC::Message to them
|
20
|
+
def execute(message)
|
21
|
+
options.keys.each do |key|
|
22
|
+
case key
|
23
|
+
when :nick
|
24
|
+
return unless options[:nick] == message.nick
|
25
|
+
when :host
|
26
|
+
return unless options[:host] == message.host
|
27
|
+
when :user
|
28
|
+
return unless options[:user] == message.user
|
29
|
+
when :channel
|
30
|
+
if message.channel
|
31
|
+
return unless options[:channel] == message.channel
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
callbacks.each do |blk|
|
37
|
+
blk.call(message)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# The rule as a String
|
42
|
+
def to_s
|
43
|
+
rule
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# == Author
|
48
|
+
# * Lee Jarvis - ljjarvis@gmail.com
|
49
|
+
#
|
50
|
+
# == Description
|
51
|
+
# This class provides an interface to manage rules. A rule should only ever be
|
52
|
+
# added using the Rules#add_rule method and retrieved using the Rules#get_rule
|
53
|
+
# method, or an alias of these.
|
54
|
+
#
|
55
|
+
# This class provides an easy way to add options or callbacks to an existing
|
56
|
+
# rule.
|
57
|
+
#
|
58
|
+
# Essentially the add_callback, add_option, and merge_options methods are just sugar
|
59
|
+
# so you don't have to edit Rule attributes directly
|
60
|
+
#
|
61
|
+
# == Example
|
62
|
+
# rules = Cinch::Rules.new
|
63
|
+
#
|
64
|
+
# rules.add('foo', [], {}, Proc.new{})
|
65
|
+
#
|
66
|
+
# rules.add_callback('foo', Proc.new{})
|
67
|
+
# rules['foo'].callbacks #=> [#<Proc:0x9f1e110@(main):100>, #<Proc:0x9f1e0f4@(main):150>]
|
68
|
+
#
|
69
|
+
# # Or assign directly
|
70
|
+
# rules.get('foo').callbacks << Proc.new {}
|
71
|
+
#
|
72
|
+
# rules['foo'].options #=> {}
|
73
|
+
# rules.add_option('foo', :nick, 'injekt')
|
74
|
+
# rules['foo'].options #=> {:nick => 'injekt'}
|
75
|
+
#
|
76
|
+
# # Or retrieve the rule first and assign directly
|
77
|
+
# rules.get_rule('foo')
|
78
|
+
# rules.options = {:foo => 'bar'}
|
79
|
+
# rules.options[:bar] = 'baz'
|
80
|
+
class Rules
|
81
|
+
def initialize
|
82
|
+
@rules = {}
|
83
|
+
end
|
84
|
+
|
85
|
+
# Add a new rule, overwrites an already existing rule
|
86
|
+
def add_rule(rule, keys, options, callback)
|
87
|
+
@rules[rule] = Rule.new(rule, keys, options, callback)
|
88
|
+
end
|
89
|
+
alias :add :add_rule
|
90
|
+
|
91
|
+
# Return a Cinch::Rule by its rule, or nil it one does not exist
|
92
|
+
def get_rule(rule)
|
93
|
+
@rules[rule]
|
94
|
+
end
|
95
|
+
alias :get :get_rule
|
96
|
+
alias :[] :get_rule
|
97
|
+
|
98
|
+
# Remove a rule
|
99
|
+
def remove_rule(rule)
|
100
|
+
@rules.delete(rule)
|
101
|
+
end
|
102
|
+
alias :remove :remove_rule
|
103
|
+
|
104
|
+
# Check if a rule exists
|
105
|
+
def include?(rule)
|
106
|
+
@rules.key?(rule)
|
107
|
+
end
|
108
|
+
alias :has_rule? :include?
|
109
|
+
|
110
|
+
# Add a callback for an already existing rule
|
111
|
+
def add_callback(rule, blk)
|
112
|
+
return unless include?(rule)
|
113
|
+
@rules[rule].callbacks << blk
|
114
|
+
end
|
115
|
+
|
116
|
+
# Add an option for an already existing rule
|
117
|
+
def add_option(rule, key, value)
|
118
|
+
return unless include?(rule)
|
119
|
+
@rules[rule].options[key] = value
|
120
|
+
end
|
121
|
+
|
122
|
+
# Merge rule options
|
123
|
+
def merge_options(rule, ops={})
|
124
|
+
return unless include?(rule)
|
125
|
+
@rules[rule].options.merge!(ops)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Iterate over the rules
|
129
|
+
def each
|
130
|
+
@rules.each {|rule, obj| yield obj }
|
131
|
+
end
|
132
|
+
|
133
|
+
# Remove all rules
|
134
|
+
def clear
|
135
|
+
@rules.clear
|
136
|
+
end
|
137
|
+
|
138
|
+
# Check if any rules exist
|
139
|
+
def empty?
|
140
|
+
@rules.empty?
|
141
|
+
end
|
142
|
+
|
143
|
+
# Return how many rules exist
|
144
|
+
def count
|
145
|
+
@rules.size
|
146
|
+
end
|
147
|
+
alias :size :count
|
148
|
+
|
149
|
+
# Return the hash of rules
|
150
|
+
def all
|
151
|
+
@rules
|
152
|
+
end
|
153
|
+
|
154
|
+
# Return an Array of rules
|
155
|
+
def to_a
|
156
|
+
@rules.keys
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
describe "Cinch::Base" do
|
4
|
+
before do
|
5
|
+
@base = Cinch::Base.new
|
6
|
+
|
7
|
+
@full = Cinch::Base.new(
|
8
|
+
:server => 'irc.freenode.org',
|
9
|
+
:nick => 'CinchBot',
|
10
|
+
:channels => ['#cinch']
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "::new" do
|
15
|
+
it "should add a default ping listener" do
|
16
|
+
@base.listeners.should include :ping
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should add a 376 listener, only if channels are set" do
|
20
|
+
@base.listeners.should_not include :'376'
|
21
|
+
@full.listeners.should include :'376'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#plugin" do
|
26
|
+
it "should compile and add a rule" do
|
27
|
+
@base.plugin('foo')
|
28
|
+
@base.rules.include?("^foo$").should == true
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should add options to an existing rule" do
|
32
|
+
@base.plugin('foo') { }
|
33
|
+
@base.plugin('foo', :bar => 'baz') { }
|
34
|
+
rule = @base.rules.get('^foo$')
|
35
|
+
rule.options.should include :bar
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should add its block to an existing rule" do
|
39
|
+
@base.plugin('foo') { }
|
40
|
+
@base.plugin('foo') { }
|
41
|
+
rule = @base.rules.get_rule('^foo$')
|
42
|
+
rule.callbacks.size.should == 2
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#on" do
|
47
|
+
it "should save a listener" do
|
48
|
+
@base.on(:foo) {}
|
49
|
+
@base.listeners.should include :foo
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should store listener blocks in an Array" do
|
53
|
+
@base.listeners[:ping].should be_kind_of Array
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#compile" do
|
58
|
+
it "should return an Array of 2 values" do
|
59
|
+
ret = @base.compile("foo")
|
60
|
+
ret.should be_kind_of(Array)
|
61
|
+
ret.size.should == 2
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return an empty set of keys if no named parameters are labeled" do
|
65
|
+
rule, keys = @base.compile("foo")
|
66
|
+
keys.should be_empty
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should return a key for each named parameter labeled" do
|
70
|
+
rule, keys = @base.compile("foo :bar :baz")
|
71
|
+
keys.size.should == 2
|
72
|
+
keys.should include "bar"
|
73
|
+
keys.should include "baz"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return a rule of type String, unless Regexp is given" do
|
77
|
+
rule, keys = @base.compile(:foo)
|
78
|
+
rule.should be_kind_of(String)
|
79
|
+
|
80
|
+
rule, keys = @base.compile(/foo/)
|
81
|
+
rule.should be_kind_of(Regexp)
|
82
|
+
keys.should be_empty
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should convert a digit type" do
|
86
|
+
rule, keys = @base.compile(":foo-digit")
|
87
|
+
rule.should == "^(\\d+?)$"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should convert a string type" do
|
91
|
+
rule, keys = @base.compile(":foo-string")
|
92
|
+
rule.should == "^(\\w+?)$"
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should convert a word type" do
|
96
|
+
rule, keys = @base.compile(":foo-word")
|
97
|
+
rule.should == "^([a-zA-Z]+?)$"
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should automatically add start and end anchors" do
|
101
|
+
rule, keys = @base.compile("foo bar baz")
|
102
|
+
rule[0].chr.should == "^"
|
103
|
+
rule[-1].chr.should == "$"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
data/spec/rules_spec.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
describe "Cinch::Rules" do
|
4
|
+
before do
|
5
|
+
@rules = Cinch::Rules.new
|
6
|
+
@rules.add_rule('foo', [], {}, Proc.new{})
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "::new" do
|
10
|
+
it "should define an empty set of rules" do
|
11
|
+
Cinch::Rules.new.empty?.should == true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#add_rule" do
|
16
|
+
it "should add a new rule" do
|
17
|
+
@rules.add_rule('bar', [], {}, Proc.new{})
|
18
|
+
@rules.all.should include 'foo'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should replace an existing rule" do
|
22
|
+
@rules.add_rule('foo', [], {}, Proc.new{})
|
23
|
+
@rules.count.should == 1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#get_rule" do
|
28
|
+
it "should return a Cinch::Rule" do
|
29
|
+
@rules.get_rule('foo').should be_kind_of Cinch::Rule
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#remove_rule" do
|
34
|
+
it "should remove a rule" do
|
35
|
+
@rules.remove_rule('foo')
|
36
|
+
@rules.include?('foo').should == false
|
37
|
+
@rules.count.should == 0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#add_callback" do
|
42
|
+
it "should add a callback for a rule" do
|
43
|
+
@rules.add_callback('foo', Proc.new{})
|
44
|
+
rule = @rules.get_rule('foo')
|
45
|
+
rule.callbacks.size.should == 2
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#add_option" do
|
50
|
+
it "should add an option for a rule" do
|
51
|
+
@rules.add_option('foo', :nick, 'injekt')
|
52
|
+
rule = @rules.get('foo')
|
53
|
+
rule.options.should include :nick
|
54
|
+
rule.options[:nick].should == 'injekt'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#merge_options" do
|
59
|
+
it "should merge rule options" do
|
60
|
+
@rules.merge_options('foo', {:bar => 'baz'})
|
61
|
+
rule = @rules['foo']
|
62
|
+
rule.options.should == {:bar => 'baz'}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#include?" do
|
67
|
+
it "should check if a rule exists" do
|
68
|
+
@rules.include?('foo').should == true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#clear" do
|
73
|
+
it "should clear all rules" do
|
74
|
+
@rules.clear
|
75
|
+
@rules.empty?.should == true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#empty?" do
|
80
|
+
it "should check if any rules exist" do
|
81
|
+
@rules.empty?.should == false
|
82
|
+
@rules.clear
|
83
|
+
@rules.empty?.should == true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#count" do
|
88
|
+
it "should show how many rules exist" do
|
89
|
+
@rules.count.should == 1
|
90
|
+
@rules.add_rule('bar', [], {}, Proc.new{})
|
91
|
+
@rules.count.should == 2
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#all" do
|
96
|
+
it "should return a Hash of all rules" do
|
97
|
+
@rules.all.should be_kind_of Hash
|
98
|
+
@rules.all.should include 'foo'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#to_a" do
|
103
|
+
it "should return an Array of rules" do
|
104
|
+
@rules.to_a.should be_kind_of Array
|
105
|
+
@rules.to_a.include?('foo').should == true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
metadata
CHANGED
@@ -4,8 +4,8 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
version: "0.
|
7
|
+
- 2
|
8
|
+
version: "0.2"
|
9
9
|
platform: ruby
|
10
10
|
authors:
|
11
11
|
- Lee 'injekt' Jarvis
|
@@ -13,7 +13,7 @@ autorequire:
|
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
15
|
|
16
|
-
date: 2010-04-
|
16
|
+
date: 2010-04-26 00:00:00 +01:00
|
17
17
|
default_executable:
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
@@ -41,18 +41,26 @@ extra_rdoc_files:
|
|
41
41
|
files:
|
42
42
|
- README.rdoc
|
43
43
|
- Rakefile
|
44
|
+
- spec/base_spec.rb
|
44
45
|
- spec/irc/socket_spec.rb
|
45
46
|
- spec/irc/helper.rb
|
46
47
|
- spec/irc/message_spec.rb
|
47
48
|
- spec/irc/parser_spec.rb
|
48
49
|
- spec/helper.rb
|
50
|
+
- spec/rules_spec.rb
|
49
51
|
- spec/options_spec.rb
|
50
52
|
- lib/cinch.rb
|
51
53
|
- lib/cinch/base.rb
|
52
54
|
- lib/cinch/irc/message.rb
|
53
55
|
- lib/cinch/irc/socket.rb
|
54
56
|
- lib/cinch/irc/parser.rb
|
57
|
+
- lib/cinch/rules.rb
|
55
58
|
- lib/cinch/irc.rb
|
59
|
+
- examples/join_part.rb
|
60
|
+
- examples/msg.rb
|
61
|
+
- examples/seen.rb
|
62
|
+
- examples/hello.rb
|
63
|
+
- examples/named-param-types.rb
|
56
64
|
has_rdoc: true
|
57
65
|
homepage: http://rdoc.injekt.net/cinch
|
58
66
|
licenses: []
|