From 5022d5368e2e3bdb98b69edc72f0bef7a8da0abf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 20:35:37 +0000 Subject: [PATCH 1/3] chore: allow fast-format to use bsd sed as well --- Rakefile | 26 ++++++++++++++++++-------- scripts/fast-format | 5 +---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Rakefile b/Rakefile index 90095bc3..7d530a32 100644 --- a/Rakefile +++ b/Rakefile @@ -40,6 +40,14 @@ end xargs = %w[xargs --no-run-if-empty --null --max-procs=0 --max-args=300 --] ruby_opt = {"RUBYOPT" => [ENV["RUBYOPT"], "--encoding=UTF-8"].compact.join(" ")} +filtered = ->(ext, dirs) do + if ENV.key?(FILES_ENV) + %w[sed -E -n -e] << "/\\.#{ext}$/p" << "--" << ENV.fetch(FILES_ENV) + else + (%w[find] + dirs + %w[-type f -and -name]) << "*.#{ext}" << "-print0" + end +end + desc("Lint `*.rb(i)`") multitask(:"lint:rubocop") do find = %w[find ./lib ./test ./rbi ./examples -type f -and ( -name *.rb -or -name *.rbi ) -print0] @@ -54,24 +62,26 @@ multitask(:"lint:rubocop") do sh("#{find.shelljoin} | #{lint.shelljoin}") end +norm_lines = %w[tr -- \n \0].shelljoin + desc("Format `*.rb`") multitask(:"format:rb") do # while `syntax_tree` is much faster than `rubocop`, `rubocop` is the only formatter with full syntax support - files = ENV.key?(FILES_ENV) ? %w[sed -E -z -n -e /\.rb$/p --] << ENV.fetch(FILES_ENV) : %w[find ./lib ./test ./examples -type f -and -name *.rb -print0] + files = filtered["rb", %w[./lib ./test ./examples]] fmt = xargs + %w[rubocop --fail-level F --autocorrect --format simple --] - sh("#{files.shelljoin} | #{fmt.shelljoin}") + sh("#{files.shelljoin} | #{norm_lines} | #{fmt.shelljoin}") end desc("Format `*.rbi`") multitask(:"format:rbi") do - files = ENV.key?(FILES_ENV) ? %w[sed -E -z -n -e /\.rbi$/p --] << ENV.fetch(FILES_ENV) : %w[find ./rbi -type f -and -name *.rbi -print0] + files = filtered["rbi", %w[./rbi]] fmt = xargs + %w[stree write --] - sh(ruby_opt, "#{files.shelljoin} | #{fmt.shelljoin}") + sh(ruby_opt, "#{files.shelljoin} | #{norm_lines} | #{fmt.shelljoin}") end desc("Format `*.rbs`") multitask(:"format:rbs") do - files = ENV.key?(FILES_ENV) ? %w[sed -E -z -n -e /\.rbs$/p --] << ENV.fetch(FILES_ENV) : %w[find ./sig -type f -name *.rbs -print0] + files = filtered["rbs", %w[./sig]] inplace = /darwin|bsd/ =~ RUBY_PLATFORM ? ["-i", ""] : %w[-i] uuid = SecureRandom.uuid @@ -100,13 +110,13 @@ multitask(:"format:rbs") do success = false # transform class aliases to type aliases, which syntax tree has no trouble with - sh("#{files.shelljoin} | #{pre.shelljoin}") + sh("#{files.shelljoin} | #{norm_lines} | #{pre.shelljoin}") # run syntax tree to format `*.rbs` files - sh(ruby_opt, "#{files.shelljoin} | #{fmt.shelljoin}") do + sh(ruby_opt, "#{files.shelljoin} | #{norm_lines} | #{fmt.shelljoin}") do success = _1 end # transform type aliases back to class aliases - sh("#{files.shelljoin} | #{pst.shelljoin}") + sh("#{files.shelljoin} | #{norm_lines} | #{pst.shelljoin}") # always run post-processing to remove comment marker fail unless success diff --git a/scripts/fast-format b/scripts/fast-format index 8df0aa26..6d5973fb 100755 --- a/scripts/fast-format +++ b/scripts/fast-format @@ -15,7 +15,4 @@ if [ $# -eq 0 ]; then exit 1 fi -FILE="$(mktemp)" -tr -- '\n' '\0' < "$1" > "$FILE" - -exec -- bundle exec rake format FORMAT_FILE="$FILE" +exec -- bundle exec rake format FORMAT_FILE="$1" From f52304dd7ef5d4dc716e173121f9d1f478275ec8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 17:24:22 +0000 Subject: [PATCH 2/3] fix: always send `filename=...` for multipart requests where a file is expected --- lib/lithic/file_part.rb | 17 ++++++++------- lib/lithic/internal/type/file_input.rb | 11 ++++++---- rbi/lithic/file_part.rbi | 2 +- sig/lithic/file_part.rbs | 2 +- test/lithic/internal/util_test.rb | 29 ++++++++++++++++++-------- 5 files changed, 39 insertions(+), 22 deletions(-) diff --git a/lib/lithic/file_part.rb b/lib/lithic/file_part.rb index bd8b24b0..cccaeda2 100644 --- a/lib/lithic/file_part.rb +++ b/lib/lithic/file_part.rb @@ -38,18 +38,21 @@ def to_json(*a) = read.to_json(*a) def to_yaml(*a) = read.to_yaml(*a) # @param content [Pathname, StringIO, IO, String] - # @param filename [String, nil] + # @param filename [Pathname, String, nil] # @param content_type [String, nil] def initialize(content, filename: nil, content_type: nil) - @content = content + @content_type = content_type @filename = - case content - in Pathname - filename.nil? ? content.basename.to_path : ::File.basename(filename) + case [filename, (@content = content)] + in [String | Pathname, _] + ::File.basename(filename) + in [nil, Pathname] + content.basename.to_path + in [nil, IO] + content.to_path else - filename.nil? ? nil : ::File.basename(filename) + filename end - @content_type = content_type end end end diff --git a/lib/lithic/internal/type/file_input.rb b/lib/lithic/internal/type/file_input.rb index 9d3feb93..0ded8cb3 100644 --- a/lib/lithic/internal/type/file_input.rb +++ b/lib/lithic/internal/type/file_input.rb @@ -82,17 +82,20 @@ def coerce(value, state:) # # @return [Pathname, StringIO, IO, String, Object] def dump(value, state:) - # rubocop:disable Lint/DuplicateBranch case value + in StringIO | String + # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2 + # while not required, a filename is recommended, and in practice many servers do expect this + Lithic::FilePart.new(value, filename: "upload") in IO state[:can_retry] = false + value.to_path.nil? ? Lithic::FilePart.new(value, filename: "upload") : value in Lithic::FilePart if value.content.is_a?(IO) state[:can_retry] = false + value else + value end - # rubocop:enable Lint/DuplicateBranch - - value end # @api private diff --git a/rbi/lithic/file_part.rbi b/rbi/lithic/file_part.rbi index 60764a08..974c9775 100644 --- a/rbi/lithic/file_part.rbi +++ b/rbi/lithic/file_part.rbi @@ -27,7 +27,7 @@ module Lithic sig do params( content: T.any(Pathname, StringIO, IO, String), - filename: T.nilable(String), + filename: T.nilable(T.any(Pathname, String)), content_type: T.nilable(String) ).returns(T.attached_class) end diff --git a/sig/lithic/file_part.rbs b/sig/lithic/file_part.rbs index c7d9684b..fcee8355 100644 --- a/sig/lithic/file_part.rbs +++ b/sig/lithic/file_part.rbs @@ -14,7 +14,7 @@ module Lithic def initialize: ( Pathname | StringIO | IO | String content, - ?filename: String?, + ?filename: (Pathname | String)?, ?content_type: String? ) -> void end diff --git a/test/lithic/internal/util_test.rb b/test/lithic/internal/util_test.rb index 0aa29518..82e590ce 100644 --- a/test/lithic/internal/util_test.rb +++ b/test/lithic/internal/util_test.rb @@ -227,20 +227,24 @@ def test_encoding_length def test_file_encode file = Pathname(__FILE__) + fileinput = Lithic::Internal::Type::Converter.dump(Lithic::Internal::Type::FileInput, "abc") headers = {"content-type" => "multipart/form-data"} cases = { - "abc" => "abc", - StringIO.new("abc") => "abc", - Lithic::FilePart.new("abc") => "abc", - Lithic::FilePart.new(StringIO.new("abc")) => "abc", - file => /^class Lithic/, - Lithic::FilePart.new(file) => /^class Lithic/ + "abc" => ["", "abc"], + StringIO.new("abc") => ["", "abc"], + fileinput => %w[upload abc], + Lithic::FilePart.new(StringIO.new("abc")) => ["", "abc"], + file => [file.basename.to_path, /^class Lithic/], + Lithic::FilePart.new(file, filename: "d o g") => ["d%20o%20g", /^class Lithic/] } - cases.each do |body, val| + cases.each do |body, testcase| + filename, val = testcase encoded = Lithic::Internal::Util.encode_content(headers, body) cgi = FakeCGI.new(*encoded) + io = cgi[""] assert_pattern do - cgi[""].read => ^val + io.original_filename => ^filename + io.read => ^val end end end @@ -261,7 +265,14 @@ def test_hash_encode cgi = FakeCGI.new(*encoded) testcase.each do |key, val| assert_pattern do - cgi[key] => ^val + parsed = + case (p = cgi[key]) + in StringIO + p.read + else + p + end + parsed => ^val end end end From c32e5e59377ac276e383328a4cda275e90e94492 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 17:24:43 +0000 Subject: [PATCH 3/3] release: 0.1.0-alpha.47 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ Gemfile.lock | 2 +- README.md | 2 +- lib/lithic/version.rb | 2 +- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ac370d2b..a9e92226 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.46" + ".": "0.1.0-alpha.47" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 451cbf34..215ba149 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.1.0-alpha.47 (2025-09-29) + +Full Changelog: [v0.1.0-alpha.46...v0.1.0-alpha.47](https://github.com/lithic-com/lithic-ruby/compare/v0.1.0-alpha.46...v0.1.0-alpha.47) + +### Bug Fixes + +* always send `filename=...` for multipart requests where a file is expected ([f52304d](https://github.com/lithic-com/lithic-ruby/commit/f52304dd7ef5d4dc716e173121f9d1f478275ec8)) + + +### Chores + +* allow fast-format to use bsd sed as well ([5022d53](https://github.com/lithic-com/lithic-ruby/commit/5022d5368e2e3bdb98b69edc72f0bef7a8da0abf)) + ## 0.1.0-alpha.46 (2025-09-26) Full Changelog: [v0.1.0-alpha.45...v0.1.0-alpha.46](https://github.com/lithic-com/lithic-ruby/compare/v0.1.0-alpha.45...v0.1.0-alpha.46) diff --git a/Gemfile.lock b/Gemfile.lock index 553dee72..385b4d74 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,7 +11,7 @@ GIT PATH remote: . specs: - lithic (0.1.0.pre.alpha.46) + lithic (0.1.0.pre.alpha.47) connection_pool GEM diff --git a/README.md b/README.md index 5e2904ae..a7c88663 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ To use this gem, install via Bundler by adding the following to your application ```ruby -gem "lithic", "~> 0.1.0.pre.alpha.46" +gem "lithic", "~> 0.1.0.pre.alpha.47" ``` diff --git a/lib/lithic/version.rb b/lib/lithic/version.rb index 60bd1b73..9146f6c3 100644 --- a/lib/lithic/version.rb +++ b/lib/lithic/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Lithic - VERSION = "0.1.0.pre.alpha.46" + VERSION = "0.1.0.pre.alpha.47" end