gossip 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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,40 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-25.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ require 'test/unit'
7
+ require 's4t-utils'
8
+ S4tUtils.set_test_paths(__FILE__)
9
+
10
+ require 'test/script/util'
11
+
12
+ unless S4tUtils.on_windows?
13
+ class TestFanoutCommandExecution < Test::Unit::TestCase
14
+ def test_scandal_and_details
15
+ as_script_test('.fanout.yml') do
16
+ result = `echo "some details" | ruby fanout --details arg "another arg"`
17
+ lines = result.split("\n")
18
+ assert_match(/arg another arg/, lines.first)
19
+ assert_match(/some details/, lines.last)
20
+ end
21
+ end
22
+
23
+ def test_scandal_alone
24
+ as_script_test('.fanout.yml') do
25
+ result = `ruby fanout --no-det arg "another arg"`
26
+ lines = result.split("\n")
27
+ assert_equal(1, lines.length)
28
+ assert_match(/arg another arg/, lines.first)
29
+ end
30
+ end
31
+
32
+ def test_details_are_default
33
+ as_script_test('.fanout.yml') do
34
+ results = `echo sloop | ruby fanout arg "another arg"`
35
+ assert_match(/sloop/, results)
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-27.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ #!/usr/bin/env ruby
7
+ #
8
+ # Created by Brian Marick on 2007-09-25.
9
+ # Copyright (c) 2007. All rights reserved.
10
+
11
+ require 'test/unit'
12
+ require 's4t-utils'
13
+ S4tUtils.set_test_paths(__FILE__)
14
+
15
+ require 'test/script/util'
16
+
17
+ unless S4tUtils.on_windows?
18
+ class TestFanoutCommandExecution < Test::Unit::TestCase
19
+ def test_revision_is_required
20
+ as_script_test('.svntell.yml') do
21
+ result = `ruby svntell --repository /svn 2>&1`
22
+ assert_match(/must choose a revision/, result)
23
+ end
24
+ end
25
+
26
+ def test_repository_is_required
27
+ as_script_test('.svntell.yml') do
28
+ result = `ruby svntell --revision 5 foo 2>&1`
29
+ assert_match(/must choose a repository/, result)
30
+ end
31
+ end
32
+
33
+ def test_svnlook_must_exist
34
+ as_script_test('.svntell.yml') do
35
+ result = `ruby svntell --svnlook /foo/bar --repository /svn --revision 5 foo 2>&1`
36
+ assert_match(%r{svnlook path '/foo/bar' does not exist.}, result)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-25.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+
7
+ class Test::Unit::TestCase
8
+ include S4tUtils
9
+
10
+ def as_script_test(config_name)
11
+ yaml = %q{
12
+ standard-output: true
13
+ }
14
+
15
+ Dir.chdir(PACKAGE_ROOT + "/scripts") do
16
+ with_local_config_file(config_name, yaml) do
17
+ yield
18
+ end
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,56 @@
1
+ require 'test/unit'
2
+ require 's4t-utils'
3
+ include S4tUtils
4
+ set_test_paths(__FILE__)
5
+
6
+ require 'test/script/util'
7
+ load "#{PACKAGE_ROOT}/scripts/watchdog"
8
+
9
+ class TestWatchdogCommand < Test::Unit::TestCase
10
+ include Gossip
11
+
12
+ class RandomWatchdogCommand < Watchdog
13
+ # Erase behaviors of no interest
14
+ def initialize; end
15
+ end
16
+
17
+
18
+ def test_command_name_ignores_ruby
19
+ dog = RandomWatchdogCommand.new
20
+ assert_equal('echo', dog.command_name(['echo', 'foo']))
21
+ assert_equal('echo.rb', dog.command_name(['ruby', 'echo.rb', 'foo']))
22
+ end
23
+
24
+ def test_command_name_is_just_basename
25
+ dog = RandomWatchdogCommand.new
26
+ assert_equal('echo.rb', dog.command_name(['ruby', '/usr/bin/echo.rb', 'foo']))
27
+ end
28
+
29
+ def test_timer
30
+ duration, result = RandomWatchdogCommand.new.time {
31
+ sleep 2
32
+ 5
33
+ }
34
+ # Rough check because time is inaccurate.
35
+ assert_true(duration >= 1.5)
36
+ assert_equal(5, result)
37
+ end
38
+
39
+
40
+ end
41
+
42
+ unless S4tUtils.on_windows?
43
+ class TestWatchdogCommandExecution < Test::Unit::TestCase
44
+ def test_command_line_only
45
+ as_script_test('.watchdog.yml') do
46
+ actual_string = `ruby watchdog ruby ../test/util/silly-little-test-program.rb 1 2`
47
+ assert_match(/Program silly-little-test-program.rb finished/, actual_string)
48
+ assert_match(/Duration: /, actual_string)
49
+ assert_match(%r{Command: ruby ../test/util/silly-little-test-program.rb 1 2}, actual_string)
50
+
51
+ assert_match(/I mostly write to standard output./, actual_string)
52
+ assert_match(/I also write to standard error./, actual_string)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-09-17.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ require 'test/unit'
7
+ require 's4t-utils'
8
+ include S4tUtils
9
+ set_test_paths(__FILE__)
10
+
11
+
12
+ require 'gossip'
13
+
14
+ class ChoicesTests < Test::Unit::TestCase
15
+ include Gossip
16
+
17
+ def test_that_crony_presence_sets_switch
18
+ # Note that the cronymaker key and Crony name must be the same.
19
+ # That duplication is an artifact of trying to make the declarations
20
+ # in the scripts (like watchdog.rb) look nice.
21
+ crony_maker = { :winner => proc {@winner = Exhibitionist.named(:winner)},
22
+ :loser => proc {@loser = Exhibitionist.named(:loser)} }
23
+
24
+ sophie = Preteen.new(crony_maker, [:winner], [:loser])
25
+ cmd = SomeRandomCommand.new(sophie)
26
+
27
+ # Switch is initialized, with default value
28
+ assert_equal(true, cmd.user_choices[:winner])
29
+ assert_equal(false, cmd.user_choices[:loser])
30
+
31
+ # Shorthand for the default value
32
+ assert_true(@winner.is_bff_by_default?)
33
+ assert_false(@loser.is_bff_by_default?)
34
+
35
+ # Cronies share user choices with command.
36
+ assert_equal(@winner.user_choices, cmd.user_choices)
37
+ assert_equal(@loser.user_choices, cmd.user_choices)
38
+ end
39
+
40
+ def test_how_command_initializes_a_crony
41
+ crony_maker = { :bff => proc {Exhibitionist.named(:bff)}}
42
+ sophie = Preteen.new(crony_maker, [:bff], [])
43
+ SomeRandomCommand.new(sophie).execute
44
+ assert_equal(['command_line_description()', # This is the crony's only part in determining whether it's called by default
45
+ 'add_configuration_choices()',
46
+ # Command line and config files are read here
47
+ 'user_choices=()', # Give crony access to user choices
48
+ 'postprocess_user_choices()',
49
+ # Can now execute.
50
+ 'hear("boyfriend!", "Joshua")'
51
+ ], sophie.cronies[0].logged)
52
+ end
53
+
54
+
55
+ class Exhibitionist < Crony
56
+ attr_reader :logged, :user_choices, :symbol
57
+
58
+ def name; symbol.to_s; end
59
+
60
+ def self.named(sym); new(sym); end
61
+ def initialize(sym)
62
+ @symbol = sym
63
+ @logged = []
64
+ super
65
+ end
66
+
67
+ def user_choices=(value)
68
+ log("user_choices=")
69
+ @user_choices = value
70
+ end
71
+
72
+ def command_line_description()
73
+ log("command_line_description")
74
+ ['-e', "--exhibitionist", "Defaults to #{is_bff_by_default?}."]
75
+ end
76
+
77
+ def add_configuration_choices(builder)
78
+ log("add_configuration_choices");
79
+ end
80
+ def postprocess_user_choices;
81
+ log("postprocess_user_choices")
82
+ end
83
+
84
+ def hear(*args)
85
+ log('hear', *args)
86
+ end
87
+
88
+ private
89
+
90
+ def log(message, *args); @logged << how_called(message, *args); end
91
+
92
+ def how_called(message, *args)
93
+ args = args.collect { |a| a.inspect }
94
+ "#{message}(" + args.join(", ") + ")"
95
+ end
96
+
97
+ end
98
+
99
+
100
+ class SomeRandomCommand < Gossip::GossipCommand
101
+
102
+ attr_reader :user_choices
103
+
104
+ def add_sources(builder)
105
+ # There must be at least a command line.
106
+ builder.add_source(CommandLineSource, :usage,
107
+ "Usage: ruby #{$0} [options] program args...")
108
+ end
109
+
110
+ def execute
111
+ preteen.tell_bffs("boyfriend!", "Joshua")
112
+ end
113
+ end
114
+
115
+
116
+ end
@@ -0,0 +1,119 @@
1
+ require 'test/unit'
2
+ require 's4t-utils'
3
+ include S4tUtils
4
+ set_test_paths(__FILE__)
5
+
6
+ require 'gossip'
7
+
8
+ class CommandTests < Test::Unit::TestCase
9
+ include Gossip
10
+
11
+ class SomeRandomCommand < GossipCommand
12
+ def script_config_file; ".localrc"; end
13
+ def gossip_config_file; ".globalrc"; end
14
+
15
+ def usage; "Usage: ruby #{$0} [options] program args..."; end
16
+ def add_sources(builder)
17
+ builder.add_source(PosixCommandLineSource, :usage, *describe_all_but_options)
18
+ builder.add_source(YamlConfigFileSource, :from_file, ".sophie.yml")
19
+ builder.add_source(XmlConfigFileSource, :from_file, ".sophie.xml")
20
+ end
21
+
22
+ def execute
23
+ preteen.tell_bffs("boyfriend!", "Joshua")
24
+ preteen.cronies.collect { |crony| crony.value }
25
+ end
26
+ end
27
+
28
+ def setup
29
+ crony_maker = {
30
+ :bff => proc {
31
+ require PACKAGE_ROOT + '/test/util/bff'
32
+ OneTestCrony.new(:default_format_string => "scandal: %s, details: %s")
33
+ },
34
+ :doghouse => proc {
35
+ require PACKAGE_ROOT + '/test/util/doghouse'
36
+ AnotherTestCrony.new(:default_format_string => "%s: %s")
37
+ }
38
+ }
39
+
40
+ @sophie = Preteen.new(crony_maker, [:bff], [:doghouse])
41
+ end
42
+
43
+ def test_behavior_when_not_overridden_is_as_set
44
+ SomeRandomCommand.new(@sophie).execute
45
+ result = @sophie.cronies.collect { |crony| crony.value }
46
+ assert_equal(["scandal: boyfriend!, details: Joshua", "doghouse crony was not told!"],
47
+ result)
48
+ end
49
+
50
+
51
+ def test_that_config_files_can_change_who_gets_told
52
+ flip = %Q{
53
+ <sophie>
54
+ <bff>false</bff>
55
+ <doghouse>true</doghouse>
56
+ </sophie>
57
+ }
58
+ with_local_config_file('.sophie.xml', flip) {
59
+ SomeRandomCommand.new(@sophie).execute
60
+ result = @sophie.cronies.collect { |crony| crony.value }
61
+ assert_equal(["bff was not told!", "boyfriend!: Joshua"],
62
+ result)
63
+ }
64
+ end
65
+
66
+
67
+
68
+ def test_that_both_switches_and_options_can_be_overridden
69
+ reconcile = %Q{
70
+ doghouse: true
71
+ }
72
+
73
+ with_command_args('--bff-format=%s/%s --doghouse-form %s+%s') {
74
+ with_local_config_file('.sophie.yml', reconcile) {
75
+ SomeRandomCommand.new(@sophie).execute
76
+ result = @sophie.cronies.collect { |crony| crony.value }
77
+ assert_equal(["boyfriend!/Joshua", "boyfriend!+Joshua"],
78
+ result)
79
+ }
80
+ }
81
+ end
82
+
83
+ def test_typical_usage_lines
84
+ with_command_args('--help') do
85
+ output = capturing_stderr do
86
+ assert_wants_to_exit do
87
+ SomeRandomCommand.new(@sophie)
88
+ end
89
+ end
90
+ lines = output.split("\n")
91
+ assert_equal("Usage: ruby #{$0} [options] program args...", lines[0])
92
+ assert_match(/Site-wide defaults/, lines[1])
93
+ assert_match(/Override them in the '.localrc' or '.globalrc' files in your home folder./, lines[2])
94
+ end
95
+ end
96
+
97
+ class LongerUsageCommand < SomeRandomCommand
98
+ def usage; ['line 1', 'line 2']; end
99
+ end
100
+
101
+ def test_that_usage_lines_can_be_an_array
102
+ with_command_args('--help') do
103
+ output = capturing_stderr do
104
+ assert_wants_to_exit do
105
+ LongerUsageCommand.new(@sophie).execute
106
+ end
107
+ end
108
+ lines = output.split("\n")
109
+ assert_equal("line 1", lines[0])
110
+ assert_equal("line 2", lines[1])
111
+ assert_match(/Site-wide defaults/, lines[2])
112
+ end
113
+
114
+ end
115
+
116
+
117
+
118
+
119
+ end
@@ -0,0 +1,46 @@
1
+ require 'test/unit'
2
+ require 's4t-utils'
3
+ include S4tUtils
4
+ set_test_paths(__FILE__)
5
+
6
+ require 'gossip'
7
+
8
+ # Most of the crony behavior is interaction with Command, so see
9
+ # command-tests.rb
10
+
11
+ class ChoicesTests < Test::Unit::TestCase
12
+ include Gossip
13
+
14
+ class ConcreteCrony < Crony
15
+ def name; 'non-abstract'; end
16
+ def symbol; :sym; end
17
+ end
18
+
19
+ def test_crony_checks_for_typos
20
+ crony = ConcreteCrony.new(:key => 'value')
21
+
22
+ assert_equal('value', crony.checked(:key))
23
+ assert_raises_with_matching_message(StandardError, /:ky is nil.*#{crony.name}.*typo/) do
24
+ crony.checked(:ky)
25
+ end
26
+ end
27
+
28
+
29
+ def test_crony_can_describe_defaults
30
+ crony = ConcreteCrony.new(:key => 'value')
31
+ assert_equal('Defaults to "value".', crony.df(:key))
32
+
33
+ assert_raises_with_matching_message(StandardError, /:ky is nil.*#{crony.name}.*typo/) do
34
+ crony.checked(:ky)
35
+ end
36
+ end
37
+
38
+ def test_crony_friendship_depends_on_user_choices
39
+ crony = ConcreteCrony.new
40
+ crony.user_choices=({:sym => true})
41
+ assert_true(crony.is_bff?)
42
+ crony.user_choices=({:sym => false})
43
+ assert_false(crony.is_bff?)
44
+ end
45
+
46
+ end
@@ -0,0 +1,70 @@
1
+ require 'test/unit'
2
+ require 's4t-utils'
3
+ include S4tUtils
4
+ set_test_paths(__FILE__)
5
+
6
+ require 'gossip/multi-exceptions'
7
+
8
+ class QueueExtensionTests < Test::Unit::TestCase
9
+ def test_to_a
10
+ queue = Queue.new
11
+ queue << 1
12
+ assert_equal([1], queue.to_a)
13
+ end
14
+ end
15
+
16
+ class MultiExceptionTests < Test::Unit::TestCase
17
+ include Gossip
18
+
19
+ def two_exceptions
20
+ retval = []
21
+ [IndexError.new("index error"),
22
+ RuntimeError.new("runtime error")].each do | ex |
23
+ begin
24
+ raise ex # You have to raise to get a backtrace.
25
+ rescue Exception => caught
26
+ retval << caught
27
+ end
28
+ end
29
+ retval
30
+ end
31
+
32
+ def setup
33
+ @ex = MultiException.new(two_exceptions)
34
+ end
35
+
36
+
37
+ def test_multi_exception_aggregates_messages
38
+ messages = @ex.message.split("\n")
39
+ assert_match(/index error/, messages[0])
40
+ assert_match(/runtime error/, messages[1])
41
+ end
42
+
43
+ def test_multi_exception_includes_exception_classes_in_messages
44
+ messages = @ex.message.split("\n")
45
+ assert_match(/IndexError/, messages[0])
46
+ assert_match(/RuntimeError/, messages[1])
47
+ end
48
+
49
+ def test_multi_exception_aggregates_backtraces_in_traces_field
50
+ assert_equal(2, @ex.traces.length)
51
+ assert_equal(1, @ex.traces[0].grep(/setup/).length)
52
+ assert_equal(1, @ex.traces[1].grep(/setup/).length)
53
+ end
54
+
55
+ def test_combined_trace
56
+ begin
57
+ MultiException.reraise_with_combined_backtrace do
58
+ raise @ex
59
+ end
60
+ rescue MultiException => ex
61
+ assert_equal(1, ex.backtrace.grep(/Trace number 0:/).length)
62
+ assert_equal(1, ex.backtrace.grep(/Trace number 1:/).length)
63
+ # The raise in this method is wiped out.
64
+ assert_equal(0, ex.backtrace.grep(/test_combined_trace/).length)
65
+ # The raises in setup are preserved.
66
+ assert_equal(2, ex.backtrace.grep(/setup/).length)
67
+ end
68
+ end
69
+
70
+ end