Hello community,

here is the log from the commit of package rubygem-multipart-post for 
openSUSE:Factory checked in at 2019-08-06 15:10:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-multipart-post (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-multipart-post.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-multipart-post"

Tue Aug  6 15:10:06 2019 rev:9 rq:717311 version:2.1.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/rubygem-multipart-post/rubygem-multipart-post.changes
    2014-10-24 10:48:33.000000000 +0200
+++ 
/work/SRC/openSUSE:Factory/.rubygem-multipart-post.new.4126/rubygem-multipart-post.changes
  2019-08-06 15:10:08.535781731 +0200
@@ -1,0 +2,11 @@
+Fri Jul 19 09:24:08 UTC 2019 - Stephan Kulow <co...@suse.com>
+
+- updated to version 2.1.1
+ see installed History.txt
+
+  <!--
+  # @markup rdoc
+  # @title CHANGELOG
+  -->
+
+-------------------------------------------------------------------

Old:
----
  multipart-post-2.0.0.gem

New:
----
  gem2rpm.yml
  multipart-post-2.1.1.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-multipart-post.spec ++++++
--- /var/tmp/diff_new_pack.iF6fUX/_old  2019-08-06 15:10:08.979781480 +0200
+++ /var/tmp/diff_new_pack.iF6fUX/_new  2019-08-06 15:10:08.979781480 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package rubygem-multipart-post
 #
-# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -12,28 +12,35 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
+#
+# This file was generated with a gem2rpm.yml and not just plain gem2rpm.
+# All sections marked as MANUAL, license headers, summaries and descriptions
+# can be maintained in that file. Please consult this file before editing any
+# of those fields
+#
+
 Name:           rubygem-multipart-post
-Version:        2.0.0
+Version:        2.1.1
 Release:        0
 %define mod_name multipart-post
 %define mod_full_name %{mod_name}-%{version}
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 BuildRequires:  %{rubygem gem2rpm}
-BuildRequires:  %{rubygem rdoc > 3.10}
 BuildRequires:  %{ruby}
 BuildRequires:  ruby-macros >= 5
 Url:            https://github.com/nicksieger/multipart-post
-Source:         http://rubygems.org/gems/%{mod_full_name}.gem
+Source:         https://rubygems.org/gems/%{mod_full_name}.gem
+Source1:        gem2rpm.yml
 Summary:        A multipart form post accessory for Net::HTTP
 License:        MIT
 Group:          Development/Languages/Ruby
 
 %description
-Use with Net::HTTP to do multipart form posts.  IO values that have
+Use with Net::HTTP to do multipart form postspec. IO values that have
 #content_type, #original_filename, and #local_path will be posted as a binary
 file.
 
@@ -43,7 +50,7 @@
 
 %install
 %gem_install \
-  --doc-files="History.txt README.md" \
+  --doc-files="History.txt LICENSE README.md" \
   -f
 
 %gem_packages

++++++ gem2rpm.yml ++++++
# ---
# ## used by gem2rpm
# :summary: this is a custom summary
# ## used by gem2rpm
# :description: |-
#   this is a custom description
#
#   it can be multiline
# ## used by gem2rpm
# :license: MIT or Ruby
# ## used by gem2rpm and gem_packages
# :version_suffix: -x_y
# ## used by gem2rpm and gem_packages
# :disable_docs: true
# ## used by gem2rpm
# :disable_automatic_rdoc_dep: true
# ## used by gem2rpm
# :preamble: |-
#   BuildRequires: foobar
#   Requires: foobar
# ## used by gem2rpm
# :patches:
#   foo.patch: -p1
#   bar.patch:
# :post_patch:
#   if you need to fiddle with the source dir before rebuilding the gem
# ## used by gem2rpm
:sources:
# - foo.desktop
# - bar.desktop
# :gem_install_args: '....'
# ## used by gem2rpm
# :pre_install: |-
#   %if 0%{?use_system_libev}
#   export USE_VENDORED_LIBEV="no"
#   %endif
# ## used by gem2rpm
# :post_install: |-
#   # delete custom files here or do other fancy stuff
#   install -D -m 0644 %{S:1} %{buildroot}%{_bindir}/gem2rpm-opensuse
# ## used by gem2rpm
# :testsuite_command: |-
#   (pushd %{buildroot}%{gem_base}/gems/%{mod_full_name} && rake test)
# ## used by gem2rpm
# :filelist: |-
#   /usr/bin/gem2rpm-opensuse
# ## used by gem2rpm
# :scripts:
#   :post: |-
#     /bin/echo foo
# ## used by gem_packages
# :main:
#   :preamble: |-
#     Requires: util-linux
#     Recommends: pwgen
#   :filelist: |-
#     /usr/bin/gem2rpm-opensuse
# ## used by gem_packages
# :custom_pkgs:
#   apache:
#     :preamble: |-
#       Requires: .....
#     :filelist: |-
#       /etc/apache2/conf.d/passenger.conf
#     :summary: Custom summary is optional
#     :description: |-
#       Custom description is optional
#
#       bar
#     :post: |-
#       /bin/echo foo
# :preamble: |-
#     %if 0%{?suse_version} && 0%{?suse_version} < 1330
#     %define rb_build_versions ruby24 ruby25
#     %define rb_default_ruby_abi ruby:2.4.0 ruby:2.5.0
#     %endif
++++++ multipart-post-2.0.0.gem -> multipart-post-2.1.1.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.rspec new/.rspec
--- old/.rspec  1970-01-01 01:00:00.000000000 +0100
+++ new/.rspec  2019-05-13 13:34:34.000000000 +0200
@@ -0,0 +1,5 @@
+--color
+--format documentation
+--backtrace
+--require spec_helper
+--warnings
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.travis.yml new/.travis.yml
--- old/.travis.yml     1970-01-01 01:00:00.000000000 +0100
+++ new/.travis.yml     2019-05-13 13:34:34.000000000 +0200
@@ -1,7 +1,20 @@
+language: ruby
+cache: bundler
+
 rvm:
-  - 1.9.3
-  - 2.0.0
-  - jruby
-branches:
-  only:
-    - master
+  - 2.0
+  - 2.1
+  - 2.2
+  - 2.3
+  - 2.4
+  - 2.5
+  - 2.6
+  - ruby-head
+  - jruby-head
+  - truffleruby
+
+matrix:
+  allow_failures:
+    - rvm: ruby-head
+    - rvm: jruby-head
+    - rvm: truffleruby
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.yardopts new/.yardopts
--- old/.yardopts       1970-01-01 01:00:00.000000000 +0100
+++ new/.yardopts       2019-05-13 13:34:34.000000000 +0200
@@ -0,0 +1,6 @@
+--no-private
+lib/**/*.rb
+-
+History.txt
+LICENSE
+README.md
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Gemfile new/Gemfile
--- old/Gemfile 1970-01-01 01:00:00.000000000 +0100
+++ new/Gemfile 2019-05-13 13:34:34.000000000 +0200
@@ -1,14 +1,6 @@
 source 'https://rubygems.org'
 gemspec
 
-platforms :mri_19 do
-  gem 'ruby-debug19'
-end
-
-platforms :mri_18 do
-  gem 'ruby-debug'
-end
-
 group :development, :test do
   gem 'rake'
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/History.txt new/History.txt
--- old/History.txt     1970-01-01 01:00:00.000000000 +0100
+++ new/History.txt     2019-05-13 13:34:34.000000000 +0200
@@ -1,3 +1,8 @@
+<!--
+# @markup rdoc
+# @title CHANGELOG
+-->
+
 === 2.0.0 / 2013-12-21
 
 - Drop Ruby 1.8 compatibility
@@ -57,4 +62,3 @@
 * 1 major enhancement
 
   * Birthday!
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/LICENSE new/LICENSE
--- old/LICENSE 1970-01-01 01:00:00.000000000 +0100
+++ new/LICENSE 2019-05-13 13:34:34.000000000 +0200
@@ -0,0 +1,21 @@
+Copyright (c) 2007-2013 Nick Sieger n...@nicksieger.com
+Copyright, 2017, by Samuel G. D. Williams.
+
+MIT license.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/README.md new/README.md
--- old/README.md       1970-01-01 01:00:00.000000000 +0100
+++ new/README.md       2019-05-13 13:34:34.000000000 +0200
@@ -1,77 +1,127 @@
-## multipart-post
+# Multipart::Post
 
-* http://github.com/nicksieger/multipart-post
+Adds a streamy multipart form post capability to `Net::HTTP`. Also supports 
other
+methods besides `POST`.
 
-![build status](https://travis-ci.org/nicksieger/multipart-post.png)
+[![Build 
Status](https://secure.travis-ci.org/socketry/multipart-post.svg)](http://travis-ci.org/socketry/multipart-post)
 
-#### DESCRIPTION:
-
-Adds a streamy multipart form post capability to Net::HTTP. Also
-supports other methods besides POST.
-
-#### FEATURES/PROBLEMS:
+## Features/Problems
 
 * Appears to actually work. A good feature to have.
-* Encapsulates posting of file/binary parts and name/value parameter parts, 
similar to 
+* Encapsulates posting of file/binary parts and name/value parameter parts, 
similar to
   most browsers' file upload forms.
-* Provides an UploadIO helper class to prepare IO objects for inclusion in the 
params
+* Provides an `UploadIO` helper class to prepare IO objects for inclusion in 
the params
   hash of the multipart post object.
 
-#### SYNOPSIS:
-
-    require 'net/http/post/multipart'
-
-    url = URI.parse('http://www.example.com/upload')
-    File.open("./image.jpg") do |jpg|
-      req = Net::HTTP::Post::Multipart.new url.path,
-        "file" => UploadIO.new(jpg, "image/jpeg", "image.jpg")
-      res = Net::HTTP.start(url.host, url.port) do |http|
-        http.request(req)
-      end
-    end
-
-To post multiple files or attachments, simply include multiple parameters with
-UploadIO values:
+## Installation
 
-    require 'net/http/post/multipart'
+    gem install multipart-post
 
-    url = URI.parse('http://www.example.com/upload')
-    req = Net::HTTP::Post::Multipart.new url.path,
-      "file1" => UploadIO.new(File.new("./image.jpg"), "image/jpeg", 
"image.jpg"),
-      "file2" => UploadIO.new(File.new("./image2.jpg"), "image/jpeg", 
"image2.jpg")
-    res = Net::HTTP.start(url.host, url.port) do |http|
-      http.request(req)
-    end
+or in your Gemfile
 
-#### REQUIREMENTS:
+    gem 'multipart-post'
 
-None
+## Usage
 
-#### INSTALL:
+```ruby
+require 'net/http/post/multipart'
 
-    gem install multipart-post
+url = URI.parse('http://www.example.com/upload')
+File.open("./image.jpg") do |jpg|
+  req = Net::HTTP::Post::Multipart.new url.path,
+    "file" => UploadIO.new(jpg, "image/jpeg", "image.jpg")
+  res = Net::HTTP.start(url.host, url.port) do |http|
+    http.request(req)
+  end
+end
+```
 
-#### LICENSE:
-
-(The MIT License)
+To post multiple files or attachments, simply include multiple parameters with
+`UploadIO` values:
 
-Copyright (c) 2007-2013 Nick Sieger <n...@nicksieger.com>
+```ruby
+require 'net/http/post/multipart'
 
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-'Software'), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+url = URI.parse('http://www.example.com/upload')
+req = Net::HTTP::Post::Multipart.new url.path,
+  "file1" => UploadIO.new(File.new("./image.jpg"), "image/jpeg", "image.jpg"),
+  "file2" => UploadIO.new(File.new("./image2.jpg"), "image/jpeg", "image2.jpg")
+res = Net::HTTP.start(url.host, url.port) do |http|
+  http.request(req)
+end
+```
+
+To post files with other normal, non-file params such as input values, you 
need to pass hashes to the `Multipart.new` method.
+
+In Rails 4 for example:
+
+```ruby
+def model_params
+  require_params = params.require(:model).permit(:param_one, :param_two, 
:param_three, :avatar)
+  require_params[:avatar] = model_params[:avatar].present? ? 
UploadIO.new(model_params[:avatar].tempfile, 
model_params[:avatar].content_type, model_params[:avatar].original_filename) : 
nil
+  require_params
+end
+
+require 'net/http/post/multipart'
+
+url = URI.parse('http://www.example.com/upload')
+Net::HTTP.start(url.host, url.port) do |http|
+  req = Net::HTTP::Post::Multipart.new(url, model_params)
+  key = "authorization_key"
+  req.add_field("Authorization", key) #add to Headers
+  http.use_ssl = (url.scheme == "https")
+  http.request(req)
+end
+```
+
+Or in plain ruby:
+
+```ruby
+def params(file)
+  params = { "description" => "A nice picture!" }
+  params[:datei] = UploadIO.new(file, "image/jpeg", "image.jpg")
+  params
+end
+
+url = URI.parse('http://www.example.com/upload')
+File.open("./image.jpg") do |file|
+  req = Net::HTTP::Post::Multipart.new(url.path, params(file))
+  res = Net::HTTP.start(url.host, url.port) do |http|
+    return http.request(req).body
+  end
+end
+```
+
+### Debugging
+
+You can debug requests and responses (e.g. status codes) for all requests by 
adding the following code:
+
+```ruby
+http = Net::HTTP.new(uri.host, uri.port)
+http.set_debug_output($stdout)
+```
+
+## License
+
+Released under the MIT license.
+
+Copyright (c) 2007-2013 Nick Sieger <n...@nicksieger.com>  
+Copyright, 2017, by [Samuel G. D. 
Williams](http://www.codeotaku.com/samuel-williams).
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Rakefile new/Rakefile
--- old/Rakefile        1970-01-01 01:00:00.000000000 +0100
+++ new/Rakefile        2019-05-13 13:34:34.000000000 +0200
@@ -1,9 +1,6 @@
 require "bundler/gem_tasks"
+require "rspec/core/rake_task"
 
-task :default => :test
+RSpec::Core::RakeTask.new(:test)
 
-require 'rake/testtask'
-Rake::TestTask.new do |t|
-  t.libs << "test"
-  t.test_files = FileList['test/**/test*.rb']
-end
+task :default => :test
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/composite_io.rb new/lib/composite_io.rb
--- old/lib/composite_io.rb     1970-01-01 01:00:00.000000000 +0100
+++ new/lib/composite_io.rb     2019-05-13 13:34:34.000000000 +0200
@@ -7,11 +7,11 @@
 # Concatenate together multiple IO objects into a single, composite IO object
 # for purposes of reading as a single stream.
 #
-# Usage:
-#
-#     crio = CompositeReadIO.new(StringIO.new('one'), StringIO.new('two'), 
StringIO.new('three'))
+# @example
+#     crio = CompositeReadIO.new(StringIO.new('one'),
+#                                StringIO.new('two'),
+#                                StringIO.new('three'))
 #     puts crio.read # => "onetwothree"
-#
 class CompositeReadIO
   # Create a new composite-read IO from the arguments, all of which should
   # respond to #read in a manner consistent with IO.
@@ -56,6 +56,8 @@
 
 # Convenience methods for dealing with files and IO that are to be uploaded.
 class UploadIO
+  attr_reader :content_type, :original_filename, :local_path, :io, :opts
+
   # Create an upload IO suitable for including in the params hash of a
   # Net::HTTP::Post::Multipart.
   #
@@ -67,13 +69,9 @@
   # uploading directly from a form in a framework, which often save the file to
   # an arbitrarily named RackMultipart file in /tmp).
   #
-  # Usage:
-  #
+  # @example
   #     UploadIO.new("file.txt", "text/plain")
   #     UploadIO.new(file_io, "text/plain", "file.txt")
-  #
-  attr_reader :content_type, :original_filename, :local_path, :io, :opts
-
   def initialize(filename_or_io, content_type, filename = nil, opts = {})
     io = filename_or_io
     local_path = ""
@@ -95,7 +93,9 @@
   end
 
   def self.convert!(io, content_type, original_filename, local_path)
-    raise ArgumentError, "convert! has been removed. You must now wrap IOs 
using:\nUploadIO.new(filename_or_io, content_type, filename=nil)\nPlease update 
your code."
+    raise ArgumentError, "convert! has been removed. You must now wrap IOs " \
+                         "using:\nUploadIO.new(filename_or_io, content_type, " 
\
+                         "filename=nil)\nPlease update your code."
   end
 
   def method_missing(*args)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/multipart_post.rb new/lib/multipart_post.rb
--- old/lib/multipart_post.rb   1970-01-01 01:00:00.000000000 +0100
+++ new/lib/multipart_post.rb   2019-05-13 13:34:34.000000000 +0200
@@ -5,5 +5,5 @@
 #++
 
 module MultipartPost
-  VERSION = "2.0.0"
+  VERSION = "2.1.1"
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/multipartable.rb new/lib/multipartable.rb
--- old/lib/multipartable.rb    1970-01-01 01:00:00.000000000 +0100
+++ new/lib/multipartable.rb    2019-05-13 13:34:34.000000000 +0200
@@ -5,25 +5,44 @@
 #++
 
 require 'parts'
-  module Multipartable
-    DEFAULT_BOUNDARY = "-----------RubyMultipartPost"
-    def initialize(path, params, headers={}, boundary = DEFAULT_BOUNDARY)
-      headers = headers.clone # don't want to modify the original variable
-      parts_headers = headers.delete(:parts) || {}
-      super(path, headers)
-      parts = params.map do |k,v|
-        case v
-        when Array
-          v.map {|item| Parts::Part.new(boundary, k, item, parts_headers[k]) }
-        else
-          Parts::Part.new(boundary, k, v, parts_headers[k])
-        end
-      end.flatten
-      parts << Parts::EpiloguePart.new(boundary)
-      ios = parts.map {|p| p.to_io }
-      self.set_content_type(headers["Content-Type"] || "multipart/form-data",
-                            { "boundary" => boundary })
-      self.content_length = parts.inject(0) {|sum,i| sum + i.length }
-      self.body_stream = CompositeReadIO.new(*ios)
-    end
+require 'securerandom'
+
+module Multipartable
+  def self.secure_boundary
+    # https://tools.ietf.org/html/rfc7230
+    #      tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
+    #                     / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
+    #                     / DIGIT / ALPHA
+    
+    # https://tools.ietf.org/html/rfc2046
+    #      bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
+    #                       "+" / "_" / "," / "-" / "." /
+    #                       "/" / ":" / "=" / "?"
+    
+    "--#{SecureRandom.uuid}"
+  end
+  
+  def initialize(path, params, headers={}, boundary = 
Multipartable.secure_boundary)
+    headers = headers.clone # don't want to modify the original variable
+    parts_headers = headers.delete(:parts) || {}
+    super(path, headers)
+    parts = params.map do |k,v|
+      case v
+      when Array
+        v.map {|item| Parts::Part.new(boundary, k, item, parts_headers[k]) }
+      else
+        Parts::Part.new(boundary, k, v, parts_headers[k])
+      end
+    end.flatten
+    parts << Parts::EpiloguePart.new(boundary)
+    ios = parts.map {|p| p.to_io }
+    self.set_content_type(headers["Content-Type"] || "multipart/form-data",
+                          { "boundary" => boundary })
+    self.content_length = parts.inject(0) {|sum,i| sum + i.length }
+    self.body_stream = CompositeReadIO.new(*ios)
+    
+    @boundary = boundary
   end
+  
+  attr :boundary
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/net/http/post/multipart.rb 
new/lib/net/http/post/multipart.rb
--- old/lib/net/http/post/multipart.rb  1970-01-01 01:00:00.000000000 +0100
+++ new/lib/net/http/post/multipart.rb  2019-05-13 13:34:34.000000000 +0200
@@ -11,14 +11,15 @@
 require 'multipartable'
 require 'parts'
 
-module Net #:nodoc:
-  class HTTP #:nodoc:
+module Net
+  class HTTP
     class Put
       class Multipart < Put
         include Multipartable
       end
     end
-    class Post #:nodoc:
+
+    class Post
       class Multipart < Post
         include Multipartable
       end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/parts.rb new/lib/parts.rb
--- old/lib/parts.rb    1970-01-01 01:00:00.000000000 +0100
+++ new/lib/parts.rb    2019-05-13 13:34:34.000000000 +0200
@@ -5,7 +5,7 @@
 #++
 
 module Parts
-  module Part #:nodoc:
+  module Part
     def self.new(boundary, name, value, headers = {})
       headers ||= {} # avoid nil values
       if file?(value)
@@ -28,8 +28,14 @@
     end
   end
 
+  # Represents a parametric part to be filled with given value.
   class ParamPart
     include Part
+
+    # @param boundary [String]
+    # @param name [#to_s]
+    # @param value [String]
+    # @param headers [Hash] Content-Type is used, if present.
     def initialize(boundary, name, value, headers = {})
       @part = build_part(boundary, name, value, headers)
       @io = StringIO.new(@part)
@@ -39,6 +45,10 @@
      @part.bytesize
     end
 
+    # @param boundary [String]
+    # @param name [#to_s]
+    # @param value [String]
+    # @param headers [Hash] Content-Type is used, if present.
     def build_part(boundary, name, value, headers = {})
       part = ''
       part << "--#{boundary}\r\n"
@@ -52,7 +62,13 @@
   # Represents a part to be filled from file IO.
   class FilePart
     include Part
+
     attr_reader :length
+
+    # @param boundary [String]
+    # @param name [#to_s]
+    # @param io [IO]
+    # @param headers [Hash]
     def initialize(boundary, name, io, headers = {})
       file_length = io.respond_to?(:length) ?  io.length : 
File.size(io.local_path)
       @head = build_head(boundary, name, io.original_filename, 
io.content_type, file_length,
@@ -62,25 +78,38 @@
       @io = CompositeReadIO.new(StringIO.new(@head), io, StringIO.new(@foot))
     end
 
-    def build_head(boundary, name, filename, type, content_len, opts = {}, 
headers = {})
-      trans_encoding = opts["Content-Transfer-Encoding"] || "binary"
-      content_disposition = opts["Content-Disposition"] || "form-data"
+    # @param boundary [String]
+    # @param name [#to_s]
+    # @param filename [String]
+    # @param type [String]
+    # @param content_len [Integer]
+    # @param opts [Hash]
+    def build_head(boundary, name, filename, type, content_len, opts = {})
+      opts = opts.clone
+
+      trans_encoding = opts.delete("Content-Transfer-Encoding") || "binary"
+      content_disposition = opts.delete("Content-Disposition") || "form-data"
 
       part = ''
       part << "--#{boundary}\r\n"
       part << "Content-Disposition: #{content_disposition}; 
name=\"#{name.to_s}\"; filename=\"#{filename}\"\r\n"
       part << "Content-Length: #{content_len}\r\n"
-      if content_id = opts["Content-ID"]
+      if content_id = opts.delete("Content-ID")
         part << "Content-ID: #{content_id}\r\n"
       end
 
-      if headers["Content-Type"] != nil
-        part <<  "Content-Type: " + headers["Content-Type"] + "\r\n"
+      if opts["Content-Type"] != nil
+        part <<  "Content-Type: " + opts["Content-Type"] + "\r\n"
       else
         part << "Content-Type: #{type}\r\n"
       end
 
       part << "Content-Transfer-Encoding: #{trans_encoding}\r\n"
+
+      opts.each do |k, v|
+        part << "#{k}: #{v}\r\n"
+      end
+
       part << "\r\n"
     end
   end
@@ -88,8 +117,9 @@
   # Represents the epilogue or closing boundary.
   class EpiloguePart
     include Part
+
     def initialize(boundary)
-      @part = "--#{boundary}--\r\n\r\n"
+      @part = "--#{boundary}--\r\n"
       @io = StringIO.new(@part)
     end
   end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        1970-01-01 01:00:00.000000000 +0100
+++ new/metadata        2019-05-13 13:34:34.000000000 +0200
@@ -1,28 +1,80 @@
 --- !ruby/object:Gem::Specification
 name: multipart-post
 version: !ruby/object:Gem::Version
-  version: 2.0.0
-  prerelease: 
+  version: 2.1.1
 platform: ruby
 authors:
 - Nick Sieger
+- Samuel Williams
 autorequire: 
 bindir: bin
 cert_chain: []
-date: 2013-12-21 00:00:00.000000000 Z
-dependencies: []
-description: ! 'Use with Net::HTTP to do multipart form posts.  IO values that 
have
+date: 2019-05-13 00:00:00.000000000 Z
+dependencies:
+- !ruby/object:Gem::Dependency
+  name: bundler
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - ">="
+      - !ruby/object:Gem::Version
+        version: '1.3'
+    - - "<"
+      - !ruby/object:Gem::Version
+        version: '3'
+  type: :development
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - ">="
+      - !ruby/object:Gem::Version
+        version: '1.3'
+    - - "<"
+      - !ruby/object:Gem::Version
+        version: '3'
+- !ruby/object:Gem::Dependency
+  name: rspec
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '3.4'
+  type: :development
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '3.4'
+- !ruby/object:Gem::Dependency
+  name: rake
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - ">="
+      - !ruby/object:Gem::Version
+        version: '0'
+  type: :development
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - ">="
+      - !ruby/object:Gem::Version
+        version: '0'
+description: 'Use with Net::HTTP to do multipart form postspec. IO values that 
have
   #content_type, #original_filename, and #local_path will be posted as a 
binary file.'
 email:
 - n...@nicksieger.com
+- samuel.willi...@oriontransfer.co.nz
 executables: []
 extensions: []
 extra_rdoc_files: []
 files:
-- .gitignore
-- .travis.yml
+- ".gitignore"
+- ".rspec"
+- ".travis.yml"
+- ".yardopts"
 - Gemfile
 - History.txt
+- LICENSE
 - Manifest.txt
 - README.md
 - Rakefile
@@ -32,48 +84,37 @@
 - lib/net/http/post/multipart.rb
 - lib/parts.rb
 - multipart-post.gemspec
-- test/multibyte.txt
-- test/net/http/post/test_multipart.rb
-- test/test_composite_io.rb
-- test/test_parts.rb
+- spec/composite_io_spec.rb
+- spec/multibyte.txt
+- spec/net/http/post/multipart_spec.rb
+- spec/parts_spec.rb
+- spec/spec_helper.rb
 homepage: https://github.com/nicksieger/multipart-post
 licenses:
 - MIT
+metadata: {}
 post_install_message: 
-rdoc_options:
-- --main
-- README.md
-- -SHN
-- -f
-- darkfish
+rdoc_options: []
 require_paths:
 - lib
 required_ruby_version: !ruby/object:Gem::Requirement
-  none: false
   requirements:
-  - - ! '>='
+  - - ">="
     - !ruby/object:Gem::Version
       version: '0'
-      segments:
-      - 0
-      hash: 3851181222699685043
 required_rubygems_version: !ruby/object:Gem::Requirement
-  none: false
   requirements:
-  - - ! '>='
+  - - ">="
     - !ruby/object:Gem::Version
       version: '0'
-      segments:
-      - 0
-      hash: 3851181222699685043
 requirements: []
-rubyforge_project: caldersphere
-rubygems_version: 1.8.23
+rubygems_version: 3.0.3
 signing_key: 
-specification_version: 3
+specification_version: 4
 summary: A multipart form post accessory for Net::HTTP.
 test_files:
-- test/multibyte.txt
-- test/net/http/post/test_multipart.rb
-- test/test_composite_io.rb
-- test/test_parts.rb
+- spec/composite_io_spec.rb
+- spec/multibyte.txt
+- spec/net/http/post/multipart_spec.rb
+- spec/parts_spec.rb
+- spec/spec_helper.rb
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/multipart-post.gemspec new/multipart-post.gemspec
--- old/multipart-post.gemspec  1970-01-01 01:00:00.000000000 +0100
+++ new/multipart-post.gemspec  2019-05-13 13:34:34.000000000 +0200
@@ -2,21 +2,22 @@
 $:.push File.expand_path("../lib", __FILE__)
 require "multipart_post"
 
-Gem::Specification.new do |s|
-  s.name        = "multipart-post"
-  s.version     = MultipartPost::VERSION
-  s.authors     = ["Nick Sieger"]
-  s.email       = ["n...@nicksieger.com"]
-  s.homepage    = "https://github.com/nicksieger/multipart-post";
-  s.summary     = %q{A multipart form post accessory for Net::HTTP.}
-  s.license     = "MIT"
-  s.description = %q{Use with Net::HTTP to do multipart form posts.  IO values 
that have #content_type, #original_filename, and #local_path will be posted as 
a binary file.}
-
-  s.rubyforge_project = "caldersphere"
-
-  s.files         = `git ls-files`.split("\n")
-  s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
-  s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| 
File.basename(f) }
-  s.rdoc_options = ["--main", "README.md", "-SHN", "-f", "darkfish"]
-  s.require_paths = ["lib"]
+Gem::Specification.new do |spec|
+  spec.name        = "multipart-post"
+  spec.version     = MultipartPost::VERSION
+  spec.authors     = ["Nick Sieger", "Samuel Williams"]
+  spec.email       = ["n...@nicksieger.com", 
"samuel.willi...@oriontransfer.co.nz"]
+  spec.homepage    = "https://github.com/nicksieger/multipart-post";
+  spec.summary     = %q{A multipart form post accessory for Net::HTTP.}
+  spec.license     = "MIT"
+  spec.description = %q{Use with Net::HTTP to do multipart form postspec. IO 
values that have #content_type, #original_filename, and #local_path will be 
posted as a binary file.}
+  
+  spec.files         = `git ls-files`.split("\n")
+  spec.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
+  spec.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| 
File.basename(f) }
+  spec.require_paths = ["lib"]
+  
+  spec.add_development_dependency 'bundler', ['>= 1.3', '< 3']
+  spec.add_development_dependency 'rspec', '~> 3.4'
+  spec.add_development_dependency 'rake'
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/composite_io_spec.rb 
new/spec/composite_io_spec.rb
--- old/spec/composite_io_spec.rb       1970-01-01 01:00:00.000000000 +0100
+++ new/spec/composite_io_spec.rb       2019-05-13 13:34:34.000000000 +0200
@@ -0,0 +1,138 @@
+# Copyright, 2012, by Nick Sieger.
+# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+require 'composite_io'
+require 'stringio'
+require 'timeout'
+
+RSpec.shared_context "composite io" do
+  it "test_full_read_from_several_ios" do
+    expect(subject.read).to be == 'the quick brown fox'
+  end
+  
+  it "test_partial_read" do
+    expect(subject.read(9)).to be == 'the quick'
+  end
+
+  it "test_partial_read_to_boundary" do
+    expect(subject.read(10)).to be == 'the quick '
+  end
+
+  it "test_read_with_size_larger_than_available" do
+    expect(subject.read(32)).to be == 'the quick brown fox'
+  end
+  
+  it "test_read_into_buffer" do
+    buf = ''
+    subject.read(nil, buf)
+    expect(buf).to be == 'the quick brown fox'
+  end
+
+  it "test_multiple_reads" do
+    expect(subject.read(4)).to be == 'the '
+    expect(subject.read(4)).to be == 'quic'
+    expect(subject.read(4)).to be == 'k br'
+    expect(subject.read(4)).to be == 'own '
+    expect(subject.read(4)).to be == 'fox'
+  end
+
+  it "test_read_after_end" do
+    subject.read
+    expect(subject.read).to be == ""
+  end
+
+  it "test_read_after_end_with_amount" do
+    subject.read(32)
+    expect(subject.read(32)).to be_nil
+  end
+  
+  it "test_second_full_read_after_rewinding" do
+    subject.read
+    subject.rewind
+    expect(subject.read).to be == 'the quick brown fox'
+  end
+  
+  # Was apparently broken on JRuby due to 
http://jira.codehaus.org/browse/JRUBY-7109
+  it "test_compatible_with_copy_stream" do
+    target_io = StringIO.new
+    Timeout.timeout(1) do # Not sure why we need this in the spec?
+      IO.copy_stream(subject, target_io)
+    end
+    expect(target_io.string).to be == "the quick brown fox"
+  end
+end
+
+RSpec.describe CompositeReadIO do
+  describe "generic io" do
+    subject {StringIO.new('the quick brown fox')}
+  
+    include_context "composite io"
+  end
+  
+  describe "composite io" do
+    subject {CompositeReadIO.new(StringIO.new('the '), StringIO.new('quick '), 
StringIO.new('brown '), StringIO.new('fox'))}
+  
+    include_context "composite io"
+  end
+  
+  describe "nested composite io" do
+    subject {CompositeReadIO.new(CompositeReadIO.new(StringIO.new('the '), 
StringIO.new('quick ')), StringIO.new('brown '), StringIO.new('fox'))}
+  
+    include_context "composite io"
+  end
+  
+  describe "unicode composite io" do
+    let(:utf8_io) {File.open(File.dirname(__FILE__)+'/multibyte.txt')}
+    let(:binary_io) {StringIO.new("\x86")}
+    
+    subject {CompositeReadIO.new(binary_io, utf8_io)}
+    
+    it "test_read_from_multibyte" do
+      expect(subject.read).to be == 
"\x86\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB\n".b
+    end
+  end
+  
+  it "test_convert_error" do
+    expect do
+      UploadIO.convert!('tmp.txt', 'text/plain', 'tmp.txt', 'tmp.txt')
+    end.to raise_error(ArgumentError, /convert! has been removed/)
+  end
+  
+  it "test_empty" do
+    expect(subject.read).to be == ""
+  end
+
+  it "test_empty_limited" do
+    expect(subject.read(1)).to be_nil
+  end
+
+  it "test_empty_parts" do
+    io = CompositeReadIO.new(StringIO.new, StringIO.new('the '), StringIO.new, 
StringIO.new('quick'))
+    expect(io.read(3)).to be == "the"
+    expect(io.read(3)).to be == " qu"
+    expect(io.read(3)).to be == "ick"
+  end
+
+  it "test_all_empty_parts" do
+    io = CompositeReadIO.new(StringIO.new, StringIO.new)
+    expect(io.read(1)).to be_nil
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/multibyte.txt new/spec/multibyte.txt
--- old/spec/multibyte.txt      1970-01-01 01:00:00.000000000 +0100
+++ new/spec/multibyte.txt      2019-05-13 13:34:34.000000000 +0200
@@ -0,0 +1 @@
+ファイル
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/net/http/post/multipart_spec.rb 
new/spec/net/http/post/multipart_spec.rb
--- old/spec/net/http/post/multipart_spec.rb    1970-01-01 01:00:00.000000000 
+0100
+++ new/spec/net/http/post/multipart_spec.rb    2019-05-13 13:34:34.000000000 
+0200
@@ -0,0 +1,123 @@
+#--
+# Copyright (c) 2007-2013 Nick Sieger.
+# See the file README.txt included with the distribution for
+# software license details.
+#++
+
+require 'net/http/post/multipart'
+
+RSpec.shared_context "net http multipart" do
+  let(:temp_file) {"temp.txt"}
+  let(:http_post) do
+    Struct.new("HTTPPost", :content_length, :body_stream, :content_type) do
+      def set_content_type(type, params = {})
+        self.content_type = type + params.map{|k,v|"; #{k}=#{v}"}.join('')
+      end
+    end
+  end
+  
+  after(:each) do
+    File.delete(temp_file) rescue nil
+  end
+  
+  def assert_results(post)
+    expect(post.content_length).to be > 0
+    expect(post.body_stream).to_not be_nil
+    
+    expect(post['content-type']).to be == "multipart/form-data; 
boundary=#{post.boundary}"
+    
+    body = post.body_stream.read
+    boundary_regex = Regexp.quote(post.boundary)
+    
+    expect(body).to be =~ /1234567890/
+    
+    # ensure there is at least one boundary
+    expect(body).to be =~ /^--#{boundary_regex}\r\n/
+    
+    # ensure there is an epilogue
+    expect(body).to be =~ /^--#{boundary_regex}--\r\n/
+    expect(body).to be =~ /text\/plain/
+    
+    if (body =~ /multivalueParam/)
+      expect(body.scan(/^.*multivalueParam.*$/).size).to be == 2
+    end
+  end
+
+  def assert_additional_headers_added(post, parts_headers)
+    post.body_stream.rewind
+    body = post.body_stream.read
+    parts_headers.each do |part, headers|
+      headers.each do |k,v|
+        expect(body).to be =~ /#{k}: #{v}/
+      end
+    end
+  end
+end
+
+RSpec.describe Net::HTTP::Post::Multipart do
+  include_context "net http multipart"
+  
+  it "test_form_multipart_body" do
+    File.open(TEMP_FILE, "w") {|f| f << "1234567890"}
+    @io = File.open(TEMP_FILE)
+    @io = UploadIO.new @io, "text/plain", TEMP_FILE
+    assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :foo => 'bar', 
:file => @io)
+  end
+
+  it "test_form_multipart_body_with_stringio" do
+    @io = StringIO.new("1234567890")
+    @io = UploadIO.new @io, "text/plain", TEMP_FILE
+    assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :foo => 'bar', 
:file => @io)
+  end
+
+  it "test_form_multiparty_body_with_parts_headers" do
+    @io = StringIO.new("1234567890")
+    @io = UploadIO.new @io, "text/plain", TEMP_FILE
+    parts = { :text => 'bar', :file => @io }
+    headers = {
+      :parts => {
+        :text => { "Content-Type" => "part/type" },
+        :file => { "Content-Transfer-Encoding" => "part-encoding" }
+      }
+    }
+
+    request = Net::HTTP::Post::Multipart.new("/foo/bar", parts, headers)
+    assert_results request
+    assert_additional_headers_added(request, headers[:parts])
+  end
+
+  it "test_form_multipart_body_with_array_value" do
+    File.open(TEMP_FILE, "w") {|f| f << "1234567890"}
+    @io = File.open(TEMP_FILE)
+    @io = UploadIO.new @io, "text/plain", TEMP_FILE
+    params = {:foo => ['bar', 'quux'], :file => @io}
+    headers = { :parts => {
+        :foo => { "Content-Type" => "application/json; charset=UTF-8" } } }
+    post = Net::HTTP::Post::Multipart.new("/foo/bar", params, headers)
+    
+    expect(post.content_length).to be > 0
+    expect(post.body_stream).to_not be_nil
+
+    body = post.body_stream.read
+    expect(body.lines.grep(/name="foo"/).length).to be == 2
+    expect(body).to be =~ /Content-Type: application\/json; charset=UTF-8/
+  end
+
+  it "test_form_multipart_body_with_arrayparam" do
+    File.open(TEMP_FILE, "w") {|f| f << "1234567890"}
+    @io = File.open(TEMP_FILE)
+    @io = UploadIO.new @io, "text/plain", TEMP_FILE
+    assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :multivalueParam 
=> ['bar','bah'], :file => @io)
+  end
+end
+
+RSpec.describe Net::HTTP::Put::Multipart do
+  include_context "net http multipart"
+  
+  it "test_form_multipart_body_put" do
+    File.open(TEMP_FILE, "w") {|f| f << "1234567890"}
+    @io = File.open(TEMP_FILE)
+    @io = UploadIO.new @io, "text/plain", TEMP_FILE
+    assert_results Net::HTTP::Put::Multipart.new("/foo/bar", :foo => 'bar', 
:file => @io)
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/parts_spec.rb new/spec/parts_spec.rb
--- old/spec/parts_spec.rb      1970-01-01 01:00:00.000000000 +0100
+++ new/spec/parts_spec.rb      2019-05-13 13:34:34.000000000 +0200
@@ -0,0 +1,102 @@
+# Copyright, 2012, by Nick Sieger.
+# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+require 'parts'
+require 'stringio'
+require 'composite_io'
+require 'tempfile'
+
+MULTIBYTE = File.dirname(__FILE__)+'/multibyte.txt'
+TEMP_FILE = "temp.txt"
+
+module AssertPartLength
+  def assert_part_length(part)
+    bytes = part.to_io.read
+    bytesize = bytes.respond_to?(:bytesize) ? bytes.bytesize : bytes.length
+    expect(bytesize).to be == part.length
+  end
+end
+
+RSpec.describe Parts do
+  let(:string_with_content_type) do
+    Class.new(String) do
+      def content_type; 'application/data'; end
+    end
+  end
+
+  it "test_file_with_upload_io" do
+    expect(Parts::Part.file?(UploadIO.new(__FILE__, "text/plain"))).to be true
+  end
+
+  it "test_file_with_modified_string" do
+    expect(Parts::Part.file?(string_with_content_type.new("Hello"))).to be 
false
+  end
+
+  it "test_new_with_modified_string" do
+    expect(Parts::Part.new("boundary", "multibyte", 
string_with_content_type.new("Hello"))).to be_kind_of(Parts::ParamPart)
+  end
+end
+
+RSpec.describe Parts::FilePart do
+  include AssertPartLength
+
+  before(:each) do
+    File.open(TEMP_FILE, "w") {|f| f << "1234567890"}
+    io =  UploadIO.new(TEMP_FILE, "text/plain")
+    @part = Parts::FilePart.new("boundary", "afile", io)
+  end
+
+  after(:each) do
+    File.delete(TEMP_FILE) rescue nil
+  end
+
+  it "test_correct_length" do
+    assert_part_length @part
+  end
+
+  it "test_multibyte_file_length" do
+    assert_part_length Parts::FilePart.new("boundary", "multibyte", 
UploadIO.new(MULTIBYTE, "text/plain"))
+  end
+
+  it "test_multibyte_filename" do
+    name = File.read(MULTIBYTE, 300)
+    file = Tempfile.new(name.respond_to?(:force_encoding) ? 
name.force_encoding("UTF-8") : name)
+    assert_part_length Parts::FilePart.new("boundary", "multibyte", 
UploadIO.new(file, "text/plain"))
+    file.close
+  end
+
+   it "test_force_content_type_header" do
+    part = Parts::FilePart.new("boundary", "afile", UploadIO.new(TEMP_FILE, 
"text/plain"), { "Content-Type" => "application/pdf" })
+    expect(part.to_io.read).to match(/Content-Type: application\/pdf/)
+  end
+end
+
+RSpec.describe Parts::ParamPart do
+  include AssertPartLength
+
+  before(:each) do
+    @part = Parts::ParamPart.new("boundary", "multibyte", File.read(MULTIBYTE))
+  end
+
+  it "test_correct_length" do
+    assert_part_length @part
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/spec_helper.rb new/spec/spec_helper.rb
--- old/spec/spec_helper.rb     1970-01-01 01:00:00.000000000 +0100
+++ new/spec/spec_helper.rb     2019-05-13 13:34:34.000000000 +0200
@@ -0,0 +1,29 @@
+
+if ENV['COVERAGE']
+       begin
+               require 'simplecov'
+               
+               SimpleCov.start do
+                       add_filter "/spec/"
+               end
+               
+               if ENV['TRAVIS']
+                       require 'coveralls'
+                       Coveralls.wear!
+               end
+       rescue LoadError
+               warn "Could not load simplecov: #{$!}"
+       end
+end
+
+require "bundler/setup"
+require "multipart_post"
+
+RSpec.configure do |config|
+       # Enable flags like --only-failures and --next-failure
+       config.example_status_persistence_file_path = ".rspec_status"
+
+       config.expect_with :rspec do |c|
+               c.syntax = :expect
+       end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/multibyte.txt new/test/multibyte.txt
--- old/test/multibyte.txt      1970-01-01 01:00:00.000000000 +0100
+++ new/test/multibyte.txt      1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-ファイル
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/net/http/post/test_multipart.rb 
new/test/net/http/post/test_multipart.rb
--- old/test/net/http/post/test_multipart.rb    1970-01-01 01:00:00.000000000 
+0100
+++ new/test/net/http/post/test_multipart.rb    1970-01-01 01:00:00.000000000 
+0100
@@ -1,110 +0,0 @@
-#--
-# Copyright (c) 2007-2013 Nick Sieger.
-# See the file README.txt included with the distribution for
-# software license details.
-#++
-
-require 'net/http/post/multipart'
-require 'test/unit'
-
-class Net::HTTP::Post::MultiPartTest < Test::Unit::TestCase
-  TEMP_FILE = "temp.txt"
-
-  HTTPPost = Struct.new("HTTPPost", :content_length, :body_stream, 
:content_type)
-  HTTPPost.module_eval do
-    def set_content_type(type, params = {})
-      self.content_type = type + params.map{|k,v|"; #{k}=#{v}"}.join('')
-    end
-  end
-
-  def teardown
-    File.delete(TEMP_FILE) rescue nil
-  end
-
-  def test_form_multipart_body
-    File.open(TEMP_FILE, "w") {|f| f << "1234567890"}
-    @io = File.open(TEMP_FILE)
-    @io = UploadIO.new @io, "text/plain", TEMP_FILE
-    assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :foo => 'bar', 
:file => @io)
-  end
-  def test_form_multipart_body_put
-    File.open(TEMP_FILE, "w") {|f| f << "1234567890"}
-    @io = File.open(TEMP_FILE)
-    @io = UploadIO.new @io, "text/plain", TEMP_FILE
-    assert_results Net::HTTP::Put::Multipart.new("/foo/bar", :foo => 'bar', 
:file => @io)
-  end
-
-  def test_form_multipart_body_with_stringio
-    @io = StringIO.new("1234567890")
-    @io = UploadIO.new @io, "text/plain", TEMP_FILE
-    assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :foo => 'bar', 
:file => @io)
-  end
-
-  def test_form_multiparty_body_with_parts_headers
-    @io = StringIO.new("1234567890")
-    @io = UploadIO.new @io, "text/plain", TEMP_FILE
-    parts = { :text => 'bar', :file => @io }
-    headers = {
-      :parts => {
-        :text => { "Content-Type" => "part/type" },
-        :file => { "Content-Transfer-Encoding" => "part-encoding" }
-      }
-    }
-
-    request = Net::HTTP::Post::Multipart.new("/foo/bar", parts, headers)
-    assert_results request
-    assert_additional_headers_added(request, headers[:parts])
-  end
-
-  def test_form_multipart_body_with_array_value
-    File.open(TEMP_FILE, "w") {|f| f << "1234567890"}
-    @io = File.open(TEMP_FILE)
-    @io = UploadIO.new @io, "text/plain", TEMP_FILE
-    params = {:foo => ['bar', 'quux'], :file => @io}
-    headers = { :parts => {
-        :foo => { "Content-Type" => "application/json; charset=UTF-8" } } }
-    post = Net::HTTP::Post::Multipart.new("/foo/bar", params, headers,
-                                          
Net::HTTP::Post::Multipart::DEFAULT_BOUNDARY)
-
-    assert post.content_length && post.content_length > 0
-    assert post.body_stream
-
-    body = post.body_stream.read
-    assert_equal 2, body.lines.grep(/name="foo"/).length
-    assert body =~ /Content-Type: application\/json; charset=UTF-8/, body
-  end
-
-  def test_form_multipart_body_with_arrayparam
-    File.open(TEMP_FILE, "w") {|f| f << "1234567890"}
-    @io = File.open(TEMP_FILE)
-    @io = UploadIO.new @io, "text/plain", TEMP_FILE
-    assert_results Net::HTTP::Post::Multipart.new("/foo/bar", :multivalueParam 
=> ['bar','bah'], :file => @io)
-  end
-
-  def assert_results(post)
-    assert post.content_length && post.content_length > 0
-    assert post.body_stream
-    assert_equal "multipart/form-data; 
boundary=#{Multipartable::DEFAULT_BOUNDARY}", post['content-type']
-    body = post.body_stream.read
-    boundary_regex = Regexp.quote Multipartable::DEFAULT_BOUNDARY
-    assert body =~ /1234567890/
-    # ensure there is at least one boundary
-    assert body =~ /^--#{boundary_regex}\r\n/
-    # ensure there is an epilogue
-    assert body =~ /^--#{boundary_regex}--\r\n/
-    assert body =~ /text\/plain/
-    if (body =~ /multivalueParam/)
-       assert_equal 2, body.scan(/^.*multivalueParam.*$/).size
-    end
-  end
-
-  def assert_additional_headers_added(post, parts_headers)
-    post.body_stream.rewind
-    body = post.body_stream.read
-    parts_headers.each do |part, headers|
-      headers.each do |k,v|
-        assert body =~ /#{k}: #{v}/
-      end
-    end
-  end
-end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/test_composite_io.rb 
new/test/test_composite_io.rb
--- old/test/test_composite_io.rb       1970-01-01 01:00:00.000000000 +0100
+++ new/test/test_composite_io.rb       1970-01-01 01:00:00.000000000 +0100
@@ -1,115 +0,0 @@
-#--
-# Copyright (c) 2007-2013 Nick Sieger.
-# See the file README.txt included with the distribution for
-# software license details.
-#++
-
-require 'composite_io'
-require 'stringio'
-require 'test/unit'
-require 'timeout'
-
-class CompositeReadIOTest < Test::Unit::TestCase
-  def setup
-    @io = CompositeReadIO.new(CompositeReadIO.new(StringIO.new('the '), 
StringIO.new('quick ')),
-            StringIO.new('brown '), StringIO.new('fox'))
-  end
-
-  def test_full_read_from_several_ios
-    assert_equal 'the quick brown fox', @io.read
-  end
-
-  unless RUBY_VERSION < '1.9'
-    def test_read_from_multibyte
-      utf8    = File.open(File.dirname(__FILE__)+'/multibyte.txt')
-      binary  = StringIO.new("\x86")
-      @io = CompositeReadIO.new(binary,utf8)
-
-      expect  = "\x86\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB\n"
-      expect.force_encoding('BINARY') if expect.respond_to?(:force_encoding)
-      assert_equal expect, @io.read
-    end
-  end
-
-  def test_partial_read
-    assert_equal 'the quick', @io.read(9)
-  end
-
-  def test_partial_read_to_boundary
-    assert_equal 'the quick ', @io.read(10)
-  end
-
-  def test_read_with_size_larger_than_available
-    assert_equal 'the quick brown fox', @io.read(32)
-  end
-
-  def test_read_into_buffer
-    buf = ''
-    @io.read(nil, buf)
-    assert_equal 'the quick brown fox', buf
-  end
-
-  def test_multiple_reads
-    assert_equal 'the ', @io.read(4)
-    assert_equal 'quic', @io.read(4)
-    assert_equal 'k br', @io.read(4)
-    assert_equal 'own ', @io.read(4)
-    assert_equal 'fox',  @io.read(4)
-  end
-
-  def test_read_after_end
-    @io.read
-    assert_equal "", @io.read
-  end
-
-  def test_read_after_end_with_amount
-    @io.read(32)
-    assert_equal nil, @io.read(32)
-  end
-  
-  def test_second_full_read_after_rewinding
-    @io.read
-    @io.rewind
-    assert_equal 'the quick brown fox', @io.read
-  end
-
-  def test_convert_error
-    assert_raises(ArgumentError) {
-      UploadIO.convert!('tmp.txt', 'text/plain', 'tmp.txt', 'tmp.txt')
-    }
-  end
-
-  ## FIXME excluding on JRuby due to
-  ## http://jira.codehaus.org/browse/JRUBY-7109
-  if IO.respond_to?(:copy_stream) && !defined?(JRUBY_VERSION)
-    def test_compatible_with_copy_stream
-      target_io = StringIO.new
-      Timeout.timeout(1) do
-        IO.copy_stream(@io, target_io)
-      end
-      assert_equal "the quick brown fox", target_io.string
-    end
-  end
-
-  def test_empty
-    io = CompositeReadIO.new
-    assert_equal "", io.read
-  end
-
-  def test_empty_limited
-    io = CompositeReadIO.new
-    assert_nil io.read(1)
-  end
-
-  def test_empty_parts
-    io = CompositeReadIO.new(StringIO.new, StringIO.new('the '), StringIO.new, 
StringIO.new('quick'))
-    assert_equal "the", io.read(3)
-    assert_equal " qu", io.read(3)
-    assert_equal "ick", io.read(4)
-  end
-
-  def test_all_empty_parts
-    io = CompositeReadIO.new(StringIO.new, StringIO.new)
-    assert_nil io.read(1)
-  end
-end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/test_parts.rb new/test/test_parts.rb
--- old/test/test_parts.rb      1970-01-01 01:00:00.000000000 +0100
+++ new/test/test_parts.rb      1970-01-01 01:00:00.000000000 +0100
@@ -1,86 +0,0 @@
-#--
-# Copyright (c) 2007-2012 Nick Sieger.
-# See the file README.txt included with the distribution for
-# software license details.
-#++
-
-require 'test/unit'
-
-require 'parts'
-require 'stringio'
-require 'composite_io'
-require 'tempfile'
-
-
-MULTIBYTE = File.dirname(__FILE__)+'/multibyte.txt'
-TEMP_FILE = "temp.txt"
-
-module AssertPartLength
-  def assert_part_length(part)
-    bytes = part.to_io.read
-    bytesize = bytes.respond_to?(:bytesize) ? bytes.bytesize : bytes.length
-    assert_equal bytesize, part.length
-  end
-end
-
-class PartTest < Test::Unit::TestCase
-  def setup
-    @string_with_content_type = Class.new(String) do
-      def content_type; 'application/data'; end
-    end
-  end
-
-  def test_file_with_upload_io
-    assert Parts::Part.file?(UploadIO.new(__FILE__, "text/plain"))
-  end
-
-  def test_file_with_modified_string
-    assert !Parts::Part.file?(@string_with_content_type.new("Hello"))
-  end
-
-  def test_new_with_modified_string
-    assert_kind_of Parts::ParamPart,
-      Parts::Part.new("boundary", "multibyte", 
@string_with_content_type.new("Hello"))
-  end
-end
-
-class FilePartTest < Test::Unit::TestCase
-  include AssertPartLength
-
-  def setup
-    File.open(TEMP_FILE, "w") {|f| f << "1234567890"}
-    io =  UploadIO.new(TEMP_FILE, "text/plain")
-    @part = Parts::FilePart.new("boundary", "afile", io)
-  end
-
-  def teardown
-    File.delete(TEMP_FILE) rescue nil
-  end
-
-  def test_correct_length
-    assert_part_length @part
-  end
-
-  def test_multibyte_file_length
-    assert_part_length Parts::FilePart.new("boundary", "multibyte", 
UploadIO.new(MULTIBYTE, "text/plain"))
-  end
-
-  def test_multibyte_filename
-    name = File.read(MULTIBYTE, 300)
-    file = Tempfile.new(name.respond_to?(:force_encoding) ? 
name.force_encoding("UTF-8") : name)
-    assert_part_length Parts::FilePart.new("boundary", "multibyte", 
UploadIO.new(file, "text/plain"))
-    file.close
-  end
-end
-
-class ParamPartTest < Test::Unit::TestCase
-  include AssertPartLength
-
-  def setup
-    @part = Parts::ParamPart.new("boundary", "multibyte", File.read(MULTIBYTE))
-  end
-
-  def test_correct_length
-    assert_part_length @part
-  end
-end


Reply via email to