multiparty 0.1.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.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2011 by David Verhasselt (david@crowdway.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ multiparty
2
+ ==========
3
+
4
+ Easily generate a multipart/form-data header and body.
5
+
6
+ Usage
7
+ -----
8
+
9
+ You can add multiple values, corresponding to multiple <input> statements:
10
+
11
+ ```ruby
12
+ @multiparty = Multiparty.new
13
+ @multiparty[:name] = "David Verhasselt"
14
+ @multiparty[:state] = "awesome"
15
+ @multiparty[:avatar] = {:filename => "avatar.jpg", :content => "...jpegdata..."}
16
+
17
+ # Retrieve the header and body like this:
18
+ @multiparty.header
19
+ # Content-Type: multipart/form-data; boundary=multiparty-boundary-1342
20
+ @multiparty.body
21
+ # --multiparty-boundary-1342
22
+ # Content-Disposition: form-data; name="name"
23
+ #
24
+ # David Verhasselt
25
+ # --multiparty-boundary-1342
26
+ # Content-Disposition: form-data; name="state"
27
+ #
28
+ # awesome
29
+ # --multiparty-boundary-1342
30
+ # Content-Disposition: form-data; name="avatar"; filename="avatar.jpg"
31
+ # Content-Type: application/octet-stream
32
+ # Content-Transfer-Encoding: binary
33
+ #
34
+ # ...jpegdata...
35
+ # --multiparty-boundary-1342--
36
+ ```
37
+
38
+ You can also add files:
39
+
40
+ ```ruby
41
+ @multiparty[:your_avatar] => File.open("foo.txt")
42
+ ```
43
+
44
+ You can specify an optional content-type. If you don't, Multiparty will try and detect the correct MIME-type based on the filename.
45
+
46
+ ```ruby
47
+ @multiparty[:your_avatar] => {:filename => "foo.jpg", :content_type => "text/plain", :content => File.read("foo.txt")}
48
+ # -> Content-Type: text/plain
49
+ @multiparty[:your_avatar] => {:filename => "foo.jpg", content => "not really jpeg")}
50
+ # -> Content-Type: image/jpeg
51
+ @multiparty[:your_avatar] => File.open("foo.jpg")
52
+ # -> Content-Type: image/jpeg
53
+ ```
54
+
55
+ Files and Tempfiles are interchangable in Multiparty:
56
+
57
+ ```ruby
58
+ tempfile = Tempfile.new("foo")
59
+ tempfile.write("Hello World!")
60
+ tempfile.rewind
61
+
62
+ @multiparty[:message] => tempfile
63
+ # is the same as
64
+ @multiparty[:message] => File.open(tempfile.path)
65
+ ```
66
+
67
+ Installation
68
+ ------------
69
+
70
+ $ gem install multiparty
71
+
72
+ Testing
73
+ -------
74
+
75
+ $ bundle install
76
+ $ rake spec
77
+
78
+ Todo
79
+ ----
80
+
81
+ * Nested multiparts ("multipart/mixed") not yet supported
82
+
83
+ Author
84
+ ------
85
+
86
+ [David Verhasselt](http://davidverhasselt.com) - david@crowdway.com
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ task :default => :spec
2
+ task :test => :spec
3
+
4
+ desc "Run specs"
5
+ task :spec do
6
+ exec "rspec spec/multiparty_spec.rb"
7
+ end
data/lib/multiparty.rb ADDED
@@ -0,0 +1,74 @@
1
+ require "mime/types"
2
+
3
+ class Multiparty
4
+ attr_accessor :boundary
5
+ attr_accessor :parts
6
+
7
+ # Multiparty.new("my-boundary")
8
+ # Multiparty.new(:boundary => "my-boundary")
9
+ def initialize(options = {})
10
+ case options
11
+ when Hash
12
+ @boundary = options[:boundary]
13
+ @content_type = options[:content_type]
14
+ when String
15
+ @boundary = options
16
+ end
17
+
18
+ @parts = {}
19
+ @content_type ||= "multipart/form-data"
20
+ @boundary ||= "multiparty-boundary-#{rand(1000000000)}"
21
+
22
+ yield self if block_given?
23
+ end
24
+
25
+ def header
26
+ "Content-Type: #{@content_type}; boundary=#{@boundary}\r\n"
27
+ end
28
+
29
+ def body
30
+ result = "--#{@boundary}\r\n"
31
+ result << parts.map do |name, value|
32
+ parse_part(name, value)
33
+ end.join("\r\n")
34
+
35
+ result << "--"
36
+ end
37
+
38
+ def parse_part(name, value)
39
+ content_disposition = "form-data"
40
+ case value
41
+ when Hash
42
+ content_disposition = value[:content_disposition] if value[:content_disposition]
43
+ content_type = value[:content_type]
44
+ filename = value[:filename]
45
+ encoding = value[:encoding]
46
+ body_part = value[:content]
47
+ when File, Tempfile
48
+ content_type = "application/octet-stream"
49
+ filename = File.split(value.path).last
50
+ body_part = value.read
51
+ else
52
+ body_part = value
53
+ end
54
+
55
+ if filename
56
+ content_type ||= MIME::Types.of(filename).first.to_s || "application/octet-stream"
57
+ encoding ||= "binary"
58
+ end
59
+
60
+ head_part = "Content-Disposition: #{content_disposition}; name=\"#{name}\""
61
+ head_part << "; filename=\"#{filename}\"" if filename
62
+ head_part << "\r\n"
63
+ head_part << "Content-Type: #{content_type}\r\n" if content_type
64
+ head_part << "Content-Transfer-Encoding: #{encoding}\r\n" if encoding
65
+
66
+ "#{head_part}\r\n#{body_part}\r\n--#{@boundary}"
67
+ end
68
+
69
+ def add_part(index, value)
70
+ parts[index] = value
71
+ end
72
+ alias_method :[]=, :add_part
73
+
74
+ end
@@ -0,0 +1,80 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "multiparty" do
4
+ it "should initialize" do
5
+ Multiparty.new.should_not be_nil
6
+ end
7
+
8
+ it "should accept a string as the boundary in #initialize" do
9
+ multiparty = Multiparty.new("my-boundary")
10
+ multiparty.boundary.should == "my-boundary"
11
+ end
12
+
13
+ it "should accept an option has in #initialize" do
14
+ multiparty = Multiparty.new :boundary => "my-boundary"
15
+ multiparty.boundary.should == "my-boundary"
16
+ end
17
+
18
+ it "should execute a block in #initialize" do
19
+ blocktest = false
20
+ Multiparty.new do
21
+ blocktest = true
22
+ end
23
+
24
+ blocktest.should be true
25
+ end
26
+
27
+ describe "instance" do
28
+ before(:each) do
29
+ @multiparty = Multiparty.new("my-boundary")
30
+ end
31
+
32
+ it "should return a correct header" do
33
+ @multiparty.header.should == "Content-Type: multipart/form-data; boundary=my-boundary\r\n"
34
+ end
35
+
36
+ it "should be able to set-index a key-value pair" do
37
+ @multiparty[:key] = :value
38
+ @multiparty[:key] = {:filename => "hello.jpg", :content => ""}
39
+ end
40
+
41
+ it "should return a correctly formed multipart response" do
42
+ @multiparty.boundary = "AaB03x"
43
+ @multiparty['submit-name'] = "Larry"
44
+ @multiparty['files'] = {:filename => "file1.txt", :content_type => "text/plain", :content => "... contents of file1.txt ..."}
45
+
46
+ @multiparty.body.gsub("\r\n", "\n").should == '--AaB03x
47
+ Content-Disposition: form-data; name="submit-name"
48
+
49
+ Larry
50
+ --AaB03x
51
+ Content-Disposition: form-data; name="files"; filename="file1.txt"
52
+ Content-Type: text/plain
53
+ Content-Transfer-Encoding: binary
54
+
55
+ ... contents of file1.txt ...
56
+ --AaB03x--'
57
+ end
58
+
59
+ it "should accept a File" do
60
+ begin
61
+ @tempfile = Tempfile.new("foo.txt")
62
+ @tempfile.write("Hi world!")
63
+ @tempfile.rewind
64
+ name = File.split(@tempfile.path).last
65
+
66
+ @multiparty[:bar] = @tempfile
67
+ @multiparty.body.gsub("\r\n", "\n").should == '--my-boundary
68
+ Content-Disposition: form-data; name="bar"; filename="' + name + '"
69
+ Content-Type: application/octet-stream
70
+ Content-Transfer-Encoding: binary
71
+
72
+ Hi world!
73
+ --my-boundary--'
74
+ ensure
75
+ @tempfile.close
76
+ @tempfile.unlink
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup(:default, :test)
4
+ Bundler.require(:default, :test)
5
+
6
+ require 'rspec'
7
+ require 'tempfile'
8
+
9
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
10
+ require "multiparty"
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: multiparty
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - David Verhasselt
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-09-18 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: mime-types
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ description: |
34
+ Easily generate a multipart/form-data header and body.
35
+
36
+ email: david@crowdway.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - README.md
45
+ - Rakefile
46
+ - LICENSE
47
+ - lib/multiparty.rb
48
+ - spec/spec_helper.rb
49
+ - spec/multiparty_spec.rb
50
+ has_rdoc: true
51
+ homepage: http://github.com/dv/multiparty
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.3.7
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Easily generate a multipart/form-data header and body.
82
+ test_files: []
83
+