mail-portertech 2.6.2.edge

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 (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