comboy-autumn 3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/README.textile +1192 -0
  2. data/autumn.gemspec +25 -0
  3. data/bin/autumn +27 -0
  4. data/lib/autumn.rb +2 -0
  5. data/lib/autumn/authentication.rb +290 -0
  6. data/lib/autumn/channel_leaf.rb +107 -0
  7. data/lib/autumn/coder.rb +166 -0
  8. data/lib/autumn/console_boot.rb +9 -0
  9. data/lib/autumn/ctcp.rb +250 -0
  10. data/lib/autumn/daemon.rb +207 -0
  11. data/lib/autumn/datamapper_hacks.rb +290 -0
  12. data/lib/autumn/foliater.rb +231 -0
  13. data/lib/autumn/formatting.rb +236 -0
  14. data/lib/autumn/generator.rb +231 -0
  15. data/lib/autumn/genesis.rb +191 -0
  16. data/lib/autumn/inheritable_attributes.rb +162 -0
  17. data/lib/autumn/leaf.rb +738 -0
  18. data/lib/autumn/log_facade.rb +49 -0
  19. data/lib/autumn/misc.rb +87 -0
  20. data/lib/autumn/script.rb +74 -0
  21. data/lib/autumn/speciator.rb +165 -0
  22. data/lib/autumn/stem.rb +919 -0
  23. data/lib/autumn/stem_facade.rb +176 -0
  24. data/resources/daemons/Anothernet.yml +3 -0
  25. data/resources/daemons/AustHex.yml +29 -0
  26. data/resources/daemons/Bahamut.yml +67 -0
  27. data/resources/daemons/Dancer.yml +3 -0
  28. data/resources/daemons/GameSurge.yml +3 -0
  29. data/resources/daemons/IRCnet.yml +3 -0
  30. data/resources/daemons/Ithildin.yml +7 -0
  31. data/resources/daemons/KineIRCd.yml +56 -0
  32. data/resources/daemons/PTlink.yml +6 -0
  33. data/resources/daemons/QuakeNet.yml +20 -0
  34. data/resources/daemons/RFC1459.yml +158 -0
  35. data/resources/daemons/RFC2811.yml +16 -0
  36. data/resources/daemons/RFC2812.yml +36 -0
  37. data/resources/daemons/RatBox.yml +25 -0
  38. data/resources/daemons/Ultimate.yml +24 -0
  39. data/resources/daemons/Undernet.yml +6 -0
  40. data/resources/daemons/Unreal.yml +110 -0
  41. data/resources/daemons/_Other.yml +7 -0
  42. data/resources/daemons/aircd.yml +33 -0
  43. data/resources/daemons/bdq-ircd.yml +3 -0
  44. data/resources/daemons/hybrid.yml +38 -0
  45. data/resources/daemons/ircu.yml +67 -0
  46. data/resources/daemons/tr-ircd.yml +8 -0
  47. data/skel/Rakefile +135 -0
  48. data/skel/config/global.yml +2 -0
  49. data/skel/config/seasons/testing/database.yml +7 -0
  50. data/skel/config/seasons/testing/leaves.yml +7 -0
  51. data/skel/config/seasons/testing/season.yml +2 -0
  52. data/skel/config/seasons/testing/stems.yml +9 -0
  53. data/skel/leaves/administrator/README +20 -0
  54. data/skel/leaves/administrator/controller.rb +67 -0
  55. data/skel/leaves/administrator/views/autumn.txt.erb +1 -0
  56. data/skel/leaves/administrator/views/reload.txt.erb +11 -0
  57. data/skel/leaves/insulter/README +17 -0
  58. data/skel/leaves/insulter/controller.rb +65 -0
  59. data/skel/leaves/insulter/views/about.txt.erb +1 -0
  60. data/skel/leaves/insulter/views/help.txt.erb +1 -0
  61. data/skel/leaves/insulter/views/insult.txt.erb +1 -0
  62. data/skel/leaves/scorekeeper/README +34 -0
  63. data/skel/leaves/scorekeeper/config.yml +2 -0
  64. data/skel/leaves/scorekeeper/controller.rb +104 -0
  65. data/skel/leaves/scorekeeper/helpers/general.rb +64 -0
  66. data/skel/leaves/scorekeeper/models/channel.rb +12 -0
  67. data/skel/leaves/scorekeeper/models/person.rb +14 -0
  68. data/skel/leaves/scorekeeper/models/pseudonym.rb +11 -0
  69. data/skel/leaves/scorekeeper/models/score.rb +14 -0
  70. data/skel/leaves/scorekeeper/tasks/stats.rake +17 -0
  71. data/skel/leaves/scorekeeper/views/about.txt.erb +1 -0
  72. data/skel/leaves/scorekeeper/views/change.txt.erb +5 -0
  73. data/skel/leaves/scorekeeper/views/history.txt.erb +11 -0
  74. data/skel/leaves/scorekeeper/views/points.txt.erb +5 -0
  75. data/skel/leaves/scorekeeper/views/usage.txt.erb +1 -0
  76. data/skel/script/console +34 -0
  77. data/skel/script/daemon +29 -0
  78. data/skel/script/destroy +48 -0
  79. data/skel/script/generate +48 -0
  80. data/skel/script/server +15 -0
  81. metadata +170 -0
@@ -0,0 +1,2 @@
1
+ ---
2
+ season: testing
@@ -0,0 +1,7 @@
1
+ ---
2
+ Example:
3
+ username: root
4
+ adapter: mysql
5
+ host: localhost
6
+ database: example_database
7
+ password: ""
@@ -0,0 +1,7 @@
1
+ ---
2
+ Administrator:
3
+ authentication:
4
+ type: op
5
+ class: Administrator
6
+ Insulter:
7
+ class: Insulter
@@ -0,0 +1,2 @@
1
+ ---
2
+ logging: debug
@@ -0,0 +1,9 @@
1
+ ---
2
+ Example:
3
+ nick: MyIRCBot
4
+ leaves:
5
+ - Administrator
6
+ - Insulter
7
+ rejoin: true
8
+ channel: "#yourchannel"
9
+ server: irc.yourircserver.com
@@ -0,0 +1,20 @@
1
+ = Administrator: An Autumn Leaf
2
+
3
+ <b>Version 1.0 (Jul 8, 2008)</b>
4
+
5
+ Author:: Tim Morgan (mailto:riscfuture@gmail.com)
6
+ Copyright:: Copyright (c)2008 Tim Morgan
7
+ License:: Distributed under the same terms as Ruby.
8
+
9
+ This leaf allows the owner of the IRC bot to perform administrative commands on
10
+ the bot, such as quitting or reloading it. In order to protect such commands
11
+ from abuse, this bot uses the Authenticator module. The Authenticator method
12
+ that is used is specified by the +authentication+ option. For more information,
13
+ see the *Authentication* section of the README.
14
+
15
+ == Usage
16
+
17
+ !autumn:: Displays information about the version of Autumn that is running this
18
+ leaf (unprotected command).
19
+ !quit:: Terminates the stem on which the message was received.
20
+ !reload:: Reloads all source files of all leaves, and all their view files.
@@ -0,0 +1,67 @@
1
+ # Controller for the Administrator leaf.
2
+
3
+ class Controller < Autumn::Leaf
4
+
5
+ # Typing this command reloads all source code for all leaves and support
6
+ # files, allowing you to make "on-the-fly" changes without restarting the
7
+ # process. It does this by reloading the source files defining the classes.
8
+ #
9
+ # If you supply the configuration name of a leaf, only that leaf is reloaded.
10
+ #
11
+ # This command does not reload the YAML configuration files, only the source
12
+ # code.
13
+
14
+ def reload_command(stem, sender, reply_to, msg)
15
+ var :leaves => Hash.new
16
+ if msg then
17
+ if Foliater.instance.leaves.include?(msg) then
18
+ begin
19
+ Foliater.instance.hot_reload Foliater.instance.leaves[msg]
20
+ rescue
21
+ logger.error "Error when reloading #{msg}:"
22
+ logger.error $!
23
+ var(:leaves)[msg] = $!.to_s
24
+ else
25
+ var(:leaves)[msg] = false
26
+ end
27
+ logger.info "#{msg}: Reloaded"
28
+ else
29
+ var :not_found => msg
30
+ end
31
+ else
32
+ Foliater.instance.leaves.each do |name, leaf|
33
+ begin
34
+ Foliater.instance.hot_reload leaf
35
+ rescue
36
+ logger.error "Error when reloading #{name}:"
37
+ logger.error $!
38
+ var(:leaves)[name] = $!.to_s
39
+ else
40
+ var(:leaves)[name] = false
41
+ end
42
+ logger.info "#{name}: Reloaded"
43
+ end
44
+ end
45
+ end
46
+ ann :reload_command, :protected => true
47
+
48
+ # Typing this command will cause the Stem to exit.
49
+
50
+ def quit_command(stem, sender, reply_to, msg)
51
+ stem.quit
52
+ end
53
+ ann :quit_command, :protected => true
54
+
55
+ # Typing this command will display information about the version of Autumn
56
+ # that is running this leaf.
57
+
58
+ def autumn_command(stem, sender, reply_to, msg)
59
+ var :version => AUTUMN_VERSION
60
+ end
61
+
62
+ # Suppress the !commands command; don't want to publicize the administrative
63
+ # features.
64
+
65
+ def commands_command(stem, sender, reply_to, msg)
66
+ end
67
+ end
@@ -0,0 +1 @@
1
+ Autumn version <%= var :version %>, an IRC bot framework for Ruby (http://github.com/RISCfuture/autumn).
@@ -0,0 +1,11 @@
1
+ <% if var(:not_found) %>
2
+ There is no leaf named <%= var :not_found %>.
3
+ <% else %>
4
+ <% var(:leaves).each do |leaf, error| %>
5
+ <% if error %>
6
+ <%= leaf %> couldn't be reloaded: <%= error %>
7
+ <% else %>
8
+ <%= leaf %> was reloaded successfully.
9
+ <% end %>
10
+ <% end %>
11
+ <% end %>
@@ -0,0 +1,17 @@
1
+ = Insulter: An Autumn Leaf
2
+
3
+ <b>Version 1.0 (Jul 4, 2008)</b>
4
+
5
+ Author:: Tim Morgan (mailto:riscfuture@gmail.com)
6
+ Copyright:: Copyright (c)2008 Tim Morgan
7
+ License:: Distributed under the same terms as Ruby. Portions of this content
8
+ are copyright (c)1996 Main Strike Telecommunications, Inc.
9
+
10
+ A simple Autumn Leaf that generates faux-Shakespearean insults. This leaf
11
+ required no database and no additional gems beyond that of a normal Autumn
12
+ install.
13
+
14
+ == Usage
15
+
16
+ !insult [name]:: The bot lets fly a barbarous insult against [name], whose very
17
+ spirit will thenceforth be crushed into a negligible pulp.
@@ -0,0 +1,65 @@
1
+ # Controller and model for the Insulter leaf; maintains the list of insult
2
+ # substrings and chooses from them randomly.
3
+
4
+ class Controller < Autumn::Leaf
5
+
6
+ # Insults the unfortunate argument of this command.
7
+
8
+ def insult_command(stem, sender, reply_to, msg)
9
+ if msg.nil? then render :help
10
+ else insult msg.capitalize end
11
+ end
12
+
13
+ # Displays information about the leaf.
14
+
15
+ def about_command(stem, sender, reply_to, msg)
16
+ end
17
+
18
+ private
19
+
20
+ ADJECTIVES = [
21
+ 'an artless', 'a bawdy', 'a beslubbering', 'a bootless', 'a churlish',
22
+ 'a clouted', 'a cockered', 'a craven', 'a currish', 'a dankish',
23
+ 'a dissembling', 'a droning', 'an errant', 'a fawning', 'a fobbing',
24
+ 'a frothy', 'a froward', 'a gleeking', 'a goatish', 'a gorbellied',
25
+ 'an impertinent', 'an infectious', 'a jarring', 'a loggerheaded',
26
+ 'a lumpish', 'a mammering', 'a mangled', 'a mewling', 'a paunchy',
27
+ 'a pribbling', 'a puking', 'a puny', 'a qualling', 'a rank', 'a reeky',
28
+ 'a roguish', 'a ruttish', 'a saucy', 'a spleeny', 'a spongy', 'a surly',
29
+ 'a tottering', 'an unmuzzled', 'a vain', 'a venomed', 'a villainous',
30
+ 'a warped', 'a wayward', 'a weedy', 'a yeasty'
31
+ ]
32
+
33
+ PARTICIPLES = [
34
+ 'base-court', 'bat-fowling', 'beef-witted', 'beetle-headed', 'boil-brained',
35
+ 'clapper-clawed', 'clay-brained', 'common-kissing', 'crook-pated',
36
+ 'dismal-dreaming', 'dizzy-eyed', 'doghearted', 'dread-bolted',
37
+ 'earth-vexing', 'elf-skinned', 'fat-kidneyed', 'fen-sucked', 'flap-mouthed',
38
+ 'fly-bitten', 'folly-fallen', 'fool-born', 'full-gorged', 'guts-griping',
39
+ 'half-faced', 'hasty-witted', 'hedge-born', 'hell-hated', 'idle-headed',
40
+ 'ill-breeding', 'ill-nurtured', 'knotty-pated', 'milk-livered',
41
+ 'motley-minded', 'onion-eyed', 'plume-plucked', 'pottle-deep', 'pox-marked',
42
+ 'reeling-ripe', 'rough-hewn', 'rude-growing', 'rump-fed', 'shard-borne',
43
+ 'sheep-biting', 'spur-galled', 'swag-bellied', 'tardy-gaited',
44
+ 'tickle-brained', 'toad-spotted', 'urchin-snouted', 'weather-bitten'
45
+ ]
46
+
47
+ NOUNS = [
48
+ 'apple-john', 'baggage', 'barnacle', 'bladder', 'boar-pig', 'bugbear',
49
+ 'bum-bailey', 'canker-blossom', 'clack-dish', 'clotpole', 'codpiece',
50
+ 'coxcomb', 'death-token', 'dewberry', 'flap-dragon', 'flax-wench',
51
+ 'flirt-gill', 'foot-licker', 'fustilarian', 'giglet', 'gudgeon', 'haggard',
52
+ 'harpy', 'hedge-pig', 'horn-beast', 'hugger-mugger', 'joithead', 'lewdster',
53
+ 'lout', 'maggot-pie', 'malt-worm', 'mammet', 'measle', 'minnow',
54
+ 'miscreant', 'moldwarp', 'mumble-news', 'nut-hook', 'pigeon-egg', 'pignut',
55
+ 'pumpion', 'puttock', 'ratsbane', 'scut', 'skainsmate', 'strumpet',
56
+ 'varlet', 'vassal', 'wagtail', 'whey-face'
57
+ ]
58
+
59
+ def insult(victim)
60
+ var :adjective => ADJECTIVES.pick
61
+ var :participle => PARTICIPLES.pick
62
+ var :noun => NOUNS.pick
63
+ var :victim => victim
64
+ end
65
+ end
@@ -0,0 +1 @@
1
+ Insulter version 1.0 (7-4-08) by Tim Morgan: An Autumn Leaf. Insults copyright (c)1996 Main Strike Telecommunications, Inc.
@@ -0,0 +1 @@
1
+ Type "!insult Ted" to crush Ted's spirit with a devastating insult.
@@ -0,0 +1 @@
1
+ <%= var :victim %>, thou art <%= var :adjective %> <%= var :participle %> <%= var :noun %>!
@@ -0,0 +1,34 @@
1
+ = Scorekeeper: An Autumn Leaf
2
+
3
+ <b>Version 3.0 (Jul 4, 2008)</b>
4
+
5
+ Author:: Tim Morgan (mailto:riscfuture@gmail.com)
6
+ Copyright:: Copyright (c)2007-2008 Tim Morgan
7
+ License:: Distributed under the same terms as Ruby.
8
+
9
+ An Autumn Leaf used for an in-channel scorekeeping system. This can operate both
10
+ as an open or closed score system. (In the former, new members are automatically
11
+ added when they receive points; in the latter, only authorized members can give
12
+ and receive points.)
13
+
14
+ Scorekeeper is a database-backed leaf. It requires the DataMapper gem
15
+ (http://www.datamapper.org) in order to run. The database stores channels and
16
+ their members, and each member's point history.
17
+
18
+ Scorekeeper supports pseudonyms. Entries in the +pseudonyms+ table can be used
19
+ to help ensure that the correct person's points are changed even when the sender
20
+ uses a nickname or abbreviation.
21
+
22
+ Scorekeeper takes one custom configuration option, +scoring+, which can be
23
+ either "open" or "closed". A closed system only allows a specified set of users
24
+ to receive and give points. An open system allows anyone to award points to
25
+ anyone.
26
+
27
+ == Usage
28
+
29
+ !points [name]:: Get a person's score
30
+ !points [name] [+|-][number] [reason]:: Change a person's score (you must have a
31
+ "+" or a "-"). A reason is optional.
32
+ !points [name] history:: Return some recent history of that person's score.
33
+ !points [name] history [time period]:: Selects history from a time period.
34
+ !points [name] history [sender]:: Selects point changes from a sender.
@@ -0,0 +1,2 @@
1
+ ---
2
+ scoring: open
@@ -0,0 +1,104 @@
1
+ require 'dm-ar-finders'
2
+
3
+ begin
4
+ gem 'chronic'
5
+ require 'chronic'
6
+ rescue Gem::LoadError
7
+ # Install the "chronic" gem for more robust date parsing
8
+ end
9
+
10
+ # Controller for the Scorekeeper leaf. This class contains only the methods
11
+ # directly relating to IRC. Other methods are stored in the helper and model
12
+ # classes.
13
+
14
+ class Controller < Autumn::Leaf
15
+
16
+ # Displays an about message.
17
+
18
+ def about_command(stem, sender, reply_to, msg)
19
+ end
20
+
21
+ # Displays the current point totals, or modifies someone's score, depending on
22
+ # the message provided with the command.
23
+
24
+ def points_command(stem, sender, reply_to, msg)
25
+ if msg.nil? or msg.empty? then
26
+ var :totals => totals(stem, reply_to)
27
+ elsif msg =~ /^(\w+)\s+history\s*(.*)$/ then
28
+ parse_history stem, reply_to, $1, $2
29
+ render :history
30
+ elsif msg =~ /^(\w+)\s+([\+\-]\d+)\s*(.*)$/ then
31
+ parse_change stem, reply_to, sender, $1, $2.to_i, $3
32
+ render :change
33
+ else
34
+ render :usage
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def points(stem, channel)
41
+ chan = Channel.find_or_create :server => server_identifier(stem), :name => channel
42
+ scores = chan.scores.all
43
+ scores.inject(Hash.new(0)) { |hsh, score| hsh[score.receiver.name] += score.change; hsh }
44
+ end
45
+
46
+ def totals(stem, channel)
47
+ points(stem, channel).sort { |a,b| b.last <=> a.last }
48
+ end
49
+
50
+ def parse_change(stem, channel, sender, victim, delta, note)
51
+ giver = find_person(stem, sender[:nick])
52
+ receiver = find_person(stem, victim)
53
+ if giver.nil? and options[:scoring] == 'open' then
54
+ giver ||= Person.create :server => server_identifier(stem), :name => sender[:nick]
55
+ end
56
+ if receiver.nil? and options[:scoring] == 'open' then
57
+ receiver ||= Person.create :server => server_identifier(stem), :name => find_in_channel(stem, channel, victim)
58
+ end
59
+ unless authorized?(giver, receiver)
60
+ var :unauthorized => true
61
+ var :receiver => receiver.nil? ? victim : receiver.name
62
+ return
63
+ end
64
+ change_points stem, channel, giver, receiver, delta, note
65
+ var :giver => giver
66
+ var :receiver => receiver
67
+ var :delta => delta
68
+ end
69
+
70
+ def parse_history(stem, channel, subject, argument)
71
+ date = argument.empty? ? nil : parse_date(argument)
72
+ scores = Array.new
73
+
74
+ chan = Channel.first(:name => channel)
75
+ person = find_person(stem, subject)
76
+ if person.nil? then
77
+ var :person => subject
78
+ var :no_history => true
79
+ return
80
+ end
81
+
82
+ if date then
83
+ start, stop = find_range(date)
84
+ scores = chan.scores.all(:conditions => [ "receiver_id = ? AND created_at >= ? AND created_at < ?", person.id, start, stop ], :order => [ :created_at.desc ], :limit => 5)
85
+ #TODO is there a way to scope by both channel and receiver?
86
+ elsif argument.empty? then
87
+ scores = chan.scores.all(:conditions => [ "receiver_id = ?", person.id ], :order => [ :created_at.desc ], :limit => 5)
88
+ #TODO is there a way to scope by both channel and receiver?
89
+ else
90
+ giver = find_person(stem, argument)
91
+ if giver.nil? then
92
+ var :giver => argument
93
+ var :receiver => person
94
+ var :no_giver_history => true
95
+ return
96
+ end
97
+ scores = chan.scores.all(:conditions => [ "receiver_id = ? AND giver_id = ?", person.id, giver.id ], :order => [ :created_at.desc ], :limit => 5)
98
+ #TODO is there a way to scope by channel, receiver, and giver?
99
+ end
100
+ var :receiver => person
101
+ var :giver => giver
102
+ var :scores => scores
103
+ end
104
+ end
@@ -0,0 +1,64 @@
1
+ # Utility methods used by Scorekeeper.
2
+
3
+ module GeneralHelper
4
+ def parse_date(str)
5
+ date = nil
6
+ begin
7
+ date = Chronic.parse(str, :context => :past, :guess => false)
8
+ rescue NameError
9
+ begin
10
+ date = Date.parse(str)
11
+ rescue ArgumentError
12
+ end
13
+ end
14
+ return date
15
+ end
16
+
17
+ def find_range(date)
18
+ start = nil
19
+ stop = nil
20
+ if date.kind_of? Range then
21
+ start = date.first
22
+ stop = date.last
23
+ elsif date.kind_of? Time then
24
+ start = date.to_date
25
+ stop = date.to_date + 1
26
+ else
27
+ start = date
28
+ stop = date + 1
29
+ end
30
+ return start, stop
31
+ end
32
+
33
+ def find_person(stem, nick)
34
+ Person.all(:server => server_identifier(stem)).each do |person|
35
+ return person if person.name.downcase == normalize(nick) or person.pseudonyms.collect { |pn| pn.name.downcase }.include? normalize(nick)
36
+ end
37
+ return nil
38
+ end
39
+
40
+ def find_in_channel(stem, channel, victim)
41
+ stem.channel_members[channel].each do |name, privilege|
42
+ return normalize(name, false) if normalize(name) == normalize(victim)
43
+ end
44
+ return victim
45
+ end
46
+
47
+ def normalize(nick, dc=true)
48
+ dc ? nick.downcase.split(/\|/)[0] : nick.split(/\|/)[0]
49
+ end
50
+
51
+ def authorized?(giver, receiver)
52
+ giver and receiver and giver.authorized? and giver.name != receiver.name
53
+ end
54
+
55
+ def change_points(stem, channel, giver, receiver, delta, note=nil)
56
+ return if delta.zero?
57
+ chan = Channel.find_or_create :server => server_identifier(stem), :name => channel
58
+ chan.scores.create :giver => giver, :receiver => receiver, :change => delta, :note => note
59
+ end
60
+
61
+ def server_identifier(stem)
62
+ "#{stem.server}:#{stem.port}"
63
+ end
64
+ end