campfire-bot_alexchee 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +11 -0
- data/.gitignore +6 -0
- data/Gemfile +12 -0
- data/README.textile +62 -0
- data/TODO +72 -0
- data/bin/campfire-bot +59 -0
- data/campfire-bot.gemspec +24 -0
- data/cfbot-stop.sh +8 -0
- data/config.example.yml +32 -0
- data/lib/bot.rb +194 -0
- data/lib/event.rb +114 -0
- data/lib/message.rb +30 -0
- data/lib/plugin.rb +77 -0
- data/lib/version.rb +3 -0
- data/plugins-example/fun.rb +95 -0
- data/spec/command_spec.rb +96 -0
- data/spec/plugin_spec.rb +43 -0
- data/spec/spec.opts +1 -0
- data/tmp/.gitignore +0 -0
- data/vendor/escape/ChangeLog +30 -0
- data/vendor/escape/Makefile +5 -0
- data/vendor/escape/README +81 -0
- data/vendor/escape/VERSION +1 -0
- data/vendor/escape/escape.rb +302 -0
- data/vendor/escape/install.rb +109 -0
- data/vendor/escape/misc/README.erb +85 -0
- data/vendor/escape/rdoc/classes/Escape/HTMLAttrValue.html +113 -0
- data/vendor/escape/rdoc/classes/Escape/HTMLEscaped.html +113 -0
- data/vendor/escape/rdoc/classes/Escape/PercentEncoded.html +113 -0
- data/vendor/escape/rdoc/classes/Escape/ShellEscaped.html +113 -0
- data/vendor/escape/rdoc/classes/Escape/StringWrapper.html +242 -0
- data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000029.html +18 -0
- data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000030.html +18 -0
- data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000031.html +18 -0
- data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000032.html +18 -0
- data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000033.html +18 -0
- data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000035.html +18 -0
- data/vendor/escape/rdoc/classes/Escape.html +427 -0
- data/vendor/escape/rdoc/classes/Escape.src/M000022.html +19 -0
- data/vendor/escape/rdoc/classes/Escape.src/M000023.html +32 -0
- data/vendor/escape/rdoc/classes/Escape.src/M000024.html +24 -0
- data/vendor/escape/rdoc/classes/Escape.src/M000025.html +19 -0
- data/vendor/escape/rdoc/classes/Escape.src/M000026.html +48 -0
- data/vendor/escape/rdoc/classes/Escape.src/M000027.html +19 -0
- data/vendor/escape/rdoc/classes/Escape.src/M000028.html +19 -0
- data/vendor/escape/rdoc/classes/TestEscapeHTML.html +182 -0
- data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000008.html +18 -0
- data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000009.html +18 -0
- data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000010.html +18 -0
- data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000011.html +18 -0
- data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.html +182 -0
- data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000012.html +18 -0
- data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000013.html +19 -0
- data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000014.html +20 -0
- data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000015.html +22 -0
- data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.html +167 -0
- data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000016.html +18 -0
- data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000017.html +20 -0
- data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000018.html +20 -0
- data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.html +167 -0
- data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000019.html +20 -0
- data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000020.html +24 -0
- data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000021.html +22 -0
- data/vendor/escape/rdoc/files/escape_rb.html +136 -0
- data/vendor/escape/rdoc/files/install_rb.html +250 -0
- data/vendor/escape/rdoc/files/install_rb.src/M000001.html +23 -0
- data/vendor/escape/rdoc/files/install_rb.src/M000002.html +31 -0
- data/vendor/escape/rdoc/files/install_rb.src/M000003.html +27 -0
- data/vendor/escape/rdoc/files/install_rb.src/M000004.html +27 -0
- data/vendor/escape/rdoc/files/install_rb.src/M000005.html +21 -0
- data/vendor/escape/rdoc/files/install_rb.src/M000006.html +23 -0
- data/vendor/escape/rdoc/files/install_rb.src/M000007.html +21 -0
- data/vendor/escape/rdoc/files/test/test-escape_rb.html +109 -0
- data/vendor/escape/rdoc/fr_class_index.html +36 -0
- data/vendor/escape/rdoc/fr_file_index.html +29 -0
- data/vendor/escape/rdoc/fr_method_index.html +61 -0
- data/vendor/escape/rdoc/index.html +24 -0
- data/vendor/escape/rdoc/rdoc-style.css +208 -0
- data/vendor/escape/test/test-escape.rb +90 -0
- metadata +209 -0
data/lib/plugin.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
module CampfireBot
|
2
|
+
class Plugin
|
3
|
+
@registered_plugins = {}
|
4
|
+
|
5
|
+
@registered_commands = []
|
6
|
+
@registered_messages = []
|
7
|
+
@registered_speakers = []
|
8
|
+
@registered_intervals = []
|
9
|
+
@registered_times = []
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_reader :registered_plugins,
|
13
|
+
:registered_commands,
|
14
|
+
:registered_messages,
|
15
|
+
:registered_speakers,
|
16
|
+
:registered_intervals,
|
17
|
+
:registered_times
|
18
|
+
|
19
|
+
@@config_defaults = {}
|
20
|
+
|
21
|
+
# Registering plugins
|
22
|
+
|
23
|
+
def inherited(child)
|
24
|
+
Plugin.registered_plugins[child.to_s] = child
|
25
|
+
end
|
26
|
+
|
27
|
+
# Event handlers
|
28
|
+
|
29
|
+
def on_command(command, *methods)
|
30
|
+
methods.each do |method|
|
31
|
+
Plugin.registered_commands << Event::Command.new(command, self.to_s, method)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def on_message(regexp, *methods)
|
36
|
+
methods.each do |method|
|
37
|
+
Plugin.registered_messages << Event::Message.new(regexp, self.to_s, method)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_speaker(speaker, *methods)
|
42
|
+
methods.each do |method|
|
43
|
+
Plugin.registered_speakers << Event::Speaker.new(speaker, self.to_s, method)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def at_interval(interval, *methods)
|
48
|
+
methods.each do |method|
|
49
|
+
Plugin.registered_intervals << Event::Interval.new(interval, self.to_s, method)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def at_time(timestamp, *methods)
|
54
|
+
methods.each do |method|
|
55
|
+
Plugin.registered_times << Event::Time.new(timestamp, self.to_s, method)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Declare a plugin configuration parameter with its default value
|
60
|
+
def config_var(name, default)
|
61
|
+
attr_reader name
|
62
|
+
@@config_defaults ||= {}
|
63
|
+
@@config_defaults[self.name] ||= {}
|
64
|
+
@@config_defaults[self.name][name] = default
|
65
|
+
end
|
66
|
+
end
|
67
|
+
def initialize
|
68
|
+
# initialize attr_readers setup with config_var
|
69
|
+
config_prefix = self.class.to_s.underscore
|
70
|
+
(@@config_defaults[self.class.name] || {}).each_pair { |name, default|
|
71
|
+
instance_variable_set("@#{name.to_s}",
|
72
|
+
bot.config["#{config_prefix}_#{name.to_s}"] ||
|
73
|
+
default)
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/version.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
class Fun < CampfireBot::Plugin
|
2
|
+
on_command 'say', :say
|
3
|
+
on_message Regexp.new("^#{bot.config['nickname']},\\s+(should|can|will|shall) (i|he|she|we|they) do it\\?", Regexp::IGNORECASE), :do_or_do_not
|
4
|
+
on_message Regexp.new("^(good morning|morning|m0ink|hello|hi|hey|whassup|what's up|yo|hola|ola|'sup|sup)(,)*\\s*(#{bot.config['nickname']}).*$", Regexp::IGNORECASE), :greet
|
5
|
+
on_message /(how's it|how are|how're) (ya |you )*(going|doing|doin).*/, :howareya
|
6
|
+
on_command "blame", :blame
|
7
|
+
on_command "trout", :trout
|
8
|
+
on_command "slap", :trout
|
9
|
+
on_command "troutslap", :trout
|
10
|
+
# on_speaker 'Tim R.', :agree_with_tim
|
11
|
+
# on_message /undo it/i, :do_it
|
12
|
+
# on_message /(^|\s)do it/i, :undo_it
|
13
|
+
# at_time 1.minute.from_now, :do_it
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@last_agreed = 20.minutes.ago
|
17
|
+
@log = Logging.logger["CampfireBot::Plugin::Fun"]
|
18
|
+
end
|
19
|
+
|
20
|
+
def say(m)
|
21
|
+
m.speak(m[:message])
|
22
|
+
end
|
23
|
+
|
24
|
+
def do_it(m = nil)
|
25
|
+
m.speak('Do it!')
|
26
|
+
end
|
27
|
+
|
28
|
+
def undo_it(m)
|
29
|
+
m.speak('Undo it!')
|
30
|
+
end
|
31
|
+
|
32
|
+
def do_or_do_not(m)
|
33
|
+
responses = ['Do it!', 'Don\'t do it!', 'Undo it!']
|
34
|
+
m.speak(responses.choice)
|
35
|
+
end
|
36
|
+
|
37
|
+
def agree_with_tim(m)
|
38
|
+
m.speak('I agree with Tim.') unless @last_agreed > 15.minutes.ago
|
39
|
+
@last_agreed = Time.now
|
40
|
+
end
|
41
|
+
|
42
|
+
def greet(m)
|
43
|
+
messages = ['Howdy', 'Wassup', 'Greets', 'Hello', 'Hey there', "It's a", 'Good day']
|
44
|
+
m.speak("#{messages.choice} #{m[:person].split(' ')[0]}")
|
45
|
+
end
|
46
|
+
|
47
|
+
def howareya(m)
|
48
|
+
messages = ["just great", "peachy", "mas o menos",
|
49
|
+
"you know how it is", "eh, ok", "pretty good. how about you?"]
|
50
|
+
m.speak(messages[rand(messages.size)])
|
51
|
+
end
|
52
|
+
|
53
|
+
def blame(m)
|
54
|
+
# TODO: capture user-submitted entries to a yaml file and regurgitate them
|
55
|
+
# TODO: put all the default ones in a separate yaml
|
56
|
+
if m[:message].strip.length > 0
|
57
|
+
blamed = m[:message].strip
|
58
|
+
else
|
59
|
+
users = m[:room].users.delete_if {|u| u[:name] == bot.campfire.me[:name]}.map {|u| u[:name]}
|
60
|
+
others = ["nobody", "my", "Microsoft", "Steve Jobs", "the terrorists", "your",
|
61
|
+
"Project Management", "Development", "Management", "Corporate", "Cartman", "the user",
|
62
|
+
"the liberal media", "Wall Street"]
|
63
|
+
|
64
|
+
# mostly blame the other users
|
65
|
+
if rand(10) >= 2
|
66
|
+
blamed = users.choice
|
67
|
+
else
|
68
|
+
blamed = others.choice
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
case blamed
|
74
|
+
when "nobody"
|
75
|
+
blamestring = "It's nobody's fault"
|
76
|
+
when "your", "my"
|
77
|
+
blamestring = "It's all #{blamed} fault"
|
78
|
+
else
|
79
|
+
blamestring = "It's all #{blamed}'s fault"
|
80
|
+
blamestring = "It's all #{blamed}' fault" if blamed[-1].chr == "s"
|
81
|
+
end
|
82
|
+
|
83
|
+
m.speak blamestring
|
84
|
+
end
|
85
|
+
|
86
|
+
def trout(m)
|
87
|
+
if m[:message].strip.length > 0
|
88
|
+
selected_user_name = m[:message].strip
|
89
|
+
else
|
90
|
+
users = m[:room].users.map{|u| u[:name] }
|
91
|
+
selected_user_name = users.choice
|
92
|
+
end
|
93
|
+
m.speak("#{m[:person]} slaps #{selected_user_name} #{["upside the head", "in the face", "on the rear", "where it counts", "in the knees", "ineffectually", "in the elbow", "on the funny bone", "in the ear", "on the nose", "in the teeth"].choice} with a #{%w(good-sized large decaying moldy spiked sabre-toothed surprised disappointed dramatic enraged rabid bug-eyed rotten foul-smelling demonic cluestick-holding).choice} trout")
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
BOT_ROOT = File.join(File.dirname(__FILE__), '..')
|
3
|
+
BOT_ENVIRONMENT = 'development'
|
4
|
+
|
5
|
+
require File.join(File.dirname(__FILE__), '../lib/bot.rb')
|
6
|
+
bot = CampfireBot::Bot.instance
|
7
|
+
require "#{BOT_ROOT}/lib/event.rb"
|
8
|
+
|
9
|
+
|
10
|
+
class TestingCommand < CampfireBot::Event::Command
|
11
|
+
|
12
|
+
def filter_message(msg)
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "processing messages" do
|
18
|
+
|
19
|
+
before(:all) do
|
20
|
+
bot = CampfireBot::Bot.instance
|
21
|
+
@nickname = bot.config['nickname']
|
22
|
+
end
|
23
|
+
|
24
|
+
before(:each) do
|
25
|
+
@command = TestingCommand.new("command", nil, nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
def match?(msg)
|
29
|
+
@command.match?({:message => msg})
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "and recognizing a command" do
|
33
|
+
|
34
|
+
it "should handle a !command" do
|
35
|
+
match?("!command").should be_true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should handle a !command with arguments" do
|
39
|
+
match?("!command foo").should be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should handle a command with nickname and a comma" do
|
43
|
+
match?("#{@nickname}, command").should be_true
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should handle a command with nickname and a colon" do
|
47
|
+
match?("#{@nickname}: command").should be_true
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should handle a command with nickname and arguments" do
|
51
|
+
match?("#{@nickname}, command foo").should be_true
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should ignore a non-matching !command" do
|
55
|
+
match?("!foo").should be_false
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should ignore an addressed non-command" do
|
59
|
+
match?("#{@nickname}, nothing").should be_false
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should ignore things that aren't commands at all" do
|
63
|
+
["nothing", "#{@nickname}, ", " ! command", "hey #{@nickname}", "!command!command", "!command,command"].each do |t|
|
64
|
+
match?(t).should be_false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "and filtering it" do
|
70
|
+
|
71
|
+
def filter(msg)
|
72
|
+
@command.filter_message({:message => msg})[:message]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should be empty with no arguments" do
|
76
|
+
filter("!command").should == ""
|
77
|
+
filter("#{@nickname}, command").should == ""
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return one argument" do
|
81
|
+
filter("!command foo").should == "foo"
|
82
|
+
filter("#{@nickname}, command foo").should == "foo"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return more than one argument" do
|
86
|
+
filter("!command foo bar baz").should == "foo bar baz"
|
87
|
+
filter("#{@nickname}, command foo bar baz").should == "foo bar baz"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should deal with some weirdness" do
|
91
|
+
filter("!command !command").should == "!command"
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
data/spec/plugin_spec.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
BOT_ROOT = File.join(File.dirname(__FILE__), '..')
|
3
|
+
BOT_ENVIRONMENT = 'test'
|
4
|
+
|
5
|
+
require File.join(File.dirname(__FILE__), '../lib/bot.rb')
|
6
|
+
bot = CampfireBot::Bot.instance
|
7
|
+
|
8
|
+
describe "config_var method" do
|
9
|
+
class ExamplePlugin < CampfireBot::Plugin
|
10
|
+
config_var :foo, "default foo"
|
11
|
+
end
|
12
|
+
|
13
|
+
def setup_plugin(klass, config={})
|
14
|
+
@bot = CampfireBot::Bot.instance
|
15
|
+
@bot.stub!(:config).and_return({'nickname' => 'Bot'}.merge(config))
|
16
|
+
@plugin = klass.new
|
17
|
+
CampfireBot::Plugin.registered_plugins[klass.to_s] = @plugin
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should setup default bug_url value" do
|
21
|
+
setup_plugin ExamplePlugin
|
22
|
+
@plugin.foo.should == "default foo"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should allow override of parameter via configuration" do
|
26
|
+
setup_plugin ExamplePlugin, 'example_plugin_foo' => 'bar'
|
27
|
+
@plugin.foo.should == "bar"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should keep defaults for two classes separate" do
|
31
|
+
class ExamplePlugin2 < CampfireBot::Plugin
|
32
|
+
config_var :bar, "default bar"
|
33
|
+
end
|
34
|
+
setup_plugin ExamplePlugin
|
35
|
+
plugin = @plugin
|
36
|
+
setup_plugin ExamplePlugin2
|
37
|
+
plugin.instance_variable_get(:@foo).should == "default foo"
|
38
|
+
@plugin.instance_variable_get(:@bar).should == "default bar"
|
39
|
+
# Used to fail with value "default bar"
|
40
|
+
plugin.instance_variable_get(:@bar).should == nil
|
41
|
+
@plugin.instance_variable_get(:@foo).should == nil
|
42
|
+
end
|
43
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/tmp/.gitignore
ADDED
File without changes
|
@@ -0,0 +1,30 @@
|
|
1
|
+
2007-02-28 Tanaka Akira <akr@fsij.org>
|
2
|
+
|
3
|
+
* escape.rb: Escape::HTMLAttrValue defined.
|
4
|
+
Escape.html_attr_value returns it.
|
5
|
+
|
6
|
+
2007-02-27 Tanaka Akira <akr@fsij.org>
|
7
|
+
|
8
|
+
* escape.rb: make StringWrapper into class.
|
9
|
+
Escape::ShellEscaped, Escape::HTMLEscaped and Escape::PercentEncoded
|
10
|
+
inherit it.
|
11
|
+
|
12
|
+
2007-02-26 Tanaka Akira <akr@fsij.org>
|
13
|
+
|
14
|
+
* escape.rb: Escape::ShellEscaped defined.
|
15
|
+
Escape.shell_command and Escape.shell_single_word returns
|
16
|
+
Escape::ShellEscaped object instead of a string.
|
17
|
+
|
18
|
+
* escape.rb: Escape::HTMLEscaped defined.
|
19
|
+
Escape.html_text and Escape.html_attr_value returns
|
20
|
+
Escape::HTMLEscaped object instead of a string.
|
21
|
+
|
22
|
+
* escape.rb: Escape::PercentEncoded defined.
|
23
|
+
Escape.uri_segment, Escape.uri_path and Escape.html_form returns
|
24
|
+
Escape::PercentEncoded object instead of a string.
|
25
|
+
|
26
|
+
* escape.rb: rename Escape.html_attr to Escape.html_attr_value.
|
27
|
+
|
28
|
+
2007-01-05 Tanaka Akira <akr@fsij.org>
|
29
|
+
|
30
|
+
* version 0.1 released.
|
@@ -0,0 +1,81 @@
|
|
1
|
+
= escape - HTML/URI/shell escaping utilities
|
2
|
+
|
3
|
+
|
4
|
+
escape library provides several HTML/URI/shell escaping functions.
|
5
|
+
|
6
|
+
== Author
|
7
|
+
|
8
|
+
Tanaka Akira <akr@fsij.org>
|
9
|
+
|
10
|
+
== Home Page
|
11
|
+
|
12
|
+
((<URL:http://www.a-k-r.org/escape/>))
|
13
|
+
|
14
|
+
== Feature
|
15
|
+
|
16
|
+
* several escaping/composing functions
|
17
|
+
* HTML text
|
18
|
+
* HTML attribute value
|
19
|
+
* HTML form (x-www-form-urlencoded)
|
20
|
+
* URI path
|
21
|
+
* shell command line
|
22
|
+
* dedicated classes for escaped strings
|
23
|
+
* escape and compose strongly related strings at once
|
24
|
+
|
25
|
+
== Usage
|
26
|
+
|
27
|
+
require 'escape'
|
28
|
+
|
29
|
+
Escape.shell_command(["echo", "*"]) #=> #<Escape::ShellEscaped: echo '*'>
|
30
|
+
Escape.uri_path("a?b/c?d/e?f") #=> #<Escape::PercentEncoded: a%3Fb/c%3Fd/e%3Ff>
|
31
|
+
Escape.html_form([["a","b"], ["c","d"]]) #=> #<Escape::PercentEncoded: a=b&c=d>
|
32
|
+
Escape.html_form({"a"=>"b", "c"=>"d"}) #=> #<Escape::PercentEncoded: a=b&c=d>
|
33
|
+
Escape.html_text("a & b < c > d") #=> #<Escape::HTMLEscaped: a & b < c > d>
|
34
|
+
Escape.html_attr_value("ab&<>\"c") #=> #<Escape::HTMLAttrValue: "ab&<>"c">
|
35
|
+
|
36
|
+
== Requirements
|
37
|
+
|
38
|
+
* ruby : http://www.ruby-lang.org/
|
39
|
+
|
40
|
+
== Download
|
41
|
+
|
42
|
+
* latest release: ((<escape-0.2.tar.gz|URL:escape-0.2.tar.gz>))
|
43
|
+
|
44
|
+
* development version in Subversion repository:
|
45
|
+
|
46
|
+
% svn co svn://svn@svn.a-k-r.org/akr/escape/trunk escape
|
47
|
+
|
48
|
+
== Install
|
49
|
+
|
50
|
+
% ruby install.rb
|
51
|
+
|
52
|
+
== Reference Manual
|
53
|
+
|
54
|
+
See rdoc/classes/Escape.html or
|
55
|
+
((<URL:http://www.a-k-r.org/escape/rdoc/classes/Escape.html>))
|
56
|
+
|
57
|
+
== License
|
58
|
+
|
59
|
+
The modified BSD licence
|
60
|
+
|
61
|
+
Redistribution and use in source and binary forms, with or without
|
62
|
+
modification, are permitted provided that the following conditions are met:
|
63
|
+
|
64
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
65
|
+
list of conditions and the following disclaimer.
|
66
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
67
|
+
this list of conditions and the following disclaimer in the documentation
|
68
|
+
and/or other materials provided with the distribution.
|
69
|
+
3. The name of the author may not be used to endorse or promote products
|
70
|
+
derived from this software without specific prior written permission.
|
71
|
+
|
72
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
73
|
+
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
74
|
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
75
|
+
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
76
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
77
|
+
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
78
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
79
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
80
|
+
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
81
|
+
OF SUCH DAMAGE.
|
@@ -0,0 +1 @@
|
|
1
|
+
0.2
|