mail 2.2.20 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mail might be problematic. Click here for more details.

@@ -1,10 +1,9 @@
1
- == Tue May 14 14:22:00 +1100 2013 Mikel Lindsaar <mikel@lindsaar.net>
2
-
3
- * Backport 2.4.2 2.4.4 fixes (fractious)
4
-
5
- == Tue Apr 26 09:49:54 UTC 2011 Mikel Lindsaar <mikel@rubyx.com>
1
+ == Tue Apr 26 09:59:56 UTC 2011 Mikel Lindsaar <mikel@rubyx.com>
6
2
 
3
+ * Remove ActiveSupport from the dependencies, load Active Support if present, or use internals if not
4
+ * Created v2.2 branch for all 2.2 related commits
7
5
  * Update activesupport require to use inflector - closes #217
6
+ * Version bump to 2.3 and gem release
8
7
 
9
8
  == Tue Apr 26 06:18:19 UTC 2011 Mikel Lindsaar <mikel@rubyx.com>
10
9
 
@@ -0,0 +1,3 @@
1
+ treetop: we need to include this in the gem spec
2
+ tlsmail: if ruby < 1.8.6... we could make it optional, or embed it in Mail
3
+ mime/types: I think we embed a simplified version, or help maintain it, it is old (2006)
data/Gemfile ADDED
@@ -0,0 +1,29 @@
1
+ source :rubygems
2
+
3
+ gem "activesupport", ">= 2.3.6"
4
+ gem "tlsmail" if RUBY_VERSION <= '1.8.6'
5
+ gem "mime-types", "~> 1.16"
6
+ gem "treetop", "~> 1.4.8"
7
+ gem "i18n", ">= 0.4.0"
8
+
9
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
10
+ gem 'jruby-openssl'
11
+ end
12
+
13
+ group :test do
14
+ gem "ZenTest", "~> 4.4.0"
15
+ gem "rake", "~> 0.8.7"
16
+ gem "bundler"
17
+ gem "rspec", "~> 1.3.0"
18
+ gem "diff-lcs"
19
+ case
20
+ when defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
21
+ # Skip it
22
+ when RUBY_PLATFORM == 'java'
23
+ # Skip it
24
+ when RUBY_VERSION < '1.9'
25
+ gem "ruby-debug"
26
+ else
27
+ # Skip it
28
+ end
29
+ end
@@ -1,4 +1,4 @@
1
1
  major:2
2
- minor:2
3
- patch:20
2
+ minor:3
3
+ patch:0
4
4
  build:
@@ -4,12 +4,6 @@ module Mail # :doc:
4
4
  require 'date'
5
5
  require 'shellwords'
6
6
 
7
- require 'active_support'
8
- require 'active_support/core_ext/class/attribute_accessors'
9
- require 'active_support/core_ext/hash/indifferent_access'
10
- require 'active_support/core_ext/object/blank'
11
- require 'active_support/inflector'
12
-
13
7
  require 'uri'
14
8
  require 'net/smtp'
15
9
  require 'mime/types'
@@ -22,7 +16,7 @@ module Mail # :doc:
22
16
  end
23
17
  end
24
18
 
25
- if RUBY_VERSION >= "1.9.1"
19
+ if RUBY_VERSION >= "1.9.0"
26
20
  require 'mail/version_specific/ruby_1_9'
27
21
  RubyVer = Ruby19
28
22
  else
@@ -33,9 +27,20 @@ module Mail # :doc:
33
27
  require 'mail/version'
34
28
 
35
29
  require 'mail/core_extensions/nil'
30
+ require 'mail/core_extensions/object'
36
31
  require 'mail/core_extensions/string'
37
32
  require 'mail/core_extensions/shellwords' unless String.new.respond_to?(:shellescape)
38
33
  require 'mail/core_extensions/smtp' if RUBY_VERSION < '1.9.3'
34
+ require 'mail/indifferent_hash'
35
+
36
+ # Only load our multibyte extensions if AS is not already loaded
37
+ if defined?(ActiveSupport)
38
+ require 'active_support/inflector'
39
+ else
40
+ require 'mail/core_extensions/string/access'
41
+ require 'mail/core_extensions/string/multibyte'
42
+ require 'mail/multibyte'
43
+ end
39
44
 
40
45
  require 'mail/patterns'
41
46
  require 'mail/utilities'
@@ -201,10 +201,11 @@ module Mail
201
201
  end
202
202
 
203
203
  def encoding=( val )
204
- if val == "text" || val.blank? then
205
- val = "8bit"
204
+ @encoding = if val == "text" || val.blank?
205
+ (only_us_ascii? ? '7bit' : '8bit')
206
+ else
207
+ val
206
208
  end
207
- @encoding = (val == "text") ? "8bit" : val
208
209
  end
209
210
 
210
211
  # Returns the preamble (any text that is before the first MIME boundary)
@@ -1,5 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
+ # This is not loaded if ActiveSupport is already loaded
4
+
3
5
  class NilClass #:nodoc:
4
6
  def to_crlf
5
7
  ''
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ # This is not loaded if ActiveSupport is already loaded
4
+
5
+ class Object
6
+ def blank?
7
+ if respond_to?(:empty?)
8
+ empty?
9
+ else
10
+ !self
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  # The following is imported from ruby 1.9.2 shellwords.rb
2
4
  #
3
5
  module Shellwords
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  module Net
2
3
  class SMTP
3
4
  # This is a backport of r30294 from ruby trunk because of a bug in net/smtp.
@@ -8,6 +8,10 @@ class String #:nodoc:
8
8
  gsub(/\n|\r\n|\r/) { "\n" }
9
9
  end
10
10
 
11
+ def blank?
12
+ self !~ /\S/
13
+ end
14
+
11
15
  unless method_defined?(:ascii_only?)
12
16
  # Provides all strings with the Ruby 1.9 method of .ascii_only? and
13
17
  # returns true or false
@@ -16,7 +20,7 @@ class String #:nodoc:
16
20
  !(self =~ /[^#{US_ASCII_REGEXP}]/)
17
21
  end
18
22
  end
19
-
23
+
20
24
  def not_ascii_only?
21
25
  !ascii_only?
22
26
  end
@@ -0,0 +1,104 @@
1
+ # encoding: utf-8
2
+
3
+ # This is not loaded if ActiveSupport is already loaded
4
+
5
+ # This is an almost cut and paste from ActiveSupport v3.0.6, copied in here so that Mail
6
+ # itself does not depend on ActiveSupport to avoid versioning conflicts
7
+
8
+ class String
9
+ unless '1.9'.respond_to?(:force_encoding)
10
+ # Returns the character at the +position+ treating the string as an array (where 0 is the first character).
11
+ #
12
+ # Examples:
13
+ # "hello".at(0) # => "h"
14
+ # "hello".at(4) # => "o"
15
+ # "hello".at(10) # => ERROR if < 1.9, nil in 1.9
16
+ def at(position)
17
+ mb_chars[position, 1].to_s
18
+ end
19
+
20
+ # Returns the remaining of the string from the +position+ treating the string as an array (where 0 is the first character).
21
+ #
22
+ # Examples:
23
+ # "hello".from(0) # => "hello"
24
+ # "hello".from(2) # => "llo"
25
+ # "hello".from(10) # => "" if < 1.9, nil in 1.9
26
+ def from(position)
27
+ mb_chars[position..-1].to_s
28
+ end
29
+
30
+ # Returns the beginning of the string up to the +position+ treating the string as an array (where 0 is the first character).
31
+ #
32
+ # Examples:
33
+ # "hello".to(0) # => "h"
34
+ # "hello".to(2) # => "hel"
35
+ # "hello".to(10) # => "hello"
36
+ def to(position)
37
+ mb_chars[0..position].to_s
38
+ end
39
+
40
+ # Returns the first character of the string or the first +limit+ characters.
41
+ #
42
+ # Examples:
43
+ # "hello".first # => "h"
44
+ # "hello".first(2) # => "he"
45
+ # "hello".first(10) # => "hello"
46
+ def first(limit = 1)
47
+ if limit == 0
48
+ ''
49
+ elsif limit >= size
50
+ self
51
+ else
52
+ mb_chars[0...limit].to_s
53
+ end
54
+ end
55
+
56
+ # Returns the last character of the string or the last +limit+ characters.
57
+ #
58
+ # Examples:
59
+ # "hello".last # => "o"
60
+ # "hello".last(2) # => "lo"
61
+ # "hello".last(10) # => "hello"
62
+ def last(limit = 1)
63
+ if limit == 0
64
+ ''
65
+ elsif limit >= size
66
+ self
67
+ else
68
+ mb_chars[(-limit)..-1].to_s
69
+ end
70
+ end
71
+ else
72
+ def at(position)
73
+ self[position]
74
+ end
75
+
76
+ def from(position)
77
+ self[position..-1]
78
+ end
79
+
80
+ def to(position)
81
+ self[0..position]
82
+ end
83
+
84
+ def first(limit = 1)
85
+ if limit == 0
86
+ ''
87
+ elsif limit >= size
88
+ self
89
+ else
90
+ to(limit - 1)
91
+ end
92
+ end
93
+
94
+ def last(limit = 1)
95
+ if limit == 0
96
+ ''
97
+ elsif limit >= size
98
+ self
99
+ else
100
+ from(-limit)
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,78 @@
1
+ # encoding: utf-8
2
+
3
+ # This is not loaded if ActiveSupport is already loaded
4
+
5
+ # This is an almost cut and paste from ActiveSupport v3.0.6, copied in here so that Mail
6
+ # itself does not depend on ActiveSupport to avoid versioning conflicts
7
+
8
+ require 'mail/multibyte'
9
+
10
+ class String
11
+ if RUBY_VERSION >= "1.9"
12
+ # == Multibyte proxy
13
+ #
14
+ # +mb_chars+ is a multibyte safe proxy for string methods.
15
+ #
16
+ # In Ruby 1.8 and older it creates and returns an instance of the Mail::Multibyte::Chars class which
17
+ # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
18
+ # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsuled string.
19
+ #
20
+ # name = 'Claus Müller'
21
+ # name.reverse # => "rell??M sualC"
22
+ # name.length # => 13
23
+ #
24
+ # name.mb_chars.reverse.to_s # => "rellüM sualC"
25
+ # name.mb_chars.length # => 12
26
+ #
27
+ # In Ruby 1.9 and newer +mb_chars+ returns +self+ because String is (mostly) encoding aware. This means that
28
+ # it becomes easy to run one version of your code on multiple Ruby versions.
29
+ #
30
+ # == Method chaining
31
+ #
32
+ # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
33
+ # method chaining on the result of any of these methods.
34
+ #
35
+ # name.mb_chars.reverse.length # => 12
36
+ #
37
+ # == Interoperability and configuration
38
+ #
39
+ # The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
40
+ # String and Char work like expected. The bang! methods change the internal string representation in the Chars
41
+ # object. Interoperability problems can be resolved easily with a +to_s+ call.
42
+ #
43
+ # For more information about the methods defined on the Chars proxy see Mail::Multibyte::Chars. For
44
+ # information about how to change the default Multibyte behaviour see Mail::Multibyte.
45
+ def mb_chars
46
+ if Mail::Multibyte.proxy_class.consumes?(self)
47
+ Mail::Multibyte.proxy_class.new(self)
48
+ else
49
+ self
50
+ end
51
+ end
52
+
53
+ def is_utf8? #:nodoc
54
+ case encoding
55
+ when Encoding::UTF_8
56
+ valid_encoding?
57
+ when Encoding::ASCII_8BIT, Encoding::US_ASCII
58
+ dup.force_encoding(Encoding::UTF_8).valid_encoding?
59
+ else
60
+ false
61
+ end
62
+ end
63
+ else
64
+ def mb_chars
65
+ if Mail::Multibyte.proxy_class.wants?(self)
66
+ Mail::Multibyte.proxy_class.new(self)
67
+ else
68
+ self
69
+ end
70
+ end
71
+
72
+ # Returns true if the string has UTF-8 semantics (a String used for purely byte resources is unlikely to have
73
+ # them), returns false otherwise.
74
+ def is_utf8?
75
+ Mail::Multibyte::Chars.consumes?(self)
76
+ end
77
+ end
78
+ end
@@ -8,7 +8,7 @@ module Mail
8
8
  # to make that happen
9
9
  # Parameters are defined in RFC2045, split keys are in RFC2231
10
10
 
11
- class ParameterHash < HashWithIndifferentAccess
11
+ class ParameterHash < IndifferentHash
12
12
 
13
13
  include Mail::Utilities
14
14
 
@@ -28,8 +28,8 @@ module Mail
28
28
  if pairs.empty? # Just dealing with a single value pair
29
29
  super(exact || key_name)
30
30
  else # Dealing with a multiple value pair or a single encoded value pair
31
- string = pairs.sort { |a,b| a.first <=> b.first }.map { |v| v.last }.join('')
32
- if mt = string.match(/([\w\-]+)'(\w\w)'(.*)/)
31
+ string = pairs.sort { |a,b| a.first.to_s <=> b.first.to_s }.map { |v| v.last }.join('')
32
+ if mt = string.match(/([\w\d\-]+)'(\w\w)'(.*)/)
33
33
  string = mt[3]
34
34
  encoding = mt[1]
35
35
  else
@@ -40,7 +40,7 @@ module Mail
40
40
  end
41
41
 
42
42
  def encoded
43
- map.sort { |a,b| a.first <=> b.first }.map do |key_name, value|
43
+ map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value|
44
44
  unless value.ascii_only?
45
45
  value = Mail::Encodings.param_encode(value)
46
46
  key_name = "#{key_name}*"
@@ -50,7 +50,7 @@ module Mail
50
50
  end
51
51
 
52
52
  def decoded
53
- map.sort { |a,b| a.first <=> b.first }.map do |key_name, value|
53
+ map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value|
54
54
  %Q{#{key_name}=#{quote_token(value)}}
55
55
  end.join("; ")
56
56
  end
@@ -0,0 +1,146 @@
1
+ # encoding: utf-8
2
+
3
+ # This is an almost cut and paste from ActiveSupport v3.0.6, copied in here so that Mail
4
+ # itself does not depend on ActiveSupport to avoid versioning conflicts
5
+
6
+ module Mail
7
+ class IndifferentHash < Hash
8
+
9
+ def initialize(constructor = {})
10
+ if constructor.is_a?(Hash)
11
+ super()
12
+ update(constructor)
13
+ else
14
+ super(constructor)
15
+ end
16
+ end
17
+
18
+ def default(key = nil)
19
+ if key.is_a?(Symbol) && include?(key = key.to_s)
20
+ self[key]
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def self.new_from_hash_copying_default(hash)
27
+ IndifferentHash.new(hash).tap do |new_hash|
28
+ new_hash.default = hash.default
29
+ end
30
+ end
31
+
32
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
33
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
34
+
35
+ # Assigns a new value to the hash:
36
+ #
37
+ # hash = HashWithIndifferentAccess.new
38
+ # hash[:key] = "value"
39
+ #
40
+ def []=(key, value)
41
+ regular_writer(convert_key(key), convert_value(value))
42
+ end
43
+
44
+ alias_method :store, :[]=
45
+
46
+ # Updates the instantized hash with values from the second:
47
+ #
48
+ # hash_1 = HashWithIndifferentAccess.new
49
+ # hash_1[:key] = "value"
50
+ #
51
+ # hash_2 = HashWithIndifferentAccess.new
52
+ # hash_2[:key] = "New Value!"
53
+ #
54
+ # hash_1.update(hash_2) # => {"key"=>"New Value!"}
55
+ #
56
+ def update(other_hash)
57
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
58
+ self
59
+ end
60
+
61
+ alias_method :merge!, :update
62
+
63
+ # Checks the hash for a key matching the argument passed in:
64
+ #
65
+ # hash = HashWithIndifferentAccess.new
66
+ # hash["key"] = "value"
67
+ # hash.key? :key # => true
68
+ # hash.key? "key" # => true
69
+ #
70
+ def key?(key)
71
+ super(convert_key(key))
72
+ end
73
+
74
+ alias_method :include?, :key?
75
+ alias_method :has_key?, :key?
76
+ alias_method :member?, :key?
77
+
78
+ # Fetches the value for the specified key, same as doing hash[key]
79
+ def fetch(key, *extras)
80
+ super(convert_key(key), *extras)
81
+ end
82
+
83
+ # Returns an array of the values at the specified indices:
84
+ #
85
+ # hash = HashWithIndifferentAccess.new
86
+ # hash[:a] = "x"
87
+ # hash[:b] = "y"
88
+ # hash.values_at("a", "b") # => ["x", "y"]
89
+ #
90
+ def values_at(*indices)
91
+ indices.collect {|key| self[convert_key(key)]}
92
+ end
93
+
94
+ # Returns an exact copy of the hash.
95
+ def dup
96
+ IndifferentHash.new(self)
97
+ end
98
+
99
+ # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
100
+ # Does not overwrite the existing hash.
101
+ def merge(hash)
102
+ self.dup.update(hash)
103
+ end
104
+
105
+ # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
106
+ # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
107
+ def reverse_merge(other_hash)
108
+ super self.class.new_from_hash_copying_default(other_hash)
109
+ end
110
+
111
+ def reverse_merge!(other_hash)
112
+ replace(reverse_merge( other_hash ))
113
+ end
114
+
115
+ # Removes a specified key from the hash.
116
+ def delete(key)
117
+ super(convert_key(key))
118
+ end
119
+
120
+ def stringify_keys!; self end
121
+ def stringify_keys; dup end
122
+ def symbolize_keys; to_hash.symbolize_keys end
123
+ def to_options!; self end
124
+
125
+ def to_hash
126
+ Hash.new(default).merge!(self)
127
+ end
128
+
129
+ protected
130
+
131
+ def convert_key(key)
132
+ key.kind_of?(Symbol) ? key.to_s : key
133
+ end
134
+
135
+ def convert_value(value)
136
+ if value.class == Hash
137
+ self.class.new_from_hash_copying_default(value)
138
+ elsif value.is_a?(Array)
139
+ value.dup.replace(value.map { |e| convert_value(e) })
140
+ else
141
+ value
142
+ end
143
+ end
144
+
145
+ end
146
+ end