Class: Mail::Field

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/mail/field.rb

Overview

Provides a single class to call to create a new structured or unstructured field. Works out per RFC what field of field it is being given and returns the correct field of class back on new.

===Per RFC 2822

2.2. Header Fields

Header fields are lines composed of a field name, followed by a colon
(":"), followed by a field body, and terminated by CRLF.  A field
name MUST be composed of printable US-ASCII characters (i.e.,
characters that have values between 33 and 126, inclusive), except
colon.  A field body may be composed of any US-ASCII characters,
except for CR and LF.  However, a field body may contain CRLF when
used in header "folding" and  "unfolding" as described in section
2.2.3.  All field bodies MUST conform to the syntax described in
sections 3 and 4 of this standard.

Defined Under Namespace

Classes: FieldError, IncompleteParseError, NilParseError, ParseError, SyntaxError

Constant Summary collapse

STRUCTURED_FIELDS =
%w[ bcc cc content-description content-disposition
content-id content-location content-transfer-encoding
content-type date from in-reply-to keywords message-id
mime-version received references reply-to
resent-bcc resent-cc resent-date resent-from
resent-message-id resent-sender resent-to
return-path sender to ]
KNOWN_FIELDS =
STRUCTURED_FIELDS + ['comments', 'subject']
FIELDS_MAP =
{
  "to" => ToField,
  "cc" => CcField,
  "bcc" => BccField,
  "message-id" => MessageIdField,
  "in-reply-to" => InReplyToField,
  "references" => ReferencesField,
  "subject" => SubjectField,
  "comments" => CommentsField,
  "keywords" => KeywordsField,
  "date" => DateField,
  "from" => FromField,
  "sender" => SenderField,
  "reply-to" => ReplyToField,
  "resent-date" => ResentDateField,
  "resent-from" => ResentFromField,
  "resent-sender" =>  ResentSenderField,
  "resent-to" => ResentToField,
  "resent-cc" => ResentCcField,
  "resent-bcc" => ResentBccField,
  "resent-message-id" => ResentMessageIdField,
  "return-path" => ReturnPathField,
  "received" => ReceivedField,
  "mime-version" => MimeVersionField,
  "content-transfer-encoding" => ContentTransferEncodingField,
  "content-description" => ContentDescriptionField,
  "content-disposition" => ContentDispositionField,
  "content-type" => ContentTypeField,
  "content-id" => ContentIdField,
  "content-location" => ContentLocationField,
}
FIELD_NAME_MAP =
FIELDS_MAP.inject({}) do |map, (field, field_klass)|
  map.update(field => field_klass::NAME)
end
FIELD_ORDER_LOOKUP =

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, value = nil, charset = 'utf-8') ⇒ Field

Create a field by name and optional value:

Mail::Field.new("field-name", "value")

=> #<Mail::Field …>

Values that aren't strings or arrays are coerced to Strings with #to_s.

Mail::Field.new("field-name", 1234)

=> #<Mail::Field …>

Mail::Field.new('content-type', ['text', 'plain', => 'UTF-8'])

=> #<Mail::Field …>



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/mail/field.rb', line 166

def initialize(name, value = nil, charset = 'utf-8')
  case
  when name.index(Constants::COLON)
    raise ArgumentError, 'Passing an unparsed header field to Mail::Field.new is not supported in Mail 2.8.0+. Use Mail::Field.parse instead.'
  when Utilities.blank?(value)
    @name = name
    @unparsed_value = nil
    @charset = charset
  else
    @name = name
    @unparsed_value = value
    @charset = charset
  end
  @name = FIELD_NAME_MAP[@name.to_s.downcase] || @name
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object



232
233
234
# File 'lib/mail/field.rb', line 232

def method_missing(name, *args, &block)
  field.send(name, *args, &block)
end

Instance Attribute Details

#unparsed_valueObject (readonly)

Returns the value of attribute unparsed_value.



152
153
154
# File 'lib/mail/field.rb', line 152

def unparsed_value
  @unparsed_value
end

Class Method Details

.field_class_for(name) ⇒ Object

:nodoc:



147
148
149
# File 'lib/mail/field.rb', line 147

def field_class_for(name) #:nodoc:
  FIELDS_MAP[name.to_s.downcase]
end

.parse(field, charset = 'utf-8') ⇒ Object

Parse a field from a raw header line:

Mail::Field.parse("field-name: field data")

=> #<Mail::Field …>



122
123
124
125
126
127
# File 'lib/mail/field.rb', line 122

def parse(field, charset = 'utf-8')
  name, value = split(field)
  if name && value
    new name, value, charset
  end
end

.split(raw_field) ⇒ Object

:nodoc:



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/mail/field.rb', line 129

def split(raw_field) #:nodoc:
  if raw_field.index(Constants::COLON)
    name, value = raw_field.split(Constants::COLON, 2)
    name.rstrip!
    if name =~ /\A#{Constants::FIELD_NAME}\z/
      [ name.rstrip, value.strip ]
    else
      Kernel.warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: invalid header name syntax: #{name.inspect}"
      nil
    end
  else
    raw_field.strip
  end
rescue => error
  warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: #{error.class}: #{error.message}"
  nil
end

Instance Method Details

#<=>(other) ⇒ Object



224
225
226
# File 'lib/mail/field.rb', line 224

def <=>(other)
  field_order_id <=> other.field_order_id
end

#==(other) ⇒ Object



216
217
218
# File 'lib/mail/field.rb', line 216

def ==(other)
  same(other) && Utilities.match_to_s(other.value, value)
end

#fieldObject



186
187
188
# File 'lib/mail/field.rb', line 186

def field
  @field ||= create_field(@name, @unparsed_value, @charset)
end

#field=(field) ⇒ Object



182
183
184
# File 'lib/mail/field.rb', line 182

def field=(field)
  @field = field
end

#field_order_idObject



228
229
230
# File 'lib/mail/field.rb', line 228

def field_order_id
  @field_order_id ||= FIELD_ORDER_LOOKUP.fetch(self.name.to_s.downcase, 100)
end

#inspectObject



206
207
208
209
210
# File 'lib/mail/field.rb', line 206

def inspect
  "#<#{self.class.name} 0x#{(object_id * 2).to_s(16)} #{instance_variables.map do |ivar|
    "#{ivar}=#{instance_variable_get(ivar).inspect}"
  end.join(" ")}>"
end

#nameObject



190
191
192
# File 'lib/mail/field.rb', line 190

def name
  @name
end

#respond_to_missing?(method_name, include_private) ⇒ Boolean

Returns:

  • (Boolean)


236
237
238
# File 'lib/mail/field.rb', line 236

def respond_to_missing?(method_name, include_private)
  field.respond_to?(method_name, include_private) || super
end

#responsible_for?(field_name) ⇒ Boolean

Returns:

  • (Boolean)


220
221
222
# File 'lib/mail/field.rb', line 220

def responsible_for?(field_name)
  name.to_s.casecmp(field_name.to_s) == 0
end

#same(other) ⇒ Object



212
213
214
# File 'lib/mail/field.rb', line 212

def same(other)
  other.kind_of?(self.class) && Utilities.match_to_s(other.name, name)
end

#to_sObject



202
203
204
# File 'lib/mail/field.rb', line 202

def to_s
  field.to_s
end

#valueObject



194
195
196
# File 'lib/mail/field.rb', line 194

def value
  field.value
end

#value=(val) ⇒ Object



198
199
200
# File 'lib/mail/field.rb', line 198

def value=(val)
  @field = create_field(name, val, @charset)
end