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.
-
#field_names ⇒ Array<String>
List part names in the order they were added.
-
#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
107 108 109 110 |
# File 'lib/philiprehberger/multipart/builder.rb', line 107 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
87 88 89 |
# File 'lib/philiprehberger/multipart/builder.rb', line 87 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 |
#field_names ⇒ Array<String>
List part names in the order they were added.
Duplicates are preserved (this is a list, not a set). The returned array is a fresh copy — mutating it does not affect the builder.
72 73 74 |
# File 'lib/philiprehberger/multipart/builder.rb', line 72 def field_names @parts.map { |p| p.name.to_s } 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
115 116 117 118 119 120 |
# File 'lib/philiprehberger/multipart/builder.rb', line 115 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
79 80 81 82 |
# File 'lib/philiprehberger/multipart/builder.rb', line 79 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.
98 99 100 101 102 |
# File 'lib/philiprehberger/multipart/builder.rb', line 98 def write_to(io) @parts.each { |part| io.write(part.to_s(@boundary)) } io.write("--#{@boundary}--\r\n") io end |