pipio 0.0.1

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 (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +2 -0
  4. data/.simplecov +5 -0
  5. data/.travis.yml +12 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +20 -0
  8. data/NEWS.md +10 -0
  9. data/README.md +88 -0
  10. data/Rakefile +13 -0
  11. data/lib/pipio.rb +34 -0
  12. data/lib/pipio/alias_registry.rb +26 -0
  13. data/lib/pipio/chat.rb +39 -0
  14. data/lib/pipio/cleaners/html_cleaner.rb +95 -0
  15. data/lib/pipio/cleaners/text_cleaner.rb +15 -0
  16. data/lib/pipio/file_reader.rb +29 -0
  17. data/lib/pipio/message_creators/auto_or_xml_message_creator.rb +25 -0
  18. data/lib/pipio/message_creators/event_message_creator.rb +47 -0
  19. data/lib/pipio/message_creators/status_message_creator.rb +19 -0
  20. data/lib/pipio/messages/auto_reply_message.rb +7 -0
  21. data/lib/pipio/messages/event.rb +67 -0
  22. data/lib/pipio/messages/message.rb +23 -0
  23. data/lib/pipio/messages/status_message.rb +26 -0
  24. data/lib/pipio/messages/xml_message.rb +43 -0
  25. data/lib/pipio/metadata.rb +34 -0
  26. data/lib/pipio/metadata_parser.rb +55 -0
  27. data/lib/pipio/parser_factory.rb +32 -0
  28. data/lib/pipio/parsers/basic_parser.rb +83 -0
  29. data/lib/pipio/parsers/html_log_parser.rb +22 -0
  30. data/lib/pipio/parsers/null_parser.rb +9 -0
  31. data/lib/pipio/parsers/text_log_parser.rb +21 -0
  32. data/lib/pipio/tag_balancer.rb +163 -0
  33. data/lib/pipio/time_parser.rb +36 -0
  34. data/lib/pipio/version.rb +3 -0
  35. data/pipio.gemspec +27 -0
  36. data/spec/pipio/alias_registry_spec.rb +37 -0
  37. data/spec/pipio/chat_spec.rb +66 -0
  38. data/spec/pipio/cleaners/html_cleaner_spec.rb +102 -0
  39. data/spec/pipio/cleaners/text_cleaner_spec.rb +29 -0
  40. data/spec/pipio/file_reader_spec.rb +130 -0
  41. data/spec/pipio/messages/auto_reply_message_spec.rb +40 -0
  42. data/spec/pipio/messages/event_spec.rb +41 -0
  43. data/spec/pipio/messages/status_message_spec.rb +43 -0
  44. data/spec/pipio/messages/xml_message_spec.rb +55 -0
  45. data/spec/pipio/metadata_parser_spec.rb +81 -0
  46. data/spec/pipio/metadata_spec.rb +72 -0
  47. data/spec/pipio/parser_factory_spec.rb +31 -0
  48. data/spec/pipio/parsers/html_log_parser_spec.rb +160 -0
  49. data/spec/pipio/parsers/null_parser_spec.rb +13 -0
  50. data/spec/pipio/parsers/text_log_parser_spec.rb +37 -0
  51. data/spec/pipio/tag_balancer_spec.rb +16 -0
  52. data/spec/pipio/time_parser_spec.rb +66 -0
  53. data/spec/pipio_spec.rb +63 -0
  54. data/spec/spec_helper.rb +18 -0
  55. data/spec/support/chat_builder.rb +29 -0
  56. data/spec/support/chat_builder_helpers.rb +41 -0
  57. data/spec/support/file_builder.rb +22 -0
  58. data/spec/support/html_chat_builder.rb +67 -0
  59. data/spec/support/logfiles/2006-12-21.223606.txt +3 -0
  60. data/spec/support/logfiles/2008-01-15.071445-0500PST.htm +5 -0
  61. data/spec/support/logfiles/2008-01-15.071445-0500PST.html +5 -0
  62. data/spec/support/text_chat_builder.rb +21 -0
  63. data/spec/test-output/README.md +1 -0
  64. data/spec/test-output/html_log_output.xml +6 -0
  65. data/spec/test-output/text_log_output.xml +4 -0
  66. metadata +193 -0
@@ -0,0 +1,31 @@
1
+ describe Pipio::ParserFactory do
2
+ let(:aliases) { '' }
3
+
4
+ %w(html htm HTML).each do |html_extension|
5
+ context "when passed a .#{html_extension} file" do
6
+ it 'returns an HtmlLogParser' do
7
+ logfile_path = "whatever.#{html_extension}"
8
+ factory = Pipio::ParserFactory.new(logfile_path, aliases)
9
+ expect(factory.parser).to be_a Pipio::HtmlLogParser
10
+ end
11
+ end
12
+ end
13
+
14
+ %w(txt TXT).each do |text_extension|
15
+ context "when passed a .#{text_extension} file" do
16
+ it 'returns a TextLogParser' do
17
+ logfile_path = "whatever.#{text_extension}"
18
+ factory = Pipio::ParserFactory.new(logfile_path, aliases)
19
+ expect(factory.parser).to be_a Pipio::TextLogParser
20
+ end
21
+ end
22
+ end
23
+
24
+ context 'when passed a non-HTML, non-text file' do
25
+ it 'returns something that responds to parse' do
26
+ other_path = 'foo.bar'
27
+ factory = Pipio::ParserFactory.new(other_path, aliases)
28
+ expect(factory.parser).to respond_to(:parse)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,160 @@
1
+ describe Pipio::HtmlLogParser do
2
+ context '#parse' do
3
+ it 'returns a Chat with the correct number of lines' do
4
+ chat = build_chat do |b|
5
+ b.first_line
6
+ 3.times { b.message }
7
+ end
8
+
9
+ expect(chat.messages.size).to eq(3)
10
+ end
11
+
12
+ it 'returns a Chat with the correct message type' do
13
+ chat = build_chat do |b|
14
+ b.first_line
15
+ b.message 'first'
16
+ b.message 'second'
17
+ end
18
+
19
+ expect(chat.messages.map(&:class)).to eq([Pipio::XMLMessage] * 2)
20
+ end
21
+
22
+ {
23
+ 'Gabe B-W logged in.' => 'online',
24
+ 'Gabe B-W logged out.' => 'offline',
25
+ 'Gabe B-W has signed on.' => 'online',
26
+ 'Gabe B-W has signed off.' => 'offline',
27
+ 'Gabe B-W has gone away.' => 'away',
28
+ 'Gabe B-W is no longer away.' => 'available',
29
+ 'Gabe B-W has become idle.' => 'idle',
30
+ 'Gabe B-W is no longer idle.' => 'available'
31
+ }.each do |line, status|
32
+ it "correctly detects status messages of format '#{line}'" do
33
+ message = first_line_of_chat do |b|
34
+ b.first_line
35
+ b.status line
36
+ end
37
+
38
+ expect(message.status).to eq(status)
39
+ end
40
+ end
41
+
42
+ it 'correctly detects libpurple events' do
43
+ message = first_line_of_chat do |b|
44
+ b.first_line
45
+ b.status 'Starting transfer of kitten.jpg from Gabe B-W'
46
+ end
47
+
48
+ expect(message.event_type).to eq('libpurpleEvent')
49
+ end
50
+
51
+ it 'correctly detects non-libpurple events' do
52
+ message = first_line_of_chat do |b|
53
+ b.first_line
54
+ b.status 'You missed 8 messages from Gabe B-W because they were too large'
55
+ end
56
+
57
+ expect(message.event_type).to eq('chat-error')
58
+ end
59
+
60
+ it 'does not build Messages for ignored events' do
61
+ chat = build_chat do |b|
62
+ b.first_line
63
+ b.status 'Gabe B-W is now known as gbw.'
64
+ end
65
+
66
+ expect(chat.messages).to eq([nil])
67
+ end
68
+
69
+ it 'correctly detects auto-reply messages' do
70
+ message = first_line_of_chat do |b|
71
+ b.first_line
72
+ b.auto_reply 'I ran out for a bit'
73
+ end
74
+
75
+ expect(message).to be_instance_of(Pipio::AutoReplyMessage)
76
+ expect(message.body).to eq('I ran out for a bit')
77
+ end
78
+
79
+ it 'parses out the screen name for the user who is doing the logging' do
80
+ message = first_line_of_chat('Gabe B-W') do |b|
81
+ b.first_line from: 'from', to: 'to'
82
+ b.message 'whatever', from: 'from', from_alias: 'Gabe B-W'
83
+ end
84
+
85
+ expect(message.sender_screen_name).to eq('from')
86
+ end
87
+
88
+ it 'parses out the alias for the user who is doing the logging' do
89
+ message = first_line_of_chat do |b|
90
+ b.first_line from: 'from', to: 'to'
91
+ b.message 'whatever', from_alias: 'Jack Alias'
92
+ end
93
+
94
+ expect(message.sender_alias).to eq('Jack Alias')
95
+ end
96
+
97
+ it 'parses out the screen name for the user on the other end' do
98
+ message = first_line_of_chat('my-alias') do |b|
99
+ b.first_line from: 'from'
100
+ b.message 'whatever', from: 'from', from_alias: 'my-alias'
101
+ end
102
+
103
+ expect(message.sender_screen_name).to eq('from')
104
+ end
105
+
106
+ it 'parses out the alias for the user on the other end' do
107
+ message = first_line_of_chat('my-alias') do |b|
108
+ b.first_line from: 'from'
109
+ b.message 'whatever', from: 'from', from_alias: 'my-alias'
110
+ end
111
+
112
+ expect(message.sender_alias).to eq('my-alias')
113
+ end
114
+
115
+ it 'parses out the time' do
116
+ message = first_line_of_chat do |b|
117
+ b.first_line
118
+ b.message 'whatever', time: '2008-01-15 07:14:45'
119
+ end
120
+
121
+ expect(message.time).to eq(Time.parse('2008-01-15 07:14:45'))
122
+ end
123
+
124
+ it 'parses out the body' do
125
+ message = first_line_of_chat do |b|
126
+ b.first_line
127
+ b.message 'body'
128
+ end
129
+
130
+ expect(message.body).to eq('body')
131
+ end
132
+
133
+ it 'double quotes hrefs in the body' do
134
+ body_with_link = %q(<a href='http://google.com'>first</a>)
135
+ message = first_line_of_chat do |b|
136
+ b.first_line
137
+ b.message body_with_link
138
+ end
139
+
140
+ expect(message.body).to eq(body_with_link.gsub("'", '"'))
141
+ end
142
+
143
+ it 'has access to the screen name of the other person' do
144
+ chat = build_chat do |b|
145
+ b.first_line to: 'person_on_the_other_end'
146
+ end
147
+
148
+ expect(chat.their_screen_name).to eq('person_on_the_other_end')
149
+ end
150
+ end
151
+
152
+ def build_chat(aliases = 'Gabe B-W', &block)
153
+ file = create_chat_file('file.html', &block)
154
+ Pipio::HtmlLogParser.new(file.path, aliases).parse
155
+ end
156
+
157
+ def first_line_of_chat(aliases = 'Gabe B-W', &block)
158
+ build_chat(aliases, &block).messages.first
159
+ end
160
+ end
@@ -0,0 +1,13 @@
1
+ describe Pipio::NullParser do
2
+ context '#parse' do
3
+ it 'does nothing' do
4
+ expect do
5
+ Pipio::NullParser.new('path/to/file', 'alias').parse
6
+ end.not_to raise_error
7
+ end
8
+
9
+ it 'returns falsy' do
10
+ expect(Pipio::NullParser.new('path/to/file', 'alias').parse).not_to be
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,37 @@
1
+ describe Pipio::TextLogParser do
2
+ describe "#parse" do
3
+ it "returns a Chat with the correct number of lines" do
4
+ chat = build_chat do |b|
5
+ b.message
6
+ end
7
+
8
+ expect(chat.messages.size).to eq(1)
9
+ end
10
+
11
+ it "returns a Chat with the correct message type" do
12
+ chat = build_chat do |b|
13
+ b.message
14
+ end
15
+
16
+ expect(chat.messages.first).to be_instance_of(Pipio::XMLMessage)
17
+ end
18
+
19
+ it "returns a Chat with the correct data" do
20
+ message = build_chat do |b|
21
+ b.first_line time: '2006-12-21 22:36:06', from: 'awesome SN'
22
+ b.message from_alias: 'Gabe B-W', time: '22:36:11',
23
+ text: "what are you doing tomorrow?"
24
+ end.messages.first
25
+
26
+ expect(message.sender_screen_name).to eq("awesomesn")
27
+ expect(message.body).to eq("what are you doing tomorrow?")
28
+ expect(message.sender_alias).to eq("Gabe B-W")
29
+ expect(message.time).to eq(Time.parse('2006-12-21 22:36:11').utc)
30
+ end
31
+ end
32
+
33
+ def build_chat(aliases = 'Gabe B-W', &block)
34
+ path = create_chat_file('file.txt', &block).path
35
+ Pipio::TextLogParser.new(path, aliases).parse
36
+ end
37
+ end
@@ -0,0 +1,16 @@
1
+ describe Pipio::TagBalancer do
2
+ describe 'text without tags' do
3
+ it 'is left untouched' do
4
+ text = 'foo!'
5
+ expect(Pipio::TagBalancer.new(text).balance).to eq(text)
6
+ end
7
+ end
8
+
9
+ describe 'text with tags' do
10
+ it 'is balanced correctly' do
11
+ unbalanced = '<p><b>this is unbalanced!'
12
+ balanced = '<p><b>this is unbalanced!</b></p>'
13
+ expect(Pipio::TagBalancer.new(unbalanced).balance).to eq(balanced)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,66 @@
1
+ describe Pipio::TimeParser, "#parse" do
2
+ it 'returns nil when timestamp is nil' do
3
+ time_parser = Pipio::TimeParser.new(2011, 2, 3)
4
+
5
+ expect(time_parser.parse(nil)).to be_nil
6
+ end
7
+
8
+ context 'when the given timestamp does have a date' do
9
+ let(:time_parser) { Pipio::TimeParser.new(2011, 4, 28) }
10
+
11
+ it 'parses "%m/%d/%Y %I:%M:%S %P"' do
12
+ timestamp = '01/22/2008 03:01:45 PM'
13
+ result = time_parser.parse(timestamp)
14
+ expect(result.year).to eq(2008)
15
+ expect(result.mon).to eq(1)
16
+ expect(result.mday).to eq(22)
17
+ expect(result.hour).to eq(15)
18
+ expect(result.min).to eq(1)
19
+ expect(result.sec).to eq(45)
20
+ end
21
+
22
+ [
23
+ '%Y-%m-%d %H:%M:%S',
24
+ '%Y/%m/%d %H:%M:%S',
25
+ '%Y-%m-%d %H:%M:%S',
26
+ '%a %b %d %H:%M:%S %Y'
27
+ ].each do |format|
28
+ it "parses '#{format}'" do
29
+ time = Time.now
30
+ timestamp = time.strftime(format)
31
+ expect(time_parser.parse(timestamp)).to eq(Time.parse(timestamp))
32
+ end
33
+ end
34
+
35
+ it 'parses "%a %d %b %Y %H:%M:%S %p %Z", respecting TZ' do
36
+ timestamp = "Sat 18 Apr 2009 10:43:35 AM PDT"
37
+ time = Time.parse(timestamp)
38
+ expect(time.utc.hour).to eq(17)
39
+ expect(time_parser.parse(timestamp)).to eq(time)
40
+ end
41
+ end
42
+
43
+ context 'when the given timestamp does not have a date' do
44
+ let(:time_parser) { Pipio::TimeParser.new(2008, 4, 27) }
45
+
46
+ it 'parses "%I:%M:%S %P"' do
47
+ result = time_parser.parse('08:01:45 PM')
48
+ expect(result.year).to eq(2008)
49
+ expect(result.mon).to eq(4)
50
+ expect(result.mday).to eq(27)
51
+ expect(result.hour).to eq(20)
52
+ expect(result.min).to eq(1)
53
+ expect(result.sec).to eq(45)
54
+ end
55
+
56
+ it 'parses "%H:%M:%S"' do
57
+ result = time_parser.parse('23:01:45')
58
+ expect(result.year).to eq(2008)
59
+ expect(result.mon).to eq(4)
60
+ expect(result.mday).to eq(27)
61
+ expect(result.hour).to eq(23)
62
+ expect(result.min).to eq(1)
63
+ expect(result.sec).to eq(45)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,63 @@
1
+ describe Pipio, ".parse" do
2
+ context "with bad input" do
3
+ it "returns false when file is not text or html" do
4
+ expect(Pipio.parse(non_html_or_txt_path, aliases)).to be_falsey
5
+ end
6
+
7
+ it "returns false for nonexistent files" do
8
+ expect(Pipio.parse('i_do_not_exist.html', aliases)).to be_falsey
9
+ expect(Pipio.parse('i_do_not_exist.txt', aliases)).to be_falsey
10
+ end
11
+
12
+ def non_html_or_txt_path
13
+ 'logfile.foobar'
14
+ end
15
+ end
16
+
17
+ context "with good input" do
18
+ context "for a text file" do
19
+ it "returns a Chat instance" do
20
+ result = Pipio.parse(text_logfile_path, aliases)
21
+ expect(result).to be_instance_of(Pipio::Chat)
22
+ end
23
+ end
24
+
25
+ context "for an htm file" do
26
+ it "returns a Chat instance" do
27
+ result = Pipio.parse(htm_logfile_path, aliases)
28
+ expect(result).to be_instance_of(Pipio::Chat)
29
+ end
30
+ end
31
+
32
+ context "for an html file" do
33
+ it "returns a Chat instance" do
34
+ result = Pipio.parse(html_logfile_path, aliases)
35
+ expect(result).to be_instance_of(Pipio::Chat)
36
+ end
37
+ end
38
+ end
39
+
40
+ def spec_directory
41
+ File.dirname(__FILE__)
42
+ end
43
+
44
+ def logfile_path
45
+ Pathname.new(File.join(spec_directory, "support", "logfiles"))
46
+ end
47
+
48
+ def text_logfile_path
49
+ logfile_path.join("2006-12-21.223606.txt")
50
+ end
51
+
52
+ def htm_logfile_path
53
+ logfile_path.join("2008-01-15.071445-0500PST.htm")
54
+ end
55
+
56
+ def html_logfile_path
57
+ logfile_path.join("2008-01-15.071445-0500PST.html")
58
+ end
59
+
60
+ def aliases
61
+ ''
62
+ end
63
+ end
@@ -0,0 +1,18 @@
1
+ require 'simplecov'
2
+
3
+ $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
4
+ $LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
5
+
6
+ require 'fileutils'
7
+ require 'pipio'
8
+ require 'mocha/api'
9
+
10
+ Dir['spec/support/**/*.rb'].each { |f| require File.expand_path(f) }
11
+
12
+ RSpec.configure do |config|
13
+ config.mock_with :mocha
14
+
15
+ config.expect_with :rspec do |c|
16
+ c.syntax = :expect
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ # Usage:
2
+ # # determine format from passed-in file
3
+ # ChatBuilder.new('file.html') do |b|
4
+ # b.first_line
5
+ # b.message from: 'name1', from_alias: 'Gabe B-W',
6
+ # time: '2010-01-30', text: 'blarg balrg'
7
+ # b.message 'blerg' from: 'name2',
8
+ # from_alias: 'another name', time: '2010-01-30'
9
+ # b.away_message
10
+ # b.status_message
11
+ # end
12
+
13
+ class ChatBuilder
14
+ DEFAULT_FROM = 'FROM_SN'
15
+
16
+ def initialize(file)
17
+ @file = file
18
+ @first_line = nil
19
+ @messages = []
20
+ end
21
+
22
+ def write(separator = "")
23
+ @file.puts(first_line)
24
+ @messages.each do |message|
25
+ @file.puts(message + separator)
26
+ end
27
+ @file.close
28
+ end
29
+ end
@@ -0,0 +1,41 @@
1
+ require File.expand_path('./file_builder', File.dirname(__FILE__))
2
+
3
+ module ChatBuilderHelpers
4
+ SPEC_DIR = File.dirname(File.dirname(__FILE__))
5
+ TMP_DIRECTORY = File.join(SPEC_DIR, 'tmp')
6
+
7
+ def create_chat_file(file_name = 'whatever.txt')
8
+ file = FileBuilder.create_file(file_name)
9
+ correct_builder_for(file).tap do |builder|
10
+ yield builder if block_given?
11
+ builder.write
12
+ end
13
+ file
14
+ end
15
+
16
+ def clean_up_generated_chat_files
17
+ FileUtils.rm_rf(TMP_DIRECTORY)
18
+ end
19
+
20
+ private
21
+
22
+ def correct_builder_for(file)
23
+ if file.path =~ /\.html?$/
24
+ HtmlChatBuilder.new(file)
25
+ else
26
+ TextChatBuilder.new(file)
27
+ end
28
+ end
29
+ end
30
+
31
+ RSpec.configure do |config|
32
+ config.include ChatBuilderHelpers
33
+
34
+ config.before do
35
+ FileUtils.mkdir_p(ChatBuilderHelpers::TMP_DIRECTORY)
36
+ end
37
+
38
+ config.after do
39
+ clean_up_generated_chat_files
40
+ end
41
+ end