tkellem 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore CHANGED
@@ -1,8 +1,8 @@
1
1
  *.gem
2
2
  .bundle
3
- Gemfile.lock
4
3
  pkg/*
5
4
  coverage/*
6
5
  doc/*
7
6
  .yardoc/*
8
7
  test.log
8
+ tmp/*
data/.travis.yml CHANGED
@@ -1,8 +1,13 @@
1
1
  language: ruby
2
+ bundler_args: --without development
2
3
  rvm:
3
4
  - "1.9.3"
4
5
  - "2.0.0"
5
- - rbx-19mode
6
6
  # uncomment this line if your project needs to run something other than `rake`:
7
7
  # script: bundle exec rspec spec
8
+ matrix:
9
+ allow_failures:
10
+ # this is intermittently failing with "attempt to unlock a mutex that is not locked" errors
11
+ # while creating an EM threadpool
12
+ - rvm: "2.0.0"
8
13
 
data/Gemfile CHANGED
@@ -4,6 +4,13 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  group :test do
7
- gem 'rspec', '~> 2.5'
8
- gem 'simplecov'
7
+ gem 'rspec', '~> 2.13.0'
8
+ gem 'mocha', '0.14.0', require: false
9
+ gem 'simplecov', require: false
10
+ gem 'coveralls', require: false
11
+ end
12
+
13
+ group :development do
14
+ gem 'guard-rspec'
15
+ gem 'rspec-nc'
9
16
  end
data/Gemfile.lock ADDED
@@ -0,0 +1,127 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ tkellem (0.9.2)
5
+ activerecord (~> 4.0.0.rc2)
6
+ eventmachine (~> 1.0.3)
7
+ rails-observers (~> 0.1.1)
8
+ sqlite3 (~> 1.3.3)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ actionpack (4.0.0.rc2)
14
+ activesupport (= 4.0.0.rc2)
15
+ builder (~> 3.1.0)
16
+ erubis (~> 2.7.0)
17
+ rack (~> 1.5.2)
18
+ rack-test (~> 0.6.2)
19
+ activemodel (4.0.0.rc2)
20
+ activesupport (= 4.0.0.rc2)
21
+ builder (~> 3.1.0)
22
+ activerecord (4.0.0.rc2)
23
+ activemodel (= 4.0.0.rc2)
24
+ activerecord-deprecated_finders (~> 1.0.2)
25
+ activesupport (= 4.0.0.rc2)
26
+ arel (~> 4.0.0)
27
+ activerecord-deprecated_finders (1.0.3)
28
+ activesupport (4.0.0.rc2)
29
+ i18n (~> 0.6, >= 0.6.4)
30
+ minitest (~> 4.2)
31
+ multi_json (~> 1.3)
32
+ thread_safe (~> 0.1)
33
+ tzinfo (~> 0.3.37)
34
+ arel (4.0.0)
35
+ atomic (1.1.9)
36
+ builder (3.1.4)
37
+ coderay (1.0.9)
38
+ colorize (0.5.8)
39
+ coveralls (0.6.7)
40
+ colorize
41
+ multi_json (~> 1.3)
42
+ rest-client
43
+ simplecov (>= 0.7)
44
+ thor
45
+ diff-lcs (1.2.4)
46
+ erubis (2.7.0)
47
+ eventmachine (1.0.3)
48
+ ffi (1.9.0)
49
+ formatador (0.2.4)
50
+ guard (1.8.1)
51
+ formatador (>= 0.2.4)
52
+ listen (>= 1.0.0)
53
+ lumberjack (>= 1.0.2)
54
+ pry (>= 0.9.10)
55
+ thor (>= 0.14.6)
56
+ guard-rspec (3.0.2)
57
+ guard (>= 1.8)
58
+ rspec (~> 2.13)
59
+ i18n (0.6.4)
60
+ listen (1.2.2)
61
+ rb-fsevent (>= 0.9.3)
62
+ rb-inotify (>= 0.9)
63
+ rb-kqueue (>= 0.2)
64
+ lumberjack (1.0.4)
65
+ metaclass (0.0.1)
66
+ method_source (0.8.1)
67
+ mime-types (1.23)
68
+ minitest (4.7.5)
69
+ mocha (0.14.0)
70
+ metaclass (~> 0.0.1)
71
+ multi_json (1.7.7)
72
+ pry (0.9.12.2)
73
+ coderay (~> 1.0.5)
74
+ method_source (~> 0.8)
75
+ slop (~> 3.4)
76
+ rack (1.5.2)
77
+ rack-test (0.6.2)
78
+ rack (>= 1.0)
79
+ rails-observers (0.1.1)
80
+ railties (~> 4.0.0.beta)
81
+ railties (4.0.0.rc2)
82
+ actionpack (= 4.0.0.rc2)
83
+ activesupport (= 4.0.0.rc2)
84
+ rake (>= 0.8.7)
85
+ thor (>= 0.18.1, < 2.0)
86
+ rake (10.1.0)
87
+ rb-fsevent (0.9.3)
88
+ rb-inotify (0.9.0)
89
+ ffi (>= 0.5.0)
90
+ rb-kqueue (0.2.0)
91
+ ffi (>= 0.5.0)
92
+ rest-client (1.6.7)
93
+ mime-types (>= 1.16)
94
+ rspec (2.13.0)
95
+ rspec-core (~> 2.13.0)
96
+ rspec-expectations (~> 2.13.0)
97
+ rspec-mocks (~> 2.13.0)
98
+ rspec-core (2.13.1)
99
+ rspec-expectations (2.13.0)
100
+ diff-lcs (>= 1.1.3, < 2.0)
101
+ rspec-mocks (2.13.1)
102
+ rspec-nc (0.0.6)
103
+ rspec (~> 2.9)
104
+ terminal-notifier (~> 1.4.2)
105
+ simplecov (0.7.1)
106
+ multi_json (~> 1.0)
107
+ simplecov-html (~> 0.7.1)
108
+ simplecov-html (0.7.1)
109
+ slop (3.4.5)
110
+ sqlite3 (1.3.7)
111
+ terminal-notifier (1.4.2)
112
+ thor (0.18.1)
113
+ thread_safe (0.1.0)
114
+ atomic
115
+ tzinfo (0.3.37)
116
+
117
+ PLATFORMS
118
+ ruby
119
+
120
+ DEPENDENCIES
121
+ coveralls
122
+ guard-rspec
123
+ mocha (= 0.14.0)
124
+ rspec (~> 2.13.0)
125
+ rspec-nc
126
+ simplecov
127
+ tkellem!
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec, cli: '-f progress -f Nc', env: { 'NO_SIMPLECOV' => '1' } do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(tkellem/)?(.+)\.rb$}) { |m| "spec/#{m[2]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  [![Build
4
4
  Status](https://travis-ci.org/codekitchen/tkellem.png)](https://travis-ci.org/codekitchen/tkellem)
5
+ [![Code Climate](https://codeclimate.com/github/codekitchen/tkellem.png)](https://codeclimate.com/github/codekitchen/tkellem)
6
+ [![Coverage Status](https://coveralls.io/repos/codekitchen/tkellem/badge.png)](https://coveralls.io/r/codekitchen/tkellem)
7
+
5
8
 
6
9
  tkellem is an IRC bouncer, a proxy that keeps you permanently logged on to an
7
10
  IRC server and stores all messages so that when your client next connects, you
@@ -1,48 +1,40 @@
1
1
  class BackwardsFileReader
2
- def self.scan(stream)
3
- scanner = new(stream)
2
+ def self.scan(stream, *init_args)
3
+ scanner = new(stream, *init_args)
4
4
  while line = scanner.readline
5
5
  break unless yield(line)
6
6
  end
7
7
  scanner.sync
8
8
  end
9
9
 
10
- def initialize(stream)
10
+ DEFAULT_READ_SIZE = 4096
11
+
12
+ def initialize(stream, read_size = DEFAULT_READ_SIZE)
11
13
  @stream = stream
12
14
  @stream.seek 0, IO::SEEK_END
13
15
  @pos = @stream.pos
14
- @offset = 0
15
16
 
16
- @read_size = [4096, @pos].min
17
+ @read_size = [read_size, @pos].min
17
18
  @line_buffer = []
18
19
  end
19
20
 
20
21
  def readline
21
- if @line_buffer.size > 2 || @pos == 0
22
- line = @line_buffer.pop
23
- if line
24
- @offset += line.length
25
- end
26
- return line
27
- end
28
-
29
- @read_size = [@read_size, @pos].min
30
- @pos -= @read_size
31
- @stream.seek(@pos, IO::SEEK_SET)
32
- @offset = -@line_buffer.reduce(0) { |n,l| n + l.length }
22
+ while @line_buffer.size < 2 && @pos > 0
23
+ @read_size = [@read_size, @pos].min
24
+ @pos -= @read_size
25
+ @stream.seek(@pos, IO::SEEK_SET)
33
26
 
34
- @line_buffer[0] = "#{@stream.read(@read_size)}#{@line_buffer[0]}"
35
- @line_buffer[0] = @line_buffer[0].scan(%r{.*\n})
36
- @line_buffer.flatten!
27
+ @line_buffer[0] = "#{@stream.read(@read_size)}#{@line_buffer[0]}"
28
+ @line_buffer[0] = @line_buffer[0].scan(%r{.*\n})
29
+ @line_buffer.flatten!
30
+ end
37
31
 
38
- readline
32
+ @line_buffer.pop
39
33
  end
40
34
 
41
35
  def sync
42
- if @offset > 0
43
- @stream.seek(-@offset, IO::SEEK_CUR)
44
- end
45
- @offset = 0
36
+ offset = @read_size - @line_buffer.inject(0) { |n, l| n + l.size }
37
+ @stream.seek(-offset, IO::SEEK_CUR) if offset != 0
46
38
  @stream
47
39
  end
48
40
  end
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'active_support/core_ext/class/attribute_accessors'
2
3
 
3
4
  require 'tkellem/irc_server'
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'active_support/core_ext/object/blank'
2
3
 
3
4
  require 'eventmachine'
@@ -91,6 +92,7 @@ module BouncerConnection
91
92
 
92
93
  def receive_line(line)
93
94
  failsafe("message: {#{line}}") do
95
+ line.force_encoding Encoding::UTF_8
94
96
  trace "from client: #{line}"
95
97
  return if line.blank?
96
98
  msg = IrcMessage.parse(line)
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'fileutils'
2
3
  require 'optparse'
3
4
 
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  module Tkellem
2
3
 
3
4
  class IrcMessage < Struct.new(:prefix, :command, :args, :ctcp)
@@ -50,10 +51,6 @@ class IrcMessage < Struct.new(:prefix, :command, :args, :ctcp)
50
51
  self.ctcp == 'ACTION'
51
52
  end
52
53
 
53
- def command?(cmd)
54
- @command.downcase == cmd.downcase
55
- end
56
-
57
54
  def replay
58
55
  line = []
59
56
  line << ":#{prefix}" unless prefix.nil?
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'eventmachine'
2
3
  require 'set'
3
4
  require 'socket'
@@ -39,6 +40,7 @@ module IrcServerConnection
39
40
 
40
41
  def receive_line(line)
41
42
  @bouncer.failsafe(:receive_line) do
43
+ line.force_encoding Encoding::UTF_8
42
44
  @bouncer.trace "from server: #{line}"
43
45
  return if line.blank?
44
46
  msg = IrcMessage.parse(line)
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'backwards_file_reader'
2
3
  require 'fileutils'
3
4
  require 'pathname'
@@ -94,7 +95,7 @@ class Backlog
94
95
  end
95
96
 
96
97
  def get_stream(ctx, for_reading = false)
97
- mode = for_reading ? 'rb' : 'ab'
98
+ mode = for_reading ? 'rb:utf-8' : 'ab:utf-8'
98
99
  ctx = ctx.gsub(%r{[\./\\]}, '')
99
100
  path = stream_path(ctx)
100
101
  return nil if !path.file? && for_reading
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'eventmachine'
2
3
 
3
4
  require 'tkellem/tkellem_bot'
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'shellwords'
2
3
  require 'yaml'
3
4
 
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'eventmachine'
2
3
  require 'active_record'
3
4
  require 'rails/observers/activerecord/active_record'
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  module Tkellem
2
- VERSION = "0.9.1"
3
+ VERSION = "0.9.2"
3
4
  end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+
3
+ describe BackwardsFileReader do
4
+ let :testfile do
5
+ Tempfile.new("tkellem-test").tap do |tf|
6
+ tf.write <<-LINES
7
+ line1
8
+ line2
9
+ line3
10
+ LINES
11
+ tf.rewind
12
+ end
13
+ end
14
+
15
+ describe '.scan' do
16
+ it "should read all lines" do
17
+ results = mock('lines')
18
+ results.expects(:got).with("line3\n")
19
+ results.expects(:got).with("line2\n")
20
+ results.expects(:got).with("line1\n")
21
+
22
+ BackwardsFileReader.scan(testfile) { |line| results.got(line); true }
23
+ testfile.pos.should == 0
24
+ end
25
+
26
+ it "should abort if the block returns false" do
27
+ results = mock('lines')
28
+ results.expects(:got).with("line3\n")
29
+ results.expects(:got).with("line2\n")
30
+ BackwardsFileReader.scan(testfile) do |line|
31
+ results.got(line)
32
+ line != "line2\n"
33
+ end
34
+ testfile.pos.should == 6
35
+ end
36
+ end
37
+
38
+ describe "#readline" do
39
+ it "should read correctly with a buffer size smaller than one line" do
40
+ reader = BackwardsFileReader.new(testfile, 2)
41
+ reader.readline.should == "line3\n"
42
+ reader.readline.should == "line2\n"
43
+ reader.readline.should == "line1\n"
44
+ reader.readline.should == nil
45
+ end
46
+
47
+ it "should read correctly with a buffer size larger than one line" do
48
+ reader = BackwardsFileReader.new(testfile, 6)
49
+ reader.readline.should == "line3\n"
50
+ reader.readline.should == "line2\n"
51
+ reader.readline.should == "line1\n"
52
+ reader.readline.should == nil
53
+ end
54
+ end
55
+
56
+ describe "#sync" do
57
+ it "should reset the stream position to the current line" do
58
+ reader = BackwardsFileReader.new(testfile)
59
+ reader.readline
60
+ reader.sync.should == testfile
61
+ testfile.pos.should == testfile.size - 6
62
+
63
+ reader = BackwardsFileReader.new(testfile)
64
+ reader.readline
65
+ reader.readline
66
+ reader.sync.should == testfile
67
+ testfile.pos.should == testfile.size - 12
68
+ end
69
+
70
+ it "should reset correctly with a buffer size smaller than one line" do
71
+ reader = BackwardsFileReader.new(testfile, 2)
72
+ reader.readline
73
+ reader.sync.should == testfile
74
+ testfile.pos.should == testfile.size - 6
75
+
76
+ reader = BackwardsFileReader.new(testfile, 2)
77
+ reader.readline
78
+ reader.readline
79
+ reader.sync.should == testfile
80
+ testfile.pos.should == testfile.size - 12
81
+ end
82
+
83
+ it "should reset correctly with a buffer size larger than one line" do
84
+ reader = BackwardsFileReader.new(testfile, 7)
85
+ reader.readline
86
+ reader.sync.should == testfile
87
+ testfile.pos.should == testfile.size - 6
88
+
89
+ reader = BackwardsFileReader.new(testfile, 7)
90
+ reader.readline
91
+ reader.readline
92
+ reader.sync.should == testfile
93
+ testfile.pos.should == testfile.size - 12
94
+ end
95
+ end
96
+
97
+ it "should support resuming" do
98
+ reader = BackwardsFileReader.new(testfile, 2)
99
+ reader.readline.should == "line3\n"
100
+ reader.sync
101
+ testfile.pos.should == testfile.size - 6
102
+ reader.readline.should == "line2\n"
103
+ reader.sync
104
+ testfile.pos.should == testfile.size - 12
105
+ reader.readline.should == "line1\n"
106
+ reader.sync
107
+ testfile.pos.should == 0
108
+ end
109
+ end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'tkellem/irc_message'
3
+ require 'time'
3
4
 
4
5
  include Tkellem
5
6
 
@@ -41,12 +42,19 @@ end
41
42
  describe IrcMessage, "#with_timestamp" do
42
43
  it "should prefix a timestamp to the last arg" do
43
44
  line = IrcMessage.parse(":some_long_prefix COMMAND first second :long arg here")
44
- require 'time'
45
45
  timestamp = Time.parse("Thu Nov 29 14:33:20 2001")
46
46
  ts_line = line.with_timestamp(timestamp)
47
47
  ts_line.should be_a(IrcMessage)
48
48
  ts_line.to_s.should == ":some_long_prefix COMMAND first second :2001-11-29 14:33:20> long arg here"
49
49
  end
50
+
51
+ it "should not prefix the date if the message is < 24 hours old" do
52
+ line = IrcMessage.parse(":some_long_prefix COMMAND first second :long arg here")
53
+ timestamp = 3.hours.ago
54
+ ts_line = line.with_timestamp(timestamp)
55
+ ts_line.should be_a(IrcMessage)
56
+ ts_line.to_s.should == ":some_long_prefix COMMAND first second :#{timestamp.strftime("%H:%M:%S")}> long arg here"
57
+ end
50
58
  end
51
59
 
52
60
  describe IrcMessage do
@@ -59,6 +67,22 @@ describe IrcMessage do
59
67
  line2.args.should == %w(one two three)
60
68
  line2.args.last.should == "three"
61
69
  end
70
+
71
+ describe ".parse_client_command" do
72
+ it "should return nil for non-client commands" do
73
+ IrcMessage.parse_client_command("PRIVMSG a :b c d").should == nil
74
+ end
75
+
76
+ it "should turn /msg into a PRIVMSG command" do
77
+ IrcMessage.parse_client_command("/msg brian hai there").should ==
78
+ IrcMessage.new(nil, "PRIVMSG", ["brian", "hai there"])
79
+ end
80
+
81
+ it "should treat other commands literally" do
82
+ IrcMessage.parse_client_command("/join #tkellem").should ==
83
+ IrcMessage.new(nil, "JOIN", ["#tkellem"])
84
+ end
85
+ end
62
86
  end
63
87
 
64
88
  describe IrcMessage, "CTCP" do
data/spec/spec_helper.rb CHANGED
@@ -2,9 +2,19 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
 
4
4
  require 'rspec'
5
- require 'simplecov'
6
- SimpleCov.start do
7
- add_filter "/spec"
5
+ require 'mocha/api'
6
+
7
+ unless ENV['NO_SIMPLECOV']
8
+ require 'simplecov'
9
+ require 'coveralls'
10
+ SimpleCov.formatter = if ENV['TRAVIS']
11
+ Coveralls::SimpleCov::Formatter
12
+ else
13
+ SimpleCov::Formatter::HTMLFormatter
14
+ end
15
+ SimpleCov.start do
16
+ add_filter "/spec"
17
+ end
8
18
  end
9
19
 
10
20
  require 'tkellem'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tkellem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-26 00:00:00.000000000 Z
12
+ date: 2013-06-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -83,9 +83,12 @@ executables:
83
83
  extensions: []
84
84
  extra_rdoc_files: []
85
85
  files:
86
+ - .coveralls.yml
86
87
  - .gitignore
87
88
  - .travis.yml
88
89
  - Gemfile
90
+ - Gemfile.lock
91
+ - Guardfile
89
92
  - LICENSE
90
93
  - README.md
91
94
  - Rakefile
@@ -101,7 +104,6 @@ files:
101
104
  - debian/rules
102
105
  - debian/source/format
103
106
  - debian/tkellem.1
104
- - examples/config.yml
105
107
  - lib/backwards_file_reader.rb
106
108
  - lib/tkellem.rb
107
109
  - lib/tkellem/bouncer.rb
@@ -129,6 +131,7 @@ files:
129
131
  - lib/tkellem/version.rb
130
132
  - resources/bot_command_descriptions.yml
131
133
  - resources/setting_descriptions.yml
134
+ - spec/backwards_file_reader_spec.rb
132
135
  - spec/bouncer_connection_spec.rb
133
136
  - spec/irc_message_spec.rb
134
137
  - spec/irc_server_spec.rb
@@ -148,7 +151,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
151
  version: '0'
149
152
  segments:
150
153
  - 0
151
- hash: 4403450271075957014
154
+ hash: -1609570308087987502
152
155
  required_rubygems_version: !ruby/object:Gem::Requirement
153
156
  none: false
154
157
  requirements:
@@ -157,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
160
  version: '0'
158
161
  segments:
159
162
  - 0
160
- hash: 4403450271075957014
163
+ hash: -1609570308087987502
161
164
  requirements: []
162
165
  rubyforge_project:
163
166
  rubygems_version: 1.8.23
@@ -165,6 +168,7 @@ signing_key:
165
168
  specification_version: 3
166
169
  summary: IRC bouncer with multi-client support
167
170
  test_files:
171
+ - spec/backwards_file_reader_spec.rb
168
172
  - spec/bouncer_connection_spec.rb
169
173
  - spec/irc_message_spec.rb
170
174
  - spec/irc_server_spec.rb
data/examples/config.yml DELETED
@@ -1,2 +0,0 @@
1
- # this file is deprecated, settings are now stored in ~/.tkellem/tkellem.sqlite3
2
- # more help to come