diff --git a/Gemfile.lock b/Gemfile.lock index 5326485..40cb1b2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,9 +2,9 @@ GEM remote: https://rubygems.org/ specs: ast (2.4.2) - json (2.7.2) + json (2.7.4) language_server-protocol (3.17.0.3) - minitest (5.23.1) + minitest (5.25.1) parallel (1.26.3) parser (3.3.5.0) ast (~> 2.4.1) @@ -14,12 +14,12 @@ GEM racc (1.8.1) rainbow (3.1.1) rake (13.2.1) - rake-compiler (1.2.7) + rake-compiler (1.2.8) rake rdoc (6.7.0) psych (>= 4.0.0) regexp_parser (2.9.2) - rubocop (1.66.1) + rubocop (1.67.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -33,7 +33,7 @@ GEM parser (>= 3.3.1.0) ruby-progressbar (1.13.0) stringio (3.1.1) - unicode-display_width (2.5.0) + unicode-display_width (2.6.0) PLATFORMS ruby diff --git a/README.md b/README.md index 6ee3069..3d744e2 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# Calcpace [![Gem Version](https://d25lcipzij17d.cloudfront.net/badge.svg?id=rb&r=r&ts=1683906897&type=6e&v=1.4.0&x2=0)](https://badge.fury.io/rb/calcpace) +# Calcpace [![Gem Version](https://d25lcipzij17d.cloudfront.net/badge.svg?id=rb&r=r&ts=1683906897&type=6e&v=1.5.0&x2=0)](https://badge.fury.io/rb/calcpace) -Calcpace is a Ruby gem designed for calculations and conversions related to distance and time. It can calculate velocity, pace, total time, and distance, accepting time in various formats, including HH:MM:SS. The gem supports conversion to 26 different units, including kilometers, miles, meters, and feet. It also provides methods to validate input. +Calcpace is a Ruby gem designed for calculations and conversions related to distance and time. It can calculate velocity, pace, total time, and distance, accepting time in various formats, including HH:MM:SS. The gem supports conversion to 42 different units, including kilometers, miles, meters, and feet. It also provides methods to validate input. ## Installation ### Add to your Gemfile ```ruby -gem 'calcpace', '~> 1.4.0' +gem 'calcpace', '~> 1.5.0' ``` Then run: @@ -109,29 +109,21 @@ converter.convert(1, :m_s_to_mi_h) # => 2.23694 | :km_to_meters | Kilometers to Meters | | :meters_to_mi | Meters to Miles | | :mi_to_meters | Miles to Meters | -| :meters_to_feet | Meters to Feet | -| :feet_to_meters | Feet to Meters | -| :meters_to_yards | Meters to Yards | -| :yards_to_meters | Yards to Meters | -| :meters_to_inches | Meters to Inches | -| :inches_to_meters | Inches to Meters | | :m_s_to_km_h | Meters per Second to Kilometers per Hour | | :km_h_to_m_s | Kilometers per Hour to Meters per Second | | :m_s_to_mi_h | Meters per Second to Miles per Hour | | :mi_h_to_m_s | Miles per Hour to Meters per Second | -| :m_s_to_nautical_mi_h| Meters per Second to Nautical Miles per Hour | -| :nautical_mi_h_to_m_s| Nautical Miles per Hour to Meters per Second | | :m_s_to_feet_s | Meters per Second to Feet per Second | | :feet_s_to_m_s | Feet per Second to Meters per Second | -| :m_s_to_knots | Meters per Second to Knots | -| :knots_to_m_s | Knots to Meters per Second | | :km_h_to_mi_h | Kilometers per Hour to Miles per Hour | | :mi_h_to_km_h | Miles per Hour to Kilometers per Hour | -You can list all the available units using the `list_units` method: +You can list all the available units using `list` methods: ```ruby -converter.list_units +converter.list_all +converter.list_distance +converter.list_speed ``` ### Other Useful Methods diff --git a/calcpace.gemspec b/calcpace.gemspec index 9db6176..1a44ba9 100644 --- a/calcpace.gemspec +++ b/calcpace.gemspec @@ -2,9 +2,9 @@ Gem::Specification.new do |s| s.name = 'calcpace' - s.version = '1.4.0' - s.summary = 'Calcpace: calculate total, distance, velocity and convert distances in an easy way.' - s.description = 'Calcpace is designed for calculations and conversions related to distance and time. It can calculate velocity, pace, total time, and distance and it supports conversion to 26 different units, including kilometers, miles, meters, and feet.' + s.version = '1.5.0' + s.summary = 'Calcpace: calculate total, distance, speed, and convert distances and velocity in an easy way.' + s.description = 'It is designed for calculations related to distance, speed and time. The gem also supports conversion to 42 different units of distance and velocity, including metric, nautical and imperial units.' s.authors = ['Joao Gilberto Saraiva'] s.email = 'joaogilberto@tuta.io' s.files = ['lib/calcpace.rb', 'lib/calcpace/calculator.rb', 'lib/calcpace/checker.rb', diff --git a/lib/calcpace.rb b/lib/calcpace.rb index d97536c..92095f9 100644 --- a/lib/calcpace.rb +++ b/lib/calcpace.rb @@ -10,7 +10,5 @@ class Calcpace include Checker include Converter - attr_reader :bigdecimal - def initialize; end end diff --git a/lib/calcpace/calculator.rb b/lib/calcpace/calculator.rb index 434774f..7bb0f51 100644 --- a/lib/calcpace/calculator.rb +++ b/lib/calcpace/calculator.rb @@ -3,67 +3,66 @@ # Module to calculate time, distance, pace and velocity module Calculator def velocity(time, distance) - check_positive(distance) - check_positive(time) + validate_positive(time, distance) distance.to_f / time end def checked_velocity(time, distance) - check_time(time) - seconds = convert_to_seconds(time) + seconds = convert_to_seconds(validate_time(time)) velocity(seconds, distance) end def clock_velocity(time, distance) - velocity_in_seconds = checked_velocity(time, distance) - convert_to_clocktime(velocity_in_seconds) + convert_to_clocktime(checked_velocity(time, distance)) end def pace(time, distance) - check_positive(distance) - check_positive(time) + validate_positive(time, distance) time.to_f / distance end def checked_pace(time, distance) - check_time(time) - seconds = convert_to_seconds(time) + seconds = convert_to_seconds(validate_time(time)) pace(seconds, distance) end def clock_pace(time, distance) - velocity_in_seconds = checked_pace(time, distance) - convert_to_clocktime(velocity_in_seconds) + convert_to_clocktime(checked_pace(time, distance)) end def time(velocity, distance) - check_positive(distance) - check_positive(velocity) + validate_positive(velocity, distance) velocity * distance end def checked_time(velocity, distance) - check_time(velocity) - velocity_seconds = convert_to_seconds(velocity) + velocity_seconds = convert_to_seconds(validate_time(velocity)) time(velocity_seconds, distance) end def clock_time(velocity, distance) - total_time_in_seconds = checked_time(velocity, distance) - convert_to_clocktime(total_time_in_seconds) + convert_to_clocktime(checked_time(velocity, distance)) end def distance(time, velocity) - check_positive(time) - check_positive(velocity) + validate_positive(time, velocity) time.to_f / velocity end def checked_distance(time, velocity) - check_time(time) - check_time(velocity) - time_seconds = convert_to_seconds(time) - velocity_seconds = convert_to_seconds(velocity) + time_seconds = convert_to_seconds(validate_time(time)) + velocity_seconds = convert_to_seconds(validate_time(velocity)) distance(time_seconds, velocity_seconds) end + + private + + def validate_positive(*values) + values.each { |value| check_positive(value) } + end + + def validate_time(time) + check_time(time) + time + end end diff --git a/lib/calcpace/checker.rb b/lib/calcpace/checker.rb index 6b6dd06..708dc07 100644 --- a/lib/calcpace/checker.rb +++ b/lib/calcpace/checker.rb @@ -3,10 +3,10 @@ # Module to check if the input is valid or of the correct type module Checker def check_positive(number) - raise 'It must be a X.X positive number' unless number.positive? + raise ArgumentError, 'It must be a positive number' unless number.is_a?(Numeric) && number.positive? end def check_time(time_string) - raise 'It must be a XX:XX:XX time' unless time_string =~ /\d{0,2}(:)*?\d{1,2}(:)\d{1,2}/ + raise ArgumentError, 'It must be a valid time in the format XX:XX:XX' unless time_string =~ /\A\d{1,2}:\d{2}:\d{2}\z/ end end diff --git a/lib/calcpace/converter.rb b/lib/calcpace/converter.rb index 896ecd5..7457bc7 100644 --- a/lib/calcpace/converter.rb +++ b/lib/calcpace/converter.rb @@ -2,33 +2,53 @@ # Module to convert units module Converter - KM_TO_MI = 0.621371 - MI_TO_KM = 1.60934 - NAUTICAL_MI_TO_KM = 1.852 - KM_TO_NAUTICAL_MI = 0.539957 - METERS_TO_KM = 0.001 - KM_TO_METERS = 1000 - METERS_TO_MI = 0.000621371 - MI_TO_METERS = 1609.34 - METERS_TO_FEET = 3.28084 - FEET_TO_METERS = 0.3048 - METERS_TO_YARDS = 1.09361 - YARDS_TO_METERS = 0.9144 - METERS_TO_INCHES = 39.3701 - INCHES_TO_METERS = 0.0254 - - M_S_TO_KM_H = 3.6 - KM_H_TO_M_S = 0.277778 - M_S_TO_MI_H = 2.23694 - MI_H_TO_M_S = 0.44704 - M_S_TO_NAUTICAL_MI_H = 1.94384 - NAUTICAL_MI_H_TO_M_S = 0.514444 - M_S_TO_FEET_S = 3.28084 - FEET_S_TO_M_S = 0.3048 - M_S_TO_KNOTS = 1.94384 - KNOTS_TO_M_S = 0.514444 - KM_H_TO_MI_H = 0.621371 - MI_H_TO_KM_H = 1.60934 + module Distance + KM_TO_MI = 0.621371 + MI_TO_KM = 1.60934 + NAUTICAL_MI_TO_KM = 1.852 + KM_TO_NAUTICAL_MI = 0.539957 + METERS_TO_KM = 0.001 + KM_TO_METERS = 1000 + METERS_TO_MI = 0.000621371 + MI_TO_METERS = 1609.34 + METERS_TO_FEET = 3.28084 + FEET_TO_METERS = 0.3048 + METERS_TO_YARDS = 1.09361 + YARDS_TO_METERS = 0.9144 + METERS_TO_INCHES = 39.3701 + INCHES_TO_METERS = 0.0254 + KM_TO_YARDS = 1093.61 + YARDS_TO_KM = 0.0009144 + KM_TO_FEET = 3280.84 + FEET_TO_KM = 0.0003048 + KM_TO_INCHES = 39_370.1 + INCHES_TO_KM = 0.0000254 + MI_TO_YARDS = 1760 + YARDS_TO_MI = 0.000568182 + MI_TO_FEET = 5280 + FEET_TO_MI = 0.000189394 + MI_TO_INCHES = 63_360 + INCHES_TO_MI = 0.0000157828 + end + + module Speed + M_S_TO_KM_H = 3.6 + KM_H_TO_M_S = 0.277778 + M_S_TO_MI_H = 2.23694 + MI_H_TO_M_S = 0.44704 + M_S_TO_NAUTICAL_MI_H = 1.94384 + NAUTICAL_MI_H_TO_M_S = 0.514444 + M_S_TO_FEET_S = 3.28084 + FEET_S_TO_M_S = 0.3048 + M_S_TO_KNOTS = 1.94384 + KNOTS_TO_M_S = 0.514444 + KM_H_TO_MI_H = 0.621371 + MI_H_TO_KM_H = 1.60934 + KM_H_TO_NAUTICAL_MI_H = 0.539957 + NAUTICAL_MI_H_TO_KM_H = 1.852 + MI_H_TO_NAUTICAL_MI_H = 0.868976 + NAUTICAL_MI_H_TO_MI_H = 1.15078 + end def convert(value, unit) check_positive(value) @@ -47,10 +67,20 @@ def convert_to_clocktime(seconds) end def constant(symbol) - Converter.const_get(symbol.to_s.upcase) + Distance.const_get(symbol.to_s.upcase) + rescue NameError + Speed.const_get(symbol.to_s.upcase) + end + + def list_all + (Distance.constants + Speed.constants).map { |c| c.downcase.to_sym } + end + + def list_speed + Speed.constants.map { |c| c.downcase.to_sym } end - def list_constants - Converter.constants.map { |c| c.downcase.to_sym } + def list_distance + Distance.constants.map { |c| c.downcase.to_sym } end end diff --git a/test/calcpace/test_calculator.rb b/test/calcpace/test_calculator.rb index 3f562bf..ef3e302 100644 --- a/test/calcpace/test_calculator.rb +++ b/test/calcpace/test_calculator.rb @@ -13,25 +13,25 @@ def test_velocity assert_equal 3.333, @checker.velocity(3600, 12_000).round(3) assert_equal 12.3, @checker.velocity(5841, 71_844.3) assert_equal 3.6, @checker.velocity(10_000, 36_000.0) - assert_raises(RuntimeError) { @checker.velocity(0, 10) } - assert_raises(RuntimeError) { @checker.velocity(10, -1) } + assert_raises(ArgumentError) { @checker.velocity(0, 10) } + assert_raises(ArgumentError) { @checker.velocity(10, -1) } end def test_checked_velocity - assert_raises(RuntimeError) { @checker.checked_velocity('', 10) } - assert_raises(RuntimeError) { @checker.checked_velocity('invalid', 10) } - assert_raises(RuntimeError) { @checker.checked_velocity('00:00:00', 0) } - assert_raises(RuntimeError) { @checker.checked_velocity('00:00:00', -1) } + assert_raises(ArgumentError) { @checker.checked_velocity('', 10) } + assert_raises(ArgumentError) { @checker.checked_velocity('invalid', 10) } + assert_raises(ArgumentError) { @checker.checked_velocity('00:00:00', 0) } + assert_raises(ArgumentError) { @checker.checked_velocity('00:00:00', -1) } assert_equal 2.778, @checker.checked_velocity('01:00:00', 10_000).round(3) assert_equal 10, @checker.checked_velocity('00:00:01', 10) assert_equal 12.3, @checker.checked_velocity('01:37:21', 71_844.3) end def test_clock_velocity - assert_raises(RuntimeError) { @checker.clock_velocity('', 10) } - assert_raises(RuntimeError) { @checker.clock_velocity('invalid', 10) } - assert_raises(RuntimeError) { @checker.clock_velocity('00:00:00', 0) } - assert_raises(RuntimeError) { @checker.clock_velocity('00:00:00', -1) } + assert_raises(ArgumentError) { @checker.clock_velocity('', 10) } + assert_raises(ArgumentError) { @checker.clock_velocity('invalid', 10) } + assert_raises(ArgumentError) { @checker.clock_velocity('00:00:00', 0) } + assert_raises(ArgumentError) { @checker.clock_velocity('00:00:00', -1) } assert_equal '00:00:02', @checker.clock_velocity('01:00:00', 10_000) assert_equal '00:00:12', @checker.clock_velocity('01:37:21', 71_844.3) end @@ -39,24 +39,24 @@ def test_clock_velocity def test_pace assert_equal 300, @checker.pace(3600, 12) assert_equal 122.81076923076924, @checker.pace(71_844.3, 585.0) - assert_raises(RuntimeError) { @checker.pace(0, 10) } - assert_raises(RuntimeError) { @checker.pace(10, -1) } + assert_raises(ArgumentError) { @checker.pace(0, 10) } + assert_raises(ArgumentError) { @checker.pace(10, -1) } end def test_checked_pace - assert_raises(RuntimeError) { @checker.checked_pace('', 10) } - assert_raises(RuntimeError) { @checker.checked_pace('invalid', 10) } - assert_raises(RuntimeError) { @checker.checked_pace('00:00:00', 0) } - assert_raises(RuntimeError) { @checker.checked_pace('00:00:00', -1) } + assert_raises(ArgumentError) { @checker.checked_pace('', 10) } + assert_raises(ArgumentError) { @checker.checked_pace('invalid', 10) } + assert_raises(ArgumentError) { @checker.checked_pace('00:00:00', 0) } + assert_raises(ArgumentError) { @checker.checked_pace('00:00:00', -1) } assert_equal 360, @checker.checked_pace('01:00:00', 10) assert_equal 474.8780487804878, @checker.checked_pace('01:37:21', 12.3) end def test_clock_pace - assert_raises(RuntimeError) { @checker.clock_pace('', 10) } - assert_raises(RuntimeError) { @checker.clock_pace('invalid', 10) } - assert_raises(RuntimeError) { @checker.clock_pace('00:00:00', 0) } - assert_raises(RuntimeError) { @checker.clock_pace('00:00:00', -1) } + assert_raises(ArgumentError) { @checker.clock_pace('', 10) } + assert_raises(ArgumentError) { @checker.clock_pace('invalid', 10) } + assert_raises(ArgumentError) { @checker.clock_pace('00:00:00', 0) } + assert_raises(ArgumentError) { @checker.clock_pace('00:00:00', -1) } assert_equal '00:06:00', @checker.clock_pace('01:00:00', 10) assert_equal '00:07:54', @checker.clock_pace('01:37:21', 12.3) end @@ -64,37 +64,37 @@ def test_clock_pace def test_time assert_equal 43_200, @checker.time(3600, 12) assert_equal 5841.0, @checker.time(12.3, 474.8780487804878) - assert_raises(RuntimeError) { @checker.time(0, 10) } - assert_raises(RuntimeError) { @checker.time(10, -1) } + assert_raises(ArgumentError) { @checker.time(0, 10) } + assert_raises(ArgumentError) { @checker.time(10, -1) } end def test_checked_time - assert_raises(RuntimeError) { @checker.checked_time('', 10) } - assert_raises(RuntimeError) { @checker.checked_time('invalid', 10) } - assert_raises(RuntimeError) { @checker.checked_time('00:00:00', 0) } - assert_raises(RuntimeError) { @checker.checked_time('00:00:00', -1) } + assert_raises(ArgumentError) { @checker.checked_time('', 10) } + assert_raises(ArgumentError) { @checker.checked_time('invalid', 10) } + assert_raises(ArgumentError) { @checker.checked_time('00:00:00', 0) } + assert_raises(ArgumentError) { @checker.checked_time('00:00:00', -1) } assert_equal 3600, @checker.checked_time('00:05:00', 12) assert_equal 71_844.3, @checker.checked_time('01:37:21', 12.3) end def test_clock_time - assert_raises(RuntimeError) { @checker.clock_time('', 10) } - assert_raises(RuntimeError) { @checker.clock_time('invalid', 10) } - assert_raises(RuntimeError) { @checker.clock_time('00:00:00', 0) } - assert_raises(RuntimeError) { @checker.clock_time('00:00:00', -1) } + assert_raises(ArgumentError) { @checker.clock_time('', 10) } + assert_raises(ArgumentError) { @checker.clock_time('invalid', 10) } + assert_raises(ArgumentError) { @checker.clock_time('00:00:00', 0) } + assert_raises(ArgumentError) { @checker.clock_time('00:00:00', -1) } assert_equal '01:00:00', @checker.clock_time('00:05:00', 12) end def test_distance assert_equal 30, @checker.distance(3600, 120) assert_equal 12.3, @checker.distance(5841.0, 474.8780487804878) - assert_raises(RuntimeError) { @checker.distance(0, 10) } - assert_raises(RuntimeError) { @checker.distance(10, -1) } + assert_raises(ArgumentError) { @checker.distance(0, 10) } + assert_raises(ArgumentError) { @checker.distance(10, -1) } end def test_checked_distance - assert_raises(RuntimeError) { @checker.checked_distance('', '00:05:00') } - assert_raises(RuntimeError) { @checker.checked_distance('01:00:00', '') } + assert_raises(ArgumentError) { @checker.checked_distance('', '00:05:00') } + assert_raises(ArgumentError) { @checker.checked_distance('01:00:00', '') } assert_equal 18.0, @checker.checked_distance('01:30:00', '00:05:00') assert_equal 15.493, @checker.checked_distance('01:37:21', '00:06:17').round(3) end diff --git a/test/calcpace/test_checker.rb b/test/calcpace/test_checker.rb index bda723e..059c40c 100644 --- a/test/calcpace/test_checker.rb +++ b/test/calcpace/test_checker.rb @@ -9,13 +9,13 @@ def setup end def test_check_positive - assert_raises(RuntimeError) { @checker.check_positive(-1) } - assert_raises(RuntimeError) { @checker.check_positive(0) } + assert_raises(ArgumentError) { @checker.check_positive(-1) } + assert_raises(ArgumentError) { @checker.check_positive(0) } assert_nil @checker.check_positive(1) end def test_check_time - assert_raises(RuntimeError) { @checker.check_time('') } + assert_raises(ArgumentError) { @checker.check_time('') } assert_nil @checker.check_time('00:00:00') end end diff --git a/test/calcpace/test_converter.rb b/test/calcpace/test_converter.rb index 50d2790..c9d5847 100644 --- a/test/calcpace/test_converter.rb +++ b/test/calcpace/test_converter.rb @@ -61,7 +61,15 @@ def test_constant assert_equal 1.852, @checker.constant(:nautical_mi_to_km) end - def test_list_constants - assert_equal 26, @checker.list_constants.size + def test_list_all + assert_equal 42, @checker.list_all.size + end + + def test_list_speed + assert_equal 16, @checker.list_speed.size + end + + def test_list_distance_constants + assert_equal 26, @checker.list_distance.size end end