mail 2.6.1 → 2.6.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.rdoc +8 -1
- data/README.md +5 -5
- data/lib/mail.rb +3 -2
- data/lib/mail/body.rb +28 -4
- data/lib/mail/{patterns.rb → constants.rb} +22 -4
- data/lib/mail/core_extensions/string.rb +5 -2
- data/lib/mail/elements/address.rb +49 -72
- data/lib/mail/elements/address_list.rb +1 -11
- data/lib/mail/encodings.rb +11 -26
- data/lib/mail/encodings/unix_to_unix.rb +17 -0
- data/lib/mail/field.rb +2 -2
- data/lib/mail/field_list.rb +1 -1
- data/lib/mail/fields/common/common_field.rb +2 -1
- data/lib/mail/fields/common/parameter_hash.rb +3 -3
- data/lib/mail/fields/unstructured_field.rb +3 -3
- data/lib/mail/header.rb +3 -2
- data/lib/mail/mail.rb +3 -1
- data/lib/mail/matchers/has_sent_mail.rb +2 -2
- data/lib/mail/message.rb +10 -5
- data/lib/mail/parsers/content_type_parser.rb +4 -2
- data/lib/mail/parsers/ragel/common.rl +2 -1
- data/lib/mail/parsers/ragel/ruby.rb +4 -3
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +1439 -1419
- data/lib/mail/utilities.rb +3 -3
- data/lib/mail/version.rb +7 -15
- data/lib/mail/version_specific/ruby_1_8.rb +2 -2
- data/lib/mail/version_specific/ruby_1_9.rb +48 -14
- metadata +36 -36
- data/VERSION +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3af499471587d4cb917ab992eb4bb45f19b9579e
|
4
|
+
data.tar.gz: f05e6aaf887b9a79b9252e7edc2dd74b81f7cb6c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75bb13148f71ffbbef303ca23f01b0c6c8a14aeea255bd528ba3ac0545c056b75ff3a420dc0578c7f15efd894a3367072496121c8479aa8ddc78e376c115168f
|
7
|
+
data.tar.gz: 0f26c569a7c210d3ee57d95cf5011f8ff4941f5c1cd054ef804f018aa829bec44db3fdde7ab2fe1a89056cf81a5e6d618735caaaf9ccf4e8810e4295256f012e
|
data/CHANGELOG.rdoc
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
== HEAD
|
2
2
|
|
3
|
-
|
3
|
+
== Version 2.6.3 - Mon Nov 3 23:53 +1100 2014 Mikel Lindsaar <mikel@reinteractive.net>
|
4
|
+
|
5
|
+
* #796 support uu encoding (grosser)
|
6
|
+
|
7
|
+
== Version 2.6.2 (Unreleased) - Wed Oct 22 13:42 -0500 2014 Benjamin Fleischer <github@benjaminfleischer.com>
|
4
8
|
|
5
9
|
Performance:
|
10
|
+
* #681 - fewer hotspot object allocations (srawlins)
|
11
|
+
* #815 - autoload parsers for load-time speed and memory usage (grosser)
|
6
12
|
|
7
13
|
Bugs:
|
14
|
+
* #736 - Mail.new copes with non-UTF8 messages marked as UTF8 (jeremy)
|
8
15
|
|
9
16
|
== Version 2.6.1 - Sun Jun 8 15:34 +1100 2014 Mikel Lindsaar <mikel@reinteractive.net>
|
10
17
|
|
data/README.md
CHANGED
@@ -15,7 +15,7 @@ Built from my experience with TMail, it is designed to be a pure ruby
|
|
15
15
|
implementation that makes generating, sending and parsing emails a no
|
16
16
|
brainer.
|
17
17
|
|
18
|
-
It is also designed
|
18
|
+
It is also designed from the ground up to work with the more modern versions
|
19
19
|
of Ruby. This is because Ruby > 1.9 handles text encodings much more wonderfully
|
20
20
|
than Ruby 1.8.x and so these features have been taken full advantage of in this
|
21
21
|
library allowing Mail to handle a lot more messages more cleanly than TMail.
|
@@ -44,10 +44,10 @@ Compatibility
|
|
44
44
|
|
45
45
|
Every Mail commit is tested by Travis on the [following platforms](https://github.com/mikel/mail/blob/master/.travis.yml)
|
46
46
|
|
47
|
-
* ruby-1.8.7
|
48
|
-
* ruby-1.9.2
|
49
|
-
* ruby-1.9.3
|
50
|
-
* ruby-2.0.0
|
47
|
+
* ruby-1.8.7 [ i686 ]
|
48
|
+
* ruby-1.9.2 [ x86_64 ]
|
49
|
+
* ruby-1.9.3 [ x86_64 ]
|
50
|
+
* ruby-2.0.0 [ x86_64 ]
|
51
51
|
* ruby-2.1.2 [ x86_64 ]
|
52
52
|
* ruby-head [ x86_64 ]
|
53
53
|
* jruby [ x86_64 ]
|
data/lib/mail.rb
CHANGED
@@ -41,7 +41,7 @@ module Mail # :doc:
|
|
41
41
|
require 'mail/multibyte'
|
42
42
|
end
|
43
43
|
|
44
|
-
require 'mail/
|
44
|
+
require 'mail/constants'
|
45
45
|
require 'mail/utilities'
|
46
46
|
require 'mail/configuration'
|
47
47
|
|
@@ -76,13 +76,14 @@ module Mail # :doc:
|
|
76
76
|
|
77
77
|
require 'mail/envelope'
|
78
78
|
|
79
|
-
|
79
|
+
register_autoload :Parsers, "mail/parsers"
|
80
80
|
|
81
81
|
# Autoload header field elements and transfer encodings.
|
82
82
|
require 'mail/elements'
|
83
83
|
require 'mail/encodings'
|
84
84
|
require 'mail/encodings/base64'
|
85
85
|
require 'mail/encodings/quoted_printable'
|
86
|
+
require 'mail/encodings/unix_to_unix'
|
86
87
|
|
87
88
|
require 'mail/matchers/has_sent_mail'
|
88
89
|
|
data/lib/mail/body.rb
CHANGED
@@ -254,18 +254,19 @@ module Mail
|
|
254
254
|
@parts = Mail::PartsList.new[val]
|
255
255
|
end
|
256
256
|
end
|
257
|
-
|
257
|
+
|
258
258
|
def split!(boundary)
|
259
259
|
self.boundary = boundary
|
260
|
-
parts =
|
260
|
+
parts = extract_parts
|
261
|
+
|
261
262
|
# Make the preamble equal to the preamble (if any)
|
262
263
|
self.preamble = parts[0].to_s.strip
|
263
264
|
# Make the epilogue equal to the epilogue (if any)
|
264
|
-
self.epilogue = parts[-1].to_s.
|
265
|
+
self.epilogue = parts[-1].to_s.strip
|
265
266
|
parts[1...-1].to_a.each { |part| @parts << Mail::Part.new(part) }
|
266
267
|
self
|
267
268
|
end
|
268
|
-
|
269
|
+
|
269
270
|
def only_us_ascii?
|
270
271
|
!(raw_source =~ /[^\x01-\x7f]/)
|
271
272
|
end
|
@@ -275,6 +276,29 @@ module Mail
|
|
275
276
|
end
|
276
277
|
|
277
278
|
private
|
279
|
+
|
280
|
+
# split parts by boundary, ignore first part if empty, append final part when closing boundary was missing
|
281
|
+
def extract_parts
|
282
|
+
parts_regex = /
|
283
|
+
(?: # non-capturing group
|
284
|
+
\A | # start of string OR
|
285
|
+
\r\n # line break
|
286
|
+
)
|
287
|
+
(
|
288
|
+
--#{Regexp.escape(boundary || "")} # boundary delimiter
|
289
|
+
(?:--)? # with non-capturing optional closing
|
290
|
+
)
|
291
|
+
(?=\s*$) # lookahead matching zero or more spaces followed by line-ending
|
292
|
+
/x
|
293
|
+
parts = raw_source.split(parts_regex).each_slice(2).to_a
|
294
|
+
parts.each_with_index { |(part, _), index| parts.delete_at(index) if index > 0 && part.blank? }
|
295
|
+
|
296
|
+
if parts.size > 1
|
297
|
+
final_separator = parts[-2][1]
|
298
|
+
parts << [""] if final_separator != "--#{boundary}--"
|
299
|
+
end
|
300
|
+
parts.map(&:first)
|
301
|
+
end
|
278
302
|
|
279
303
|
def crlf_boundary
|
280
304
|
"\r\n--#{boundary}\r\n"
|
@@ -1,20 +1,20 @@
|
|
1
1
|
# encoding: us-ascii
|
2
2
|
module Mail
|
3
|
-
module
|
3
|
+
module Constants
|
4
4
|
white_space = %Q|\x9\x20|
|
5
5
|
text = %Q|\x1-\x8\xB\xC\xE-\x7f|
|
6
6
|
field_name = %Q|\x21-\x39\x3b-\x7e|
|
7
7
|
qp_safe = %Q|\x20-\x3c\x3e-\x7e|
|
8
|
-
|
8
|
+
|
9
9
|
aspecial = %Q|()<>[]:;@\\,."| # RFC5322
|
10
10
|
tspecial = %Q|()<>@,;:\\"/[]?=| # RFC2045
|
11
11
|
sp = %Q| |
|
12
12
|
control = %Q|\x00-\x1f\x7f-\xff|
|
13
|
-
|
13
|
+
|
14
14
|
if control.respond_to?(:force_encoding)
|
15
15
|
control = control.force_encoding(Encoding::BINARY)
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
CRLF = /\r\n/
|
19
19
|
WSP = /[#{white_space}]/
|
20
20
|
FWS = /#{CRLF}#{WSP}*/
|
@@ -33,5 +33,23 @@ module Mail
|
|
33
33
|
ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{sp}]/n
|
34
34
|
PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
|
35
35
|
TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{sp}]/n
|
36
|
+
ENCODED_VALUE = /\=\?[^?]+\?([QB])\?[^?]*?\?\=/mi
|
37
|
+
|
38
|
+
EMPTY = ''
|
39
|
+
SPACE = ' '
|
40
|
+
UNDERSCORE = '_'
|
41
|
+
HYPHEN = '-'
|
42
|
+
COLON = ':'
|
43
|
+
ASTERISK = '*'
|
44
|
+
CR = "\r"
|
45
|
+
LF = "\n"
|
46
|
+
CR_ENCODED = "=0D"
|
47
|
+
LF_ENCODED = "=0A"
|
48
|
+
CAPITAL_M = 'M'
|
49
|
+
EQUAL_LF = "=\n"
|
50
|
+
NULL_SENDER = '<>'
|
51
|
+
|
52
|
+
Q_VALUES = ['Q','q']
|
53
|
+
B_VALUES = ['B','b']
|
36
54
|
end
|
37
55
|
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
class String #:nodoc:
|
3
3
|
|
4
|
+
CRLF = "\r\n"
|
5
|
+
LF = "\n"
|
6
|
+
|
4
7
|
if RUBY_VERSION >= '1.9'
|
5
8
|
# This 1.9 only regex can save a reasonable amount of time (~20%)
|
6
9
|
# by not matching "\r\n" so the string is returned unchanged in
|
@@ -11,11 +14,11 @@ class String #:nodoc:
|
|
11
14
|
end
|
12
15
|
|
13
16
|
def to_crlf
|
14
|
-
to_str.gsub(CRLF_REGEX,
|
17
|
+
to_str.gsub(CRLF_REGEX, CRLF)
|
15
18
|
end
|
16
19
|
|
17
20
|
def to_lf
|
18
|
-
to_str.gsub(/\r\n|\r/,
|
21
|
+
to_str.gsub(/\r\n|\r/, LF)
|
19
22
|
end
|
20
23
|
|
21
24
|
unless String.instance_methods(false).map {|m| m.to_sym}.include?(:blank?)
|
@@ -3,15 +3,15 @@ module Mail
|
|
3
3
|
class Address
|
4
4
|
|
5
5
|
include Mail::Utilities
|
6
|
-
|
6
|
+
|
7
7
|
# Mail::Address handles all email addresses in Mail. It takes an email address string
|
8
8
|
# and parses it, breaking it down into its component parts and allowing you to get the
|
9
9
|
# address, comments, display name, name, local part, domain part and fully formatted
|
10
10
|
# address.
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
|
13
13
|
# handles all obsolete versions including obsolete domain routing on the local part.
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
16
16
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
17
17
|
# a.address #=> 'mikel@test.lindsaar.net'
|
@@ -25,12 +25,11 @@ module Mail
|
|
25
25
|
if value.nil?
|
26
26
|
@parsed = false
|
27
27
|
@data = nil
|
28
|
-
return
|
29
28
|
else
|
30
29
|
parse(value)
|
31
30
|
end
|
32
31
|
end
|
33
|
-
|
32
|
+
|
34
33
|
# Returns the raw input of the passed in string, this is before it is passed
|
35
34
|
# by the parser.
|
36
35
|
def raw
|
@@ -47,37 +46,37 @@ module Mail
|
|
47
46
|
def format
|
48
47
|
parse unless @parsed
|
49
48
|
if @data.nil?
|
50
|
-
|
49
|
+
EMPTY
|
51
50
|
elsif display_name
|
52
|
-
[quote_phrase(display_name), "<#{address}>", format_comments].compact.join(
|
51
|
+
[quote_phrase(display_name), "<#{address}>", format_comments].compact.join(SPACE)
|
53
52
|
elsif address
|
54
|
-
[address, format_comments].compact.join(
|
53
|
+
[address, format_comments].compact.join(SPACE)
|
55
54
|
else
|
56
55
|
raw
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
60
|
-
# Returns the address that is in the address itself. That is, the
|
59
|
+
# Returns the address that is in the address itself. That is, the
|
61
60
|
# local@domain string, without any angle brackets or the like.
|
62
|
-
#
|
61
|
+
#
|
63
62
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
64
63
|
# a.address #=> 'mikel@test.lindsaar.net'
|
65
64
|
def address
|
66
65
|
parse unless @parsed
|
67
66
|
domain ? "#{local}@#{domain}" : local
|
68
67
|
end
|
69
|
-
|
68
|
+
|
70
69
|
# Provides a way to assign an address to an already made Mail::Address object.
|
71
|
-
#
|
70
|
+
#
|
72
71
|
# a = Address.new
|
73
72
|
# a.address = 'Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>'
|
74
73
|
# a.address #=> 'mikel@test.lindsaar.net'
|
75
74
|
def address=(value)
|
76
75
|
parse(value)
|
77
76
|
end
|
78
|
-
|
77
|
+
|
79
78
|
# Returns the display name of the email address passed in.
|
80
|
-
#
|
79
|
+
#
|
81
80
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
82
81
|
# a.display_name #=> 'Mikel Lindsaar'
|
83
82
|
def display_name
|
@@ -85,9 +84,9 @@ module Mail
|
|
85
84
|
@display_name ||= get_display_name
|
86
85
|
Encodings.decode_encode(@display_name.to_s, @output_type) if @display_name
|
87
86
|
end
|
88
|
-
|
87
|
+
|
89
88
|
# Provides a way to assign a display name to an already made Mail::Address object.
|
90
|
-
#
|
89
|
+
#
|
91
90
|
# a = Address.new
|
92
91
|
# a.address = 'mikel@test.lindsaar.net'
|
93
92
|
# a.display_name = 'Mikel Lindsaar'
|
@@ -98,7 +97,7 @@ module Mail
|
|
98
97
|
|
99
98
|
# Returns the local part (the left hand side of the @ sign in the email address) of
|
100
99
|
# the address
|
101
|
-
#
|
100
|
+
#
|
102
101
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
103
102
|
# a.local #=> 'mikel'
|
104
103
|
def local
|
@@ -108,47 +107,43 @@ module Mail
|
|
108
107
|
|
109
108
|
# Returns the domain part (the right hand side of the @ sign in the email address) of
|
110
109
|
# the address
|
111
|
-
#
|
110
|
+
#
|
112
111
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
113
112
|
# a.domain #=> 'test.lindsaar.net'
|
114
113
|
def domain
|
115
114
|
parse unless @parsed
|
116
115
|
strip_all_comments(get_domain) if get_domain
|
117
116
|
end
|
118
|
-
|
117
|
+
|
119
118
|
# Returns an array of comments that are in the email, or an empty array if there
|
120
119
|
# are no comments
|
121
|
-
#
|
120
|
+
#
|
122
121
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
123
122
|
# a.comments #=> ['My email address']
|
124
123
|
def comments
|
125
124
|
parse unless @parsed
|
126
|
-
|
127
|
-
nil
|
128
|
-
else
|
129
|
-
get_comments.map { |c| c.squeeze(" ") }
|
130
|
-
end
|
125
|
+
get_comments.map { |c| c.squeeze(SPACE) } unless get_comments.empty?
|
131
126
|
end
|
132
|
-
|
127
|
+
|
133
128
|
# Sometimes an address will not have a display name, but might have the name
|
134
129
|
# as a comment field after the address. This returns that name if it exists.
|
135
|
-
#
|
130
|
+
#
|
136
131
|
# a = Address.new('mikel@test.lindsaar.net (Mikel Lindsaar)')
|
137
132
|
# a.name #=> 'Mikel Lindsaar'
|
138
133
|
def name
|
139
134
|
parse unless @parsed
|
140
135
|
get_name
|
141
136
|
end
|
142
|
-
|
137
|
+
|
143
138
|
# Returns the format of the address, or returns nothing
|
144
|
-
#
|
139
|
+
#
|
145
140
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
146
141
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
147
142
|
def to_s
|
148
143
|
parse unless @parsed
|
149
144
|
format
|
150
145
|
end
|
151
|
-
|
146
|
+
|
152
147
|
# Shows the Address object basic details, including the Address
|
153
148
|
# a = Address.new('Mikel (My email) <mikel@test.lindsaar.net>')
|
154
149
|
# a.inspect #=> "#<Mail::Address:14184910 Address: |Mikel <mikel@test.lindsaar.net> (My email)| >"
|
@@ -156,43 +151,42 @@ module Mail
|
|
156
151
|
parse unless @parsed
|
157
152
|
"#<#{self.class}:#{self.object_id} Address: |#{to_s}| >"
|
158
153
|
end
|
159
|
-
|
154
|
+
|
160
155
|
def encoded
|
161
156
|
@output_type = :encode
|
162
157
|
format
|
163
158
|
end
|
164
|
-
|
159
|
+
|
165
160
|
def decoded
|
166
161
|
@output_type = :decode
|
167
162
|
format
|
168
163
|
end
|
169
164
|
|
165
|
+
def group
|
166
|
+
@data && @data.group
|
167
|
+
end
|
168
|
+
|
170
169
|
private
|
171
|
-
|
170
|
+
|
172
171
|
def parse(value = nil)
|
173
172
|
@parsed = true
|
173
|
+
@data = nil
|
174
174
|
|
175
175
|
case value
|
176
|
-
when NilClass
|
177
|
-
@data = nil
|
178
|
-
nil
|
179
176
|
when Mail::Parsers::AddressStruct
|
180
177
|
@data = value
|
181
178
|
when String
|
182
|
-
|
183
|
-
if value.blank?
|
184
|
-
@data = nil
|
185
|
-
else
|
179
|
+
unless value.blank?
|
186
180
|
address_list = Mail::Parsers::AddressListsParser.new.parse(value)
|
187
181
|
@data = address_list.addresses.first
|
188
182
|
end
|
189
183
|
end
|
190
184
|
end
|
191
|
-
|
185
|
+
|
192
186
|
def strip_all_comments(string)
|
193
187
|
unless comments.blank?
|
194
188
|
comments.each do |comment|
|
195
|
-
string = string.gsub("(#{comment})",
|
189
|
+
string = string.gsub("(#{comment})", EMPTY)
|
196
190
|
end
|
197
191
|
end
|
198
192
|
string.strip
|
@@ -202,53 +196,36 @@ module Mail
|
|
202
196
|
unless comments.blank?
|
203
197
|
comments.each do |comment|
|
204
198
|
if @data.domain && @data.domain.include?("(#{comment})")
|
205
|
-
value = value.gsub("(#{comment})",
|
199
|
+
value = value.gsub("(#{comment})", EMPTY)
|
206
200
|
end
|
207
201
|
end
|
208
202
|
end
|
209
203
|
value.to_s.strip
|
210
204
|
end
|
211
|
-
|
205
|
+
|
212
206
|
def get_display_name
|
213
207
|
if @data.display_name
|
214
208
|
str = strip_all_comments(@data.display_name.to_s)
|
215
|
-
elsif @data.comments
|
216
|
-
|
217
|
-
str = strip_domain_comments(format_comments)
|
218
|
-
else
|
219
|
-
str = nil
|
220
|
-
end
|
221
|
-
else
|
222
|
-
nil
|
223
|
-
end
|
224
|
-
|
225
|
-
if str.blank?
|
226
|
-
nil
|
227
|
-
else
|
228
|
-
str
|
209
|
+
elsif @data.comments && @data.domain
|
210
|
+
str = strip_domain_comments(format_comments)
|
229
211
|
end
|
212
|
+
|
213
|
+
str unless str.blank?
|
230
214
|
end
|
231
|
-
|
215
|
+
|
232
216
|
def get_name
|
233
217
|
if display_name
|
234
218
|
str = display_name
|
235
|
-
|
236
|
-
|
237
|
-
comment_text = comments.join(' ').squeeze(" ")
|
238
|
-
str = "(#{comment_text})"
|
239
|
-
end
|
219
|
+
elsif comments
|
220
|
+
str = "(#{comments.join(SPACE).squeeze(SPACE)})"
|
240
221
|
end
|
241
222
|
|
242
|
-
|
243
|
-
nil
|
244
|
-
else
|
245
|
-
unparen(str)
|
246
|
-
end
|
223
|
+
unparen(str) unless str.blank?
|
247
224
|
end
|
248
|
-
|
225
|
+
|
249
226
|
def format_comments
|
250
227
|
if comments
|
251
|
-
comment_text = comments.map {|c| escape_paren(c) }.join(
|
228
|
+
comment_text = comments.map {|c| escape_paren(c) }.join(SPACE).squeeze(SPACE)
|
252
229
|
@format_comments ||= "(#{comment_text})"
|
253
230
|
else
|
254
231
|
nil
|
@@ -262,7 +239,7 @@ module Mail
|
|
262
239
|
def get_domain
|
263
240
|
@data && @data.domain
|
264
241
|
end
|
265
|
-
|
242
|
+
|
266
243
|
def get_comments
|
267
244
|
@data && @data.comments
|
268
245
|
end
|