mime 0.3.0 → 0.4.0

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 (35) hide show
  1. data/README.rdoc +192 -140
  2. data/lib/mime/composite_media.rb +230 -0
  3. data/lib/mime/content_formats/text_flowed.rb +6 -6
  4. data/lib/mime/discrete_media.rb +73 -0
  5. data/lib/mime/discrete_media_factory.rb +19 -13
  6. data/lib/mime/header.rb +48 -0
  7. data/lib/mime/headers/internet.rb +124 -27
  8. data/lib/mime/headers/mime.rb +38 -27
  9. data/lib/mime/mail.rb +51 -0
  10. data/lib/mime/media.rb +30 -0
  11. data/lib/mime/parser.rb +1 -1
  12. data/lib/mime.rb +27 -9
  13. data/test/scaffold/application.msg +2 -5
  14. data/test/scaffold/audio.msg +2 -5
  15. data/test/scaffold/image.msg +0 -0
  16. data/test/scaffold/multipart_alternative.msg +7 -7
  17. data/test/scaffold/multipart_alternative_related.msg +0 -0
  18. data/test/scaffold/multipart_form_data_file_and_text.msg +0 -0
  19. data/test/scaffold/multipart_form_data_mixed.msg +0 -0
  20. data/test/scaffold/multipart_form_data_text.msg +12 -12
  21. data/test/scaffold/multipart_mixed_inline_and_attachment.msg +0 -0
  22. data/test/scaffold/multipart_mixed_inline_and_attachment2.msg +0 -0
  23. data/test/scaffold/multipart_related.msg +0 -0
  24. data/test/scaffold/rfc822_composite.msg +0 -0
  25. data/test/scaffold/{plain_text_email.msg → rfc822_discrete.msg} +5 -5
  26. data/test/scaffold/text.msg +2 -5
  27. data/test/scaffold/video.msg +2 -5
  28. data/test/test_mime.rb +323 -150
  29. data/test/test_text_flowed.rb +1 -1
  30. metadata +13 -12
  31. data/lib/mime/composite_media_type.rb +0 -169
  32. data/lib/mime/discrete_media_type.rb +0 -78
  33. data/lib/mime/header_container.rb +0 -32
  34. data/lib/mime/media_type.rb +0 -51
  35. data/lib/mime/message.rb +0 -61
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-28 00:00:00.000000000 Z
12
+ date: 2014-04-18 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'A library for building RFC compliant Multipurpose Internet Mail Extensions
15
15
 
@@ -32,14 +32,14 @@ files:
32
32
  - lib/mime/headers/internet.rb
33
33
  - lib/mime/discrete_media_factory.rb
34
34
  - lib/mime/error.rb
35
- - lib/mime/header_container.rb
36
35
  - lib/mime/parser.rb
37
36
  - lib/mime/content_types.rb
38
- - lib/mime/media_type.rb
39
- - lib/mime/composite_media_type.rb
40
- - lib/mime/discrete_media_type.rb
41
- - lib/mime/message.rb
37
+ - lib/mime/media.rb
38
+ - lib/mime/composite_media.rb
42
39
  - lib/mime/content_formats/text_flowed.rb
40
+ - lib/mime/header.rb
41
+ - lib/mime/mail.rb
42
+ - lib/mime/discrete_media.rb
43
43
  - lib/mime.rb
44
44
  - test/scaffold/application.msg
45
45
  - test/scaffold/unknown.yyy
@@ -47,23 +47,24 @@ files:
47
47
  - test/scaffold/mini.mov
48
48
  - test/scaffold/image.jpg
49
49
  - test/scaffold/book.pdf
50
- - test/scaffold/plain_text_email.msg
51
50
  - test/scaffold/song.mp3
52
51
  - test/scaffold/ruby.png
53
52
  - test/scaffold/multipart_alternative.msg
54
- - test/scaffold/multipart_alternative_related.msg
55
- - test/scaffold/multipart_related.msg
56
53
  - test/scaffold/multipart_mixed_inline_and_attachment2.msg
57
54
  - test/scaffold/image.msg
58
55
  - test/scaffold/multipart_form_data_file_and_text.msg
59
56
  - test/scaffold/data.xml
60
- - test/scaffold/multipart_form_data_mixed.msg
57
+ - test/scaffold/rfc822_composite.msg
61
58
  - test/scaffold/text.msg
62
59
  - test/scaffold/main.css
63
- - test/scaffold/multipart_mixed_inline_and_attachment.msg
60
+ - test/scaffold/multipart_alternative_related.msg
64
61
  - test/scaffold/multipart_form_data_text.msg
65
62
  - test/scaffold/audio.msg
63
+ - test/scaffold/multipart_related.msg
64
+ - test/scaffold/rfc822_discrete.msg
66
65
  - test/scaffold/data.htm
66
+ - test/scaffold/multipart_form_data_mixed.msg
67
+ - test/scaffold/multipart_mixed_inline_and_attachment.msg
67
68
  - test/test_mime.rb-try
68
69
  - test/test_mime.rb
69
70
  - test/test_text_flowed.rb
@@ -1,169 +0,0 @@
1
- module MIME
2
-
3
- #
4
- # Composite entities are handled using MIME mechanisms. A MIME processor must
5
- # handle the body directly. A CompositeMediaType object is composed of one or
6
- # more CompositeMediaType and/or DiscreteMediaType objects.
7
- #
8
- # This class is abstract.
9
- #
10
- class CompositeMediaType < MediaType
11
-
12
- def initialize content_type
13
- AbstractClassError.no_instantiation(self, CompositeMediaType)
14
-
15
- super(nil, content_type)
16
- @entities = Array.new
17
- end
18
-
19
- #
20
- # Add a MediaType object to the message.
21
- #
22
- def add_entity entity
23
- raise Error.new('can only add MediaType objects') unless entity.is_a? MediaType
24
- @entities.unshift(entity)
25
- end
26
-
27
- #
28
- # Attach a MediaType object to the message.
29
- #
30
- def attach_entity entity, params = {}
31
- entity.set_content_disposition('attachment', params)
32
- add_entity(entity)
33
- end
34
-
35
- #
36
- # Inline a MediaType object in the message.
37
- #
38
- def inline_entity entity, params = {}
39
- entity.set_content_disposition('inline', params)
40
- add_entity(entity)
41
- end
42
-
43
- end
44
-
45
- #
46
- # MessageMedia is intended to encapsulate another message. In particular,
47
- # the <em>message/rfc822</em> content type is used to encapsulate RFC 822
48
- # messages.
49
- #
50
- # TODO Implement
51
- #
52
- class MessageMedia < CompositeMediaType
53
- end
54
-
55
- #
56
- # The abstract base class for all multipart message subtypes. The entities of
57
- # a multipart message are delimited by a unique boundary.
58
- #
59
- class MultipartMedia < CompositeMediaType
60
-
61
- def initialize content_type
62
- AbstractClassError.no_instantiation(self, MultipartMedia)
63
- super
64
- end
65
-
66
- #
67
- # The boundary used to separate the message entities.
68
- #
69
- def boundary
70
- @boundary ||= "Boundary_#{unique_id}"
71
- end
72
-
73
- #
74
- # Return the multipart representation of the body.
75
- #
76
- def body
77
- all_entities = @entities.join("\r\n--#{boundary}\r\n")
78
- "--#{boundary}\r\n#{all_entities}\r\n--#{boundary}--\r\n"
79
- end
80
-
81
- end
82
-
83
- #
84
- # The Alternative subtype indicates that each contained entity is an
85
- # alternatively formatted version of the same content. The most complex
86
- # version should be added to the message first, i.e. it will be sequentially
87
- # last in the message.
88
- #
89
- class MultipartMedia::Alternative < MultipartMedia
90
-
91
- #
92
- # Returns a MultipartMedia::Alternative object with a content type of
93
- # multipart/alternative.
94
- #
95
- def initialize
96
- super("multipart/alternative; boundary=#{boundary}")
97
- end
98
-
99
- end
100
-
101
- #
102
- # The FormData subtype expresses values for HTML form data submissions.
103
- # ---
104
- # RFCs consulted during implementation:
105
- #
106
- # * RFC-1867 Form-based File Upload in HTML
107
- # * RFC-2388 Returning Values from Forms: multipart/form-data
108
- #
109
- class MultipartMedia::FormData < MultipartMedia
110
-
111
- #
112
- # Returns a MultipartMedia::FormData object with a content type of
113
- # multipart/form-data.
114
- #
115
- def initialize
116
- super("multipart/form-data; boundary=#{boundary}")
117
- end
118
-
119
- #
120
- # Add the MediaType object, +entity+, to the FormData object. +name+ is
121
- # typically an HTML input tag variable name. If the input tag is of type
122
- # _file_, then +filename+ must be specified to indicate a file upload.
123
- #
124
- def add_entity entity, name, filename = nil
125
- entity.set_content_disposition('form-data', 'name' => name, 'filename' => filename)
126
- super(entity)
127
- end
128
-
129
- end
130
-
131
- #
132
- # The Mixed subtype aggregates contextually independent entities.
133
- #
134
- class MultipartMedia::Mixed < MultipartMedia
135
-
136
- #
137
- # Returns a MultipartMedia::Mixed object with a content type of
138
- # multipart/mixed.
139
- #
140
- def initialize
141
- super("multipart/mixed; boundary=#{boundary}")
142
- end
143
-
144
- end
145
-
146
- #
147
- # The Related subtype aggregates multiple related entities. The message
148
- # consists of a root (the first entity) which references subsequent inline
149
- # entities. Message entities should be referenced by their Content-ID header.
150
- # The syntax of a reference is unspecified and is instead dictated by the
151
- # encoding or protocol used in the entity.
152
- # ---
153
- # RFC consulted during implementation:
154
- #
155
- # * RFC-2387 The MIME Multipart/Related Content-type
156
- #
157
- class MultipartMedia::Related < MultipartMedia
158
-
159
- #
160
- # Returns a MultipartMedia::Related object with a content type of
161
- # multipart/related.
162
- #
163
- def initialize
164
- super("multipart/related; boundary=#{boundary}")
165
- end
166
-
167
- end
168
-
169
- end
@@ -1,78 +0,0 @@
1
- module MIME
2
-
3
- #
4
- # Discrete media types must be handled by non-MIME mechanisms; they are
5
- # opaque to MIME processors. Therefore, the body of a DiscreteMediaType
6
- # object does not need further MIME processing.
7
- #
8
- # This class is abstract.
9
- #
10
- class DiscreteMediaType < MediaType
11
- def initialize(body, media_subtype, content_params)
12
- AbstractClassError.no_instantiation(self, DiscreteMediaType)
13
- super(body, "#{@media_type}/#{media_subtype}", content_params)
14
- end
15
- end
16
-
17
- #
18
- # ApplicationMedia is intended for discrete data that is to be processed by
19
- # some type of application program. The body contains information which must
20
- # be processed by an application before it is viewable or usable by a user.
21
- #
22
- # ApplicationMedia is the catch all class. If your content cannot be
23
- # identified as another DiscreteMediaType, then it is application media.
24
- #
25
- class ApplicationMedia < DiscreteMediaType
26
- def initialize(body, subtype = 'octet-stream', params = {})
27
- @media_type = 'application'
28
- super
29
- end
30
- end
31
-
32
- #
33
- # AudioMedia is intended for discrete audio content. The +subtype+ indicates
34
- # the specific audio format, such as *mpeg* or *midi*.
35
- #
36
- class AudioMedia < DiscreteMediaType
37
- def initialize(body, subtype = 'basic', params = {})
38
- @media_type = 'audio'
39
- super
40
- end
41
- end
42
-
43
- #
44
- # ImageMedia is intented for discrete image content. The +subtype+ indicates
45
- # the specific image format, such as *jpeg* or *gif*.
46
- #
47
- class ImageMedia < DiscreteMediaType
48
- def initialize(body, subtype = 'jpeg', params = {})
49
- @media_type = 'image'
50
- super
51
- end
52
- end
53
-
54
- #
55
- # TextMedia is intended for content which is principally textual in form. The
56
- # +subtype+ indicates the specific text type, such as *plain* or *html*.
57
- #
58
- class TextMedia < DiscreteMediaType
59
- def initialize(body, subtype = 'plain', params = {})
60
- @media_type = 'text'
61
- super
62
- end
63
- end
64
-
65
- #
66
- # VideoMedia is intended for discrete video content. The content +subtype+
67
- # indicates the specific video format. The RFC describes video media as
68
- # content that contains a time-varying-picture image, possibly with color and
69
- # coordinated sound.
70
- #
71
- class VideoMedia < DiscreteMediaType
72
- def initialize(body, subtype = 'mpeg', params = {})
73
- @media_type = 'video'
74
- super
75
- end
76
- end
77
-
78
- end
@@ -1,32 +0,0 @@
1
- module MIME
2
-
3
- #
4
- # Storage for RFC 2822 headers.
5
- #
6
- class HeaderContainer
7
-
8
- #
9
- # Return a new header container object.
10
- #
11
- def initialize
12
- @headers = Hash.new
13
- end
14
-
15
- #
16
- # Convert all headers to their string equivalents and join them using the
17
- # RFC 2822 CRLF line separator.
18
- #
19
- def to_s
20
- @headers.to_a.map {|kv| kv.join(": ")}.join("\r\n")
21
- end
22
-
23
- #
24
- # Add the +name+/+value+ pair to the header container.
25
- #
26
- def add name, value
27
- @headers.store(name, value)
28
- end
29
-
30
- end
31
-
32
- end
@@ -1,51 +0,0 @@
1
- require 'mime/error'
2
- require 'mime/header_container'
3
- require 'mime/headers/mime'
4
-
5
- module MIME
6
-
7
- #
8
- # Abstract top-level media type class.
9
- #
10
- class MediaType
11
-
12
- include Headers::MIME
13
-
14
- attr_reader :headers
15
- attr_accessor :body
16
- protected :body, :body=
17
-
18
- def initialize body, content_type, content_params = {}
19
- AbstractClassError.no_instantiation(self, MediaType)
20
-
21
- @headers = HeaderContainer.new
22
- @body = body
23
- self.content_id = unique_id
24
- self.content_type =
25
- if content_params.empty?
26
- content_type
27
- else
28
- params = content_params.to_a.map {|kv| kv.join('=')}.join('; ')
29
- "#{content_type}; #{params}"
30
- end
31
- end
32
-
33
- #
34
- # Transform the the MediaType object into a MIME message.
35
- #
36
- def to_s
37
- "#{headers}\r\n\r\n#{body}"
38
- end
39
-
40
- private
41
-
42
- #
43
- # Generate a globally unique identifier for use in boundaries and IDs.
44
- #
45
- def unique_id
46
- "#{object_id.abs}#{rand}"
47
- end
48
-
49
- end
50
-
51
- end
data/lib/mime/message.rb DELETED
@@ -1,61 +0,0 @@
1
- require 'time'
2
- require 'mime/headers/internet'
3
- require 'mime/headers/mime'
4
-
5
-
6
- module MIME
7
-
8
- #
9
- # Construct textual messages using the RFC 2822 Internet message format.
10
- #
11
- class Message
12
-
13
- include Headers::Internet
14
- include Headers::MIME
15
-
16
- # HeaderContainer access
17
- attr_reader :headers
18
-
19
- attr_accessor :body
20
-
21
- #
22
- # Return a Message object with body optionally set to +body+.
23
- #
24
- def initialize body = nil
25
- @body = body
26
- @headers = HeaderContainer.new
27
- self.date = Time.now.rfc2822
28
- self.message_id = "#{rand(1E9)}@#{__id__.abs}"
29
- self.mime_version = "1.0 (Ruby MIME v#{VERSION})"
30
- end
31
-
32
- #
33
- # Return the Internet message formatted representation of the instance.
34
- #
35
- def to_s
36
- #--
37
- # In an RFC 2822 message, the header and body sections must be separated
38
- # by two line breaks (CRLF). One line break is deliberately missing,
39
- # allowing a body supplier to append headers to the top-level message
40
- # header section. Consequently, the body supplier is responsible for
41
- # handling the body-header separation. Furthermore, if the +body+ is
42
- # empty, the header section will be properly terminated, creating a
43
- # standards compliant message.
44
- #++
45
-
46
- # FIXME writing directly to body VS setting body with a MediaType gives an
47
- # imbalance of "\r\n". Setting body directly with string requires a CRLF
48
- # prepended, but not the case for TextMedia for instance. So where do we
49
- # handle this? Perhaps HeaderContainer#to_s should append a CRLF, or
50
- # self#body should detect String and automatically prepend CRLF??? Then we
51
- # remove the CRLF here between the headers and body.
52
- #
53
- # Also, TextMedia adds the Content-ID and Content-Type headers, which we
54
- # don't get if body is set directly with String. Does this matter?
55
-
56
- "#{headers}\r\n#{body}\r\n"
57
- end
58
-
59
- end
60
-
61
- end