jabber-tee 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,47 @@
1
+ # Jabber TEE
2
+
3
+ This is a simple command line tool for writing input from the client to a remote jabber server and outputting to the console.
4
+
5
+ # Installing
6
+
7
+ The command line tool can be installed with:
8
+
9
+ gem install jabber-tee
10
+
11
+ # Using
12
+
13
+ The general idea is that you can pipe anything from the console into this, and it will be sent to the remote jabber server:
14
+
15
+ cat huge_text_file.txt | jabber-tee -u peon@bigcorp.com --room working-hard@rooms.bigcorp.com --nick 'Worker Drone'
16
+
17
+ # Configuration
18
+
19
+ Because entering the same information on the command line for this thing can be tedious, you can create a ~/.jabber-tee.yml file that fills in all of the basic configuration. This file also allows you to further customize the output that is sent to the jabber server.
20
+
21
+ An example configuration file:
22
+
23
+ # Global configuration values:
24
+ username: my.name@jabber.org
25
+ nick: 'Gabe'
26
+
27
+ # Individual profiles that customize global variables
28
+ profiles:
29
+ new-hotness:
30
+ # Uses the standard username, above
31
+ nick: 'Mr. Super Cool'
32
+ room: 'HipCentral'
33
+
34
+ somebody.else:
35
+ username: supercooldude@gmail.com
36
+ nick: 'Rocksteady Gabe'
37
+ to: somebody.else@gmail.com
38
+
39
+ work-stuff:
40
+ username: peon@bigcorp.com
41
+ nick: 'Worker Drone'
42
+ room: working-hard@rooms.bigcorp.com
43
+
44
+ You can then activate these individual profiles from the command line with the '-P' flag. So, the above command could be replaced with:
45
+
46
+ cat huge_text_file.txt | jabber-tee -P work-stuff
47
+
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift File.expand_path("../spec", __FILE__)
3
+
4
+ require 'fileutils'
5
+ require 'rake'
6
+ require 'rubygems'
7
+ require 'spec/rake/spectask'
8
+ require 'jabber-tee/version'
9
+
10
+ task :default => :spec
11
+
12
+ desc "Run the RSpec tests"
13
+ Spec::Rake::SpecTask.new(:spec) do |t|
14
+ t.spec_files = FileList['spec/**/*_spec.rb']
15
+ t.spec_opts = ['-b', '-c', '-f', 'p']
16
+ t.fail_on_error = false
17
+ end
18
+
19
+ begin
20
+ require 'jeweler'
21
+ Jeweler::Tasks.new do |gem|
22
+ gem.name = 'jabber-tee'
23
+ gem.version = JabberTee::Version.to_s
24
+ gem.executables = %W{jabber-tee}
25
+ gem.summary = 'Simple command line utility for piping the output from one command to both the console and a remote jabber server.'
26
+ gem.description = "Installs the 'jabber-pipe' utility for sending messages to a remote jabber server. Instead of a standard client, it reads from standard in and continues to write to the console."
27
+ gem.email = ['madeonamac@gmail.com']
28
+ gem.authors = ['Gabe McArthur']
29
+ gem.homepage = 'http://github.com/gabemc/jabber-tee'
30
+ gem.files = FileList["[A-Z]*", "{bin,lib,spec}/**/*"]
31
+
32
+ gem.add_dependency 'highline', '>=1.5.2'
33
+ gem.add_dependency 'xmpp4r', '>=0.5'
34
+
35
+ gem.add_development_dependency 'rspec', '>=1.3.0'
36
+ end
37
+ rescue LoadError
38
+ puts "Jeweler or dependencies are not available. Install it with: sudo gem install jeweler"
39
+ end
40
+
41
+ desc "Deploys the gem to rubygems.org"
42
+ task :gem => :release do
43
+ system("gem build jabber-tee.gemspec")
44
+ system("gem push jabber-tee-#{JabberTee::Version.to_s}.gem")
45
+ end
46
+
47
+ desc "Does the full release cycle."
48
+ task :deploy => [:gem, :clean] do
49
+ end
50
+
51
+ desc "Cleans the gem files up."
52
+ task :clean do
53
+ FileUtils.rm(Dir.glob('*.gemspec'))
54
+ FileUtils.rm(Dir.glob('*.gem'))
55
+ end
data/bin/jabber-tee ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'jabber-tee/cli'
5
+ JabberTee::CLI.new(ARGV).execute!
data/lib/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,156 @@
1
+ require 'optparse'
2
+ require 'jabber-tee/errors'
3
+ require 'jabber-tee/version'
4
+ require 'jabber-tee/client'
5
+ require 'jabber-tee/configuration'
6
+
7
+ module JabberTee
8
+ class CLI
9
+ attr_reader :options, :args
10
+
11
+ def initialize(args)
12
+ @args = args
13
+ end
14
+
15
+ def execute!
16
+ begin
17
+ parse!(@args.dup)
18
+ config = load_configuration
19
+
20
+ if config.destination_missing?
21
+ raise JabberTee::ConfigurationError.new("Either the --to or --room flag is required.")
22
+ end
23
+
24
+ client = Client.new(config)
25
+ client.pump!
26
+ rescue SystemExit => e
27
+ raise
28
+ rescue JabberTee::ConfigurationError => e
29
+ print_error(e.message)
30
+ rescue OptionParser::InvalidOption => e
31
+ print_error(e.message)
32
+ rescue Exception => e
33
+ STDERR.puts e.backtrace
34
+ print_error(e.message)
35
+ end
36
+ end
37
+
38
+ def parse!(args)
39
+ parse_options(args)
40
+ validate_args(args)
41
+ end
42
+
43
+ def parse_options(args)
44
+ @options ||= {}
45
+ @parsed_options ||= OptionParser.new do |opts|
46
+ opts.banner = "Usage: #{File.basename($0)} [OPTIONS] "
47
+ opts.separator <<DESC
48
+ Description:
49
+ This is a simple tool for reading from STDIN and writing
50
+ to both STDOUT and a remote jabber server. It does not handle
51
+ reading from STDERR, so you will need to re-direct 2>&1 before
52
+ piping it to this tool.
53
+
54
+ The configuration file should live under ~/.jabber-tee.yml.
55
+ Please see http://github.com/gabemc/jabber-tee for more
56
+ information.
57
+
58
+ Options:
59
+ DESC
60
+ opts.separator " Connecting:"
61
+ opts.on('-u', '--username USERNAME',
62
+ "The user@host.org name to connect to the jabber server.") do |u|
63
+ options[:username] = u
64
+ end
65
+ opts.on('-p', '--password PASSWORD',
66
+ "The password for the user to connect to the jabber server.",
67
+ "If not given or defined in the .jabber-tee.yml file,",
68
+ "it will be asked during runtime.") do |p|
69
+ options[:password] = p
70
+ end
71
+ opts.on('-n', '--nick NICKNAME',
72
+ "The nickname to use when connecting to the server.") do |n|
73
+ options[:nick] = n
74
+ end
75
+ opts.on('-a', '--anonymous',
76
+ "Disregards the username information and logs in using anonymous",
77
+ "authentication. Either the --username or the --authentication",
78
+ "flag are required.") do |a|
79
+ options[:anonymous] = true
80
+ end
81
+ opts.on('-P', '--profile PROFILE',
82
+ "The name of the profile, as defined in the .jabber-tee.yml",
83
+ "file to use to connect with.") do |p|
84
+ options[:profile] = p
85
+ end
86
+ opts.on('--sasl',
87
+ "By default, the connection does not use SASL authentication.",
88
+ "This enables SASL connections") do |s|
89
+ options[:sasl] = true
90
+ end
91
+ opts.on('--digest',
92
+ "When not using SASL, you can use the digest",
93
+ "authentication mechanism.") do |d|
94
+ options[:digest] = true
95
+ end
96
+ opts.separator ""
97
+
98
+ opts.separator " Output: (One required)"
99
+ opts.on('-t', '--to TO',
100
+ "Who to send the message to.") do |t|
101
+ options[:to] = t
102
+ end
103
+ opts.on('-r', '--room ROOM',
104
+ "The room to send the messages to.") do |r|
105
+ options[:room] = r
106
+ end
107
+ opts.separator ""
108
+
109
+ opts.separator " Informative:"
110
+ opts.on('-v', '--version',
111
+ "Show the version information") do |v|
112
+ puts "#{File.basename($0)} version: #{JabberTee::Version.to_s}"
113
+ exit
114
+ end
115
+ opts.on('-h', '--help',
116
+ "Show this help message") do
117
+ puts opts
118
+ exit
119
+ end
120
+ opts.separator ""
121
+
122
+ end.parse!(args)
123
+ end
124
+
125
+ def validate_args(args)
126
+ if args.length > 0
127
+ raise JabberTee::ConfigurationError.new("This command takes no extra arguments: #{args[0]}")
128
+ end
129
+ end
130
+
131
+ private
132
+ def print_error(e)
133
+ STDERR.puts "#{File.basename($0)}: #{e}"
134
+ STDERR.puts "#{File.basename($0)}: Try '--help' for more information"
135
+ exit 1
136
+ end
137
+
138
+ JABBER_FILE = '.jabber-tee.yml'
139
+
140
+ def load_configuration
141
+ home = ENV['HOME'] # TODO: Windows users?
142
+ config_file = File.join(home, JABBER_FILE)
143
+
144
+ if File.exists?(config_file)
145
+ reader = ConfigurationReader.new(config_file)
146
+ if options.has_key?(:profile)
147
+ reader.profile(options[:profile]).merge(options)
148
+ else
149
+ reader.profile.merge(options)
150
+ end
151
+ else
152
+ Configuration.new(options)
153
+ end
154
+ end
155
+ end # CLI
156
+ end
@@ -0,0 +1,46 @@
1
+ require 'jabber-tee/errors'
2
+
3
+ require 'rubygems'
4
+ require 'xmpp4r'
5
+ require 'xmpp4r/muc'
6
+
7
+ module JabberTee
8
+ class Client
9
+ attr_reader :config, :client
10
+
11
+ def initialize(config)
12
+ @config = config
13
+ @client = Jabber::Client.new(Jabber::JID.new("#{config.username}/#{config.nick}"))
14
+ client.connect
15
+ client.auth(config.password)
16
+
17
+ if config.in_room?
18
+ @muc = Jabber::MUC::SimpleMUCClient.new(client)
19
+ @muc.join(Jabber::JID.new("#{config.room}/#{config.nick}"))
20
+ end
21
+ end
22
+
23
+ def pump!
24
+ if $stdin.tty?
25
+ $STDERR.puts "Unable to pipe jabber-tee from a TTY"
26
+ exit(1)
27
+ else
28
+ $stdin.each do |line|
29
+ line.chomp!
30
+ say(line)
31
+ puts line
32
+ end
33
+ end
34
+ end
35
+
36
+ def say(message)
37
+ if config.in_room?
38
+ @muc.say(message)
39
+ else
40
+ msg = Jabber::Message.new(config.to, message)
41
+ msg.type = :chat
42
+ client.send(msg)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,90 @@
1
+ require 'jabber-tee/errors'
2
+
3
+ require 'rubygems'
4
+ require 'highline/import'
5
+ require 'yaml'
6
+
7
+ module JabberTee
8
+
9
+ class ConfigurationReader
10
+ def initialize(yaml_file)
11
+ if !File.exists?(yaml_file)
12
+ raise JabberTee::ConfigurationError.new("Unable to locate the configuration file.")
13
+ end
14
+
15
+ yaml = nil
16
+ file = File.open(yaml_file) {|f| yaml = f.read }
17
+ @config = YAML::load(yaml)
18
+ end
19
+
20
+ def profile(name=nil)
21
+ if name.nil?
22
+ Configuration.new(@config)
23
+ else
24
+ config = Configuration.new(@config)
25
+ profiles = @config['profiles']
26
+ if profiles.nil?
27
+ raise JabberTee::ConfigurationError.new("Unable to load an profiles from your home configuration.")
28
+ end
29
+ profile = profiles[name]
30
+ if config.nil?
31
+ raise JabberTee::ConfigurationError.new("Unable to load the #{name} profile from your home configuration.")
32
+ end
33
+ config.merge(profile)
34
+ end
35
+ end
36
+ end
37
+
38
+ class Configuration
39
+ ATTRIBUTES = ['username', 'nick', 'password', 'anonymous', 'sasl', 'digest', 'room', 'to']
40
+
41
+ attr_reader :username, :nick, :to, :room
42
+
43
+ def initialize(options=nil)
44
+ if !options.nil?
45
+ merge(options)
46
+ end
47
+ end
48
+
49
+ def merge(options)
50
+ ATTRIBUTES.each do |attr|
51
+ if options.has_key?(attr.to_sym) || options.has_key?(attr)
52
+ value = options[attr.to_sym] || options[attr]
53
+ instance_variable_set("@#{attr}", value)
54
+ end
55
+ end
56
+ self
57
+ end
58
+
59
+ def password
60
+ if @password.nil?
61
+ @password = ask("#{username}: password: ") {|q| q.echo = false }
62
+ end
63
+ @password
64
+ end
65
+
66
+ def anonymous?
67
+ !@anonymous.nil? && username.nil?
68
+ end
69
+
70
+ def sasl?
71
+ !@sasl.nil?
72
+ end
73
+
74
+ def digest?
75
+ !@digest.nil?
76
+ end
77
+
78
+ def in_room?
79
+ !@room.nil?
80
+ end
81
+
82
+ def destination_missing?
83
+ @room.nil? && @to.nil?
84
+ end
85
+
86
+ def to_s
87
+ "<JabberTee::Configuration{:username => '#{username}', :room => '#{room}', :to => '#{to}', :anonymous => #{anonymous?}, :sasl => #{sasl?}}>"
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,6 @@
1
+
2
+ module JabberTee
3
+ Error = Class.new(RuntimeError)
4
+
5
+ ConfigurationError = Class.new(JabberTee::Error)
6
+ end
@@ -0,0 +1,12 @@
1
+ require 'scanf'
2
+
3
+ module JabberTee
4
+ class Version
5
+ CURRENT = File.read(File.dirname(__FILE__) + '/../VERSION')
6
+ MAJOR, MINOR, TINY = CURRENT.scanf('%d.%d.%d')
7
+
8
+ def self.to_s
9
+ CURRENT
10
+ end
11
+ end
12
+ end
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'helpers'
2
+ require 'jabber-tee/cli'
3
+
4
+ module JabberTee
5
+
6
+ module CLIHelper
7
+ def parse(*args)
8
+ cli = CLI.new(args)
9
+ cli.parse_options(args)
10
+ cli
11
+ end
12
+
13
+ def validate(*args)
14
+ cli = CLI.new(args)
15
+ cli.parse_options(args)
16
+ cli.validate_args(args)
17
+ cli
18
+ end
19
+
20
+ def check(sym, flags, value)
21
+ flags.each do |flag|
22
+ if value.is_a?(String)
23
+ parse(flag, value).options[sym].should eql(value)
24
+ else
25
+ parse(flag).options[sym].should eql(value)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "Jabber Tee CLI interface" do
32
+ include CLIHelper
33
+
34
+ describe "when just checking arguments" do
35
+ it "should parse the username correctly" do
36
+ check(:username, ['-u', '--username'], 'someuser')
37
+ end
38
+
39
+ it "should parse the password correctly" do
40
+ check(:password, ['-p', '--password'], 'super_!!_secret')
41
+ end
42
+
43
+ it "should parse the sasl flag correctly" do
44
+ check(:sasl, ['--sasl'], true)
45
+ end
46
+
47
+ it "should parse the digest flag correctly" do
48
+ check(:digest, ['--digest'], true)
49
+ end
50
+
51
+ it "should parse the anonymous flag correctly" do
52
+ check(:anonymous, ['-a', '--anonymous'], true)
53
+ end
54
+
55
+ it "should parse the room flag correctly" do
56
+ check(:room, ['-r', '--room'], 'ROOM')
57
+ end
58
+
59
+ it "should parse the nickname flag correctly" do
60
+ check(:nick, ['-n', '--nick'], 'nickname!')
61
+ end
62
+ end
63
+
64
+ describe "while validating the arguments" do
65
+ CE = JabberTee::ConfigurationError
66
+
67
+ it "should fail when there are extra arguments" do
68
+ attempting_to { validate('extra-arg') }.should raise_error(CE, /extra/)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,91 @@
1
+ require 'jabber-tee/configuration'
2
+ require 'helpers'
3
+
4
+ module JabberTee
5
+ describe "ConfigurationReader" do
6
+ it "should fail when the yaml file doesn't exist" do
7
+ attempting_to { ConfigurationReader.new('doesnt-exist.yml') }.should raise_error(ConfigurationError, /locate/)
8
+ end
9
+
10
+ it "should load a yaml file and pull the default profile" do
11
+ r = ConfigurationReader.new('spec/test-config-1.yaml')
12
+ c = r.profile
13
+
14
+ c.username.should eql('gabe@someplace.org')
15
+ c.room.should be(nil)
16
+ end
17
+
18
+ it "should be able to load sub-profiles" do
19
+ r = ConfigurationReader.new('spec/test-config-1.yaml')
20
+ c = r.profile('standard')
21
+
22
+ c.room.should eql('cudos@rooms.someplace.org')
23
+ end
24
+
25
+ it "should fail when the profiles section doesn't exist" do
26
+ r = ConfigurationReader.new('spec/test-config-2.yaml')
27
+ attempting_to { r.profile('standard') }.should raise_error(ConfigurationError, /profiles/)
28
+ end
29
+
30
+ it "should fail when the profile doesn't exist" do
31
+ r = ConfigurationReader.new('spec/test-config-1.yaml')
32
+ attempting_to { r.profile('non-existant') }.should raise_error(ConfigurationError, /non-existant/)
33
+ end
34
+ end
35
+
36
+ describe "The Configuration" do
37
+ it "should initialize default values to nil" do
38
+ c = Configuration.new
39
+ c.username.should be(nil)
40
+ end
41
+
42
+ it "should set anonymous to false by default" do
43
+ c = Configuration.new
44
+ c.anonymous?.should be(false)
45
+ end
46
+
47
+ it "should set SASL mode to false by default" do
48
+ c = Configuration.new
49
+ c.sasl?.should be(false)
50
+ end
51
+
52
+ it "should set the digest mode to false by default" do
53
+ c = Configuration.new
54
+ c.digest?.should be(false)
55
+ end
56
+
57
+ it "should se the 'in_room?' attribute to false by default" do
58
+ c = Configuration.new
59
+ c.in_room?.should be(false)
60
+ end
61
+
62
+ it "should merge options correctly" do
63
+ options = {:username => 'gabe', :password => 'supersecret'}
64
+ c = Configuration.new(options)
65
+ c.username.should eql('gabe')
66
+ c.password.should eql('supersecret')
67
+ end
68
+
69
+ it "should set 'anonymous' to false when a username is provided" do
70
+ options = {:username => 'gabe' }
71
+ c = Configuration.new(options)
72
+ c.anonymous?.should be(false)
73
+ end
74
+
75
+ it "should merge options correctly more than once" do
76
+ init = {:username => 'gabe', :password => 'supersecret'}
77
+ options = {:room => 'rc@someplace'}
78
+ c = Configuration.new(init)
79
+ c.merge(options)
80
+ c.in_room?.should be(true)
81
+ c.room.should eql('rc@someplace')
82
+ end
83
+
84
+ it "should set the 'to' field correctly" do
85
+ c = Configuration.new
86
+ c.merge({:to => 'to-me'})
87
+ c.in_room?.should be(false)
88
+ c.to.should eql('to-me')
89
+ end
90
+ end
91
+ end
data/spec/helpers.rb ADDED
@@ -0,0 +1,9 @@
1
+
2
+
3
+ def attempting(&block)
4
+ lambda &block
5
+ end
6
+
7
+ def attempting_to(&block)
8
+ lambda &block
9
+ end
@@ -0,0 +1,13 @@
1
+ username: 'gabe@someplace.org'
2
+ password: 'pinchme!Imsecret!'
3
+ nick: 'Gabe'
4
+
5
+ profiles:
6
+ standard:
7
+ room: 'cudos@rooms.someplace.org'
8
+ sasl: true
9
+ weird:
10
+ username: 'weirdo@someplaceelse.org'
11
+ password: 'notsosecret'
12
+ nick: 'Jabberwocky Slayer'
13
+ to: 'jabber-monster@someplaceelse.org'
@@ -0,0 +1,5 @@
1
+
2
+ username: 'gabe@someplace.org'
3
+ password: 'pinchme!Imsecret!'
4
+ nick: 'Gabe'
5
+
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jabber-tee
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Gabe McArthur
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-23 00:00:00 -07:00
19
+ default_executable: jabber-tee
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: highline
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 1
32
+ - 5
33
+ - 2
34
+ version: 1.5.2
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: xmpp4r
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 1
46
+ segments:
47
+ - 0
48
+ - 5
49
+ version: "0.5"
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: rspec
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 27
61
+ segments:
62
+ - 1
63
+ - 3
64
+ - 0
65
+ version: 1.3.0
66
+ type: :development
67
+ version_requirements: *id003
68
+ description: Installs the 'jabber-pipe' utility for sending messages to a remote jabber server. Instead of a standard client, it reads from standard in and continues to write to the console.
69
+ email:
70
+ - madeonamac@gmail.com
71
+ executables:
72
+ - jabber-tee
73
+ extensions: []
74
+
75
+ extra_rdoc_files:
76
+ - README.markdown
77
+ files:
78
+ - README.markdown
79
+ - Rakefile
80
+ - bin/jabber-tee
81
+ - lib/VERSION
82
+ - lib/jabber-tee/cli.rb
83
+ - lib/jabber-tee/client.rb
84
+ - lib/jabber-tee/configuration.rb
85
+ - lib/jabber-tee/errors.rb
86
+ - lib/jabber-tee/version.rb
87
+ - spec/cli_spec.rb
88
+ - spec/configuration_spec.rb
89
+ - spec/helpers.rb
90
+ - spec/test-config-1.yaml
91
+ - spec/test-config-2.yaml
92
+ has_rdoc: true
93
+ homepage: http://github.com/gabemc/jabber-tee
94
+ licenses: []
95
+
96
+ post_install_message:
97
+ rdoc_options:
98
+ - --charset=UTF-8
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 3
116
+ segments:
117
+ - 0
118
+ version: "0"
119
+ requirements: []
120
+
121
+ rubyforge_project:
122
+ rubygems_version: 1.3.7
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Simple command line utility for piping the output from one command to both the console and a remote jabber server.
126
+ test_files:
127
+ - spec/helpers.rb
128
+ - spec/configuration_spec.rb
129
+ - spec/cli_spec.rb