multipart_body 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ require 'multipart_body/multipart_body'
2
+ require 'multipart_body/part'
@@ -0,0 +1,26 @@
1
+ class MultipartBody
2
+ attr_accessor :parts, :boundary
3
+
4
+ def initialize(parts = nil, boundary = nil)
5
+ @parts = []
6
+ @boundary = boundary || "----multipart-boundary-#{rand(1000000)}"
7
+
8
+ if parts.is_a? Hash
9
+ @parts = parts.map {|name, body| Part.new(:name => name, :body => body) }
10
+ elsif parts.is_a?(Array) && parts.first.is_a?(Part)
11
+ @parts = parts
12
+ end
13
+
14
+ self
15
+ end
16
+
17
+ def self.from_hash(parts_hash)
18
+ multipart = self.new(parts_hash)
19
+ end
20
+
21
+ def to_s
22
+ output = "--#{@boundary}\r\n"
23
+ output << @parts.join("\r\n--#{@boundary}\r\n")
24
+ output << "\r\n--#{@boundary}--"
25
+ end
26
+ end
@@ -0,0 +1,43 @@
1
+ class Part < Struct.new(:name, :body, :filename, :content_type, :encoding)
2
+ def initialize(*args)
3
+ if args.flatten.first.is_a? Hash
4
+ from_hash(args.flatten.first)
5
+ elsif args.length > 0
6
+ from_args(*args)
7
+ end
8
+ end
9
+
10
+ def from_hash(hash)
11
+ hash.each_pair do |k, v|
12
+ self[k] = v
13
+ end
14
+ end
15
+
16
+ def from_args(name, body, filename=nil)
17
+ self[:name] = name
18
+ self[:body] = body
19
+ self[:filename] = filename
20
+ end
21
+
22
+ def header
23
+ header = "Content-Disposition: form-data; name=\"#{name}\""
24
+ header << "; filename=\"#{filename}\"" if filename
25
+ header << "\r\nContent-Type: #{content_type}" if content_type
26
+ header << "\r\nContent-Transfer-Encoding: #{encoding}" if encoding
27
+ header
28
+ end
29
+
30
+ # TODO: Implement encodings
31
+ def encoded_body
32
+ case encoding
33
+ when nil
34
+ body
35
+ else
36
+ raise "Encodings have not been implemented"
37
+ end
38
+ end
39
+
40
+ def to_s
41
+ "#{header}\r\n\r\n#{encoded_body}"
42
+ end
43
+ end
@@ -0,0 +1,30 @@
1
+ # MultipartBody
2
+ The multipart body is an attempt to bring consistency to multipart content in Ruby. When developing CloudMailin we struggled to find a gem to help us create multipart bodies. Many different libraries had implemented multipart bodies through their own implementation but non could be used independently.
3
+
4
+ The aim of MultipartBody is to ensure consistency when creating (and parsing in future) multipart content
5
+
6
+ ## Usage
7
+
8
+ require 'multipart_body'
9
+
10
+ # From a hash
11
+ multipart = Multipart.new(:field1 => 'content', :field2 => 'something else')
12
+
13
+ # With parts
14
+ part = Part.new(:name => 'name', :body => 'body', :filename => 'f.txt', :content_type => 'text/plain', :encoding => :base64)
15
+
16
+ # or to specify just the name, body and optional filename
17
+ part = Part.new('name', 'content', 'file.txt')
18
+ multipart = Multipart.new([part])
19
+
20
+ # Output
21
+ part.to_s #=> The part with headers and content
22
+ multipart.to_s #=> The full list of parts joined by boundaries
23
+
24
+ ## TODO
25
+ * Implement Parsing
26
+ * Add different encodings
27
+ * Add the ability to automatically add files and have the filename set
28
+
29
+ ## License
30
+ Copyright 2010 by Steve Smith ([CloudMailin](http://cloudmailin.com)) and is released under the MIT license.
@@ -0,0 +1,122 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class MultipartBodyTest < Test::Unit::TestCase
4
+ context "MultipartBodyBody" do
5
+ setup do
6
+ @hash = {:test => 'test', :two => 'two'}
7
+ @parts = [Part.new('name', 'value'), Part.new('name2', 'value2')]
8
+ end
9
+
10
+ should "return a new multipart when sent #from_hash" do
11
+ multipart = MultipartBody.from_hash(@hash)
12
+ assert_equal MultipartBody, multipart.class
13
+ end
14
+
15
+ should "create a list of parts from the hash when sent #from_hash" do
16
+ multipart = MultipartBody.from_hash(@hash)
17
+ assert_equal @hash, Hash[multipart.parts.map{|part| [part.name, part.body] }]
18
+ end
19
+
20
+ should "add to the list of parts when sent #new with a hash" do
21
+ multipart = MultipartBody.new(@hash)
22
+ assert_equal @hash, Hash[multipart.parts.map{|part| [part.name, part.body] }]
23
+ end
24
+
25
+ should "correctly add parts sent #new with parts" do
26
+ multipart = MultipartBody.new(@parts)
27
+ assert_same_elements @parts, multipart.parts
28
+ end
29
+
30
+ should "assign a boundary if it is not given" do
31
+ multpart = MultipartBody.new()
32
+ assert_match /[\w\d-]{10,}/, multpart.boundary
33
+ end
34
+
35
+ should "use the boundary provided if given" do
36
+ multipart = MultipartBody.new(nil, "my-boundary")
37
+ assert_equal "my-boundary", multipart.boundary
38
+ end
39
+
40
+ should "starts with a boundary when sent #to_s" do
41
+ multipart = MultipartBody.new(@parts)
42
+ assert_match /^--#{multipart.boundary}/i, multipart.to_s
43
+ end
44
+
45
+ should "end with a boundary when sent #to_s" do
46
+ multipart = MultipartBody.new(@parts)
47
+ assert_match /--#{multipart.boundary}--\z/i, multipart.to_s
48
+ end
49
+
50
+ should "contain the parts joined by a boundary when sent #to_s" do
51
+ multipart = MultipartBody.new(@parts)
52
+ assert_match multipart.parts.join("\r\n--#{multipart.boundary}\r\n"), multipart.to_s
53
+ end
54
+ end
55
+
56
+ context "a Part" do
57
+ setup do
58
+ @part = Part
59
+ end
60
+
61
+ should "assign values when sent #new with a hash" do
62
+ part = Part.new(:name => 'test', :body => 'content', :filename => 'name')
63
+ assert_equal 'test', part.name
64
+ assert_equal 'content', part.body
65
+ assert_equal 'name', part.filename
66
+ end
67
+
68
+ should "assign values when sent #new with values" do
69
+ part = Part.new('test', 'content', 'name')
70
+ assert_equal 'test', part.name
71
+ assert_equal 'content', part.body
72
+ assert_equal 'name', part.filename
73
+ end
74
+
75
+ should "be happy when sent #new with args without a filename" do
76
+ part = Part.new('test', 'content')
77
+ assert_equal 'test', part.name
78
+ assert_equal 'content', part.body
79
+ assert_equal nil, part.filename
80
+ end
81
+
82
+ should "create an empty part when sent #new with nothing" do
83
+ part = Part.new()
84
+ assert_equal nil, part.name
85
+ assert_equal nil, part.body
86
+ assert_equal nil, part.filename
87
+ end
88
+
89
+ should "include a content disposition when sent #header name" do
90
+ part = Part.new(:name => 'key', :body => 'content')
91
+ assert_match /content-disposition: form-data; name="key"/i, part.header
92
+ end
93
+
94
+ should "include no filename when sent #header and a filename is not set" do
95
+ part = Part.new(:name => 'key', :body => 'content')
96
+ assert_no_match /content-disposition: .+; name=".+"; filename="?.*"?/i, part.header
97
+ end
98
+
99
+ should "include a filename when sent #header and a filename is set" do
100
+ part = Part.new(:name => 'key', :body => 'content', :filename => 'file.jpg')
101
+ assert_match /content-disposition: .+; name=".+"; filename="file.jpg"/i, part.header
102
+ end
103
+
104
+ should "return the original body if encoding is not set" do
105
+ part = Part.new(:name => 'key', :body => 'content')
106
+ assert_equal 'content', part.encoded_body
107
+ end
108
+
109
+ # TODO: Implement encoding tests
110
+ should "raise an exception when an encoding is passed" do
111
+ part = Part.new(:name => 'key', :body => 'content', :encoding => :base64)
112
+ assert_raises RuntimeError do
113
+ part.encoded_body
114
+ end
115
+ end
116
+
117
+ should "output the header and body when sent #to_s" do
118
+ part = Part.new(:name => 'key', :body => 'content')
119
+ assert_equal "#{part.header}\r\n\r\n#{part.body}", part.to_s
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'multipart_body'
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: multipart_body
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Steve Smith
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-17 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: A ruby library to create multipart bodies.
23
+ email: gems@scsworld.co.uk
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - readme.md
32
+ - lib/multipart_body/multipart_body.rb
33
+ - lib/multipart_body/part.rb
34
+ - lib/multipart_body.rb
35
+ - test/test.rb
36
+ - test/test_helper.rb
37
+ has_rdoc: true
38
+ homepage: http://github.com/cloudmailin/multipart_body
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ hash: 3
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.3.7
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: MultipartBody allows you to create consistant multipart bodies
71
+ test_files:
72
+ - test/test.rb
73
+ - test/test_helper.rb