Class: Philiprehberger::Multipart::Builder
- Inherits:
-
Object
- Object
- Philiprehberger::Multipart::Builder
- Defined in:
- lib/philiprehberger/multipart/builder.rb
Overview
DSL builder for constructing multipart/form-data bodies
Instance Attribute Summary collapse
-
#boundary ⇒ String
readonly
The multipart boundary string.
-
#parts ⇒ Array<Part>
readonly
The parts added to the builder.
Instance Method Summary collapse
-
#content_length ⇒ Integer
Calculate the byte size of the multipart body.
-
#content_type ⇒ String
Return the Content-Type header value with boundary.
-
#field(name, value) ⇒ self
Add a text field.
-
#file(name, path_or_io, filename: nil, content_type: nil) ⇒ self
Add a file field.
-
#headers ⇒ Hash
Return the headers hash for the request.
-
#initialize(boundary: nil) ⇒ Builder
constructor
A new instance of Builder.
-
#part(name) ⇒ Part?
Look up the first part previously added with the given name.
-
#to_s ⇒ String
Render the complete multipart body as a string.
-
#write_to(io) ⇒ #write
Stream the multipart body to an IO object.
Constructor Details
#initialize(boundary: nil) ⇒ Builder
Returns a new instance of Builder.
17 18 19 20 |
# File 'lib/philiprehberger/multipart/builder.rb', line 17 def initialize(boundary: nil) @boundary = boundary || generate_boundary @parts = [] end |
Instance Attribute Details
#boundary ⇒ String (readonly)
Returns the multipart boundary string.
11 12 13 |
# File 'lib/philiprehberger/multipart/builder.rb', line 11 def boundary @boundary end |
#parts ⇒ Array<Part> (readonly)
Returns the parts added to the builder.
14 15 16 |
# File 'lib/philiprehberger/multipart/builder.rb', line 14 def parts @parts end |
Instance Method Details
#content_length ⇒ Integer
Calculate the byte size of the multipart body
97 98 99 100 |
# File 'lib/philiprehberger/multipart/builder.rb', line 97 def content_length size = @parts.sum { |part| part.to_s(@boundary).bytesize } size + "--#{@boundary}--\r\n".bytesize end |
#content_type ⇒ String
Return the Content-Type header value with boundary
77 78 79 |
# File 'lib/philiprehberger/multipart/builder.rb', line 77 def content_type "multipart/form-data; boundary=#{@boundary}" end |
#field(name, value) ⇒ self
Add a text field
27 28 29 30 |
# File 'lib/philiprehberger/multipart/builder.rb', line 27 def field(name, value) @parts << Part.new(name, value.to_s) self end |
#file(name, path_or_io, filename: nil, content_type: nil) ⇒ self
Add a file field
Accepts either a file path (String) or an IO object (responds to :read). When passing an IO object, the ‘filename:` keyword is required. Content type is auto-detected from the filename when not provided.
44 45 46 47 48 49 50 51 |
# File 'lib/philiprehberger/multipart/builder.rb', line 44 def file(name, path_or_io, filename: nil, content_type: nil) if path_or_io.respond_to?(:read) add_io_file(name, path_or_io, filename, content_type) else add_path_file(name, path_or_io, filename, content_type) end self end |
#headers ⇒ Hash
Return the headers hash for the request
105 106 107 108 109 110 |
# File 'lib/philiprehberger/multipart/builder.rb', line 105 def headers { 'Content-Type' => content_type, 'Content-Length' => content_length.to_s } end |
#part(name) ⇒ Part?
Look up the first part previously added with the given name.
Allows post-construction tweaks, e.g. ‘builder.part(’avatar’).content_type = ‘image/webp’‘. String and Symbol lookups are equivalent.
61 62 63 64 |
# File 'lib/philiprehberger/multipart/builder.rb', line 61 def part(name) needle = name.to_s @parts.find { |p| p.name.to_s == needle } end |
#to_s ⇒ String
Render the complete multipart body as a string
69 70 71 72 |
# File 'lib/philiprehberger/multipart/builder.rb', line 69 def to_s body = @parts.map { |part| part.to_s(@boundary) }.join "#{body}--#{@boundary}--\r\n" end |
#write_to(io) ⇒ #write
Stream the multipart body to an IO object
Writes each part directly to the IO without building the full body string in memory. Useful for large file uploads.
88 89 90 91 92 |
# File 'lib/philiprehberger/multipart/builder.rb', line 88 def write_to(io) @parts.each { |part| io.write(part.to_s(@boundary)) } io.write("--#{@boundary}--\r\n") io end |