# frozen_string_literal: true
# Immutable-style Struct to hold calculated circle metrics cleanly (Ruby 3.0+ keyword_init)
CircleMetrics = Struct.new(:diameter, :circumference, :area, keyword_init: true)
# Calculates the diameter, circumference, and area of a circle.
#
# @param radius [Numeric] The radius of the circle (must be non-negative).
# @return [CircleMetrics] An object containing the calculated results.
# @raise [TypeError] If the radius is not a numeric value.
# @raise [ArgumentError] If the radius is negative.
def calculate_circle_metrics(radius)
# Validate input type
unless radius.is_a?(Numeric)
raise TypeError, "Radius must be a numeric value."
end
# Guard clause: radius cannot be negative
if radius < 0
raise ArgumentError, "Radius cannot be negative."
end
diameter = 2.0 * radius
circumference = 2.0 * Math::PI * radius
# Standard multiplication (radius * radius) is more efficient than radius**2
area = Math::PI * (radius * radius)
CircleMetrics.new(
diameter: diameter,
circumference: circumference,
area: area
)
end
# --- Example Usage ---
begin
radius = 3.0
# Retrieve calculated metrics
metrics = calculate_circle_metrics(radius)
# Output results formatted to 2 decimal places using kernel format
puts "Radius: #{radius}"
puts "Diameter: #{metrics.diameter}"
puts "Circumference: #{format('%.2f', metrics.circumference)}"
puts "Area: #{format('%.2f', metrics.area)}"
rescue StandardError => e
warn "Error: #{e.message}"
exit(1)
end
# run:
#
# Radius: 3.0
# Diameter: 6.0
# Circumference: 18.85
# Area: 28.27
#