From 7c21ab667f859c7552dad4090829c976c4127f49 Mon Sep 17 00:00:00 2001 From: Rubionic Date: Tue, 3 Feb 2026 16:41:12 +0000 Subject: [PATCH 1/3] feat: inline palm_civet dependency The palm_civet dependency has not seen any releases for a long time. Given its small complexity, this commit inlines it into the cloud_controller codebase to reduce external dependencies. Changes: - Added lib/cloud_controller/palm_civet.rb with the inlined implementation - Added spec/unit/lib/cloud_controller/palm_civet_spec.rb with all tests - Updated ByteConverter to use the inlined VCAP::CloudController::PalmCivet - Removed palm_civet gem from Gemfile Fixes rubionic/cloud_controller_ng#1 --- Gemfile | 1 - .../app_manifest/byte_converter.rb | 2 +- lib/cloud_controller/palm_civet.rb | 91 ++++++++++ .../lib/cloud_controller/palm_civet_spec.rb | 161 ++++++++++++++++++ 4 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 lib/cloud_controller/palm_civet.rb create mode 100644 spec/unit/lib/cloud_controller/palm_civet_spec.rb diff --git a/Gemfile b/Gemfile index e7dffa5f72f..d75051b3db8 100644 --- a/Gemfile +++ b/Gemfile @@ -22,7 +22,6 @@ gem 'newrelic_rpm' gem 'nokogiri', '>=1.10.5' gem 'oj' gem 'openssl', '>= 3.2' -gem 'palm_civet' gem 'prometheus-client' gem 'public_suffix' gem 'puma' diff --git a/lib/cloud_controller/app_manifest/byte_converter.rb b/lib/cloud_controller/app_manifest/byte_converter.rb index fc6f8b1be46..338502ce7ff 100644 --- a/lib/cloud_controller/app_manifest/byte_converter.rb +++ b/lib/cloud_controller/app_manifest/byte_converter.rb @@ -1,4 +1,4 @@ -require 'palm_civet' +require 'cloud_controller/palm_civet' module VCAP::CloudController class ByteConverter diff --git a/lib/cloud_controller/palm_civet.rb b/lib/cloud_controller/palm_civet.rb new file mode 100644 index 00000000000..b02d2b92d20 --- /dev/null +++ b/lib/cloud_controller/palm_civet.rb @@ -0,0 +1,91 @@ +module VCAP + module CloudController + module PalmCivet + BYTE = 1.0 + KILOBYTE = 1024 * BYTE + MEGABYTE = 1024 * KILOBYTE + GIGABYTE = 1024 * MEGABYTE + TERABYTE = 1024 * GIGABYTE + BYTESPATTERN = /^(-?\d+(?:\.\d+)?)([KMGT]i?B?|B)$/i + + class InvalidByteQuantityError < RuntimeError + def initialize(msg="byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB") + super + end + end + + # Returns a human-readable byte string of the form 10M, 12.5K, and so forth. + # The following units are available: + # * T: Terabyte + # * G: Gigabyte + # * M: Megabyte + # * K: Kilobyte + # * B: Byte + # The unit that results in the smallest number greater than or equal to 1 is + # always chosen. + def self.byte_size(bytes) + if !bytes.is_a? Numeric + raise TypeError, "must be an integer or float" + end + + case + when bytes >= TERABYTE + unit = "T" + value = bytes / TERABYTE + when bytes >= GIGABYTE + unit = "G" + value = bytes / GIGABYTE + when bytes >= MEGABYTE + unit = "M" + value = bytes / MEGABYTE + when bytes >= KILOBYTE + unit = "K" + value = bytes / KILOBYTE + when bytes >= BYTE + unit = "B" + value = bytes + else + return "0" + end + + value = "%g" % ("%.1f" % value) + return value << unit + end + + # Parses a string formatted by bytes_size as bytes. Note binary-prefixed and + # SI prefixed units both mean a base-2 units: + # * KB = K = KiB = 1024 + # * MB = M = MiB = 1024 * K + # * GB = G = GiB = 1024 * M + # * TB = T = TiB = 1024 * G + def self.to_bytes(bytes) + matches = BYTESPATTERN.match(bytes.strip) + if matches == nil + raise InvalidByteQuantityError + end + + value = Float(matches[1]) + + case matches[2][0].capitalize + when "T" + value = value * TERABYTE + when "G" + value = value * GIGABYTE + when "M" + value = value * MEGABYTE + when "K" + value = value * KILOBYTE + end + + return value.to_i + rescue TypeError + raise InvalidByteQuantityError + end + + # Parses a string formatted by byte_size as megabytes. + def self.to_megabytes(bytes) + (self.to_bytes(bytes) / MEGABYTE).to_i + end + end + end +end diff --git a/spec/unit/lib/cloud_controller/palm_civet_spec.rb b/spec/unit/lib/cloud_controller/palm_civet_spec.rb new file mode 100644 index 00000000000..b6934aa9020 --- /dev/null +++ b/spec/unit/lib/cloud_controller/palm_civet_spec.rb @@ -0,0 +1,161 @@ +require 'spec_helper' +require 'cloud_controller/palm_civet' + +module VCAP::CloudController + RSpec.describe PalmCivet do + describe "#byte_size" do + it "prints in the largest possible unit" do + expect(PalmCivet.byte_size(10 * PalmCivet::TERABYTE)).to eq("10T") + expect(PalmCivet.byte_size(10.5 * PalmCivet::TERABYTE)).to eq("10.5T") + + expect(PalmCivet.byte_size(10 * PalmCivet::GIGABYTE)).to eq("10G") + expect(PalmCivet.byte_size(10.5 * PalmCivet::GIGABYTE)).to eq("10.5G") + + expect(PalmCivet.byte_size(100 * PalmCivet::MEGABYTE)).to eq("100M") + expect(PalmCivet.byte_size(100.5 * PalmCivet::MEGABYTE)).to eq("100.5M") + + expect(PalmCivet.byte_size(100 * PalmCivet::KILOBYTE)).to eq("100K") + expect(PalmCivet.byte_size(100.5 * PalmCivet::KILOBYTE)).to eq("100.5K") + + expect(PalmCivet.byte_size(1)).to eq("1B") + end + + it "prints '0' for zero bytes" do + expect(PalmCivet.byte_size(0)).to eq("0") + end + + it "raises a type error on non-number values" do + expect { + PalmCivet.byte_size("something else") + }.to raise_error(TypeError, "must be an integer or float") + end + end + + describe "#to_bytes" do + it "parses byte amounts with short units (e.g. M, G)" do + expect(PalmCivet.to_bytes("5B")).to eq(5) + expect(PalmCivet.to_bytes("5K")).to eq(5 * PalmCivet::KILOBYTE) + expect(PalmCivet.to_bytes("5M")).to eq(5 * PalmCivet::MEGABYTE) + expect(PalmCivet.to_bytes("5G")).to eq(5 * PalmCivet::GIGABYTE) + expect(PalmCivet.to_bytes("5T")).to eq(5 * PalmCivet::TERABYTE) + end + + it "parses byte amounts that are float (e.g. 5.3KB)" do + expect(PalmCivet.to_bytes("13.5KB")).to eq(13824) + expect(PalmCivet.to_bytes("4.5KB")).to eq(4608) + expect(PalmCivet.to_bytes("2.55KB")).to eq(2611) + end + + it "parses byte amounts with long units (e.g MB, GB)" do + expect(PalmCivet.to_bytes("5MB")).to eq(5 * PalmCivet::MEGABYTE) + expect(PalmCivet.to_bytes("5mb")).to eq(5 * PalmCivet::MEGABYTE) + expect(PalmCivet.to_bytes("2GB")).to eq(2 * PalmCivet::GIGABYTE) + expect(PalmCivet.to_bytes("3TB")).to eq(3 * PalmCivet::TERABYTE) + end + + it "parses byte amounts with long binary units (e.g MiB, GiB)" do + expect(PalmCivet.to_bytes("5MiB")).to eq(5 * PalmCivet::MEGABYTE) + expect(PalmCivet.to_bytes("5mib")).to eq(5 * PalmCivet::MEGABYTE) + expect(PalmCivet.to_bytes("2GiB")).to eq(2 * PalmCivet::GIGABYTE) + expect(PalmCivet.to_bytes("3TiB")).to eq(3 * PalmCivet::TERABYTE) + end + + it "allows whitespace before and after the value" do + expect(PalmCivet.to_bytes("\t\n\r 5MB ")).to eq(5 * PalmCivet::MEGABYTE) + end + + context 'when the byte amount is 0' do + it 'returns 0 bytes' do + expect(PalmCivet.to_bytes("0TB")).to eq(0) + end + end + + context 'when the byte amount is negative' do + it 'returns a negative amount of bytes' do + expect(PalmCivet.to_bytes('-200B')).to eq(-200) + end + end + + context "raises an error" do + it "when the unit is missing" do + expect { + PalmCivet.to_bytes("5") + }.to raise_error(PalmCivet::InvalidByteQuantityError) + end + + it "when the unit is unrecognized" do + expect { + PalmCivet.to_bytes("5MBB") + }.to raise_error(PalmCivet::InvalidByteQuantityError) + + expect { + PalmCivet.to_bytes("5BB") + }.to raise_error(PalmCivet::InvalidByteQuantityError) + end + end + end + + describe "#to_megabytes" do + it "parses byte amounts with short units (e.g. M, G)" do + expect(PalmCivet.to_megabytes("5B")).to eq(0) + expect(PalmCivet.to_megabytes("5K")).to eq(0) + expect(PalmCivet.to_megabytes("5M")).to eq(5) + expect(PalmCivet.to_megabytes("5m")).to eq(5) + expect(PalmCivet.to_megabytes("5G")).to eq(5120) + expect(PalmCivet.to_megabytes("5T")).to eq(5242880) + end + + it "parses byte amounts with long units (e.g MB, GB)" do + expect(PalmCivet.to_megabytes("5B")).to eq(0) + expect(PalmCivet.to_megabytes("5KB")).to eq(0) + expect(PalmCivet.to_megabytes("5MB")).to eq(5) + expect(PalmCivet.to_megabytes("5mb")).to eq(5) + expect(PalmCivet.to_megabytes("5GB")).to eq(5120) + expect(PalmCivet.to_megabytes("5TB")).to eq(5242880) + end + + it "parses byte amounts with long binary units (e.g MiB, GiB)" do + expect(PalmCivet.to_megabytes("5B")).to eq(0) + expect(PalmCivet.to_megabytes("5KiB")).to eq(0) + expect(PalmCivet.to_megabytes("5MiB")).to eq(5) + expect(PalmCivet.to_megabytes("5mib")).to eq(5) + expect(PalmCivet.to_megabytes("5GiB")).to eq(5120) + expect(PalmCivet.to_megabytes("5TiB")).to eq(5242880) + end + + it "allows whitespace before and after the value" do + expect(PalmCivet.to_megabytes("\t\n\r 5MB ")).to eq(5) + end + + context 'when the byte amount is 0' do + it 'returns 0 megabytes' do + expect(PalmCivet.to_megabytes('0TB')).to eq(0) + end + end + + context 'when the byte amount is negative' do + it 'returns a negative amount of megabytes' do + expect(PalmCivet.to_megabytes('-200MB')).to eq(-200) + end + end + + context "raises an error" do + it "when the unit is missing" do + expect { + PalmCivet.to_megabytes("5") + }.to raise_error(PalmCivet::InvalidByteQuantityError) + end + + it "when the unit is unrecognized" do + expect { + PalmCivet.to_megabytes("5MBB") + }.to raise_error(PalmCivet::InvalidByteQuantityError) + + expect { + PalmCivet.to_megabytes("5BB") + }.to raise_error(PalmCivet::InvalidByteQuantityError) + end + end + end + end +end From f77e3a30795d12edcdda8b2e12fa667fcfeddf85 Mon Sep 17 00:00:00 2001 From: rkoster Date: Fri, 20 Feb 2026 08:18:20 +0000 Subject: [PATCH 2/3] refactor: rename PalmCivet to ByteQuantity and add MIT license headers - Rename module from PalmCivet to ByteQuantity for clarity - Rename files from palm_civet.rb to byte_quantity.rb - Add MIT license attribution headers per original gem license - Update Gemfile.lock to remove palm_civet gem reference - Update all references in byte_converter.rb --- Gemfile.lock | 4 +- .../app_manifest/byte_converter.rb | 10 +- .../{palm_civet.rb => byte_quantity.rb} | 7 +- .../cloud_controller/byte_quantity_spec.rb | 166 ++++++++++++++++++ .../lib/cloud_controller/palm_civet_spec.rb | 161 ----------------- 5 files changed, 178 insertions(+), 170 deletions(-) rename lib/cloud_controller/{palm_civet.rb => byte_quantity.rb} (93%) create mode 100644 spec/unit/lib/cloud_controller/byte_quantity_spec.rb delete mode 100644 spec/unit/lib/cloud_controller/palm_civet_spec.rb diff --git a/Gemfile.lock b/Gemfile.lock index f9234801379..1a2b912bcc3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -349,7 +349,6 @@ GEM openssl (4.0.0) os (1.1.4) ostruct (0.6.3) - palm_civet (1.1.0) parallel (1.27.0) parallel_tests (5.5.0) parallel @@ -660,7 +659,6 @@ DEPENDENCIES nokogiri (>= 1.10.5) oj openssl (>= 3.2) - palm_civet parallel_tests pg prometheus-client @@ -705,4 +703,4 @@ DEPENDENCIES webrick (~> 1.9.2) BUNDLED WITH - 2.4.19 + 2.6.9 diff --git a/lib/cloud_controller/app_manifest/byte_converter.rb b/lib/cloud_controller/app_manifest/byte_converter.rb index 338502ce7ff..32c0661bd74 100644 --- a/lib/cloud_controller/app_manifest/byte_converter.rb +++ b/lib/cloud_controller/app_manifest/byte_converter.rb @@ -1,4 +1,4 @@ -require 'cloud_controller/palm_civet' +require 'cloud_controller/byte_quantity' module VCAP::CloudController class ByteConverter @@ -10,8 +10,8 @@ def convert_to_mb(human_readable_byte_value) return nil if human_readable_byte_value.blank? raise NonNumericError unless human_readable_byte_value.to_s.match?(/\A-?\d+(?:\.\d+)?/) - PalmCivet.to_megabytes(human_readable_byte_value.to_s) - rescue PalmCivet::InvalidByteQuantityError + ByteQuantity.to_megabytes(human_readable_byte_value.to_s) + rescue ByteQuantity::InvalidByteQuantityError raise InvalidUnitsError end @@ -19,8 +19,8 @@ def convert_to_b(human_readable_byte_value) return nil if human_readable_byte_value.blank? raise NonNumericError unless human_readable_byte_value.to_s.match?(/\A-?\d+(?:\.\d+)?/) - PalmCivet.to_bytes(human_readable_byte_value.to_s) - rescue PalmCivet::InvalidByteQuantityError + ByteQuantity.to_bytes(human_readable_byte_value.to_s) + rescue ByteQuantity::InvalidByteQuantityError raise InvalidUnitsError end diff --git a/lib/cloud_controller/palm_civet.rb b/lib/cloud_controller/byte_quantity.rb similarity index 93% rename from lib/cloud_controller/palm_civet.rb rename to lib/cloud_controller/byte_quantity.rb index b02d2b92d20..69308ed12d5 100644 --- a/lib/cloud_controller/palm_civet.rb +++ b/lib/cloud_controller/byte_quantity.rb @@ -1,6 +1,11 @@ +# Derived from the palm_civet library +# Copyright (c) 2013 Anand Gaitonde +# Licensed under the MIT License +# https://github.com/goodmustache/palm_civet + module VCAP module CloudController - module PalmCivet + module ByteQuantity BYTE = 1.0 KILOBYTE = 1024 * BYTE MEGABYTE = 1024 * KILOBYTE diff --git a/spec/unit/lib/cloud_controller/byte_quantity_spec.rb b/spec/unit/lib/cloud_controller/byte_quantity_spec.rb new file mode 100644 index 00000000000..ae79ba924a1 --- /dev/null +++ b/spec/unit/lib/cloud_controller/byte_quantity_spec.rb @@ -0,0 +1,166 @@ +# Derived from the palm_civet library +# Copyright (c) 2013 Anand Gaitonde +# Licensed under the MIT License +# https://github.com/goodmustache/palm_civet + +require 'spec_helper' +require 'cloud_controller/byte_quantity' + +module VCAP::CloudController + RSpec.describe ByteQuantity do + describe "#byte_size" do + it "prints in the largest possible unit" do + expect(ByteQuantity.byte_size(10 * ByteQuantity::TERABYTE)).to eq("10T") + expect(ByteQuantity.byte_size(10.5 * ByteQuantity::TERABYTE)).to eq("10.5T") + + expect(ByteQuantity.byte_size(10 * ByteQuantity::GIGABYTE)).to eq("10G") + expect(ByteQuantity.byte_size(10.5 * ByteQuantity::GIGABYTE)).to eq("10.5G") + + expect(ByteQuantity.byte_size(100 * ByteQuantity::MEGABYTE)).to eq("100M") + expect(ByteQuantity.byte_size(100.5 * ByteQuantity::MEGABYTE)).to eq("100.5M") + + expect(ByteQuantity.byte_size(100 * ByteQuantity::KILOBYTE)).to eq("100K") + expect(ByteQuantity.byte_size(100.5 * ByteQuantity::KILOBYTE)).to eq("100.5K") + + expect(ByteQuantity.byte_size(1)).to eq("1B") + end + + it "prints '0' for zero bytes" do + expect(ByteQuantity.byte_size(0)).to eq("0") + end + + it "raises a type error on non-number values" do + expect { + ByteQuantity.byte_size("something else") + }.to raise_error(TypeError, "must be an integer or float") + end + end + + describe "#to_bytes" do + it "parses byte amounts with short units (e.g. M, G)" do + expect(ByteQuantity.to_bytes("5B")).to eq(5) + expect(ByteQuantity.to_bytes("5K")).to eq(5 * ByteQuantity::KILOBYTE) + expect(ByteQuantity.to_bytes("5M")).to eq(5 * ByteQuantity::MEGABYTE) + expect(ByteQuantity.to_bytes("5G")).to eq(5 * ByteQuantity::GIGABYTE) + expect(ByteQuantity.to_bytes("5T")).to eq(5 * ByteQuantity::TERABYTE) + end + + it "parses byte amounts that are float (e.g. 5.3KB)" do + expect(ByteQuantity.to_bytes("13.5KB")).to eq(13824) + expect(ByteQuantity.to_bytes("4.5KB")).to eq(4608) + expect(ByteQuantity.to_bytes("2.55KB")).to eq(2611) + end + + it "parses byte amounts with long units (e.g MB, GB)" do + expect(ByteQuantity.to_bytes("5MB")).to eq(5 * ByteQuantity::MEGABYTE) + expect(ByteQuantity.to_bytes("5mb")).to eq(5 * ByteQuantity::MEGABYTE) + expect(ByteQuantity.to_bytes("2GB")).to eq(2 * ByteQuantity::GIGABYTE) + expect(ByteQuantity.to_bytes("3TB")).to eq(3 * ByteQuantity::TERABYTE) + end + + it "parses byte amounts with long binary units (e.g MiB, GiB)" do + expect(ByteQuantity.to_bytes("5MiB")).to eq(5 * ByteQuantity::MEGABYTE) + expect(ByteQuantity.to_bytes("5mib")).to eq(5 * ByteQuantity::MEGABYTE) + expect(ByteQuantity.to_bytes("2GiB")).to eq(2 * ByteQuantity::GIGABYTE) + expect(ByteQuantity.to_bytes("3TiB")).to eq(3 * ByteQuantity::TERABYTE) + end + + it "allows whitespace before and after the value" do + expect(ByteQuantity.to_bytes("\t\n\r 5MB ")).to eq(5 * ByteQuantity::MEGABYTE) + end + + context 'when the byte amount is 0' do + it 'returns 0 bytes' do + expect(ByteQuantity.to_bytes("0TB")).to eq(0) + end + end + + context 'when the byte amount is negative' do + it 'returns a negative amount of bytes' do + expect(ByteQuantity.to_bytes('-200B')).to eq(-200) + end + end + + context "raises an error" do + it "when the unit is missing" do + expect { + ByteQuantity.to_bytes("5") + }.to raise_error(ByteQuantity::InvalidByteQuantityError) + end + + it "when the unit is unrecognized" do + expect { + ByteQuantity.to_bytes("5MBB") + }.to raise_error(ByteQuantity::InvalidByteQuantityError) + + expect { + ByteQuantity.to_bytes("5BB") + }.to raise_error(ByteQuantity::InvalidByteQuantityError) + end + end + end + + describe "#to_megabytes" do + it "parses byte amounts with short units (e.g. M, G)" do + expect(ByteQuantity.to_megabytes("5B")).to eq(0) + expect(ByteQuantity.to_megabytes("5K")).to eq(0) + expect(ByteQuantity.to_megabytes("5M")).to eq(5) + expect(ByteQuantity.to_megabytes("5m")).to eq(5) + expect(ByteQuantity.to_megabytes("5G")).to eq(5120) + expect(ByteQuantity.to_megabytes("5T")).to eq(5242880) + end + + it "parses byte amounts with long units (e.g MB, GB)" do + expect(ByteQuantity.to_megabytes("5B")).to eq(0) + expect(ByteQuantity.to_megabytes("5KB")).to eq(0) + expect(ByteQuantity.to_megabytes("5MB")).to eq(5) + expect(ByteQuantity.to_megabytes("5mb")).to eq(5) + expect(ByteQuantity.to_megabytes("5GB")).to eq(5120) + expect(ByteQuantity.to_megabytes("5TB")).to eq(5242880) + end + + it "parses byte amounts with long binary units (e.g MiB, GiB)" do + expect(ByteQuantity.to_megabytes("5B")).to eq(0) + expect(ByteQuantity.to_megabytes("5KiB")).to eq(0) + expect(ByteQuantity.to_megabytes("5MiB")).to eq(5) + expect(ByteQuantity.to_megabytes("5mib")).to eq(5) + expect(ByteQuantity.to_megabytes("5GiB")).to eq(5120) + expect(ByteQuantity.to_megabytes("5TiB")).to eq(5242880) + end + + it "allows whitespace before and after the value" do + expect(ByteQuantity.to_megabytes("\t\n\r 5MB ")).to eq(5) + end + + context 'when the byte amount is 0' do + it 'returns 0 megabytes' do + expect(ByteQuantity.to_megabytes('0TB')).to eq(0) + end + end + + context 'when the byte amount is negative' do + it 'returns a negative amount of megabytes' do + expect(ByteQuantity.to_megabytes('-200MB')).to eq(-200) + end + end + + context "raises an error" do + it "when the unit is missing" do + expect { + ByteQuantity.to_megabytes("5") + }.to raise_error(ByteQuantity::InvalidByteQuantityError) + end + + it "when the unit is unrecognized" do + expect { + ByteQuantity.to_megabytes("5MBB") + }.to raise_error(ByteQuantity::InvalidByteQuantityError) + + expect { + ByteQuantity.to_megabytes("5BB") + }.to raise_error(ByteQuantity::InvalidByteQuantityError) + end + end + end + end +end diff --git a/spec/unit/lib/cloud_controller/palm_civet_spec.rb b/spec/unit/lib/cloud_controller/palm_civet_spec.rb deleted file mode 100644 index b6934aa9020..00000000000 --- a/spec/unit/lib/cloud_controller/palm_civet_spec.rb +++ /dev/null @@ -1,161 +0,0 @@ -require 'spec_helper' -require 'cloud_controller/palm_civet' - -module VCAP::CloudController - RSpec.describe PalmCivet do - describe "#byte_size" do - it "prints in the largest possible unit" do - expect(PalmCivet.byte_size(10 * PalmCivet::TERABYTE)).to eq("10T") - expect(PalmCivet.byte_size(10.5 * PalmCivet::TERABYTE)).to eq("10.5T") - - expect(PalmCivet.byte_size(10 * PalmCivet::GIGABYTE)).to eq("10G") - expect(PalmCivet.byte_size(10.5 * PalmCivet::GIGABYTE)).to eq("10.5G") - - expect(PalmCivet.byte_size(100 * PalmCivet::MEGABYTE)).to eq("100M") - expect(PalmCivet.byte_size(100.5 * PalmCivet::MEGABYTE)).to eq("100.5M") - - expect(PalmCivet.byte_size(100 * PalmCivet::KILOBYTE)).to eq("100K") - expect(PalmCivet.byte_size(100.5 * PalmCivet::KILOBYTE)).to eq("100.5K") - - expect(PalmCivet.byte_size(1)).to eq("1B") - end - - it "prints '0' for zero bytes" do - expect(PalmCivet.byte_size(0)).to eq("0") - end - - it "raises a type error on non-number values" do - expect { - PalmCivet.byte_size("something else") - }.to raise_error(TypeError, "must be an integer or float") - end - end - - describe "#to_bytes" do - it "parses byte amounts with short units (e.g. M, G)" do - expect(PalmCivet.to_bytes("5B")).to eq(5) - expect(PalmCivet.to_bytes("5K")).to eq(5 * PalmCivet::KILOBYTE) - expect(PalmCivet.to_bytes("5M")).to eq(5 * PalmCivet::MEGABYTE) - expect(PalmCivet.to_bytes("5G")).to eq(5 * PalmCivet::GIGABYTE) - expect(PalmCivet.to_bytes("5T")).to eq(5 * PalmCivet::TERABYTE) - end - - it "parses byte amounts that are float (e.g. 5.3KB)" do - expect(PalmCivet.to_bytes("13.5KB")).to eq(13824) - expect(PalmCivet.to_bytes("4.5KB")).to eq(4608) - expect(PalmCivet.to_bytes("2.55KB")).to eq(2611) - end - - it "parses byte amounts with long units (e.g MB, GB)" do - expect(PalmCivet.to_bytes("5MB")).to eq(5 * PalmCivet::MEGABYTE) - expect(PalmCivet.to_bytes("5mb")).to eq(5 * PalmCivet::MEGABYTE) - expect(PalmCivet.to_bytes("2GB")).to eq(2 * PalmCivet::GIGABYTE) - expect(PalmCivet.to_bytes("3TB")).to eq(3 * PalmCivet::TERABYTE) - end - - it "parses byte amounts with long binary units (e.g MiB, GiB)" do - expect(PalmCivet.to_bytes("5MiB")).to eq(5 * PalmCivet::MEGABYTE) - expect(PalmCivet.to_bytes("5mib")).to eq(5 * PalmCivet::MEGABYTE) - expect(PalmCivet.to_bytes("2GiB")).to eq(2 * PalmCivet::GIGABYTE) - expect(PalmCivet.to_bytes("3TiB")).to eq(3 * PalmCivet::TERABYTE) - end - - it "allows whitespace before and after the value" do - expect(PalmCivet.to_bytes("\t\n\r 5MB ")).to eq(5 * PalmCivet::MEGABYTE) - end - - context 'when the byte amount is 0' do - it 'returns 0 bytes' do - expect(PalmCivet.to_bytes("0TB")).to eq(0) - end - end - - context 'when the byte amount is negative' do - it 'returns a negative amount of bytes' do - expect(PalmCivet.to_bytes('-200B')).to eq(-200) - end - end - - context "raises an error" do - it "when the unit is missing" do - expect { - PalmCivet.to_bytes("5") - }.to raise_error(PalmCivet::InvalidByteQuantityError) - end - - it "when the unit is unrecognized" do - expect { - PalmCivet.to_bytes("5MBB") - }.to raise_error(PalmCivet::InvalidByteQuantityError) - - expect { - PalmCivet.to_bytes("5BB") - }.to raise_error(PalmCivet::InvalidByteQuantityError) - end - end - end - - describe "#to_megabytes" do - it "parses byte amounts with short units (e.g. M, G)" do - expect(PalmCivet.to_megabytes("5B")).to eq(0) - expect(PalmCivet.to_megabytes("5K")).to eq(0) - expect(PalmCivet.to_megabytes("5M")).to eq(5) - expect(PalmCivet.to_megabytes("5m")).to eq(5) - expect(PalmCivet.to_megabytes("5G")).to eq(5120) - expect(PalmCivet.to_megabytes("5T")).to eq(5242880) - end - - it "parses byte amounts with long units (e.g MB, GB)" do - expect(PalmCivet.to_megabytes("5B")).to eq(0) - expect(PalmCivet.to_megabytes("5KB")).to eq(0) - expect(PalmCivet.to_megabytes("5MB")).to eq(5) - expect(PalmCivet.to_megabytes("5mb")).to eq(5) - expect(PalmCivet.to_megabytes("5GB")).to eq(5120) - expect(PalmCivet.to_megabytes("5TB")).to eq(5242880) - end - - it "parses byte amounts with long binary units (e.g MiB, GiB)" do - expect(PalmCivet.to_megabytes("5B")).to eq(0) - expect(PalmCivet.to_megabytes("5KiB")).to eq(0) - expect(PalmCivet.to_megabytes("5MiB")).to eq(5) - expect(PalmCivet.to_megabytes("5mib")).to eq(5) - expect(PalmCivet.to_megabytes("5GiB")).to eq(5120) - expect(PalmCivet.to_megabytes("5TiB")).to eq(5242880) - end - - it "allows whitespace before and after the value" do - expect(PalmCivet.to_megabytes("\t\n\r 5MB ")).to eq(5) - end - - context 'when the byte amount is 0' do - it 'returns 0 megabytes' do - expect(PalmCivet.to_megabytes('0TB')).to eq(0) - end - end - - context 'when the byte amount is negative' do - it 'returns a negative amount of megabytes' do - expect(PalmCivet.to_megabytes('-200MB')).to eq(-200) - end - end - - context "raises an error" do - it "when the unit is missing" do - expect { - PalmCivet.to_megabytes("5") - }.to raise_error(PalmCivet::InvalidByteQuantityError) - end - - it "when the unit is unrecognized" do - expect { - PalmCivet.to_megabytes("5MBB") - }.to raise_error(PalmCivet::InvalidByteQuantityError) - - expect { - PalmCivet.to_megabytes("5BB") - }.to raise_error(PalmCivet::InvalidByteQuantityError) - end - end - end - end -end From f0f6c66220a35d59019098d4657efb88f780417a Mon Sep 17 00:00:00 2001 From: rkoster Date: Fri, 20 Feb 2026 08:34:18 +0000 Subject: [PATCH 3/3] style: fix rubocop offenses in byte_quantity files - Use single-quoted strings - Use do/end for multi-line blocks - Use sprintf instead of String#% - Use self-assignment shorthand (*=) - Use unless instead of if with negation - Use nil? predicate instead of == nil - Remove redundant return statements - Remove redundant self - Add underscores to large numeric literals - Provide exception object to raise --- lib/cloud_controller/byte_quantity.rb | 46 +++-- .../cloud_controller/byte_quantity_spec.rb | 172 +++++++++--------- 2 files changed, 107 insertions(+), 111 deletions(-) diff --git a/lib/cloud_controller/byte_quantity.rb b/lib/cloud_controller/byte_quantity.rb index 69308ed12d5..6d752f2e751 100644 --- a/lib/cloud_controller/byte_quantity.rb +++ b/lib/cloud_controller/byte_quantity.rb @@ -14,7 +14,7 @@ module ByteQuantity BYTESPATTERN = /^(-?\d+(?:\.\d+)?)([KMGT]i?B?|B)$/i class InvalidByteQuantityError < RuntimeError - def initialize(msg="byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB") + def initialize(msg='byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB') super end end @@ -29,32 +29,30 @@ def initialize(msg="byte quantity must be a positive integer with a unit of meas # The unit that results in the smallest number greater than or equal to 1 is # always chosen. def self.byte_size(bytes) - if !bytes.is_a? Numeric - raise TypeError, "must be an integer or float" - end + raise TypeError.new('must be an integer or float') unless bytes.is_a? Numeric case when bytes >= TERABYTE - unit = "T" + unit = 'T' value = bytes / TERABYTE when bytes >= GIGABYTE - unit = "G" + unit = 'G' value = bytes / GIGABYTE when bytes >= MEGABYTE - unit = "M" + unit = 'M' value = bytes / MEGABYTE when bytes >= KILOBYTE - unit = "K" + unit = 'K' value = bytes / KILOBYTE when bytes >= BYTE - unit = "B" + unit = 'B' value = bytes else - return "0" + return '0' end - value = "%g" % ("%.1f" % value) - return value << unit + value = sprintf('%g', sprintf('%.1f', value)) + value << unit end # Parses a string formatted by bytes_size as bytes. Note binary-prefixed and @@ -65,31 +63,29 @@ def self.byte_size(bytes) # * TB = T = TiB = 1024 * G def self.to_bytes(bytes) matches = BYTESPATTERN.match(bytes.strip) - if matches == nil - raise InvalidByteQuantityError - end + raise InvalidByteQuantityError if matches.nil? value = Float(matches[1]) case matches[2][0].capitalize - when "T" - value = value * TERABYTE - when "G" - value = value * GIGABYTE - when "M" - value = value * MEGABYTE - when "K" - value = value * KILOBYTE + when 'T' + value *= TERABYTE + when 'G' + value *= GIGABYTE + when 'M' + value *= MEGABYTE + when 'K' + value *= KILOBYTE end - return value.to_i + value.to_i rescue TypeError raise InvalidByteQuantityError end # Parses a string formatted by byte_size as megabytes. def self.to_megabytes(bytes) - (self.to_bytes(bytes) / MEGABYTE).to_i + (to_bytes(bytes) / MEGABYTE).to_i end end end diff --git a/spec/unit/lib/cloud_controller/byte_quantity_spec.rb b/spec/unit/lib/cloud_controller/byte_quantity_spec.rb index ae79ba924a1..bf99ae01d33 100644 --- a/spec/unit/lib/cloud_controller/byte_quantity_spec.rb +++ b/spec/unit/lib/cloud_controller/byte_quantity_spec.rb @@ -8,70 +8,70 @@ module VCAP::CloudController RSpec.describe ByteQuantity do - describe "#byte_size" do - it "prints in the largest possible unit" do - expect(ByteQuantity.byte_size(10 * ByteQuantity::TERABYTE)).to eq("10T") - expect(ByteQuantity.byte_size(10.5 * ByteQuantity::TERABYTE)).to eq("10.5T") + describe '#byte_size' do + it 'prints in the largest possible unit' do + expect(ByteQuantity.byte_size(10 * ByteQuantity::TERABYTE)).to eq('10T') + expect(ByteQuantity.byte_size(10.5 * ByteQuantity::TERABYTE)).to eq('10.5T') - expect(ByteQuantity.byte_size(10 * ByteQuantity::GIGABYTE)).to eq("10G") - expect(ByteQuantity.byte_size(10.5 * ByteQuantity::GIGABYTE)).to eq("10.5G") + expect(ByteQuantity.byte_size(10 * ByteQuantity::GIGABYTE)).to eq('10G') + expect(ByteQuantity.byte_size(10.5 * ByteQuantity::GIGABYTE)).to eq('10.5G') - expect(ByteQuantity.byte_size(100 * ByteQuantity::MEGABYTE)).to eq("100M") - expect(ByteQuantity.byte_size(100.5 * ByteQuantity::MEGABYTE)).to eq("100.5M") + expect(ByteQuantity.byte_size(100 * ByteQuantity::MEGABYTE)).to eq('100M') + expect(ByteQuantity.byte_size(100.5 * ByteQuantity::MEGABYTE)).to eq('100.5M') - expect(ByteQuantity.byte_size(100 * ByteQuantity::KILOBYTE)).to eq("100K") - expect(ByteQuantity.byte_size(100.5 * ByteQuantity::KILOBYTE)).to eq("100.5K") + expect(ByteQuantity.byte_size(100 * ByteQuantity::KILOBYTE)).to eq('100K') + expect(ByteQuantity.byte_size(100.5 * ByteQuantity::KILOBYTE)).to eq('100.5K') - expect(ByteQuantity.byte_size(1)).to eq("1B") + expect(ByteQuantity.byte_size(1)).to eq('1B') end it "prints '0' for zero bytes" do - expect(ByteQuantity.byte_size(0)).to eq("0") + expect(ByteQuantity.byte_size(0)).to eq('0') end - it "raises a type error on non-number values" do - expect { - ByteQuantity.byte_size("something else") - }.to raise_error(TypeError, "must be an integer or float") + it 'raises a type error on non-number values' do + expect do + ByteQuantity.byte_size('something else') + end.to raise_error(TypeError, 'must be an integer or float') end end - describe "#to_bytes" do - it "parses byte amounts with short units (e.g. M, G)" do - expect(ByteQuantity.to_bytes("5B")).to eq(5) - expect(ByteQuantity.to_bytes("5K")).to eq(5 * ByteQuantity::KILOBYTE) - expect(ByteQuantity.to_bytes("5M")).to eq(5 * ByteQuantity::MEGABYTE) - expect(ByteQuantity.to_bytes("5G")).to eq(5 * ByteQuantity::GIGABYTE) - expect(ByteQuantity.to_bytes("5T")).to eq(5 * ByteQuantity::TERABYTE) + describe '#to_bytes' do + it 'parses byte amounts with short units (e.g. M, G)' do + expect(ByteQuantity.to_bytes('5B')).to eq(5) + expect(ByteQuantity.to_bytes('5K')).to eq(5 * ByteQuantity::KILOBYTE) + expect(ByteQuantity.to_bytes('5M')).to eq(5 * ByteQuantity::MEGABYTE) + expect(ByteQuantity.to_bytes('5G')).to eq(5 * ByteQuantity::GIGABYTE) + expect(ByteQuantity.to_bytes('5T')).to eq(5 * ByteQuantity::TERABYTE) end - it "parses byte amounts that are float (e.g. 5.3KB)" do - expect(ByteQuantity.to_bytes("13.5KB")).to eq(13824) - expect(ByteQuantity.to_bytes("4.5KB")).to eq(4608) - expect(ByteQuantity.to_bytes("2.55KB")).to eq(2611) + it 'parses byte amounts that are float (e.g. 5.3KB)' do + expect(ByteQuantity.to_bytes('13.5KB')).to eq(13_824) + expect(ByteQuantity.to_bytes('4.5KB')).to eq(4608) + expect(ByteQuantity.to_bytes('2.55KB')).to eq(2611) end - it "parses byte amounts with long units (e.g MB, GB)" do - expect(ByteQuantity.to_bytes("5MB")).to eq(5 * ByteQuantity::MEGABYTE) - expect(ByteQuantity.to_bytes("5mb")).to eq(5 * ByteQuantity::MEGABYTE) - expect(ByteQuantity.to_bytes("2GB")).to eq(2 * ByteQuantity::GIGABYTE) - expect(ByteQuantity.to_bytes("3TB")).to eq(3 * ByteQuantity::TERABYTE) + it 'parses byte amounts with long units (e.g MB, GB)' do + expect(ByteQuantity.to_bytes('5MB')).to eq(5 * ByteQuantity::MEGABYTE) + expect(ByteQuantity.to_bytes('5mb')).to eq(5 * ByteQuantity::MEGABYTE) + expect(ByteQuantity.to_bytes('2GB')).to eq(2 * ByteQuantity::GIGABYTE) + expect(ByteQuantity.to_bytes('3TB')).to eq(3 * ByteQuantity::TERABYTE) end - it "parses byte amounts with long binary units (e.g MiB, GiB)" do - expect(ByteQuantity.to_bytes("5MiB")).to eq(5 * ByteQuantity::MEGABYTE) - expect(ByteQuantity.to_bytes("5mib")).to eq(5 * ByteQuantity::MEGABYTE) - expect(ByteQuantity.to_bytes("2GiB")).to eq(2 * ByteQuantity::GIGABYTE) - expect(ByteQuantity.to_bytes("3TiB")).to eq(3 * ByteQuantity::TERABYTE) + it 'parses byte amounts with long binary units (e.g MiB, GiB)' do + expect(ByteQuantity.to_bytes('5MiB')).to eq(5 * ByteQuantity::MEGABYTE) + expect(ByteQuantity.to_bytes('5mib')).to eq(5 * ByteQuantity::MEGABYTE) + expect(ByteQuantity.to_bytes('2GiB')).to eq(2 * ByteQuantity::GIGABYTE) + expect(ByteQuantity.to_bytes('3TiB')).to eq(3 * ByteQuantity::TERABYTE) end - it "allows whitespace before and after the value" do + it 'allows whitespace before and after the value' do expect(ByteQuantity.to_bytes("\t\n\r 5MB ")).to eq(5 * ByteQuantity::MEGABYTE) end context 'when the byte amount is 0' do it 'returns 0 bytes' do - expect(ByteQuantity.to_bytes("0TB")).to eq(0) + expect(ByteQuantity.to_bytes('0TB')).to eq(0) end end @@ -81,54 +81,54 @@ module VCAP::CloudController end end - context "raises an error" do - it "when the unit is missing" do - expect { - ByteQuantity.to_bytes("5") - }.to raise_error(ByteQuantity::InvalidByteQuantityError) + context 'when it raises an error' do + it 'raises when the unit is missing' do + expect do + ByteQuantity.to_bytes('5') + end.to raise_error(ByteQuantity::InvalidByteQuantityError) end - it "when the unit is unrecognized" do - expect { - ByteQuantity.to_bytes("5MBB") - }.to raise_error(ByteQuantity::InvalidByteQuantityError) + it 'raises when the unit is unrecognized' do + expect do + ByteQuantity.to_bytes('5MBB') + end.to raise_error(ByteQuantity::InvalidByteQuantityError) - expect { - ByteQuantity.to_bytes("5BB") - }.to raise_error(ByteQuantity::InvalidByteQuantityError) + expect do + ByteQuantity.to_bytes('5BB') + end.to raise_error(ByteQuantity::InvalidByteQuantityError) end end end - describe "#to_megabytes" do - it "parses byte amounts with short units (e.g. M, G)" do - expect(ByteQuantity.to_megabytes("5B")).to eq(0) - expect(ByteQuantity.to_megabytes("5K")).to eq(0) - expect(ByteQuantity.to_megabytes("5M")).to eq(5) - expect(ByteQuantity.to_megabytes("5m")).to eq(5) - expect(ByteQuantity.to_megabytes("5G")).to eq(5120) - expect(ByteQuantity.to_megabytes("5T")).to eq(5242880) + describe '#to_megabytes' do + it 'parses byte amounts with short units (e.g. M, G)' do + expect(ByteQuantity.to_megabytes('5B')).to eq(0) + expect(ByteQuantity.to_megabytes('5K')).to eq(0) + expect(ByteQuantity.to_megabytes('5M')).to eq(5) + expect(ByteQuantity.to_megabytes('5m')).to eq(5) + expect(ByteQuantity.to_megabytes('5G')).to eq(5120) + expect(ByteQuantity.to_megabytes('5T')).to eq(5_242_880) end - it "parses byte amounts with long units (e.g MB, GB)" do - expect(ByteQuantity.to_megabytes("5B")).to eq(0) - expect(ByteQuantity.to_megabytes("5KB")).to eq(0) - expect(ByteQuantity.to_megabytes("5MB")).to eq(5) - expect(ByteQuantity.to_megabytes("5mb")).to eq(5) - expect(ByteQuantity.to_megabytes("5GB")).to eq(5120) - expect(ByteQuantity.to_megabytes("5TB")).to eq(5242880) + it 'parses byte amounts with long units (e.g MB, GB)' do + expect(ByteQuantity.to_megabytes('5B')).to eq(0) + expect(ByteQuantity.to_megabytes('5KB')).to eq(0) + expect(ByteQuantity.to_megabytes('5MB')).to eq(5) + expect(ByteQuantity.to_megabytes('5mb')).to eq(5) + expect(ByteQuantity.to_megabytes('5GB')).to eq(5120) + expect(ByteQuantity.to_megabytes('5TB')).to eq(5_242_880) end - it "parses byte amounts with long binary units (e.g MiB, GiB)" do - expect(ByteQuantity.to_megabytes("5B")).to eq(0) - expect(ByteQuantity.to_megabytes("5KiB")).to eq(0) - expect(ByteQuantity.to_megabytes("5MiB")).to eq(5) - expect(ByteQuantity.to_megabytes("5mib")).to eq(5) - expect(ByteQuantity.to_megabytes("5GiB")).to eq(5120) - expect(ByteQuantity.to_megabytes("5TiB")).to eq(5242880) + it 'parses byte amounts with long binary units (e.g MiB, GiB)' do + expect(ByteQuantity.to_megabytes('5B')).to eq(0) + expect(ByteQuantity.to_megabytes('5KiB')).to eq(0) + expect(ByteQuantity.to_megabytes('5MiB')).to eq(5) + expect(ByteQuantity.to_megabytes('5mib')).to eq(5) + expect(ByteQuantity.to_megabytes('5GiB')).to eq(5120) + expect(ByteQuantity.to_megabytes('5TiB')).to eq(5_242_880) end - it "allows whitespace before and after the value" do + it 'allows whitespace before and after the value' do expect(ByteQuantity.to_megabytes("\t\n\r 5MB ")).to eq(5) end @@ -144,21 +144,21 @@ module VCAP::CloudController end end - context "raises an error" do - it "when the unit is missing" do - expect { - ByteQuantity.to_megabytes("5") - }.to raise_error(ByteQuantity::InvalidByteQuantityError) + context 'when it raises an error' do + it 'raises when the unit is missing' do + expect do + ByteQuantity.to_megabytes('5') + end.to raise_error(ByteQuantity::InvalidByteQuantityError) end - it "when the unit is unrecognized" do - expect { - ByteQuantity.to_megabytes("5MBB") - }.to raise_error(ByteQuantity::InvalidByteQuantityError) + it 'raises when the unit is unrecognized' do + expect do + ByteQuantity.to_megabytes('5MBB') + end.to raise_error(ByteQuantity::InvalidByteQuantityError) - expect { - ByteQuantity.to_megabytes("5BB") - }.to raise_error(ByteQuantity::InvalidByteQuantityError) + expect do + ByteQuantity.to_megabytes('5BB') + end.to raise_error(ByteQuantity::InvalidByteQuantityError) end end end