ruby-gmail 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,4 +1,10 @@
1
- === 0.0.8 / 2009/12-23
1
+ === 0.0.9 / 2010-04-17
2
+
3
+ * 1 bugfix
4
+
5
+ * Fixed content-transfer-encoding when sending email
6
+
7
+ === 0.0.8 / 2009-12-23
2
8
 
3
9
  * 1 bugfix
4
10
 
data/Manifest.txt CHANGED
@@ -6,6 +6,7 @@ lib/gmail.rb
6
6
  lib/ietf/rfc2045.rb
7
7
  lib/ietf/rfc822.rb
8
8
  lib/mime/entity.rb
9
+ lib/mime/entity_tmail.rb
9
10
  lib/mime/message.rb
10
11
  lib/smtp_tls.rb
11
12
  Manifest.txt
data/README.markdown CHANGED
@@ -12,7 +12,8 @@ Extra thanks for specific feature contributions from:
12
12
 
13
13
  * [Justin Perkins](http://github.com/justinperkins)
14
14
  * [Mikkel Malmberg](http://github.com/mikker)
15
-
15
+ * [Julien Blanchard](http://github.com/julienXX)
16
+ * [Federico Galassi](http://github.com/fgalassi)
16
17
 
17
18
  ## Description
18
19
 
@@ -74,11 +75,11 @@ A Rubyesque interface to Gmail, with all the tools you'll need. Search, read and
74
75
  * ruby
75
76
  * net/smtp
76
77
  * net/imap
77
- * shared-mime-info rubygem
78
+ * shared-mime-info rubygem (for MIME-detection when attaching files)
78
79
 
79
80
  ## Install
80
81
 
81
- sudo gem install ruby-gmail -s http://gemcutter.org
82
+ gem install ruby-gmail
82
83
 
83
84
  ## License
84
85
 
data/Rakefile CHANGED
@@ -10,3 +10,21 @@ Hoe.spec 'ruby-gmail' do
10
10
  self.url = "http://dcparker.github.com/ruby-gmail"
11
11
  self.post_install_message = "\n\033[34mIf ruby-gmail saves you TWO hours of work, want to compensate me for, like, a half-hour?\nSupport me in making new and better gems:\033[0m \033[31;4mhttp://pledgie.com/campaigns/7087\033[0m\n\n"
12
12
  end
13
+
14
+ begin
15
+ require 'jeweler'
16
+ Jeweler::Tasks.new do |gem|
17
+ gem.name = "ruby-gmail"
18
+ gem.summary = %Q{A Rubyesque interface to Gmail, with all the tools you'll need.}
19
+ gem.description = %Q{A Rubyesque interface to Gmail, with all the tools you'll need. Search, read and send multipart emails; archive, mark as read/unread, delete emails; and manage labels.}
20
+ gem.email = "gems@behindlogic.com"
21
+ gem.homepage = "http://dcparker.github.com/ruby-gmail"
22
+ gem.authors = ["BehindLogic"]
23
+ gem.post_install_message = "\n\033[34mIf ruby-gmail saves you TWO hours of work, want to compensate me for, like, a half-hour?\nSupport me in making new and better gems:\033[0m \033[31;4mhttp://pledgie.com/campaigns/7087\033[0m\n\n"
24
+ gem.add_dependency('shared-mime-info', '>= 0')
25
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
26
+ end
27
+ Jeweler::GemcutterTasks.new
28
+ rescue LoadError
29
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
30
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.9
data/lib/gmail.rb CHANGED
@@ -3,7 +3,7 @@ require 'net/smtp'
3
3
  require 'smtp_tls'
4
4
 
5
5
  class Gmail
6
- VERSION = '0.0.8'
6
+ VERSION = '0.0.9'
7
7
 
8
8
  class NoLabel < RuntimeError; end
9
9
 
@@ -53,6 +53,14 @@ class Gmail
53
53
  imap.create(name)
54
54
  end
55
55
 
56
+ # List the available labels
57
+ def labels
58
+ (@imap.list("", "%") + @imap.list("[Gmail]/", "%")).inject([]) do |lables,label|
59
+ label[:name].each_line { |l| labels << l }
60
+ labels
61
+ end
62
+ end
63
+
56
64
  def in_mailbox(mailbox, &block)
57
65
  raise ArgumentError, "Must provide a code block" unless block_given?
58
66
  mailbox_stack << mailbox
@@ -80,7 +88,7 @@ class Gmail
80
88
  block.call(lambda {|to, body|
81
89
  from = meta.username
82
90
  puts "Sending from #{from} to #{to}:\n#{body}"
83
- smtp.send_message(body, from, to)
91
+ smtp.send_message(body.to_s, from, to)
84
92
  })
85
93
  puts "SMTP closing."
86
94
  end
data/lib/ietf/rfc2045.rb CHANGED
@@ -4,7 +4,7 @@ module IETF
4
4
  def self.parse_rfc2045_from(raw)
5
5
  headers, raw = IETF::RFC822.parse_rfc822_from(raw)
6
6
 
7
- if headers['content-type'] =~ /multipart\/(\w+); boundary=([\"\']?)(.*)\2?/
7
+ if headers['content-type'] =~ /multipart\/(\w+); boundary=([\"\'])(.*)\2/ || headers['content-type'] =~ /multipart\/(\w+); boundary(=)(.*)$/
8
8
  content = {}
9
9
  content[:type] = $1
10
10
  content[:boundary] = $3
data/lib/mime/entity.rb CHANGED
@@ -11,11 +11,11 @@ module MIME
11
11
  end
12
12
  class Entity
13
13
  def initialize(one=nil,two=nil)
14
- if one.is_a?(Hash) || two.is_a?(Hash)
14
+ if one.is_a?(Hash) || two.is_a?(Hash) # Intent is to generate a message from parameters
15
15
  @headers = one.is_a?(Hash) ? one : two
16
16
  set_content one if one.is_a?(String)
17
17
  @encoding = 'quoted-printable' unless encoding
18
- elsif one.is_a?(String)
18
+ elsif one.is_a?(String) # Intent is to parse a message body
19
19
  @raw = one.gsub(/\r/,'').gsub(/\n/, "\r\n") # normalizes end-of-line characters
20
20
  from_parsed(IETF::RFC2045.parse_rfc2045_from(@raw))
21
21
  end
@@ -150,7 +150,7 @@ module MIME
150
150
  # Renders this data structure into a string, encoded
151
151
  def to_s
152
152
  multipart_boundary # initialize the boundary if necessary
153
- headers.inject('') {|a,(k,v)| a << "#{MIME.capitalize_header(k)}: #{v}\r\n"} + "\r\n" + if content.is_a?(Array)
153
+ {'charset' => 'utf-8', 'content-transfer-encoding' => @encoding}.merge(headers).inject('') {|a,(k,v)| a << "#{MIME.capitalize_header(k)}: #{v}\r\n"} + "\r\n" + if content.is_a?(Array)
154
154
  "\r\n--#{multipart_boundary}\r\n" + content.collect {|part| part.to_s }.join("\r\n--#{multipart_boundary}\r\n") + "\r\n--#{multipart_boundary}--\r\n"
155
155
  else
156
156
  content.to_s
@@ -0,0 +1,217 @@
1
+ require 'tmail'
2
+ require 'ietf/rfc2045'
3
+ String::ALPHANUMERIC_CHARACTERS = ('a'..'z').to_a + ('A'..'Z').to_a unless defined? String::ALPHANUMERIC_CHARACTERS
4
+ def String.random(size)
5
+ length = String::ALPHANUMERIC_CHARACTERS.length
6
+ (0...size).collect { String::ALPHANUMERIC_CHARACTERS[Kernel.rand(length)] }.join
7
+ end
8
+
9
+ module MIME
10
+ def self.capitalize_header(header_name)
11
+ header_name.gsub(/^(\w)/) {|m| m.capitalize}.gsub(/-(\w)/) {|n| '-' + n[1].chr.capitalize}
12
+ end
13
+ class Entity
14
+ def initialize(one=nil,two=nil)
15
+ if one.is_a?(Hash) || two.is_a?(Hash) # Intent is to generate a message from parameters
16
+ @headers = one.is_a?(Hash) ? one : two
17
+ set_content one if one.is_a?(String)
18
+ @encoding = 'quoted-printable' unless encoding
19
+ elsif one.is_a?(String) # Intent is to parse a message body
20
+ @raw = one.gsub(/\r/,'').gsub(/\n/, "\r\n") # normalizes end-of-line characters
21
+ @tmail = TMail::Mail.parse(@raw)
22
+ from_tmail(@tmail)
23
+ elsif one.is_a?(TMail::Mail)
24
+ @tmail = one
25
+ from_tmail(@tmail)
26
+ end
27
+ end
28
+
29
+ def inspect
30
+ "<#{self.class.name}##{object_id} Headers:{#{headers.collect {|k,v| "#{k}=#{v}"}.join(' ')}} content:#{multipart? ? 'multipart' : 'flat'}>"
31
+ end
32
+
33
+ # This means we have a structure from IETF::RFC2045.
34
+ # Entity is: [headers, content], while content may be an array of Entities.
35
+ # Or, {:type, :boundary, :content}
36
+ def from_parsed(parsed)
37
+ case parsed
38
+ when Array
39
+ if parsed[0].is_a?(Hash) && (parsed[1].is_a?(Hash) || parsed[1].is_a?(String))
40
+ @headers = parsed[0]
41
+ @content = parsed[1].is_a?(Hash) ? parsed[1][:content].collect {|p| Entity.new.from_parsed(p)} : parsed[1]
42
+ if parsed[1].is_a?(Hash)
43
+ @multipart_type = parsed[1][:type]
44
+ @multipart_boundary = parsed[1][:boundary]
45
+ raise "IETF PARSING FAIL! (empty boundary)" if @multipart_boundary == ''
46
+ end
47
+ else
48
+ raise "IETF PARSING FAIL! ('A' structure)"
49
+ end
50
+ return self
51
+ when Hash
52
+ if parsed.has_key?(:type) && parsed.has_key?(:boundary) && parsed.has_key?(:content)
53
+ @content = parsed[:content].is_a?(Array) ? parsed[:content].collect {|p| Entity.new.from_parsed(p)} : parsed[:content]
54
+ else
55
+ raise "IETF PARSING FAIL! ('H' structure)"
56
+ end
57
+ return self
58
+ end
59
+ raise ArgumentError, "Must pass in either: [an array with two elements: headers(hash) and content(string or array)] OR [a hash containing :type, :boundary, and :content(being the former or a string)]"
60
+ end
61
+ def from_tmail(tmail)
62
+ raise ArgumentError, "Expecting a TMail::Mail object." unless tmail.is_a?(TMail::Mail)
63
+ @headers ||= Hash.new {|h,k| @tmail.header[k].to_s }
64
+ if multipart?
65
+ @content = @tmail.parts.collect { |tpart| Entity.new.from_tmail(tpart) }
66
+ else
67
+ set_content @tmail.body # TMail has already decoded it, but we need it still encoded
68
+ end
69
+ end
70
+
71
+ ##############
72
+ # ATTRIBUTES #
73
+
74
+ # An Entity has Headers.
75
+ def headers
76
+ @headers ||= {}
77
+ end
78
+ # An Entity has Content.
79
+ # IF the Content-Type is a multipart type,
80
+ # the content will be one or more Entities.
81
+ attr_reader :content, :multipart_type
82
+
83
+ #################
84
+ # Macro Methods #
85
+
86
+ def multipart?
87
+ return @tmail.multipart? if @tmail
88
+ !!(headers['content-type'] =~ /multipart\//) if headers['content-type']
89
+ end
90
+ def multipart_type
91
+ if headers['content-type'] =~ /multipart\/(\w+)/
92
+ $1
93
+ end if headers['content-type']
94
+ end
95
+ # Auto-generates a boundary if one doesn't yet exist.
96
+ def multipart_boundary
97
+ return nil unless multipart?
98
+ unless @multipart_boundary ||= (@tmail && @tmail.header['content-type'] ? @tmail.header['content-type'].params['boundary'] : nil)
99
+ # Content-Type: multipart/mixed; boundary=000e0cd28d1282f4ba04788017e5
100
+ @multipart_boundary = String.random(25)
101
+ headers['content-type'] = "multipart/#{multipart_type}; boundary=#{@multipart_boundary}"
102
+ @multipart_boundary
103
+ end
104
+ @multipart_boundary
105
+ end
106
+ def attachment?
107
+ @tmail.disposition_is_attachment? || headers['content-disposition'] =~ /^form-data;.* filename=[\"\']?[^\"\']+[\"\']?/ if headers['content-disposition']
108
+ end
109
+ alias :file? :attachment?
110
+ def part_filename
111
+ # Content-Disposition: attachment; filename="summary.txt"
112
+ if headers['content-disposition'] =~ /; filename=[\"\']?([^\"\']+)/
113
+ $1
114
+ end if headers['content-disposition']
115
+ end
116
+
117
+ def encoding
118
+ @encoding ||= headers['content-transfer-encoding'] || nil
119
+ end
120
+ # Re-encodes content if necessary when a new encoding is set
121
+ def encoding=(new_encoding)
122
+ raw_content = decoded_content # nil if multipart
123
+ @encoding = new_encoding
124
+ set_content(raw_content) if raw_content # skips if multipart
125
+ @encoding
126
+ end
127
+ alias :set_encoding :encoding=
128
+
129
+ def find_part(options)
130
+ find_parts(options,true).first
131
+ end
132
+ def find_parts(options,find_only_one=false)
133
+ parts = []
134
+ return nil unless (options[:content_type] && headers['content-type']) || (options[:content_disposition] && headers['content-disposition'])
135
+ # Do I match your search?
136
+ iam = true
137
+ iam = false if options[:content_type] && headers['content-type'] !~ /^#{options[:content_type]}(?=;|$)/
138
+ iam = false if options[:content_disposition] && headers['content-disposition'] !~ /^#{options[:content_disposition]}(?=;|$)/
139
+ parts << self if iam
140
+ return parts unless parts.empty?
141
+ # Do any of my children match your search?
142
+ content.each do |part|
143
+ parts.concat part.find_parts(options,find_only_one)
144
+ return parts if !parts.empty? && find_only_one
145
+ end if multipart?
146
+ return parts
147
+ end
148
+
149
+ def save_to_file(path=nil)
150
+ filename = path if path && !File.exists?(path) # If path doesn't exist, assume it's a filename
151
+ filename ||= path + '/' + part_filename if path && attachment? # If path does exist, and we're saving an attachment, use the attachment filename
152
+ filename ||= (attachment? ? part_filename : path) # If there is no path and we're saving an attachment, use the attachment filename; otherwise use path (whether it is present or not)
153
+ filename ||= '.' # No path supplied, and not saving an attachment. We'll just save it in the current directory.
154
+ if File.directory?(filename)
155
+ i = 0
156
+ begin
157
+ i += 1
158
+ filename = filename + "/attachment-#{i}"
159
+ end until !File.exists(filename)
160
+ end
161
+ # After all that trouble to get a filename to save to...
162
+ File.open(filename, 'w') do |file|
163
+ file << decoded_content
164
+ end
165
+ end
166
+
167
+ ##########################
168
+ # CONVERTING / RENDERING #
169
+
170
+ # Renders this data structure into a string, encoded
171
+ def to_s
172
+ multipart_boundary # initialize the boundary if necessary, so it will be included in the headers
173
+ headers.inject('') {|a,(k,v)| a << "#{MIME.capitalize_header(k)}: #{v}\r\n"} + "\r\n" + if content.is_a?(Array)
174
+ "\r\n--#{multipart_boundary}\r\n" + content.collect {|part| part.to_s }.join("\r\n--#{multipart_boundary}\r\n") + "\r\n--#{multipart_boundary}--\r\n"
175
+ else
176
+ content.to_s
177
+ end
178
+ end
179
+
180
+ # Converts this data structure into a string, but decoded if necessary
181
+ def decoded_content
182
+ return nil if @content.is_a?(Array)
183
+ case encoding.to_s.downcase
184
+ when 'quoted-printable'
185
+ @content.unpack('M')[0]
186
+ when 'base64'
187
+ @content.unpack('m')[0]
188
+ # when '7bit'
189
+ # # should get this 7bit encoding done too...
190
+ else
191
+ @content
192
+ end
193
+ end
194
+
195
+ # You can set new content, and it will be saved in encoded form.
196
+ def set_content(raw)
197
+ @content = raw.is_a?(Array) ? raw :
198
+ case encoding.to_s.downcase
199
+ when 'quoted-printable'
200
+ [raw].pack('M')
201
+ when 'base64'
202
+ [raw].pack('m')
203
+ else
204
+ raw
205
+ end
206
+ end
207
+ alias :content= :set_content
208
+
209
+ private
210
+ def transfer_to(other)
211
+ other.instance_variable_set(:@content, @content.dup) if @content
212
+ other.headers.clear
213
+ other.headers.merge!(Hash[*headers.dup.select {|k,v| k =~ /content/}.flatten])
214
+ end
215
+
216
+ end
217
+ end
data/lib/mime/message.rb CHANGED
@@ -1,5 +1,4 @@
1
- require 'mime/entity'
2
- require 'shared-mime-info'
1
+ require 'mime/entity_tmail'
3
2
  module MIME
4
3
  # A Message is really a MIME::Entity,
5
4
  # but should be used for the outermost Entity, because
@@ -52,6 +51,7 @@ module MIME
52
51
  short_filename = filename.match(/([^\\\/]+)$/)[1]
53
52
 
54
53
  # Generate the attachment piece
54
+ require 'shared-mime-info'
55
55
  attachment = Entity.new(
56
56
  'content-type' => MIME.check(filename).type + "; \r\n name=\"#{short_filename}\"",
57
57
  'content-disposition' => "attachment; \r\n filename=\"#{short_filename}\"",
@@ -61,10 +61,10 @@ module MIME
61
61
 
62
62
  # Enclose in a top-level multipart/mixed
63
63
  if multipart? && multipart_type == 'mixed'
64
- # If already enclosed, all we have to do is add the attachment part
64
+ # If we're already dealing with a mixed multipart, all we have to do is add the attachment part
65
65
  (@content ||= []) << attachment
66
66
  else
67
- # If there is no content, add a little message about the attachment(s).
67
+ # If there is no content yet, add a little message about the attachment(s).
68
68
  set_content 'See attachment(s)' if @content.nil?
69
69
  # Generate the new top-level multipart, transferring what is here already into a child object
70
70
  new_content = Entity.new
@@ -72,7 +72,7 @@ module MIME
72
72
  transfer_to(new_content)
73
73
  headers.reject! {|k,v| k =~ /content/}
74
74
  headers['content-type'] = 'multipart/mixed'
75
- headers.delete 'content-transfer-encoding' # because now it's useless.
75
+ headers.delete 'content-transfer-encoding' # because we don't need a transfer-encoding on a multipart package.
76
76
  @content = [new_content, attachment]
77
77
  end
78
78
 
metadata CHANGED
@@ -1,82 +1,60 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-gmail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 9
9
+ version: 0.0.9
5
10
  platform: ruby
6
11
  authors:
7
- - Daniel Parker
12
+ - BehindLogic
8
13
  autorequire:
9
14
  bindir: bin
10
- cert_chain:
11
- - |
12
- -----BEGIN CERTIFICATE-----
13
- MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMQ0wCwYDVQQDDARnZW1z
14
- MRswGQYKCZImiZPyLGQBGRYLYmVoaW5kbG9naWMxEzARBgoJkiaJk/IsZAEZFgNj
15
- b20wHhcNMDkxMTE5MDQ0NzIzWhcNMTAxMTE5MDQ0NzIzWjBBMQ0wCwYDVQQDDARn
16
- ZW1zMRswGQYKCZImiZPyLGQBGRYLYmVoaW5kbG9naWMxEzARBgoJkiaJk/IsZAEZ
17
- FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDs+2PvSoBC5mCz
18
- Nm95RXKOb/u+CmPA70DoG9cF0zipCie003Vm0DYL3Rtobcr32eMvHxkWoJ6xoz0I
19
- h74yNKtHjTTCxj86HWBPsE6xVMxVCftClndjCyKsiMiqvvp1wDNO0FFK+6LijmL3
20
- 2Xkp4brWq1JO92y9vYct34R7o2X//+nwZs+sss+EYhNdvdUJfWy7tA5dghGdLvRn
21
- UhJJSAtTefkBCwO7bufLEt+n7wIRbiJJ5dDCwE3NIX4wUSrNeYwXGXA/Ybki+BUl
22
- 3KJF9IC0XR9fY9DGF0FXBKrkfDlZRrnQOem2aIxeuln0KQLJXXJuDTQPHO+mK3EG
23
- UPhR7IAHAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
24
- BBQn32ZStKmqwFqs2vuglYzkvDzBZjANBgkqhkiG9w0BAQUFAAOCAQEAe3Z+iMmy
25
- IX9ChQW4hNNb1HOpgCMc2RL+vUwku9WE95dZ+BE4A6mOYTj5JXdYf4R4Z2vavr+d
26
- nwJWtXPeIBWxireb8gUU0DwqodYTpsmkj5LD1zIaZ59rXlwDA9O0V4fwE1iRG5MD
27
- mB7m8fT8WNOeg4AfjH4aSiHI1+HX1RQkc7KFdLotKnCevzYU6Jza5VUbXyJ+yCEH
28
- DFARN3mkfGI+18MRDEi39nK2O/bBd6Wf0cYPEKsGQjNNAIBtv9belepSMd1KKfQ2
29
- L7j8CnNDCrsHDe7/251D85wSvTH4Q/41NE5ahdCkkHwzDJeyhXpmNuUSswdn7woz
30
- teST6sOe8lUhZQ==
31
- -----END CERTIFICATE-----
15
+ cert_chain: []
32
16
 
33
- date: 2009-12-23 00:00:00 -05:00
17
+ date: 2010-04-18 00:00:00 -04:00
34
18
  default_executable:
35
19
  dependencies:
36
20
  - !ruby/object:Gem::Dependency
37
21
  name: shared-mime-info
38
- type: :runtime
39
- version_requirement:
40
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
41
24
  requirements:
42
25
  - - ">="
43
26
  - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
44
29
  version: "0"
45
- version:
46
- - !ruby/object:Gem::Dependency
47
- name: hoe
48
- type: :development
49
- version_requirement:
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: 2.3.3
55
- version:
30
+ type: :runtime
31
+ version_requirements: *id001
56
32
  description: A Rubyesque interface to Gmail, with all the tools you'll need. Search, read and send multipart emails; archive, mark as read/unread, delete emails; and manage labels.
57
- email:
58
- - gems@behindlogic.com
33
+ email: gems@behindlogic.com
59
34
  executables: []
60
35
 
61
36
  extensions: []
62
37
 
63
38
  extra_rdoc_files:
64
- - History.txt
65
- - Manifest.txt
39
+ - README.markdown
66
40
  files:
67
41
  - .autotest
68
42
  - History.txt
43
+ - Manifest.txt
44
+ - README.markdown
45
+ - Rakefile
46
+ - VERSION
47
+ - lib/gmail.rb
69
48
  - lib/gmail/mailbox.rb
70
49
  - lib/gmail/message.rb
71
- - lib/gmail.rb
72
50
  - lib/ietf/rfc2045.rb
73
51
  - lib/ietf/rfc822.rb
74
52
  - lib/mime/entity.rb
53
+ - lib/mime/entity_tmail.rb
75
54
  - lib/mime/message.rb
76
55
  - lib/smtp_tls.rb
77
- - Manifest.txt
78
- - Rakefile
79
- - README.markdown
56
+ - test/test_gmail.rb
57
+ - test/test_helper.rb
80
58
  has_rdoc: true
81
59
  homepage: http://dcparker.github.com/ruby-gmail
82
60
  licenses: []
@@ -85,29 +63,30 @@ post_install_message: "\n\
85
63
  \e[34mIf ruby-gmail saves you TWO hours of work, want to compensate me for, like, a half-hour?\n\
86
64
  Support me in making new and better gems:\e[0m \e[31;4mhttp://pledgie.com/campaigns/7087\e[0m\n\n"
87
65
  rdoc_options:
88
- - --main
89
- - README.markdown
66
+ - --charset=UTF-8
90
67
  require_paths:
91
68
  - lib
92
69
  required_ruby_version: !ruby/object:Gem::Requirement
93
70
  requirements:
94
71
  - - ">="
95
72
  - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
96
75
  version: "0"
97
- version:
98
76
  required_rubygems_version: !ruby/object:Gem::Requirement
99
77
  requirements:
100
78
  - - ">="
101
79
  - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
102
82
  version: "0"
103
- version:
104
83
  requirements: []
105
84
 
106
- rubyforge_project: ruby-gmail
107
- rubygems_version: 1.3.5
85
+ rubyforge_project:
86
+ rubygems_version: 1.3.6
108
87
  signing_key:
109
88
  specification_version: 3
110
- summary: A Rubyesque interface to Gmail, with all the tools you'll need
89
+ summary: A Rubyesque interface to Gmail, with all the tools you'll need.
111
90
  test_files:
112
91
  - test/test_gmail.rb
113
92
  - test/test_helper.rb
data.tar.gz.sig DELETED
@@ -1,2 +0,0 @@
1
- �j|,�r�%�B��ZC��B'�6,��r�g�V~�9ï�+�mcL���L��.�#�_�x.&�#LX��!�ȧi×T�_�e2������k�s��-[`�c���G���^J����y3EYY�<��^X q
2
- �?D
metadata.gz.sig DELETED
Binary file