mail-portertech 2.6.2.edge

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +753 -0
  3. data/CONTRIBUTING.md +60 -0
  4. data/Dependencies.txt +2 -0
  5. data/Gemfile +15 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +683 -0
  8. data/Rakefile +29 -0
  9. data/TODO.rdoc +9 -0
  10. data/lib/mail.rb +91 -0
  11. data/lib/mail/attachments_list.rb +104 -0
  12. data/lib/mail/body.rb +291 -0
  13. data/lib/mail/check_delivery_params.rb +20 -0
  14. data/lib/mail/configuration.rb +75 -0
  15. data/lib/mail/core_extensions/nil.rb +19 -0
  16. data/lib/mail/core_extensions/object.rb +13 -0
  17. data/lib/mail/core_extensions/smtp.rb +24 -0
  18. data/lib/mail/core_extensions/string.rb +43 -0
  19. data/lib/mail/core_extensions/string/access.rb +145 -0
  20. data/lib/mail/core_extensions/string/multibyte.rb +78 -0
  21. data/lib/mail/elements.rb +14 -0
  22. data/lib/mail/elements/address.rb +270 -0
  23. data/lib/mail/elements/address_list.rb +51 -0
  24. data/lib/mail/elements/content_disposition_element.rb +26 -0
  25. data/lib/mail/elements/content_location_element.rb +21 -0
  26. data/lib/mail/elements/content_transfer_encoding_element.rb +17 -0
  27. data/lib/mail/elements/content_type_element.rb +31 -0
  28. data/lib/mail/elements/date_time_element.rb +22 -0
  29. data/lib/mail/elements/envelope_from_element.rb +39 -0
  30. data/lib/mail/elements/message_ids_element.rb +24 -0
  31. data/lib/mail/elements/mime_version_element.rb +22 -0
  32. data/lib/mail/elements/phrase_list.rb +16 -0
  33. data/lib/mail/elements/received_element.rb +26 -0
  34. data/lib/mail/encodings.rb +304 -0
  35. data/lib/mail/encodings/7bit.rb +31 -0
  36. data/lib/mail/encodings/8bit.rb +31 -0
  37. data/lib/mail/encodings/base64.rb +33 -0
  38. data/lib/mail/encodings/binary.rb +31 -0
  39. data/lib/mail/encodings/quoted_printable.rb +39 -0
  40. data/lib/mail/encodings/transfer_encoding.rb +58 -0
  41. data/lib/mail/envelope.rb +30 -0
  42. data/lib/mail/field.rb +247 -0
  43. data/lib/mail/field_list.rb +33 -0
  44. data/lib/mail/fields.rb +35 -0
  45. data/lib/mail/fields/bcc_field.rb +56 -0
  46. data/lib/mail/fields/cc_field.rb +55 -0
  47. data/lib/mail/fields/comments_field.rb +41 -0
  48. data/lib/mail/fields/common/address_container.rb +16 -0
  49. data/lib/mail/fields/common/common_address.rb +135 -0
  50. data/lib/mail/fields/common/common_date.rb +35 -0
  51. data/lib/mail/fields/common/common_field.rb +57 -0
  52. data/lib/mail/fields/common/common_message_id.rb +48 -0
  53. data/lib/mail/fields/common/parameter_hash.rb +58 -0
  54. data/lib/mail/fields/content_description_field.rb +19 -0
  55. data/lib/mail/fields/content_disposition_field.rb +70 -0
  56. data/lib/mail/fields/content_id_field.rb +62 -0
  57. data/lib/mail/fields/content_location_field.rb +42 -0
  58. data/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
  59. data/lib/mail/fields/content_type_field.rb +201 -0
  60. data/lib/mail/fields/date_field.rb +57 -0
  61. data/lib/mail/fields/from_field.rb +55 -0
  62. data/lib/mail/fields/in_reply_to_field.rb +56 -0
  63. data/lib/mail/fields/keywords_field.rb +44 -0
  64. data/lib/mail/fields/message_id_field.rb +82 -0
  65. data/lib/mail/fields/mime_version_field.rb +53 -0
  66. data/lib/mail/fields/optional_field.rb +13 -0
  67. data/lib/mail/fields/received_field.rb +75 -0
  68. data/lib/mail/fields/references_field.rb +56 -0
  69. data/lib/mail/fields/reply_to_field.rb +55 -0
  70. data/lib/mail/fields/resent_bcc_field.rb +55 -0
  71. data/lib/mail/fields/resent_cc_field.rb +55 -0
  72. data/lib/mail/fields/resent_date_field.rb +35 -0
  73. data/lib/mail/fields/resent_from_field.rb +55 -0
  74. data/lib/mail/fields/resent_message_id_field.rb +34 -0
  75. data/lib/mail/fields/resent_sender_field.rb +62 -0
  76. data/lib/mail/fields/resent_to_field.rb +55 -0
  77. data/lib/mail/fields/return_path_field.rb +65 -0
  78. data/lib/mail/fields/sender_field.rb +67 -0
  79. data/lib/mail/fields/structured_field.rb +51 -0
  80. data/lib/mail/fields/subject_field.rb +16 -0
  81. data/lib/mail/fields/to_field.rb +55 -0
  82. data/lib/mail/fields/unstructured_field.rb +204 -0
  83. data/lib/mail/header.rb +274 -0
  84. data/lib/mail/indifferent_hash.rb +146 -0
  85. data/lib/mail/mail.rb +267 -0
  86. data/lib/mail/matchers/has_sent_mail.rb +157 -0
  87. data/lib/mail/message.rb +2160 -0
  88. data/lib/mail/multibyte.rb +42 -0
  89. data/lib/mail/multibyte/chars.rb +474 -0
  90. data/lib/mail/multibyte/exceptions.rb +8 -0
  91. data/lib/mail/multibyte/unicode.rb +400 -0
  92. data/lib/mail/multibyte/utils.rb +60 -0
  93. data/lib/mail/network.rb +14 -0
  94. data/lib/mail/network/delivery_methods/exim.rb +52 -0
  95. data/lib/mail/network/delivery_methods/file_delivery.rb +45 -0
  96. data/lib/mail/network/delivery_methods/sendmail.rb +89 -0
  97. data/lib/mail/network/delivery_methods/smtp.rb +142 -0
  98. data/lib/mail/network/delivery_methods/smtp_connection.rb +61 -0
  99. data/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
  100. data/lib/mail/network/retriever_methods/base.rb +63 -0
  101. data/lib/mail/network/retriever_methods/imap.rb +173 -0
  102. data/lib/mail/network/retriever_methods/pop3.rb +140 -0
  103. data/lib/mail/network/retriever_methods/test_retriever.rb +43 -0
  104. data/lib/mail/parsers.rb +26 -0
  105. data/lib/mail/parsers/address_lists_parser.rb +132 -0
  106. data/lib/mail/parsers/content_disposition_parser.rb +67 -0
  107. data/lib/mail/parsers/content_location_parser.rb +35 -0
  108. data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
  109. data/lib/mail/parsers/content_type_parser.rb +64 -0
  110. data/lib/mail/parsers/date_time_parser.rb +36 -0
  111. data/lib/mail/parsers/envelope_from_parser.rb +45 -0
  112. data/lib/mail/parsers/message_ids_parser.rb +39 -0
  113. data/lib/mail/parsers/mime_version_parser.rb +41 -0
  114. data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
  115. data/lib/mail/parsers/ragel.rb +17 -0
  116. data/lib/mail/parsers/ragel/common.rl +184 -0
  117. data/lib/mail/parsers/ragel/date_time.rl +30 -0
  118. data/lib/mail/parsers/ragel/parser_info.rb +61 -0
  119. data/lib/mail/parsers/ragel/ruby.rb +39 -0
  120. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
  121. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
  122. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
  123. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
  124. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
  125. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
  126. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
  127. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
  128. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
  129. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
  130. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
  131. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
  132. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2129 -0
  133. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
  134. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
  135. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
  136. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
  137. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
  138. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
  139. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
  140. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
  141. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
  142. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
  143. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
  144. data/lib/mail/parsers/received_parser.rb +47 -0
  145. data/lib/mail/part.rb +120 -0
  146. data/lib/mail/parts_list.rb +57 -0
  147. data/lib/mail/patterns.rb +37 -0
  148. data/lib/mail/utilities.rb +225 -0
  149. data/lib/mail/values/unicode_tables.dat +0 -0
  150. data/lib/mail/version.rb +4 -0
  151. data/lib/mail/version_specific/ruby_1_8.rb +119 -0
  152. data/lib/mail/version_specific/ruby_1_9.rb +159 -0
  153. metadata +276 -0
@@ -0,0 +1,37 @@
1
+ %%{
2
+ machine received;
3
+
4
+ include rb_actions "rb_actions.rl";
5
+ include common "../../common.rl";
6
+
7
+ getkey data_unpacked[p];
8
+
9
+ main := received;
10
+ }%%
11
+
12
+ module Mail
13
+ module Parsers
14
+ module Ragel
15
+ module ReceivedMachine
16
+ %%write data;
17
+
18
+ def self.parse(data)
19
+ p = 0
20
+ eof = data.length
21
+ stack = []
22
+
23
+ actions = []
24
+ data_unpacked = data.bytes.to_a
25
+ %%write init;
26
+ %%write exec;
27
+
28
+ if p == eof && cs >= %%{ write first_final; }%%
29
+ return actions, nil
30
+ else
31
+ return [], "Only able to parse up to #{data[0..p]}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ %%{
2
+ machine <%= parser_name %>;
3
+
4
+ include rb_actions "rb_actions.rl";
5
+ include common "../../common.rl";
6
+
7
+ getkey data_unpacked[p];
8
+
9
+ main := <%= parser_name %>;
10
+ }%%
11
+
12
+ module Mail
13
+ module Parsers
14
+ module Ragel
15
+ module <%= parser_name_cc %>
16
+ %%write data;
17
+
18
+ def self.parse(data)
19
+ p = 0
20
+ eof = data.length
21
+ stack = []
22
+
23
+ actions = []
24
+ data_unpacked = data.bytes.to_a
25
+ %%write init;
26
+ %%write exec;
27
+
28
+ if p == eof && cs >= %%{ write first_final; }%%
29
+ return actions, nil
30
+ else
31
+ return [], "Only able to parse up to #{data[0..p]}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,47 @@
1
+ module Mail::Parsers
2
+ class ReceivedParser
3
+
4
+ def parse(s)
5
+ actions, error = Ragel.parse(:received, s)
6
+ if error
7
+ raise Mail::Field::ParseError.new(Mail::ReceivedElement, s, error)
8
+ end
9
+
10
+ received = ReceivedStruct.new
11
+
12
+ received_tokens_s = date_s = time_s = nil
13
+ actions.each_slice(2) do |action_id, p|
14
+ action = Mail::Parsers::Ragel::ACTIONS[action_id]
15
+ case action
16
+
17
+ # Received Tokens:
18
+ when :received_tokens_s then received_tokens_s = p
19
+ when :received_tokens_e
20
+ received.info = s[received_tokens_s..(p-1)]
21
+
22
+ # Date
23
+ when :date_s then date_s = p
24
+ when :date_e
25
+ received.date = s[date_s..(p-1)].strip
26
+
27
+ # Time
28
+ when :time_s then time_s = p
29
+ when :time_e
30
+ received.time = s[time_s..(p-1)]
31
+
32
+ when :angle_addr_s, :comment_e, :comment_s,
33
+ :domain_e, :domain_s, :local_dot_atom_e,
34
+ :local_dot_atom_pre_comment_e,
35
+ :local_dot_atom_pre_comment_s,
36
+ :local_dot_atom_s, :qstr_e, :qstr_s,
37
+ :local_quoted_string_s, :local_quoted_string_e
38
+ # ignored actions
39
+
40
+ else
41
+ raise Mail::Field::ParseError.new(Mail::ReceivedElement, s, "Failed to process unknown action: #{action}")
42
+ end
43
+ end
44
+ received
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,120 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ class Part < Message
4
+
5
+ # Creates a new empty Content-ID field and inserts it in the correct order
6
+ # into the Header. The ContentIdField object will automatically generate
7
+ # a unique content ID if you try and encode it or output it to_s without
8
+ # specifying a content id.
9
+ #
10
+ # It will preserve the content ID you specify if you do.
11
+ def add_content_id(content_id_val = '')
12
+ header['content-id'] = content_id_val
13
+ end
14
+
15
+ # Returns true if the part has a content ID field, the field may or may
16
+ # not have a value, but the field exists or not.
17
+ def has_content_id?
18
+ header.has_content_id?
19
+ end
20
+
21
+ def inline_content_id
22
+ # TODO: Deprecated in 2.2.2 - Remove in 2.3
23
+ STDERR.puts("Part#inline_content_id is deprecated, please call Part#cid instead")
24
+ cid
25
+ end
26
+
27
+ def cid
28
+ add_content_id unless has_content_id?
29
+ uri_escape(unbracket(content_id))
30
+ end
31
+
32
+ def url
33
+ "cid:#{cid}"
34
+ end
35
+
36
+ def inline?
37
+ header[:content_disposition].disposition_type == 'inline' if header[:content_disposition]
38
+ end
39
+
40
+ def add_required_fields
41
+ super
42
+ add_content_id if !has_content_id? && inline?
43
+ end
44
+
45
+ def add_required_message_fields
46
+ # Override so we don't add Date, MIME-Version, or Message-ID.
47
+ end
48
+
49
+ def delivery_status_report_part?
50
+ (main_type =~ /message/i && sub_type =~ /delivery-status/i) && body =~ /Status:/
51
+ end
52
+
53
+ def delivery_status_data
54
+ delivery_status_report_part? ? parse_delivery_status_report : {}
55
+ end
56
+
57
+ def bounced?
58
+ if action.is_a?(Array)
59
+ !!(action.first =~ /failed/i)
60
+ else
61
+ !!(action =~ /failed/i)
62
+ end
63
+ end
64
+
65
+
66
+ # Either returns the action if the message has just a single report, or an
67
+ # array of all the actions, one for each report
68
+ def action
69
+ get_return_values('action')
70
+ end
71
+
72
+ def final_recipient
73
+ get_return_values('final-recipient')
74
+ end
75
+
76
+ def error_status
77
+ get_return_values('status')
78
+ end
79
+
80
+ def diagnostic_code
81
+ get_return_values('diagnostic-code')
82
+ end
83
+
84
+ def remote_mta
85
+ get_return_values('remote-mta')
86
+ end
87
+
88
+ def retryable?
89
+ !(error_status =~ /^5/)
90
+ end
91
+
92
+ private
93
+
94
+ def get_return_values(key)
95
+ if delivery_status_data[key].is_a?(Array)
96
+ delivery_status_data[key].map { |a| a.value }
97
+ else
98
+ delivery_status_data[key].value
99
+ end
100
+ end
101
+
102
+ # A part may not have a header.... so, just init a body if no header
103
+ def parse_message
104
+ header_part, body_part = raw_source.split(/#{CRLF}#{WSP}*#{CRLF}/m, 2)
105
+ if header_part =~ HEADER_LINE
106
+ self.header = header_part
107
+ self.body = body_part
108
+ else
109
+ self.header = "Content-Type: text/plain\r\n"
110
+ self.body = raw_source
111
+ end
112
+ end
113
+
114
+ def parse_delivery_status_report
115
+ @delivery_status_data ||= Header.new(body.to_s.gsub("\r\n\r\n", "\r\n"))
116
+ end
117
+
118
+ end
119
+
120
+ end
@@ -0,0 +1,57 @@
1
+ module Mail
2
+ class PartsList < Array
3
+
4
+ def attachments
5
+ Mail::AttachmentsList.new(self)
6
+ end
7
+
8
+ def collect
9
+ if block_given?
10
+ ary = PartsList.new
11
+ each { |o| ary << yield(o) }
12
+ ary
13
+ else
14
+ to_a
15
+ end
16
+ end
17
+
18
+ undef :map
19
+ alias_method :map, :collect
20
+
21
+ def map!
22
+ raise NoMethodError, "#map! is not defined, please call #collect and create a new PartsList"
23
+ end
24
+
25
+ def collect!
26
+ raise NoMethodError, "#collect! is not defined, please call #collect and create a new PartsList"
27
+ end
28
+
29
+ def sort
30
+ self.class.new(super)
31
+ end
32
+
33
+ def sort!(order)
34
+ # stable sort should be used to maintain the relative order as the parts are added
35
+ i = 0;
36
+ sorted = self.sort_by do |a|
37
+ # OK, 10000 is arbitrary... if anyone actually wants to explicitly sort 10000 parts of a
38
+ # single email message... please show me a use case and I'll put more work into this method,
39
+ # in the meantime, it works :)
40
+ [get_order_value(a, order), i += 1]
41
+ end
42
+ self.clear
43
+ sorted.each { |p| self << p }
44
+ end
45
+
46
+ private
47
+
48
+ def get_order_value(part, order)
49
+ if part.respond_to?(:content_type) && !part[:content_type].nil?
50
+ order.index(part[:content_type].string.downcase) || 10000
51
+ else
52
+ 10000
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: us-ascii
2
+ module Mail
3
+ module Patterns
4
+ white_space = %Q|\x9\x20|
5
+ text = %Q|\x1-\x8\xB\xC\xE-\x7f|
6
+ field_name = %Q|\x21-\x39\x3b-\x7e|
7
+ qp_safe = %Q|\x20-\x3c\x3e-\x7e|
8
+
9
+ aspecial = %Q|()<>[]:;@\\,."| # RFC5322
10
+ tspecial = %Q|()<>@,;:\\"/[]?=| # RFC2045
11
+ sp = %Q| |
12
+ control = %Q|\x00-\x1f\x7f-\xff|
13
+
14
+ if control.respond_to?(:force_encoding)
15
+ control = control.force_encoding(Encoding::BINARY)
16
+ end
17
+
18
+ CRLF = /\r\n/
19
+ WSP = /[#{white_space}]/
20
+ FWS = /#{CRLF}#{WSP}*/
21
+ TEXT = /[#{text}]/ # + obs-text
22
+ FIELD_NAME = /[#{field_name}]+/
23
+ FIELD_PREFIX = /\A(#{FIELD_NAME})/
24
+ FIELD_BODY = /.+/m
25
+ FIELD_LINE = /^[#{field_name}]+:\s*.+$/
26
+ FIELD_SPLIT = /^(#{FIELD_NAME})\s*:\s*(#{FIELD_BODY})?$/
27
+ HEADER_LINE = /^([#{field_name}]+:\s*.+)$/
28
+ HEADER_SPLIT = /#{CRLF}(?!#{WSP})/
29
+
30
+ QP_UNSAFE = /[^#{qp_safe}]/
31
+ QP_SAFE = /[#{qp_safe}]/
32
+ CONTROL_CHAR = /[#{control}]/n
33
+ ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{sp}]/n
34
+ PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
35
+ TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{sp}]/n
36
+ end
37
+ end
@@ -0,0 +1,225 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module Utilities
4
+ include Patterns
5
+
6
+ # Returns true if the string supplied is free from characters not allowed as an ATOM
7
+ def atom_safe?( str )
8
+ not ATOM_UNSAFE === str
9
+ end
10
+
11
+ # If the string supplied has ATOM unsafe characters in it, will return the string quoted
12
+ # in double quotes, otherwise returns the string unmodified
13
+ def quote_atom( str )
14
+ atom_safe?( str ) ? str : dquote(str)
15
+ end
16
+
17
+ # If the string supplied has PHRASE unsafe characters in it, will return the string quoted
18
+ # in double quotes, otherwise returns the string unmodified
19
+ def quote_phrase( str )
20
+ if RUBY_VERSION >= '1.9'
21
+ original_encoding = str.encoding
22
+ str.force_encoding('ASCII-8BIT')
23
+ if (PHRASE_UNSAFE === str)
24
+ quoted_str = dquote(str).force_encoding(original_encoding)
25
+ str.force_encoding(original_encoding)
26
+ quoted_str
27
+ else
28
+ str.force_encoding(original_encoding)
29
+ end
30
+ else
31
+ (PHRASE_UNSAFE === str) ? dquote(str) : str
32
+ end
33
+ end
34
+
35
+ # Returns true if the string supplied is free from characters not allowed as a TOKEN
36
+ def token_safe?( str )
37
+ not TOKEN_UNSAFE === str
38
+ end
39
+
40
+ # If the string supplied has TOKEN unsafe characters in it, will return the string quoted
41
+ # in double quotes, otherwise returns the string unmodified
42
+ def quote_token( str )
43
+ token_safe?( str ) ? str : dquote(str)
44
+ end
45
+
46
+ # Wraps supplied string in double quotes and applies \-escaping as necessary,
47
+ # unless it is already wrapped.
48
+ #
49
+ # Example:
50
+ #
51
+ # string = 'This is a string'
52
+ # dquote(string) #=> '"This is a string"'
53
+ #
54
+ # string = 'This is "a string"'
55
+ # dquote(string #=> '"This is \"a string\"'
56
+ def dquote( str )
57
+ '"' + unquote(str).gsub(/[\\"]/n) {|s| '\\' + s } + '"'
58
+ end
59
+
60
+ # Unwraps supplied string from inside double quotes and
61
+ # removes any \-escaping.
62
+ #
63
+ # Example:
64
+ #
65
+ # string = '"This is a string"'
66
+ # unquote(string) #=> 'This is a string'
67
+ #
68
+ # string = '"This is \"a string\""'
69
+ # unqoute(string) #=> 'This is "a string"'
70
+ def unquote( str )
71
+ if str =~ /^"(.*?)"$/
72
+ $1.gsub(/\\(.)/, '\1')
73
+ else
74
+ str
75
+ end
76
+ end
77
+
78
+ # Wraps a string in parenthesis and escapes any that are in the string itself.
79
+ #
80
+ # Example:
81
+ #
82
+ # paren( 'This is a string' ) #=> '(This is a string)'
83
+ def paren( str )
84
+ RubyVer.paren( str )
85
+ end
86
+
87
+ # Unwraps a string from being wrapped in parenthesis
88
+ #
89
+ # Example:
90
+ #
91
+ # str = '(This is a string)'
92
+ # unparen( str ) #=> 'This is a string'
93
+ def unparen( str )
94
+ match = str.match(/^\((.*?)\)$/)
95
+ match ? match[1] : str
96
+ end
97
+
98
+ # Wraps a string in angle brackets and escapes any that are in the string itself
99
+ #
100
+ # Example:
101
+ #
102
+ # bracket( 'This is a string' ) #=> '<This is a string>'
103
+ def bracket( str )
104
+ RubyVer.bracket( str )
105
+ end
106
+
107
+ # Unwraps a string from being wrapped in parenthesis
108
+ #
109
+ # Example:
110
+ #
111
+ # str = '<This is a string>'
112
+ # unbracket( str ) #=> 'This is a string'
113
+ def unbracket( str )
114
+ match = str.match(/^\<(.*?)\>$/)
115
+ match ? match[1] : str
116
+ end
117
+
118
+ # Escape parenthesies in a string
119
+ #
120
+ # Example:
121
+ #
122
+ # str = 'This is (a) string'
123
+ # escape_paren( str ) #=> 'This is \(a\) string'
124
+ def escape_paren( str )
125
+ RubyVer.escape_paren( str )
126
+ end
127
+
128
+ def uri_escape( str )
129
+ uri_parser.escape(str)
130
+ end
131
+
132
+ def uri_unescape( str )
133
+ uri_parser.unescape(str)
134
+ end
135
+
136
+ def uri_parser
137
+ @uri_parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI
138
+ end
139
+
140
+ # Matches two objects with their to_s values case insensitively
141
+ #
142
+ # Example:
143
+ #
144
+ # obj2 = "This_is_An_object"
145
+ # obj1 = :this_IS_an_object
146
+ # match_to_s( obj1, obj2 ) #=> true
147
+ def match_to_s( obj1, obj2 )
148
+ obj1.to_s.casecmp(obj2.to_s) == 0
149
+ end
150
+
151
+ # Capitalizes a string that is joined by hyphens correctly.
152
+ #
153
+ # Example:
154
+ #
155
+ # string = 'resent-from-field'
156
+ # capitalize_field( string ) #=> 'Resent-From-Field'
157
+ def capitalize_field( str )
158
+ str.to_s.split("-").map { |v| v.capitalize }.join("-")
159
+ end
160
+
161
+ # Takes an underscored word and turns it into a class name
162
+ #
163
+ # Example:
164
+ #
165
+ # constantize("hello") #=> "Hello"
166
+ # constantize("hello-there") #=> "HelloThere"
167
+ # constantize("hello-there-mate") #=> "HelloThereMate"
168
+ def constantize( str )
169
+ str.to_s.split(/[-_]/).map { |v| v.capitalize }.to_s
170
+ end
171
+
172
+ # Swaps out all underscores (_) for hyphens (-) good for stringing from symbols
173
+ # a field name.
174
+ #
175
+ # Example:
176
+ #
177
+ # string = :resent_from_field
178
+ # dasherize ( string ) #=> 'resent_from_field'
179
+ def dasherize( str )
180
+ str.to_s.gsub('_', '-')
181
+ end
182
+
183
+ # Swaps out all hyphens (-) for underscores (_) good for stringing to symbols
184
+ # a field name.
185
+ #
186
+ # Example:
187
+ #
188
+ # string = :resent_from_field
189
+ # underscoreize ( string ) #=> 'resent_from_field'
190
+ def underscoreize( str )
191
+ str.to_s.downcase.gsub('-', '_')
192
+ end
193
+
194
+ if RUBY_VERSION <= '1.8.6'
195
+
196
+ def map_lines( str, &block )
197
+ results = []
198
+ str.each_line do |line|
199
+ results << yield(line)
200
+ end
201
+ results
202
+ end
203
+
204
+ def map_with_index( enum, &block )
205
+ results = []
206
+ enum.each_with_index do |token, i|
207
+ results[i] = yield(token, i)
208
+ end
209
+ results
210
+ end
211
+
212
+ else
213
+
214
+ def map_lines( str, &block )
215
+ str.each_line.map(&block)
216
+ end
217
+
218
+ def map_with_index( enum, &block )
219
+ enum.each_with_index.map(&block)
220
+ end
221
+
222
+ end
223
+
224
+ end
225
+ end