codebrulee-aide 0.0.4
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 +82 -0
- data/bin/aide +8 -0
- data/lib/aide.rb +11 -0
- data/lib/aide/actioncontext.rb +49 -0
- data/lib/aide/bot.rb +176 -0
- data/lib/aide/dsl.rb +74 -0
- data/lib/aide/errors.rb +8 -0
- data/lib/aide/version.rb +9 -0
- metadata +69 -0
data/README
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
= Aide - What can Jabber do for you?
|
2
|
+
|
3
|
+
http://github.com/duwanis/aide
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Aide is a DSL for defining and running Jabber bots.
|
8
|
+
In order to have a good grasp on how to use Aide, you'll want to familiarize
|
9
|
+
yourself with two classes: Aide::Dsl (used to actually read the Aide DSL), and
|
10
|
+
Aide::ActionContext (blocks defined using the DSL get executed in the scope of
|
11
|
+
an ActionContext). More thorough documentation will be coming soon...
|
12
|
+
|
13
|
+
== FEATURES/PROBLEMS:
|
14
|
+
|
15
|
+
It doesn't do anything yet. This is the main problem, really.
|
16
|
+
|
17
|
+
== EXAMPLE:
|
18
|
+
|
19
|
+
Check out example.aide in the source. If you install the gem
|
20
|
+
(see INSTALL below), you should be able to do the following to
|
21
|
+
see the results of parsing the file (or any other file matching
|
22
|
+
the DSL):
|
23
|
+
aide example.aide
|
24
|
+
|
25
|
+
|
26
|
+
== REQUIREMENTS:
|
27
|
+
|
28
|
+
Patience.
|
29
|
+
|
30
|
+
|
31
|
+
== INSTALL:
|
32
|
+
|
33
|
+
sudo gem install duwanis-aide --source=http://gems.github.com
|
34
|
+
|
35
|
+
== ROADMAP:
|
36
|
+
|
37
|
+
Here's the plan:
|
38
|
+
- 0.1 - Functionality in place to create a very simple bot. Can take in any
|
39
|
+
number of static commands, but nothing fancy.
|
40
|
+
- 0.2 - Help/describe functionality built in by default.
|
41
|
+
- 0.3 - Dynamic commands.
|
42
|
+
- 0.4 - Ability to subscribe to an XMPP Publisher (XEP-0060)
|
43
|
+
- 0.5 - Scheduled tasks (e.g. "execute this code every minute")
|
44
|
+
- 0.6 - Ability to act as an XMPP Publisher (XEP-0060)
|
45
|
+
- 0.7 - Command-line interface for publishing events (e.g. aide-publish [botname] [event])
|
46
|
+
- 0.8 - ?????
|
47
|
+
- 0.9 - Profit!
|
48
|
+
- 1.0 - Fully functional 1.0 release.
|
49
|
+
|
50
|
+
== HISTORY:
|
51
|
+
|
52
|
+
- 0.0.4 - Beginnings of xmpp4r integration.
|
53
|
+
- 0.0.2 - Bot class started, DSL is done in a sane way (no more creating kernel
|
54
|
+
methods, woo)
|
55
|
+
- 0.0.1 - Proof of concept. DSL is somewhat spec'd out, and you
|
56
|
+
are now capable of parsing files (albeit crudely).
|
57
|
+
- 0.0.0 - A new project is born!
|
58
|
+
|
59
|
+
== LICENSE:
|
60
|
+
|
61
|
+
(The MIT License)
|
62
|
+
|
63
|
+
Copyright (c) 2008 Tommy Morgan
|
64
|
+
|
65
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
66
|
+
a copy of this software and associated documentation files (the
|
67
|
+
'Software'), to deal in the Software without restriction, including
|
68
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
69
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
70
|
+
permit persons to whom the Software is furnished to do so, subject to
|
71
|
+
the following conditions:
|
72
|
+
|
73
|
+
The above copyright notice and this permission notice shall be
|
74
|
+
included in all copies or substantial portions of the Software.
|
75
|
+
|
76
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
77
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
78
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
79
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
80
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
81
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
82
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/bin/aide
ADDED
data/lib/aide.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Just to make our requires at the top of the gem a little easier.
|
2
|
+
require 'pathname'
|
3
|
+
$:.unshift(Pathname(__FILE__).dirname.expand_path)
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'xmpp4r'
|
7
|
+
|
8
|
+
require 'aide/errors'
|
9
|
+
require 'aide/bot'
|
10
|
+
require 'aide/dsl'
|
11
|
+
require 'aide/version'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Aide
|
2
|
+
##
|
3
|
+
# This class is used to provide an execution context for processing messages.
|
4
|
+
# It houses all the attributes and helper methods that are to be exposed to
|
5
|
+
# the blocks that are passed in to Aide via the Aide::Dsl.with method.
|
6
|
+
# These contexts are created and destroyed on a per-message basis, so all
|
7
|
+
# attribute values refer to the message that is currently being processed.
|
8
|
+
#
|
9
|
+
class ActionContext
|
10
|
+
#String - The Jabber address from which the message was sent.
|
11
|
+
attr_accessor :from
|
12
|
+
#String - The Jabber address to which the message was sent.
|
13
|
+
attr_accessor :to
|
14
|
+
#String - The text of the message, minus the portion that was
|
15
|
+
#matched by the bot.
|
16
|
+
attr_accessor :message
|
17
|
+
#String - The full text of the message, including the portion that
|
18
|
+
#was matched by the bot.
|
19
|
+
attr_accessor :text
|
20
|
+
#Symbol - The type of the message (e.g. :chat, :group, etc.)
|
21
|
+
attr_accessor :type
|
22
|
+
#Aide::Bot - The bot instance that received and is acting on this
|
23
|
+
#message.
|
24
|
+
attr_accessor :bot
|
25
|
+
|
26
|
+
##
|
27
|
+
# Sends a message back to the jabber id that sent the original message.
|
28
|
+
#=== Parameters:
|
29
|
+
# - *text*: String. The text of the message to send.
|
30
|
+
#
|
31
|
+
def respond(text)
|
32
|
+
send(text, from)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Sends a message to the specified jabber id.
|
37
|
+
#=== Parameters:
|
38
|
+
# - *text*: String. The text of the message to send.
|
39
|
+
# - *to*: String. The jabber id to send the message to.
|
40
|
+
#
|
41
|
+
def send(text, to)
|
42
|
+
response = Message.new(to, text)
|
43
|
+
response.type = :chat
|
44
|
+
|
45
|
+
bot.send(response)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
data/lib/aide/bot.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
module Aide
|
2
|
+
##
|
3
|
+
# The Bot class is the workhorse of aide. It is responsible for representing
|
4
|
+
# and executing the logic described by the dsl, and interacts with xmpp4r
|
5
|
+
# in order to send and receive messages via the jabber protocol.
|
6
|
+
#
|
7
|
+
class Bot
|
8
|
+
|
9
|
+
#Hash[String, Block] - the match strings to look for, and the code to execute when found.
|
10
|
+
attr_writer :actions
|
11
|
+
|
12
|
+
#String - the username to sign this bot in with.
|
13
|
+
attr_writer :username
|
14
|
+
#Password - the password for this bot to use.
|
15
|
+
attr_writer :password
|
16
|
+
#Array[String] - a list of jabber IDs to allow this bot to interact with. Precludes block_list.
|
17
|
+
attr_accessor :allow_list
|
18
|
+
#Array[String] - a list of jabber IDs to explicitly block. Ignored if allow_list is set.
|
19
|
+
attr_accessor :block_list
|
20
|
+
|
21
|
+
##
|
22
|
+
#Creates a new Bot instance.
|
23
|
+
#
|
24
|
+
def initialize
|
25
|
+
@actions = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
#Logs this Bot instance in to the jabber network and starts it listening
|
30
|
+
#for messages.
|
31
|
+
#=== Preconditions
|
32
|
+
#This method assumes that the Bot has already been properly configured;
|
33
|
+
#specifically, that at least the username and password properties have
|
34
|
+
#been set.
|
35
|
+
#=== Postconditions
|
36
|
+
#- The Bot will be logged on,
|
37
|
+
#- Its presence will be set to 'chat,' and
|
38
|
+
#- It will be listening for messages from privileged users in its own thread
|
39
|
+
#(see is_user_allowed?)
|
40
|
+
#=== Returns
|
41
|
+
#+nil+
|
42
|
+
#
|
43
|
+
def login
|
44
|
+
if @password == nil or @username == nil
|
45
|
+
raise Aide::Login_Error, "credentials missing"
|
46
|
+
end
|
47
|
+
@client = Jabber::Client.new(Jabber::JID.new(@username))
|
48
|
+
@client.connect
|
49
|
+
|
50
|
+
#actual authentication with the host
|
51
|
+
begin
|
52
|
+
@client.auth(@password)
|
53
|
+
rescue Jabber::AuthenticationFailure => af
|
54
|
+
raise Aide::Login_Error, "Authentication failure: #{af.message}", af.backtrace
|
55
|
+
end
|
56
|
+
|
57
|
+
@client.send(Jabber::Presence.new)
|
58
|
+
@thread = Thread.new do
|
59
|
+
@client.add_message_callback do |m|
|
60
|
+
if m.type == :chat and is_user_allowed? m.from.split('/')[0]
|
61
|
+
process_message m
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
#Sends the given message.
|
70
|
+
#=== Parameters
|
71
|
+
#- *message*: Jabber::Message. The message to send.
|
72
|
+
#
|
73
|
+
def send(message)
|
74
|
+
@client.send message
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
#Examines the given message to see if any actions need to be performed
|
79
|
+
#on it. If this message matches any actions defined for this Bot, an
|
80
|
+
#Aide::ActionContext is created and used to evaluate the block associated
|
81
|
+
#with that action.
|
82
|
+
#=== Parameters
|
83
|
+
#- *message*: Jabber::Message. The message to process.
|
84
|
+
#
|
85
|
+
def process_message(message)
|
86
|
+
results = match(message.body)
|
87
|
+
return nil unless results #no need to do anything if there's no match
|
88
|
+
|
89
|
+
context = Aide::ActionContext.new
|
90
|
+
block = @actions[results[:action_name]]
|
91
|
+
context.message = results[:message]
|
92
|
+
context.from = message.from
|
93
|
+
context.to = message.to
|
94
|
+
context.bot = self
|
95
|
+
context.text = message.body
|
96
|
+
context.type = message.type
|
97
|
+
context.instance_eval(block.call)
|
98
|
+
|
99
|
+
nil #no need to complicate things by returning the results of the block
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
#Log the bot out of jabber and kill the thread that is listening for
|
104
|
+
#messages.
|
105
|
+
#
|
106
|
+
def logout
|
107
|
+
@client.close
|
108
|
+
@thread.stop
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
#Given the text of a message, determines if that text matches any of the
|
113
|
+
#actions defined for this Bot.
|
114
|
+
#=== Parameters
|
115
|
+
#- *text*: String. The text of the message to check for matches.
|
116
|
+
#=== Returns
|
117
|
+
#Hash[:action_name, :message]
|
118
|
+
#Where :action_name corresponds to the name of the action this text
|
119
|
+
#matches, and :message corresponds to everything in +text+ after the match.
|
120
|
+
#Returns +nil+ if no match was found.
|
121
|
+
#
|
122
|
+
def match(text)
|
123
|
+
nil
|
124
|
+
# defaulting to no match until this method is implemented
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
#Checks a given username to see if it is explicitly allowed or blocked.
|
129
|
+
#=== Parameters
|
130
|
+
#- *username*: String. The username to check privileges for.
|
131
|
+
#=== Returns
|
132
|
+
#+boolean+ - the value of this boolean depends on the level of privileges
|
133
|
+
#set when the Bot was configured. If an allow_list is defined, then that
|
134
|
+
#list has highest precedence - +true+ is returned if the user is in that
|
135
|
+
#list, and +false+ is returned otherwise. If allow_list is not defined,
|
136
|
+
#but block_list is, then the inverse check is performed (+true+ is
|
137
|
+
#returned when the user is absent from the block_list, and vice-versa).
|
138
|
+
#If neither list is defined then the user is assumed to be authorized.
|
139
|
+
#
|
140
|
+
def is_user_allowed?(username)
|
141
|
+
return @allow_list.member?(username) if @allow_list
|
142
|
+
return !@block_list.member?(username) if @block_list
|
143
|
+
return true
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# Adds an action to the bot.
|
148
|
+
#=== Parameters:
|
149
|
+
#- *match*: String. The text to match for this action.
|
150
|
+
#- *block*: Proc. The code to execute when this action is fired.
|
151
|
+
#
|
152
|
+
def add_action(match, block)
|
153
|
+
@actions[match] = block
|
154
|
+
end
|
155
|
+
|
156
|
+
##
|
157
|
+
# Allows for appending to the allow_list.
|
158
|
+
#=== Parameters:
|
159
|
+
#- *list*: Array[String]. The list of users to add to the allow_list.
|
160
|
+
#
|
161
|
+
def add_allow_list(list)
|
162
|
+
@allow_list ||= []
|
163
|
+
@allow_list += list
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Allows for appending to the block_list.
|
168
|
+
#=== Parameters:
|
169
|
+
#- *list*: Array[String]. The list of users to add to the block_list.
|
170
|
+
#
|
171
|
+
def add_block_list(list)
|
172
|
+
@block_list ||= []
|
173
|
+
@block_list += list
|
174
|
+
end
|
175
|
+
end # Bot
|
176
|
+
end # Aide
|
data/lib/aide/dsl.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
module Aide
|
2
|
+
##
|
3
|
+
#The Dsl class is used for parsing Aide dsl files. All of the functions made
|
4
|
+
#available by this class are available to any dsl file.
|
5
|
+
#TODO: This class needs better documentation.
|
6
|
+
#
|
7
|
+
class Dsl
|
8
|
+
##
|
9
|
+
# Creates a new Dsl instance.
|
10
|
+
#=== Parameters:
|
11
|
+
#- *bot*: Aide::Bot. The bot this dsl will modify/set up.
|
12
|
+
#- *filename*: String. The file to parse, if any; defaults to nil.
|
13
|
+
#=== Yields:
|
14
|
+
#Yields self after the file is parsed.
|
15
|
+
#
|
16
|
+
def initialize(bot, filename = nil)
|
17
|
+
@bot = bot
|
18
|
+
load_file filename if filename
|
19
|
+
yield self if block_given?
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Sets the username for the Bot that is being loaded.
|
24
|
+
#
|
25
|
+
def bot_username(text)
|
26
|
+
@bot.username=text
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Sets the password for the Bot that is being loaded.
|
31
|
+
#
|
32
|
+
def bot_password(text)
|
33
|
+
@bot.password=text
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Adds *people to the allow_list.
|
38
|
+
#
|
39
|
+
def allow(*people)
|
40
|
+
@bot.add_allow_list people
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Adds *people to the block_list.
|
45
|
+
#
|
46
|
+
def block(*people)
|
47
|
+
@bot.add_block_list people
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Defines an action for the bot.
|
52
|
+
#===Parameters:
|
53
|
+
#- *text*: String. The text to match on.
|
54
|
+
#- *&block*: Block. The code to execute when *text* is found (see Aide::ActionContext)
|
55
|
+
#
|
56
|
+
def with(text,&block)
|
57
|
+
@bot.add_action text, block
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Reads in and parses a Dsl file.
|
62
|
+
#
|
63
|
+
def load_file(filename)
|
64
|
+
instance_eval(File.read(filename), filename)
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Parses a block as though it were a Dsl file.
|
69
|
+
#
|
70
|
+
def load_block(&block)
|
71
|
+
instance_eval(&block)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/aide/errors.rb
ADDED
data/lib/aide/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: codebrulee-aide
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tommy Morgan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-06-09 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: xmpp4r
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.3.0
|
23
|
+
version:
|
24
|
+
description: Aide provides a DSL for quickly and easily building Jabber (XMPP) bots.
|
25
|
+
email: tommy.morgan@gmail.com
|
26
|
+
executables:
|
27
|
+
- aide
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- README
|
34
|
+
- bin/aide
|
35
|
+
- lib/aide.rb
|
36
|
+
- lib/aide/actioncontext.rb
|
37
|
+
- lib/aide/bot.rb
|
38
|
+
- lib/aide/dsl.rb
|
39
|
+
- lib/aide/errors.rb
|
40
|
+
- lib/aide/version.rb
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://github.com/duwanis/aide
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options:
|
45
|
+
- --main
|
46
|
+
- README
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
requirements: []
|
62
|
+
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 1.0.1
|
65
|
+
signing_key:
|
66
|
+
specification_version: 2
|
67
|
+
summary: A DSL for defining and running Jabber bots.
|
68
|
+
test_files: []
|
69
|
+
|