gossip 0.3.0

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.
Files changed (63) hide show
  1. data/History.txt +9 -0
  2. data/LICENSE.txt +34 -0
  3. data/Manifest.txt +62 -0
  4. data/README.txt +6 -0
  5. data/Rakefile +137 -0
  6. data/examples/all-config-file-choices.yml +36 -0
  7. data/lib/gossip.rb +32 -0
  8. data/lib/gossip/command.rb +122 -0
  9. data/lib/gossip/cronies/campfire.rb +72 -0
  10. data/lib/gossip/cronies/jabber.rb +66 -0
  11. data/lib/gossip/cronies/smtp.rb +121 -0
  12. data/lib/gossip/cronies/stdout.rb +24 -0
  13. data/lib/gossip/cronies/trac.rb +82 -0
  14. data/lib/gossip/cronies/twitter.rb +50 -0
  15. data/lib/gossip/crony.rb +102 -0
  16. data/lib/gossip/multi-exceptions.rb +47 -0
  17. data/lib/gossip/preteen.rb +86 -0
  18. data/lib/gossip/site-config.rb +94 -0
  19. data/lib/gossip/social-universe.rb +18 -0
  20. data/lib/gossip/version.rb +8 -0
  21. data/pages/classes.html +58 -0
  22. data/pages/cronies.html +256 -0
  23. data/pages/css/LICENSE.txt +1 -0
  24. data/pages/css/Thumbs.db +0 -0
  25. data/pages/css/bg2.gif +0 -0
  26. data/pages/css/gossip5-header-flip.jpg +0 -0
  27. data/pages/css/left.gif +0 -0
  28. data/pages/css/left_on.gif +0 -0
  29. data/pages/css/main.css +242 -0
  30. data/pages/css/right.gif +0 -0
  31. data/pages/css/right_on.gif +0 -0
  32. data/pages/css/tvline.gif +0 -0
  33. data/pages/images/campfire.png +0 -0
  34. data/pages/images/classes.png +0 -0
  35. data/pages/images/deployment.png +0 -0
  36. data/pages/images/jabber-big.png +0 -0
  37. data/pages/images/jabber.png +0 -0
  38. data/pages/images/trac-bigger.png +0 -0
  39. data/pages/images/trac-detail.png +0 -0
  40. data/pages/images/twitter.png +0 -0
  41. data/pages/index.html +45 -0
  42. data/pages/installation.html +95 -0
  43. data/pages/scripts.html +166 -0
  44. data/pages/src/classes.graffle +0 -0
  45. data/pages/starting-to-use.html +200 -0
  46. data/pages/writing-new-scripts.html +38 -0
  47. data/scripts/fanout +64 -0
  48. data/scripts/svntell +71 -0
  49. data/scripts/watchdog +86 -0
  50. data/setup.rb +1585 -0
  51. data/test/script/fanout-slowtests.rb +40 -0
  52. data/test/script/svntell-slowtests.rb +40 -0
  53. data/test/script/util.rb +22 -0
  54. data/test/script/watchdog-slowtests.rb +56 -0
  55. data/test/unit/command-crony-interaction-tests.rb +116 -0
  56. data/test/unit/command-tests.rb +119 -0
  57. data/test/unit/crony-tests.rb +46 -0
  58. data/test/unit/multi-exception-tests.rb +70 -0
  59. data/test/unit/preteen-tests.rb +81 -0
  60. data/test/util/bff.rb +45 -0
  61. data/test/util/doghouse.rb +42 -0
  62. data/test/util/silly-little-test-program.rb +6 -0
  63. metadata +181 -0
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-16.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+
7
+ require 'tinder'
8
+ require 'gossip/crony'
9
+
10
+
11
+ module Gossip
12
+
13
+ # CampfireCrony adds a notice to a Campfire (http://www.campfirenow.com)
14
+ # chat room.
15
+ class CampfireCrony < Crony
16
+
17
+ def name; "campfire"; end
18
+ def symbol; :campfire; end
19
+
20
+ def command_line_description
21
+ ["-c", "--campfire",
22
+ "Control display to Campfire chat room.",
23
+ "Defaults to #{is_bff_by_default?}."]
24
+ end
25
+
26
+ def add_configuration_choices(builder)
27
+ builder.add_choice(:campfire_login,
28
+ :default => checked(:default_login)) { | command_line |
29
+ command_line.uses_option("--campfire-login LOGIN",
30
+ "Your Campfire login, an email address",
31
+ df(:default_login)
32
+ )
33
+ }
34
+
35
+ builder.add_choice(:campfire_password,
36
+ :default => checked(:default_password)) { | command_line |
37
+ command_line.uses_option("--campfire-password PASSWORD",
38
+ "Your Campfire password.",
39
+ df(:default_password)
40
+ )
41
+ }
42
+
43
+ builder.add_choice(:campfire_subdomain,
44
+ :default => checked(:default_subdomain)) { | command_line |
45
+ command_line.uses_option("--campfire-subdomain NAME",
46
+ "Your Campfire subdomain.",
47
+ "(As in 'subdomain.campfire.com')",
48
+ df(:default_subdomain)
49
+ )
50
+ }
51
+
52
+ builder.add_choice(:campfire_room,
53
+ :default => checked(:default_room)) { | command_line |
54
+ command_line.uses_option("--campfire-room NAME",
55
+ "A campfire room to receive the message.",
56
+ df(:default_room)
57
+ )
58
+ }
59
+
60
+ end
61
+
62
+ def hear(scandal, details)
63
+ connection = Tinder::Campfire.new(@user_choices[:campfire_subdomain])
64
+ connection.login(@user_choices[:campfire_login], @user_choices[:campfire_password])
65
+ raise StandardError, "Login to Campfire failed." unless connection.logged_in?
66
+ room = connection.find_room_by_name(@user_choices[:campfire_room])
67
+ room.paste([scandal, details].join("\n"))
68
+ connection.logout
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-15.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ require 'xmpp4r'
7
+ require 'gossip/crony'
8
+
9
+ module Gossip
10
+ class JabberCrony < Crony
11
+ include Jabber
12
+
13
+ def name; "jabber"; end
14
+ def symbol; :jabber; end
15
+
16
+ def command_line_description
17
+ ['-j', "--jabber",
18
+ "Control IM notification.",
19
+ "Defaults to #{is_bff_by_default?}."]
20
+ end
21
+
22
+ def add_configuration_choices(builder)
23
+ builder.add_choice(:jabber_to,
24
+ :default => checked(:default_to),
25
+ :type => [:string]) { | command_line |
26
+ command_line.uses_option("--jabber-to RECIPIENTS",
27
+ "Recipients of Jabber instant messages.",
28
+ "This can be a comma-separated list.",
29
+ df(:default_to)
30
+ )
31
+ }
32
+
33
+ builder.add_choice(:jabber_account,
34
+ :default => checked(:default_account)) { | command_line |
35
+ command_line.uses_option("--jabber-account SENDER",
36
+ "Your Jabber account.",
37
+ "Note that this includes the Jabber server.",
38
+ df(:default_account)
39
+ )
40
+ }
41
+
42
+ builder.add_choice(:jabber_password,
43
+ :default => checked(:default_password)) { | command_line |
44
+ command_line.uses_option("--jabber-password PASSWORD",
45
+ "Your Jabber password.",
46
+ df(:default_password)
47
+ )
48
+ }
49
+ end
50
+
51
+ def hear(scandal, details)
52
+ my_jid = JID.new(@user_choices[:jabber_account])
53
+ cl = Client.new(my_jid, false)
54
+ cl.connect
55
+ cl.auth(@user_choices[:jabber_password])
56
+ details = [scandal, details].join("\n")
57
+ @user_choices[:jabber_to].each do | recipient |
58
+ m = Message::new(recipient, details).
59
+ set_type(:normal).set_id('1').set_subject(scandal)
60
+ cl.send(m)
61
+ end
62
+ cl.close
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-15.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ require 'net/smtp'
7
+
8
+ module Gossip
9
+
10
+ # This Crony sends email.
11
+ class SmtpCrony < Crony
12
+
13
+ def name; 'mail'; end
14
+ def symbol; :mail; end
15
+
16
+ def command_line_description
17
+ ['-m', "--mail",
18
+ "Control mail notification.",
19
+ "Defaults to #{is_bff_by_default?}."]
20
+ end
21
+
22
+ def add_configuration_choices(builder)
23
+ builder.add_choice(:mail_to,
24
+ :default => checked(:default_to),
25
+ :type => [:string]) { | command_line |
26
+ command_line.uses_option("--mail-to RECIPIENTS",
27
+ "Recipients of mail.",
28
+ "This can be a comma-separated list.",
29
+ df(:default_to)
30
+ )
31
+ }
32
+
33
+ builder.add_choice(:mail_from,
34
+ :default => checked(:default_from)) { | command_line |
35
+ command_line.uses_option("--mail-from SENDER",
36
+ "The sender of the mail (appears in From line).",
37
+ df(:default_from)
38
+ )
39
+ }
40
+
41
+ builder.add_choice(:mail_server,
42
+ :default => checked(:default_smtp_server)) { | command_line |
43
+ command_line.uses_option("--mail-server HOSTNAME",
44
+ "SMTP server. #{df(:default_smtp_server)}"
45
+ )
46
+ }
47
+
48
+ builder.add_choice(:mail_port,
49
+ :type => :integer,
50
+ :default => checked(:default_smtp_port)) { | command_line |
51
+ command_line.uses_option("--mail-port NUMBER",
52
+ "Mail port on that server.",
53
+ df(:default_smtp_port)
54
+ )
55
+ }
56
+
57
+ builder.add_choice(:mail_account,
58
+ :default => checked(:default_smtp_account)) { | command_line |
59
+ command_line.uses_option("--mail-account USERNAME",
60
+ "Your account name on the SMTP server.",
61
+ df(:default_smtp_account)
62
+ )
63
+ }
64
+
65
+ builder.add_choice(:mail_from_domain,
66
+ :default => checked(:default_from_domain)) { | command_line |
67
+ command_line.uses_option("--mail-from-domain HOSTNAME",
68
+ "The server the mail supposedly comes from.",
69
+ "(Not necessarily the SMTP server.)",
70
+ df(:default_from_domain)
71
+ )
72
+ }
73
+
74
+ builder.add_choice(:mail_password,
75
+ :default => checked(:default_smtp_password)) { | command_line |
76
+ command_line.uses_option("--mail-password HOSTNAME",
77
+ "Your password on the SMTP server.",
78
+ df(:default_smtp_password)
79
+ )
80
+ }
81
+
82
+ auth_types = ['plain', 'login', 'cram_md5']
83
+ builder.add_choice(:mail_authentication,
84
+ :type => auth_types,
85
+ :default => checked(:default_smtp_authentication)) { | command_line |
86
+ command_line.uses_option("--mail-authentication TYPE",
87
+ "The kind of authentication your SMTP server uses.",
88
+ "One of #{friendly_list('or', auth_types)}.",
89
+ df(:default_smtp_authentication)
90
+ )
91
+ }
92
+ end
93
+
94
+ def postprocess_user_choices
95
+ @user_choices[:mail_authentication] =
96
+ @user_choices[:mail_authentication].to_sym
97
+ end
98
+
99
+ def hear(scandal, details)
100
+ from = @user_choices[:mail_from]
101
+ to = @user_choices[:mail_to]
102
+ Net::SMTP.start(@user_choices[:mail_server], @user_choices[:mail_port],
103
+ @user_choices[:mail_from_domain],
104
+ @user_choices[:mail_account],
105
+ @user_choices[:mail_password],
106
+ @user_choices[:mail_authentication]) { | smtp |
107
+ mail = "
108
+ . From: #{from}
109
+ . To: #{to.join(', ')}
110
+ . Subject: [watchdog] #{scandal}
111
+ .
112
+ . #{details}
113
+ ".without_pretty_margin('.')
114
+ smtp.send_message(mail, from, to)
115
+ }
116
+ end
117
+ end
118
+
119
+
120
+
121
+ end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-15.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ require 'gossip/crony'
7
+
8
+ module Gossip
9
+ class StdoutCrony < Crony
10
+ def name; "terminal"; end
11
+ def symbol; :standard_output; end
12
+
13
+ def command_line_description
14
+ ["-s", "--standard-output",
15
+ "Control display to terminal (standard output).",
16
+ "Defaults to #{is_bff_by_default?}."]
17
+ end
18
+
19
+ def hear(scandal, details)
20
+ all = [scandal, details].join($/)
21
+ puts all.indent_by(2)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-19.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+
7
+ require 'gossip/crony'
8
+
9
+
10
+ module Gossip
11
+ # Right now, TracCrony is kind of a hack. It uses trac-admin(1) to
12
+ # edit a wiki page. If configured to do so, Trac will add wiki changes
13
+ # into the Timeline. OK, it's more than "kind of" a hack.
14
+ #
15
+ # Note that you must be running a command that uses a Trac crony on
16
+ # the Trac server itself.
17
+ #
18
+ # An alternative would be to use Mechanize. This was easier for now.
19
+ class TracCrony < Crony
20
+
21
+ def name; "trac"; end
22
+ def symbol; :trac; end
23
+
24
+ def command_line_description
25
+ ["-T", "--trac",
26
+ "Control display to Trac timeline.",
27
+ "Defaults to #{is_bff_by_default?}."]
28
+ end
29
+
30
+ def add_configuration_choices(builder)
31
+ builder.add_choice(:trac_admin_path,
32
+ :default => checked(:default_trac_admin_path)) { | command_line |
33
+ command_line.uses_option("--trac-admin-path PATH",
34
+ "Absolute pathname to trac-admin(1).",
35
+ df(:default_trac_admin_path)
36
+ )
37
+ }
38
+
39
+ builder.add_choice(:trac_environment_path,
40
+ :default => checked(:default_environment_path)) { | command_line |
41
+ command_line.uses_option("--trac-environment-path PATH",
42
+ "Your Trac environment.",
43
+ df(:default_environment_path)
44
+ )
45
+ }
46
+
47
+ builder.add_choice(:trac_page_name,
48
+ :default => checked(:default_page_name)) { | command_line |
49
+ command_line.uses_option("--trac-page-name PAGE",
50
+ "A Trac wiki page to receive the message.",
51
+ df(:default_page_name)
52
+ )
53
+ }
54
+
55
+ builder.add_choice(:trac_content_file,
56
+ :default => checked(:default_content_file)) { | command_line |
57
+ command_line.uses_option("--trac-content-file FILE",
58
+ "A file to use as the content of the page.",
59
+ df(:default_content_file)
60
+ )
61
+ }
62
+
63
+ end
64
+
65
+ def hear(scandal, details)
66
+ trac_admin = @user_choices[:trac_admin_path]
67
+ env = @user_choices[:trac_environment_path]
68
+ page = @user_choices[:trac_page_name]
69
+ file = @user_choices[:trac_content_file]
70
+ current = File.exist?(file) ? File.read(file) : ""
71
+ File.open(file, "w") do | io |
72
+ io.puts(scandal)
73
+ io.puts(details.gsub(/$/, '[[BR]]'))
74
+ io.puts('---------------')
75
+ io.puts current
76
+ end
77
+ exec = "#{trac_admin} #{env} wiki import #{page} #{file}"
78
+ `#{exec}`
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-24.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ require 'twitter'
7
+ require 'gossip/crony'
8
+
9
+
10
+ module Gossip
11
+
12
+ # TwitterCrony updates Twitter (http://www.twitter.com) status. Note:
13
+ # only the text of the scandal is used, not the details.
14
+ class TwitterCrony < Crony
15
+
16
+ def name; "twitter"; end
17
+ def symbol; :twitter; end
18
+
19
+ def command_line_description
20
+ ["-t", "--twitter",
21
+ "Control whether Twitter updates are made.",
22
+ "Defaults to #{is_bff_by_default?}."]
23
+ end
24
+
25
+ def add_configuration_choices(builder)
26
+ builder.add_choice(:twitter_login,
27
+ :default => checked(:default_login)) { | command_line |
28
+ command_line.uses_option("--twitter-login LOGIN",
29
+ "Your Twitter login",
30
+ df(:default_login)
31
+ )
32
+ }
33
+
34
+ builder.add_choice(:twitter_password,
35
+ :default => checked(:default_password)) { | command_line |
36
+ command_line.uses_option("--twitter-password PASSWORD",
37
+ "Your Twitter password.",
38
+ df(:default_password)
39
+ )
40
+ }
41
+
42
+ end
43
+
44
+ def hear(scandal, details)
45
+ twit = Twitter::Base.new(@user_choices[:twitter_login], @user_choices[:twitter_password])
46
+ twit.update(scandal)
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,102 @@
1
+ #! /opt/local/bin/ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-15.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ module Gossip
7
+
8
+ # This is the base class for the different Crony objects that the Preteen
9
+ # gossips with. A Crony object is something like mail, Twitter, Jabber, or
10
+ # anything that can accept a message and do something useful with it.
11
+ #
12
+ # To understand Crony, you should first understand GossipCommand and
13
+ # Preteen. It's helpful to understand the user-choices gem:
14
+ # http://http://user-choices.rubyforge.org
15
+ class Crony
16
+
17
+ # Each Crony will require some information like an account name, a
18
+ # password, etc. Those can be specified by the user. If not, these
19
+ # values are used. By convention, the keys in the hash begin with
20
+ # :default_. So not override initialize; the work is done elsewhere.
21
+ def initialize(defaults = {})
22
+ @defaults = defaults
23
+ end
24
+
25
+ # This does the work of accepting a message and doing something useful
26
+ # with it. Must be overridden. The _scandal_ is a short description.
27
+ # Some types of Crony (such as twitter) pay attention only to it, and
28
+ # ignore the _details_.
29
+ def hear(scandal, details)
30
+ subclass_responsibility
31
+ end
32
+
33
+ # This method returns a string identifying the Crony. It is used
34
+ # in error messages. Must be overridden.
35
+ def name
36
+ subclass_responsibility
37
+ end
38
+
39
+ # This symbol identifies the crony within Ruby code. Must be overridden.
40
+ def symbol
41
+ subclass_responsibility
42
+ end
43
+
44
+ # There is a single configuration choice used to include the Crony in the
45
+ # gossip or exclude her. This method returns an array of strings describing
46
+ # that option. It should be in the format used by OptionParser (optparse).
47
+ # Must be overridden.
48
+ def command_line_description
49
+ subclass_responsibility
50
+ end
51
+
52
+ # This method describes how the user can control the Crony's behavior
53
+ # in a config file or on the command-line. This method is called from
54
+ # UserChoices::Command#add_choices; see its documentation (in the
55
+ # user-choices gem). Or look at subclasses for examples.
56
+ #
57
+ # Don't bother overriding this if there are no configuration choices.
58
+ def add_configuration_choices(builder)
59
+ end
60
+
61
+ # This method is called from UserChoices::Command::postprocess_user_choices.
62
+ # See the documentation for the user-choices gem.
63
+ def postprocess_user_choices
64
+ end
65
+
66
+ attr_writer :is_bff_by_default, :user_choices # :nodoc:
67
+
68
+ # By default, will this Crony be told gossip?
69
+ def is_bff_by_default?; @is_bff_by_default; end
70
+
71
+ # Is this Crony, at this moment, a Best Friend Forever who will be
72
+ # told gossip by the Preteen? (is_bff_by_default? is used to find the
73
+ # starting value of this boolean.)
74
+ def is_bff?
75
+ @user_choices[symbol]
76
+ end
77
+
78
+ def add_bff_choice(builder) # :nodoc:
79
+ builder.add_choice(self.symbol,
80
+ :type => :boolean,
81
+ :default => is_bff_by_default?) { | command_line |
82
+ command_line.uses_switch(*command_line_description)
83
+ }
84
+ end
85
+
86
+ def checked(symbol) # :nodoc:
87
+ prog1(@defaults[symbol]) do | value |
88
+ if value.nil?
89
+ raise StandardError,
90
+ "#{symbol.inspect} is nil for #{name} - likely a typo in a configuration file.\n" +
91
+ @defaults.inspect
92
+ end
93
+ end
94
+ end
95
+
96
+ def df(symbol) # :nodoc:
97
+ "Defaults to #{checked(symbol).inspect}."
98
+ end
99
+ end
100
+
101
+ end
102
+