mail 1.0.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.
- data/.gitignore +4 -0
- data/Manifest.txt +106 -0
- data/README.rdoc +441 -0
- data/Rakefile +38 -0
- data/lib/mail.rb +86 -0
- data/lib/mail/attachment.rb +90 -0
- data/lib/mail/body.rb +149 -0
- data/lib/mail/configuration.rb +90 -0
- data/lib/mail/core_extensions.rb +6 -0
- data/lib/mail/core_extensions/blank.rb +41 -0
- data/lib/mail/core_extensions/nil.rb +15 -0
- data/lib/mail/core_extensions/string.rb +31 -0
- data/lib/mail/elements/address.rb +293 -0
- data/lib/mail/elements/address_list.rb +62 -0
- data/lib/mail/elements/content_disposition_element.rb +34 -0
- data/lib/mail/elements/content_transfer_encoding_element.rb +21 -0
- data/lib/mail/elements/content_type_element.rb +39 -0
- data/lib/mail/elements/date_time_element.rb +26 -0
- data/lib/mail/elements/envelope_from_element.rb +34 -0
- data/lib/mail/elements/message_ids_element.rb +29 -0
- data/lib/mail/elements/mime_version_element.rb +26 -0
- data/lib/mail/elements/phrase_list.rb +21 -0
- data/lib/mail/elements/received_element.rb +30 -0
- data/lib/mail/encodings/base64.rb +17 -0
- data/lib/mail/encodings/encodings.rb +24 -0
- data/lib/mail/encodings/quoted_printable.rb +26 -0
- data/lib/mail/envelope.rb +35 -0
- data/lib/mail/field.rb +202 -0
- data/lib/mail/field_list.rb +33 -0
- data/lib/mail/fields/bcc_field.rb +40 -0
- data/lib/mail/fields/cc_field.rb +40 -0
- data/lib/mail/fields/comments_field.rb +41 -0
- data/lib/mail/fields/common/common_address.rb +62 -0
- data/lib/mail/fields/common/common_date.rb +35 -0
- data/lib/mail/fields/common/common_field.rb +128 -0
- data/lib/mail/fields/common/common_message_id.rb +35 -0
- data/lib/mail/fields/content_description_field.rb +15 -0
- data/lib/mail/fields/content_disposition_field.rb +34 -0
- data/lib/mail/fields/content_id_field.rb +50 -0
- data/lib/mail/fields/content_transfer_encoding_field.rb +28 -0
- data/lib/mail/fields/content_type_field.rb +50 -0
- data/lib/mail/fields/date_field.rb +44 -0
- data/lib/mail/fields/from_field.rb +40 -0
- data/lib/mail/fields/in_reply_to_field.rb +42 -0
- data/lib/mail/fields/keywords_field.rb +22 -0
- data/lib/mail/fields/message_id_field.rb +70 -0
- data/lib/mail/fields/mime_version_field.rb +42 -0
- data/lib/mail/fields/optional_field.rb +11 -0
- data/lib/mail/fields/received_field.rb +49 -0
- data/lib/mail/fields/references_field.rb +42 -0
- data/lib/mail/fields/reply_to_field.rb +40 -0
- data/lib/mail/fields/resent_bcc_field.rb +40 -0
- data/lib/mail/fields/resent_cc_field.rb +40 -0
- data/lib/mail/fields/resent_date_field.rb +16 -0
- data/lib/mail/fields/resent_from_field.rb +40 -0
- data/lib/mail/fields/resent_message_id_field.rb +20 -0
- data/lib/mail/fields/resent_sender_field.rb +48 -0
- data/lib/mail/fields/resent_to_field.rb +40 -0
- data/lib/mail/fields/return_path_field.rb +34 -0
- data/lib/mail/fields/sender_field.rb +48 -0
- data/lib/mail/fields/structured_field.rb +32 -0
- data/lib/mail/fields/subject_field.rb +14 -0
- data/lib/mail/fields/to_field.rb +40 -0
- data/lib/mail/fields/unstructured_field.rb +27 -0
- data/lib/mail/header.rb +213 -0
- data/lib/mail/mail.rb +120 -0
- data/lib/mail/message.rb +648 -0
- data/lib/mail/network/deliverable.rb +42 -0
- data/lib/mail/network/retrievable.rb +63 -0
- data/lib/mail/parsers/address_lists.rb +61 -0
- data/lib/mail/parsers/address_lists.treetop +19 -0
- data/lib/mail/parsers/content_disposition.rb +358 -0
- data/lib/mail/parsers/content_disposition.treetop +45 -0
- data/lib/mail/parsers/content_transfer_encoding.rb +179 -0
- data/lib/mail/parsers/content_transfer_encoding.treetop +25 -0
- data/lib/mail/parsers/content_type.rb +507 -0
- data/lib/mail/parsers/content_type.treetop +58 -0
- data/lib/mail/parsers/date_time.rb +111 -0
- data/lib/mail/parsers/date_time.treetop +11 -0
- data/lib/mail/parsers/envelope_from.rb +188 -0
- data/lib/mail/parsers/envelope_from.treetop +32 -0
- data/lib/mail/parsers/message_ids.rb +42 -0
- data/lib/mail/parsers/message_ids.treetop +15 -0
- data/lib/mail/parsers/mime_version.rb +141 -0
- data/lib/mail/parsers/mime_version.treetop +19 -0
- data/lib/mail/parsers/phrase_lists.rb +42 -0
- data/lib/mail/parsers/phrase_lists.treetop +15 -0
- data/lib/mail/parsers/received.rb +68 -0
- data/lib/mail/parsers/received.treetop +11 -0
- data/lib/mail/parsers/rfc2045.rb +406 -0
- data/lib/mail/parsers/rfc2045.treetop +35 -0
- data/lib/mail/parsers/rfc2822.rb +5005 -0
- data/lib/mail/parsers/rfc2822.treetop +402 -0
- data/lib/mail/parsers/rfc2822_obsolete.rb +3607 -0
- data/lib/mail/parsers/rfc2822_obsolete.treetop +241 -0
- data/lib/mail/part.rb +120 -0
- data/lib/mail/patterns.rb +42 -0
- data/lib/mail/utilities.rb +142 -0
- data/lib/mail/version.rb +10 -0
- data/lib/mail/version_specific/multibyte.rb +62 -0
- data/lib/mail/version_specific/multibyte/chars.rb +701 -0
- data/lib/mail/version_specific/multibyte/exceptions.rb +8 -0
- data/lib/mail/version_specific/multibyte/unicode_database.rb +71 -0
- data/lib/mail/version_specific/ruby_1_8.rb +61 -0
- data/lib/mail/version_specific/ruby_1_8_string.rb +88 -0
- data/lib/mail/version_specific/ruby_1_9.rb +49 -0
- metadata +192 -0
@@ -0,0 +1,241 @@
|
|
1
|
+
module Mail
|
2
|
+
grammar RFC2822Obsolete
|
3
|
+
|
4
|
+
rule obs_qp
|
5
|
+
"\\" [\x00-\x7F]
|
6
|
+
end
|
7
|
+
|
8
|
+
rule obs_text
|
9
|
+
LF* CR* (obs_char LF* CR*)*
|
10
|
+
end
|
11
|
+
|
12
|
+
rule obs_char
|
13
|
+
[\x00-\x09] / # %d0-127 except CR and
|
14
|
+
[\x0B-\x0C] / # LF
|
15
|
+
[\x0E-\x7F]
|
16
|
+
end
|
17
|
+
|
18
|
+
rule obs_utext
|
19
|
+
obs_text
|
20
|
+
end
|
21
|
+
|
22
|
+
rule obs_phrase
|
23
|
+
(word / ".")+
|
24
|
+
end
|
25
|
+
|
26
|
+
rule obs_phrase_list
|
27
|
+
phrase / (phrase? CFWS? "," CFWS?)+ phrase?
|
28
|
+
end
|
29
|
+
|
30
|
+
rule obs_FWS
|
31
|
+
WSP+ (CRLF WSP+)*
|
32
|
+
end
|
33
|
+
|
34
|
+
rule obs_day_of_week
|
35
|
+
CFWS? day_name CFWS?
|
36
|
+
end
|
37
|
+
|
38
|
+
rule obs_year
|
39
|
+
CFWS? (DIGIT DIGIT) CFWS?
|
40
|
+
end
|
41
|
+
|
42
|
+
rule obs_month
|
43
|
+
CFWS month_name CFWS
|
44
|
+
end
|
45
|
+
|
46
|
+
rule obs_day
|
47
|
+
CFWS? (DIGIT / (DIGIT DIGIT)) CFWS?
|
48
|
+
end
|
49
|
+
|
50
|
+
rule obs_hour
|
51
|
+
CFWS? (DIGIT DIGIT) CFWS?
|
52
|
+
end
|
53
|
+
|
54
|
+
rule obs_minute
|
55
|
+
CFWS? (DIGIT DIGIT) CFWS?
|
56
|
+
end
|
57
|
+
|
58
|
+
rule obs_second
|
59
|
+
CFWS? (DIGIT DIGIT) CFWS?
|
60
|
+
end
|
61
|
+
|
62
|
+
rule obs_zone
|
63
|
+
"UT" / "GMT" / # Universal Time
|
64
|
+
# North American UT
|
65
|
+
# offsets
|
66
|
+
"EST" / "EDT" / # Eastern: - 5/ - 4
|
67
|
+
"CST" / "CDT" / # Central: - 6/ - 5
|
68
|
+
"MST" / "MDT" / # Mountain: - 7/ - 6
|
69
|
+
"PST" / "PDT" / # Pacific: - 8/ - 7
|
70
|
+
#
|
71
|
+
[\x41-\x49] / # Military zones - "A"
|
72
|
+
[\x4B-\x5A] / # through "I" and "K"
|
73
|
+
[\x61-\x69] / # through "Z", both
|
74
|
+
[\x6B-\x7A] # upper and lower case
|
75
|
+
end
|
76
|
+
|
77
|
+
rule obs_angle_addr
|
78
|
+
CFWS? "<" obs_route? addr_spec ">" CFWS?
|
79
|
+
end
|
80
|
+
|
81
|
+
rule obs_route
|
82
|
+
CFWS? obs_domain_list ":" CFWS?
|
83
|
+
end
|
84
|
+
|
85
|
+
rule obs_domain_list
|
86
|
+
"@" domain (("," )* CFWS? "@" domain)*
|
87
|
+
end
|
88
|
+
|
89
|
+
rule obs_local_part
|
90
|
+
word ("." word)*
|
91
|
+
end
|
92
|
+
|
93
|
+
rule obs_domain
|
94
|
+
atom ("." atom)*
|
95
|
+
end
|
96
|
+
|
97
|
+
rule obs_mbox_list
|
98
|
+
(mailbox? CFWS? "," CFWS?)+ mailbox?
|
99
|
+
end
|
100
|
+
|
101
|
+
rule obs_addr_list
|
102
|
+
(address? CFWS? "," CFWS?)+ address?
|
103
|
+
end
|
104
|
+
|
105
|
+
rule obs_fields
|
106
|
+
(obs_return /
|
107
|
+
obs_received /
|
108
|
+
obs_orig_date /
|
109
|
+
obs_from /
|
110
|
+
obs_sender /
|
111
|
+
obs_reply_to /
|
112
|
+
obs_to /
|
113
|
+
obs_cc /
|
114
|
+
obs_bcc /
|
115
|
+
obs_message_id /
|
116
|
+
obs_in_reply_to /
|
117
|
+
obs_references /
|
118
|
+
obs_subject /
|
119
|
+
obs_comments /
|
120
|
+
obs_keywords /
|
121
|
+
obs_resent_date /
|
122
|
+
obs_resent_from /
|
123
|
+
obs_resent_send /
|
124
|
+
obs_resent_rply /
|
125
|
+
obs_resent_to /
|
126
|
+
obs_resent_cc /
|
127
|
+
obs_resent_bcc /
|
128
|
+
obs_resent_mid /
|
129
|
+
obs_optional)*
|
130
|
+
end
|
131
|
+
|
132
|
+
rule obs_orig_date
|
133
|
+
"Date" WSP* ":" date_time CRLF
|
134
|
+
end
|
135
|
+
|
136
|
+
rule obs_from
|
137
|
+
"From" WSP* ":" mailbox_list CRLF
|
138
|
+
end
|
139
|
+
|
140
|
+
rule obs_sender
|
141
|
+
"Sender" WSP* ":" mailbox CRLF
|
142
|
+
end
|
143
|
+
|
144
|
+
rule obs_reply_to
|
145
|
+
"Reply-To" WSP* ":" mailbox_list CRLF
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
rule obs_to
|
150
|
+
"To" WSP* ":" address_list CRLF
|
151
|
+
end
|
152
|
+
|
153
|
+
rule obs_cc
|
154
|
+
"Cc" WSP* ":" address_list CRLF
|
155
|
+
end
|
156
|
+
|
157
|
+
rule obs_bcc
|
158
|
+
"Bcc" WSP* ":" (address_list / CFWS?) CRLF
|
159
|
+
end
|
160
|
+
|
161
|
+
rule obs_message_id
|
162
|
+
"Message-ID" WSP* ":" msg_id CRLF
|
163
|
+
end
|
164
|
+
|
165
|
+
rule obs_in_reply_to
|
166
|
+
"In-Reply-To" WSP* ":" (phrase / msg_id)* CRLF
|
167
|
+
end
|
168
|
+
|
169
|
+
rule obs_references
|
170
|
+
"References" WSP* ":" (phrase / msg_id)* CRLF
|
171
|
+
end
|
172
|
+
|
173
|
+
rule obs_id_left
|
174
|
+
local_part
|
175
|
+
end
|
176
|
+
|
177
|
+
rule obs_id_right
|
178
|
+
domain
|
179
|
+
end
|
180
|
+
|
181
|
+
rule obs_subject
|
182
|
+
"Subject" WSP* ":" unstructured CRLF
|
183
|
+
end
|
184
|
+
|
185
|
+
rule obs_comments
|
186
|
+
"Comments" WSP* ":" unstructured CRLF
|
187
|
+
end
|
188
|
+
|
189
|
+
rule obs_keywords
|
190
|
+
"Keywords" WSP* ":" obs_phrase_list CRLF
|
191
|
+
end
|
192
|
+
|
193
|
+
rule obs_resent_from
|
194
|
+
"Resent-From" WSP* ":" mailbox_list CRLF
|
195
|
+
end
|
196
|
+
|
197
|
+
rule obs_resent_send
|
198
|
+
"Resent-Sender" WSP* ":" mailbox CRLF
|
199
|
+
end
|
200
|
+
|
201
|
+
rule obs_resent_date
|
202
|
+
"Resent-Date" WSP* ":" date_time CRLF
|
203
|
+
end
|
204
|
+
|
205
|
+
rule obs_resent_to
|
206
|
+
"Resent-To" WSP* ":" address_list CRLF
|
207
|
+
end
|
208
|
+
|
209
|
+
rule obs_resent_cc
|
210
|
+
"Resent-Cc" WSP* ":" address_list CRLF
|
211
|
+
end
|
212
|
+
|
213
|
+
rule obs_resent_bcc
|
214
|
+
"Resent-Bcc" WSP* ":" (address_list / CFWS?) CRLF
|
215
|
+
end
|
216
|
+
|
217
|
+
rule obs_resent_mid
|
218
|
+
"Resent-Message-ID" WSP* ":" msg_id CRLF
|
219
|
+
end
|
220
|
+
|
221
|
+
rule obs_resent_rply
|
222
|
+
"Resent-Reply-To" WSP* ":" address_list CRLF
|
223
|
+
end
|
224
|
+
|
225
|
+
rule obs_return
|
226
|
+
"Return-Path" WSP* ":" path CRLF
|
227
|
+
end
|
228
|
+
|
229
|
+
rule obs_received
|
230
|
+
"Received" WSP* ":" name_val_list CRLF
|
231
|
+
end
|
232
|
+
|
233
|
+
rule obs_path
|
234
|
+
obs_angle_addr
|
235
|
+
end
|
236
|
+
|
237
|
+
rule obs_optional
|
238
|
+
field_name WSP* ":" unstructured CRLF
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
data/lib/mail/part.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mail
|
3
|
+
class Part < Message
|
4
|
+
|
5
|
+
def initialize(*args, &block)
|
6
|
+
if args.flatten[0].is_a?(Hash)
|
7
|
+
options_hash = args.flatten[0]
|
8
|
+
super('') # Make an empty message, we are dealing with an attachment
|
9
|
+
@attachment = Mail::Attachment.new(options_hash)
|
10
|
+
self.content_type = "#{attachment.mime_type}; filename=\"#{attachment.filename}\""
|
11
|
+
self.content_transfer_encoding = "Base64"
|
12
|
+
self.content_disposition = "attachment; filename=\"#{attachment.filename}\""
|
13
|
+
self.body = attachment.encoded
|
14
|
+
else
|
15
|
+
super
|
16
|
+
if content_type.parameters['filename']
|
17
|
+
@attachment = Mail::Attachment.new(:filename => content_type.parameters['filename'],
|
18
|
+
:data => body.to_s,
|
19
|
+
:encoding => content_transfer_encoding.to_s)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Creates a new empty Content-ID field and inserts it in the correct order
|
25
|
+
# into the Header. The ContentIdField object will automatically generate
|
26
|
+
# a unique content ID if you try and encode it or output it to_s without
|
27
|
+
# specifying a content id.
|
28
|
+
#
|
29
|
+
# It will preserve the content ID you specify if you do.
|
30
|
+
def add_content_id(content_id_val = '')
|
31
|
+
header['content-id'] = content_id_val
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns true if this part is an attachment
|
35
|
+
def attachment?
|
36
|
+
@attachment ? true : false
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the attachment data if there is any
|
40
|
+
def attachment
|
41
|
+
@attachment
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the filename of the attachment
|
45
|
+
def filename
|
46
|
+
if attachment?
|
47
|
+
attachment.filename
|
48
|
+
else
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns true if the part has a content ID field, the field may or may
|
54
|
+
# not have a value, but the field exists or not.
|
55
|
+
def has_content_id?
|
56
|
+
header.has_content_id?
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_required_fields
|
60
|
+
add_content_id unless has_content_id?
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
def delivery_status_report_part?
|
65
|
+
main_type =~ /message/i && sub_type =~ /delivery-status/i
|
66
|
+
end
|
67
|
+
|
68
|
+
def delivery_status_data
|
69
|
+
delivery_status_report_part? ? parse_delivery_status_report : {}
|
70
|
+
end
|
71
|
+
|
72
|
+
def bounced?
|
73
|
+
(action =~ /failed/i)
|
74
|
+
end
|
75
|
+
|
76
|
+
def action
|
77
|
+
delivery_status_data['action'].value
|
78
|
+
end
|
79
|
+
|
80
|
+
def final_recipient
|
81
|
+
delivery_status_data['final-recipient'].value
|
82
|
+
end
|
83
|
+
|
84
|
+
def error_status
|
85
|
+
delivery_status_data['status'].value
|
86
|
+
end
|
87
|
+
|
88
|
+
def diagnostic_code
|
89
|
+
delivery_status_data['diagnostic-code'].value
|
90
|
+
end
|
91
|
+
|
92
|
+
def remote_mta
|
93
|
+
delivery_status_data['remote-mta'].value
|
94
|
+
end
|
95
|
+
|
96
|
+
def retryable?
|
97
|
+
!(error_status =~ /^5/)
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
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 = header_part
|
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,42 @@
|
|
1
|
+
module Mail
|
2
|
+
module Patterns
|
3
|
+
|
4
|
+
white_space = %Q|\x9\x20|
|
5
|
+
text = %Q|\x1-\x8\xB\xC\xE-\x7f|
|
6
|
+
field_name = %Q|\x21-\x39\x3b-\x7e|
|
7
|
+
field_body = text
|
8
|
+
|
9
|
+
aspecial = %Q|()<>[]:;.\\,"|
|
10
|
+
tspecial = %Q|()<>[];:\\,"/?=|
|
11
|
+
lwsp = %Q| \t\r\n|
|
12
|
+
control = %Q|\x00-\x1f\x7f-\xff|
|
13
|
+
|
14
|
+
CRLF = /\r\n/
|
15
|
+
WSP = /[#{white_space}]/
|
16
|
+
FWS = /#{CRLF}#{WSP}*/
|
17
|
+
TEXT = /[#{text}]/ # + obs-text
|
18
|
+
FIELD_NAME = /[#{field_name}]+/
|
19
|
+
FIELD_BODY = /[#{field_body}]+/
|
20
|
+
FIELD_LINE = /^[#{field_name}]+:\s*[#{field_body}]+$/
|
21
|
+
HEADER_LINE = /^([#{field_name}]+:\s*[#{field_body}]+)/
|
22
|
+
|
23
|
+
CONTROL_CHAR = /[#{control}]/n
|
24
|
+
ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{lwsp}]/n
|
25
|
+
PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
|
26
|
+
TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}]/n
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
module InstanceMethods
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.included(receiver)
|
37
|
+
receiver.extend ClassMethods
|
38
|
+
receiver.send :include, InstanceMethods
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mail
|
3
|
+
module Utilities
|
4
|
+
|
5
|
+
module ClassMethods # :nodoc:
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
|
11
|
+
include Patterns
|
12
|
+
|
13
|
+
# Returns true if the string supplied is free from characters not allowed as an ATOM
|
14
|
+
def atom_safe?( str )
|
15
|
+
not ATOM_UNSAFE === str
|
16
|
+
end
|
17
|
+
|
18
|
+
# If the string supplied has ATOM unsafe characters in it, will return the string quoted
|
19
|
+
# in double quotes, otherwise returns the string unmodified
|
20
|
+
def quote_atom( str )
|
21
|
+
(ATOM_UNSAFE === str) ? dquote(str) : str
|
22
|
+
end
|
23
|
+
|
24
|
+
# If the string supplied has PHRASE unsafe characters in it, will return the string quoted
|
25
|
+
# in double quotes, otherwise returns the string unmodified
|
26
|
+
def quote_phrase( str )
|
27
|
+
(PHRASE_UNSAFE === str) ? dquote(str) : str
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns true if the string supplied is free from characters not allowed as a TOKEN
|
31
|
+
def token_safe?( str )
|
32
|
+
not TOKEN_UNSAFE === str
|
33
|
+
end
|
34
|
+
|
35
|
+
# If the string supplied has TOKEN unsafe characters in it, will return the string quoted
|
36
|
+
# in double quotes, otherwise returns the string unmodified
|
37
|
+
def quote_token( str )
|
38
|
+
(TOKEN_UNSAFE === str) ? dquote(str) : str
|
39
|
+
end
|
40
|
+
|
41
|
+
# Wraps supplied string in double quotes unless it is already wrapped.
|
42
|
+
#
|
43
|
+
# Additionally will escape any double quotation marks in the string with a single
|
44
|
+
# backslash in front of the '"' character.
|
45
|
+
def dquote( str )
|
46
|
+
str = $1 if str =~ /^"(.*)?"$/
|
47
|
+
# First remove all escaped double quotes:
|
48
|
+
str = str.gsub(/\\"/, '"')
|
49
|
+
# Then wrap and re-escape all double quotes
|
50
|
+
'"' + str.gsub(/["]/n) {|s| '\\' + s } + '"'
|
51
|
+
end
|
52
|
+
|
53
|
+
# Unwraps supplied string from inside double quotes.
|
54
|
+
#
|
55
|
+
# Example:
|
56
|
+
#
|
57
|
+
# string = '"This is a string"'
|
58
|
+
# unquote(string) #=> 'This is a string'
|
59
|
+
def unquote( str )
|
60
|
+
str =~ /^"(.*?)"$/ ? $1 : str
|
61
|
+
end
|
62
|
+
|
63
|
+
# Wraps a string in parenthesis and escapes any that are in the string itself.
|
64
|
+
#
|
65
|
+
# Example:
|
66
|
+
#
|
67
|
+
# string
|
68
|
+
def paren( str )
|
69
|
+
RubyVer.paren( str )
|
70
|
+
end
|
71
|
+
|
72
|
+
# Unwraps a string from being wrapped in parenthesis
|
73
|
+
#
|
74
|
+
# Example:
|
75
|
+
#
|
76
|
+
# str = '(This is a string)'
|
77
|
+
# unparen( str ) #=> 'This is a string'
|
78
|
+
def unparen( str )
|
79
|
+
str =~ /^\((.*?)\)$/ ? $1 : str
|
80
|
+
end
|
81
|
+
|
82
|
+
# Escape parenthesies in a string
|
83
|
+
#
|
84
|
+
# Example:
|
85
|
+
#
|
86
|
+
# str = 'This is (a) string'
|
87
|
+
# escape_paren( str ) #=> 'This is \(a\) string'
|
88
|
+
def escape_paren( str )
|
89
|
+
RubyVer.escape_paren( str )
|
90
|
+
end
|
91
|
+
|
92
|
+
# Matches two objects with their to_s values case insensitively
|
93
|
+
#
|
94
|
+
# Example:
|
95
|
+
#
|
96
|
+
# obj2 = "This_is_An_object"
|
97
|
+
# obj1 = :this_IS_an_object
|
98
|
+
# match_to_s( obj1, obj2 ) #=> true
|
99
|
+
def match_to_s( obj1, obj2 )
|
100
|
+
obj1.to_s.downcase == obj2.to_s.downcase
|
101
|
+
end
|
102
|
+
|
103
|
+
# Capitalizes a string that is joined by hyphens correctly.
|
104
|
+
#
|
105
|
+
# Example:
|
106
|
+
#
|
107
|
+
# string = 'resent-from-field'
|
108
|
+
# capitalize_field( string ) #=> 'Resent-From-Field'
|
109
|
+
def capitalize_field( str )
|
110
|
+
str.to_s.split("-").map { |v| v.capitalize }.join("-")
|
111
|
+
end
|
112
|
+
|
113
|
+
# Takes an underscored word and turns it into a class name
|
114
|
+
#
|
115
|
+
# Example:
|
116
|
+
#
|
117
|
+
# constantize("hello") #=> "Hello"
|
118
|
+
# constantize("hello-there") #=> "HelloThere"
|
119
|
+
# constantize("hello-there-mate") #=> "HelloThereMate"
|
120
|
+
def constantize( str )
|
121
|
+
str.to_s.split(/[-_]/).map { |v| v.capitalize }.to_s
|
122
|
+
end
|
123
|
+
|
124
|
+
# Swaps out all hyphens (-) for underscores (_) good for symbolizing
|
125
|
+
# a field name.
|
126
|
+
#
|
127
|
+
# Example:
|
128
|
+
#
|
129
|
+
# string = 'Resent-From-Field'
|
130
|
+
# underscoreize ( string ) #=> 'resent_from_field'
|
131
|
+
def underscoreize( str )
|
132
|
+
str.to_s.downcase.gsub('_', '-')
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.included(receiver) # :nodoc:
|
138
|
+
receiver.extend ClassMethods
|
139
|
+
receiver.send :include, InstanceMethods
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|