bodyparts 0.1.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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Max Ogden
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,11 @@
1
+ = bodyparts
2
+
3
+ Separates new messages from included reply chains in the body of forwarded emails
4
+
5
+ == Usage
6
+
7
+ BodyParts.find_reply_in( valid raw_email_source or Mail object)
8
+
9
+ == Copyright
10
+
11
+ Copyright (c) 2010 Max Ogden. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "bodyparts"
8
+ gem.summary = %Q{Separates new messages from included reply chains in the body of forwarded emails}
9
+ gem.description = %Q{Separates new messages from included reply chains in the body of forwarded emails}
10
+ gem.email = "max@maxogden.com"
11
+ gem.homepage = "http://github.com/maxogden/bodyparts"
12
+ gem.authors = ["Max Ogden"]
13
+ gem.add_dependency "mail", ">= 0"
14
+ gem.add_development_dependency "rspec", ">= 1.2.9"
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "bodyparts #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bodyparts.gemspec ADDED
@@ -0,0 +1,58 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{bodyparts}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Max Ogden"]
12
+ s.date = %q{2010-06-08}
13
+ s.description = %q{Separates new messages from included reply chains in the body of forwarded emails}
14
+ s.email = %q{max@maxogden.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "bodyparts.gemspec",
27
+ "lib/bodyparts.rb",
28
+ "spec/bodyparts_spec.rb",
29
+ "spec/emails.yml",
30
+ "spec/spec_helper.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/maxogden/bodyparts}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.6}
36
+ s.summary = %q{Separates new messages from included reply chains in the body of forwarded emails}
37
+ s.test_files = [
38
+ "spec/bodyparts_spec.rb",
39
+ "spec/spec_helper.rb"
40
+ ]
41
+
42
+ if s.respond_to? :specification_version then
43
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
47
+ s.add_runtime_dependency(%q<mail>, [">= 0"])
48
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
49
+ else
50
+ s.add_dependency(%q<mail>, [">= 0"])
51
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
52
+ end
53
+ else
54
+ s.add_dependency(%q<mail>, [">= 0"])
55
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
56
+ end
57
+ end
58
+
data/lib/bodyparts.rb ADDED
@@ -0,0 +1,37 @@
1
+ require 'mail'
2
+
3
+ class BodyParts
4
+ def self.find_reply_in(email)
5
+ email = Mail::Message.new(email) unless email.class == Mail::Message
6
+ message_id = email.message_id
7
+ x_mailer = email['x-mailer']
8
+
9
+ rules = [
10
+ { :server => 'Gmail',
11
+ :reply_delimiter => /^On.*?wrote:.$/m
12
+ },
13
+ { :server => 'Yahoo! Mail',
14
+ :reply_delimiter => /^_+\r\nFrom:/
15
+ },
16
+ { :server => 'Microsoft Live Mail/Hotmail',
17
+ :reply_delimiter => /\r\n\r\n(Date|Subject):/
18
+ },
19
+ { :server => 'Outlook Express/AOL Webmail',
20
+ :reply_delimiter => /^-+.*Original Message.*-+/
21
+ }
22
+ ]
23
+
24
+ if email.multipart?
25
+ body = email.parts.first.body.raw_source
26
+ else
27
+ body = email.body.raw_source
28
+ end
29
+
30
+ matches = []
31
+ rules.each {|rule| matches << body.match(rule[:reply_delimiter])}
32
+ matches.compact!
33
+ match = matches.sort_by {|m| m.begin(0)}.first
34
+ new_message = body[0, match.begin(0)]
35
+ {:new_message => new_message.strip, :rest_of_thread => body[match.begin(0)..-1].strip}
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "BodyParts" do
4
+ %w(gmail yahoo hotmail aol_webmail generic).each do |mail_server|
5
+ it "should strip out the replies from a #{mail_server} message containing forwarded junk" do
6
+ mail_server = FakeMessage.fake_emails[mail_server.to_sym]
7
+ message = FakeMessage.new_mail(mail_server[:headers])
8
+ BodyParts.find_reply_in(message.to_s)[:new_message].should == mail_server[:reply_text]
9
+ end
10
+ end
11
+
12
+ it "should always use the first reply delimiter in a message containing multiple replies" do
13
+ multiple_replies = FakeMessage.fake_emails[:multiple_replies]
14
+ message = FakeMessage.new_mail(multiple_replies[:headers])
15
+ BodyParts.find_reply_in(message.to_s)[:new_message].should == multiple_replies[:reply_text]
16
+ end
17
+
18
+ it "should return the rest of the thread" do
19
+ generic = FakeMessage.fake_emails[:generic]
20
+ message = FakeMessage.new_mail(generic[:headers])
21
+ BodyParts.find_reply_in(message.to_s).should == {:new_message => generic[:reply_text], :rest_of_thread => generic[:rest_of_thread].gsub("\n", "\r\n").strip}
22
+ end
23
+ end
data/spec/emails.yml ADDED
@@ -0,0 +1,131 @@
1
+ ---
2
+ :gmail:
3
+ :reply_text:
4
+ Ok, I'm sayin' Friday at 7pm. Let the dorking commence!
5
+ :headers:
6
+ message_id:
7
+ <AANLkTinVIyGS4MHiwUMu4Mo5LjPybutttacofWZZb@mail.gmail.com>
8
+ body: |
9
+ Ok, I'm sayin' Friday at 7pm. Let the dorking commence!
10
+
11
+ On Tue, Jun 8, 2010 at 10:19 AM, Jang Bifflez <
12
+ jang@bifflez.com> wrote:
13
+
14
+ > Thank you for your input on this issue.
15
+ >
16
+ > I am in total agreement. I have gotten the approval of the client.
17
+ >
18
+ > Best,
19
+ > Jang
20
+ :yahoo:
21
+ :reply_text:
22
+ What is the strength of the snake wizard?
23
+ :headers:
24
+ message_id:
25
+ <AANLkTinVIyGwikipediaHiwPybutttacofWZZb@yahoos.com>
26
+ body: |
27
+ What is the strength of the snake wizard?
28
+
29
+ ________________________________
30
+ From: "Bongo Pizza&#269;i&#363;t&#279;-Ferengi" <bongo.pizza@yahoo.com>
31
+ To: bifflez@jangtown.com
32
+ Cc: Donkey Car <donkey@car.com>
33
+ Sent: Thu, April 1, 2010 1:52:09 PM
34
+ Subject: Re: hay guys
35
+
36
+ I figured it out.
37
+ Additional question - can I challenge the snake wizard?
38
+ :hotmail:
39
+ :reply_text:
40
+ thanks for the quote. how much for just a jingle?
41
+ :headers:
42
+ return_path:
43
+ <skeletor@hotmail.com>
44
+ body: |
45
+ thanks for the quote. how much for just a jingle?
46
+
47
+ Date: Mon, 8 Feb 2010 18:26:27 +0000
48
+ From: skeletor@hotmail.com
49
+ To: philcollins@hotmail.com
50
+ Subject: theme song for axis of evil
51
+ Hi skeletor=2C
52
+
53
+ I charge 900 million a day
54
+
55
+ Thanks=2C
56
+
57
+ phil =20
58
+ _________________________________________________________________
59
+ Your E-mail and More On-the-Go. Get Windows Live Hotmail Free.
60
+ https://signup.live.com/signup.aspx?id=3D60969=
61
+ :aol_webmail:
62
+ :reply_text:
63
+ Cats in buckets! Oh my!
64
+ :headers:
65
+ body: |
66
+ Cats in buckets! Oh my!
67
+
68
+ -----Original Message-----
69
+ From: bobthevet@animalresearchhouse.co.uk
70
+ To: concernedcatlady@aol.com
71
+ Sent: Wed, Apr 28, 2010 9:52 am
72
+ Subject: catastrophe
73
+
74
+ Hello,
75
+ there are cats in buckets over here
76
+ Thanks!
77
+ x_mailer:
78
+ AOL Webmail 31509-STANDARD
79
+ :generic:
80
+ :reply_text:
81
+ What do you mean yer all out of ham?!?!?
82
+ :rest_of_thread: |
83
+ ----- Original Message -----
84
+ From: jimmy dean <jimmydean@sausages.com>
85
+ To: charles darwin
86
+ Sent: Sun Jun 28 18:15:32 2009
87
+ Subject: Re: origin of meat
88
+
89
+ Hi charles,
90
+
91
+ I was wondering if you knew the origin of meat species, in particular ham.
92
+
93
+ I am all out of ham and was wondering how to procure some more
94
+
95
+ :headers:
96
+ body: |
97
+ What do you mean yer all out of ham?!?!?
98
+ ----- Original Message -----
99
+ From: jimmy dean <jimmydean@sausages.com>
100
+ To: charles darwin
101
+ Sent: Sun Jun 28 18:15:32 2009
102
+ Subject: Re: origin of meat
103
+
104
+ Hi charles,
105
+
106
+ I was wondering if you knew the origin of meat species, in particular ham.
107
+
108
+ I am all out of ham and was wondering how to procure some more
109
+ :multiple_replies:
110
+ :reply_text:
111
+ i refuse to endorse that product. it never worked for me
112
+ :headers:
113
+ body: |
114
+ i refuse to endorse that product. it never worked for me
115
+
116
+ ----- Original Message -----
117
+ From: luke skywalker <luke@jedi.com>
118
+ To: darth vader
119
+ Sent: Sun Jun 28 18:15:32 2009
120
+ Subject: fwd: vicks vaporub
121
+
122
+ hey vader,
123
+
124
+ palpatine wants to know if you are gonna shoot that commercial for the VapoRub decogestant
125
+
126
+ luke
127
+
128
+ On Tue, Jun 8, 2010 at 10:19 AM, Jang Bifflez <
129
+ palpatine@thedarkside.com> wrote:
130
+
131
+ > can you ask vader if he wants to go through with that gig at Vicks VapoRub
@@ -0,0 +1,29 @@
1
+ require 'spec'
2
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/bodyparts.rb')
3
+
4
+
5
+ class FakeMessage
6
+ def self.fake_emails
7
+ YAML.load_file(File.expand_path(File.dirname(__FILE__) + '/emails.yml'))
8
+ end
9
+
10
+ def self.default_mail_headers
11
+ { "body" => "I would like to let you know that the special fabric softener that you emailed to my postbox was quite nice",
12
+ "from" => "flubs@gebarchnik.com",
13
+ "to" => "donkeytron@wizzled.biz",
14
+ "message_id" => "<abc45566@revetonkatruck.local.tmail>",
15
+ "date" => "Wed, 23 Sep 2009 09:11:23 -0700"
16
+ }
17
+ end
18
+
19
+ def self.new_mail(custom_headers={})
20
+ headers = default_mail_headers.merge(custom_headers)
21
+ mail = Mail.new do
22
+ text_part do
23
+ body headers.delete("body")
24
+ end
25
+ end
26
+ headers.each {|header, content| mail[header] = content }
27
+ mail
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bodyparts
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Max Ogden
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-08 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: mail
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: rspec
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 1
41
+ - 2
42
+ - 9
43
+ version: 1.2.9
44
+ type: :development
45
+ version_requirements: *id002
46
+ description: Separates new messages from included reply chains in the body of forwarded emails
47
+ email: max@maxogden.com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - LICENSE
54
+ - README.rdoc
55
+ files:
56
+ - .document
57
+ - .gitignore
58
+ - LICENSE
59
+ - README.rdoc
60
+ - Rakefile
61
+ - VERSION
62
+ - bodyparts.gemspec
63
+ - lib/bodyparts.rb
64
+ - spec/bodyparts_spec.rb
65
+ - spec/emails.yml
66
+ - spec/spec_helper.rb
67
+ has_rdoc: true
68
+ homepage: http://github.com/maxogden/bodyparts
69
+ licenses: []
70
+
71
+ post_install_message:
72
+ rdoc_options:
73
+ - --charset=UTF-8
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ requirements: []
91
+
92
+ rubyforge_project:
93
+ rubygems_version: 1.3.6
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: Separates new messages from included reply chains in the body of forwarded emails
97
+ test_files:
98
+ - spec/bodyparts_spec.rb
99
+ - spec/spec_helper.rb