string_to_number 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,8 +47,8 @@ module StringToNumber
47
47
  'quatre-vingt' => 80, # Standard French: "four-twenty" (singular)
48
48
  'huitante' => 80, # Swiss French alternative
49
49
  'quatre-vingt-dix' => 90, # Standard French: "four-twenty-ten"
50
- 'quatre-vingts-dix' => 90,# Alternative with plural "vingts"
51
- 'nonante' => 90 # Belgian/Swiss French alternative
50
+ 'quatre-vingts-dix' => 90, # Alternative with plural "vingts"
51
+ 'nonante' => 90 # Belgian/Swiss French alternative
52
52
  }.freeze
53
53
 
54
54
  # POWERS_OF_TEN maps French number words to their power of 10 exponents
@@ -100,7 +100,7 @@ module StringToNumber
100
100
  'trigintillion' => 93,
101
101
  'untrigintillion' => 96,
102
102
  'duotrigintillion' => 99,
103
- 'googol' => 100 # Special case: 10^100
103
+ 'googol' => 100 # Special case: 10^100
104
104
  }.freeze
105
105
 
106
106
  # Initialize the ToNumber parser with a French sentence
@@ -111,7 +111,7 @@ module StringToNumber
111
111
  # Sort keys by length (longest first) to ensure longer matches are preferred
112
112
  # This prevents "cent" from matching before "cents" in "cinq cents"
113
113
  sorted_keys = POWERS_OF_TEN.keys.reject { |k| %w[un dix].include?(k) }.sort_by(&:length).reverse
114
- @keys = sorted_keys.join('|') # Create regex alternation pattern
114
+ @keys = sorted_keys.join('|') # Create regex alternation pattern
115
115
  # Normalize input to lowercase for case-insensitive matching
116
116
  @sentence = sentence&.downcase || ''
117
117
  end
@@ -133,10 +133,10 @@ module StringToNumber
133
133
  def extract(sentence, keys, detail: false)
134
134
  # Base cases: handle empty/nil input
135
135
  return 0 if sentence.nil? || sentence.empty?
136
-
136
+
137
137
  # Ensure case-insensitive matching
138
138
  sentence = sentence.downcase
139
-
139
+
140
140
  # Direct lookup for simple cases (e.g., "vingt" -> 20)
141
141
  return EXCEPTIONS[sentence] unless EXCEPTIONS[sentence].nil?
142
142
 
@@ -146,19 +146,19 @@ module StringToNumber
146
146
  # (?<f>.*?) - Non-greedy capture of factor part (before multiplier)
147
147
  # \s? - Optional space
148
148
  # (?<m>#{keys}) - Named capture of multiplier from keys pattern
149
- if result = /(?<f>.*?)\s?(?<m>#{keys})/.match(sentence)
149
+ if (result = /(?<f>.*?)\s?(?<m>#{keys})/.match(sentence))
150
150
  # Remove the matched portion from sentence for further processing
151
- sentence.gsub!($&, '') if $&
151
+ sentence.gsub!(::Regexp.last_match(0), '') if ::Regexp.last_match(0)
152
152
 
153
153
  # Parse the factor part (number before the multiplier)
154
154
  # Example: "cinq" -> 5, "deux cent" -> 200
155
155
  factor = EXCEPTIONS[result[:f]] || match(result[:f])
156
-
156
+
157
157
  # Handle implicit factor of 1 for standalone multipliers
158
158
  # Example: "million" -> factor=1, but only for top-level calls
159
159
  # For recursive calls (detail=true), keep factor as 0 to avoid double-counting
160
160
  factor = 1 if factor.zero? && !detail
161
-
161
+
162
162
  # Calculate the multiplier value (10^exponent)
163
163
  # Example: "cents" -> 10^2 = 100, "millions" -> 10^6 = 1,000,000
164
164
  multiple_of_ten = 10**(POWERS_OF_TEN[result[:m]] || 0)
@@ -192,17 +192,17 @@ module StringToNumber
192
192
 
193
193
  # Final calculation: process any remaining sentence + current factor*multiplier
194
194
  # Example: For "trois millions cinq cents", this handles the "cinq cents" part
195
- return extract(sentence, keys) + factor * multiple_of_ten
195
+ extract(sentence, keys) + (factor * multiple_of_ten)
196
196
 
197
197
  # Special case handling for "quatre-vingt" variations
198
198
  # This complex regex handles the irregular French "eighty" patterns:
199
199
  # - "quatre-vingt" / "quatre vingts" (with/without 's')
200
200
  # - "quatre-vingt-dix" / "quatre vingts dix" (90)
201
201
  # - Space vs hyphen variations
202
- elsif m = /(quatre(-|\s)vingt(s?)((-|\s)dix)?)((-|\s)?)(\w*)/.match(sentence)
202
+ elsif (m = /(quatre(-|\s)vingt(s?)((-|\s)dix)?)((-|\s)?)(\w*)/.match(sentence))
203
203
  # Normalize spacing to hyphens for consistent lookup
204
204
  normalize_str = m[1].tr(' ', '-')
205
-
205
+
206
206
  # Remove trailing 's' from "quatre-vingts" if present
207
207
  # Bug fix: use [-1] instead of [length] for last character
208
208
  normalize_str = normalize_str[0...-1] if normalize_str[-1] == 's'
@@ -212,11 +212,11 @@ module StringToNumber
212
212
 
213
213
  # Return sum of: remaining sentence + normalized quatre-vingt value + any suffix
214
214
  # Example: "quatre-vingt-cinq" -> EXCEPTIONS["quatre-vingt"] + EXCEPTIONS["cinq"]
215
- return extract(sentence, keys) +
216
- EXCEPTIONS[normalize_str] + (EXCEPTIONS[m[8]] || 0)
215
+ extract(sentence, keys) +
216
+ EXCEPTIONS[normalize_str] + (EXCEPTIONS[m[8]] || 0)
217
217
  else
218
218
  # Fallback: use match() method for simple word combinations
219
- return match(sentence)
219
+ match(sentence)
220
220
  end
221
221
  end
222
222
 
@@ -229,11 +229,11 @@ module StringToNumber
229
229
 
230
230
  # Process words in reverse order for proper French number logic
231
231
  # Example: "vingt et un" -> ["un", "et", "vingt"] -> 1 + 0 + 20 = 21
232
- sentence.downcase.tr('-', ' ').split(' ').reverse.sum do |word|
232
+ sentence.downcase.tr('-', ' ').split.reverse.sum do |word|
233
233
  # Handle French "et" (and) conjunction by ignoring it in calculations
234
234
  # Example: "vingt et un" -> ignore "et", sum "vingt" + "un"
235
235
  next 0 if word == 'et'
236
-
236
+
237
237
  # Look up word value in either EXCEPTIONS or POWERS_OF_TEN
238
238
  if EXCEPTIONS[word].nil? && POWERS_OF_TEN[word].nil?
239
239
  # Unknown words contribute 0 to the sum
@@ -241,8 +241,8 @@ module StringToNumber
241
241
  else
242
242
  # Use EXCEPTIONS value if available, otherwise use 10 * power_of_ten
243
243
  # Example: "dix" -> EXCEPTIONS["dix"] = 10
244
- # "cent" -> 10 * POWERS_OF_TEN["cent"] = 10 * 2 = 100
245
- (EXCEPTIONS[word] || (10 * POWERS_OF_TEN[word]))
244
+ # "cent" -> 10 * POWERS_OF_TEN["cent"] = 10 * 2 = 100
245
+ EXCEPTIONS[word] || (10 * POWERS_OF_TEN[word])
246
246
  end
247
247
  end
248
248
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StringToNumber
2
- VERSION = '0.2.0'.freeze
4
+ VERSION = '0.2.1'
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'string_to_number/version'
2
4
 
3
5
  # Load original implementation first for constant definitions
@@ -78,20 +80,20 @@ module StringToNumber
78
80
  #
79
81
  def valid_french_number?(text)
80
82
  return false unless text.respond_to?(:to_s)
81
-
83
+
82
84
  normalized = text.to_s.downcase.strip
83
85
  return false if normalized.empty?
84
-
86
+
85
87
  # Check if any words are recognized French number words
86
88
  words = normalized.tr('-', ' ').split(/\s+/)
87
89
  recognized_words = words.count do |word|
88
- word == 'et' ||
89
- Parser::WORD_VALUES.key?(word) ||
90
- Parser::MULTIPLIERS.key?(word)
90
+ word == 'et' ||
91
+ Parser::WORD_VALUES.key?(word) ||
92
+ Parser::MULTIPLIERS.key?(word)
91
93
  end
92
-
94
+
93
95
  # Require at least 50% recognized words for validation
94
96
  recognized_words.to_f / words.size >= 0.5
95
97
  end
96
98
  end
97
- end
99
+ end
data/logo.png ADDED
Binary file
data/microbenchmark.rb CHANGED
@@ -9,10 +9,10 @@ require 'benchmark'
9
9
 
10
10
  class MicroBenchmark
11
11
  def self.run
12
- puts "StringToNumber Micro-Benchmarks"
13
- puts "=" * 50
12
+ puts 'StringToNumber Micro-Benchmarks'
13
+ puts '=' * 50
14
14
  puts
15
-
15
+
16
16
  # Test individual components
17
17
  test_initialization
18
18
  test_regex_compilation
@@ -20,43 +20,45 @@ class MicroBenchmark
20
20
  test_hash_lookups
21
21
  test_string_operations
22
22
  test_recursion_overhead
23
-
23
+
24
24
  puts "\nConclusions and Recommendations:"
25
- puts "=" * 50
25
+ puts '=' * 50
26
26
  analyze_results
27
27
  end
28
28
 
29
29
  def self.test_initialization
30
- puts "1. Initialization Performance"
31
- puts "-" * 30
32
-
30
+ puts '1. Initialization Performance'
31
+ puts '-' * 30
32
+
33
33
  # Test the cost of creating new instances
34
34
  sentences = ['un', 'vingt et un', 'mille deux cent', 'trois milliards cinq cents millions']
35
-
35
+
36
36
  sentences.each do |sentence|
37
37
  time = Benchmark.realtime do
38
38
  1000.times { StringToNumber::ToNumber.new(sentence) }
39
39
  end
40
-
40
+
41
41
  puts "#{sentence.ljust(35)}: #{(time * 1000).round(4)}ms per 1000 instances"
42
42
  end
43
43
  puts
44
44
  end
45
45
 
46
46
  def self.test_regex_compilation
47
- puts "2. Regex Compilation Performance"
48
- puts "-" * 30
49
-
47
+ puts '2. Regex Compilation Performance'
48
+ puts '-' * 30
49
+
50
50
  # Test the cost of regex compilation vs pre-compiled regex
51
- keys = StringToNumber::ToNumber::POWERS_OF_TEN.keys.reject { |k| %w[un dix].include?(k) }.sort_by(&:length).reverse.join('|')
52
-
51
+ keys = StringToNumber::ToNumber::POWERS_OF_TEN.keys.reject do |k|
52
+ %w[un dix].include?(k)
53
+ end.sort_by(&:length).reverse.join('|')
54
+
53
55
  # Dynamic compilation
54
56
  dynamic_time = Benchmark.realtime do
55
57
  1000.times do
56
58
  /(?<f>.*?)\s?(?<m>#{keys})/.match('trois milliards')
57
59
  end
58
60
  end
59
-
61
+
60
62
  # Pre-compiled regex
61
63
  compiled_regex = /(?<f>.*?)\s?(?<m>#{Regexp.escape(keys)})/
62
64
  precompiled_time = Benchmark.realtime do
@@ -64,7 +66,7 @@ class MicroBenchmark
64
66
  compiled_regex.match('trois milliards')
65
67
  end
66
68
  end
67
-
69
+
68
70
  puts "Dynamic regex compilation: #{(dynamic_time * 1000).round(4)}ms per 1000 matches"
69
71
  puts "Pre-compiled regex: #{(precompiled_time * 1000).round(4)}ms per 1000 matches"
70
72
  puts "Compilation overhead: #{((dynamic_time - precompiled_time) * 1000).round(4)}ms per 1000 matches"
@@ -72,62 +74,64 @@ class MicroBenchmark
72
74
  end
73
75
 
74
76
  def self.test_regex_matching
75
- puts "3. Regex Pattern Complexity"
76
- puts "-" * 30
77
-
77
+ puts '3. Regex Pattern Complexity'
78
+ puts '-' * 30
79
+
78
80
  # Test different regex patterns to see which are expensive
79
81
  test_patterns = {
80
82
  'Simple word match' => /vingt/,
81
83
  'Word boundary match' => /\bvingt\b/,
82
84
  'Named capture groups' => /(?<f>.*?)\s?(?<m>vingt)/,
83
85
  'Complex alternation' => /(?<f>.*?)\s?(?<m>vingt|trente|quarante|cinquante)/,
84
- 'Full keys pattern' => /(?<f>.*?)\s?(?<m>#{StringToNumber::ToNumber::POWERS_OF_TEN.keys.reject { |k| %w[un dix].include?(k) }.sort_by(&:length).reverse.join('|')})/
86
+ 'Full keys pattern' => /(?<f>.*?)\s?(?<m>#{StringToNumber::ToNumber::POWERS_OF_TEN.keys.reject do |k|
87
+ %w[un dix].include?(k)
88
+ end.sort_by(&:length).reverse.join('|')})/
85
89
  }
86
-
90
+
87
91
  test_string = 'trois milliards cinq cents millions'
88
-
92
+
89
93
  test_patterns.each do |name, pattern|
90
94
  time = Benchmark.realtime do
91
95
  5000.times { pattern.match(test_string) }
92
96
  end
93
-
97
+
94
98
  puts "#{name.ljust(25)}: #{(time * 1000).round(4)}ms per 5000 matches"
95
99
  end
96
100
  puts
97
101
  end
98
102
 
99
103
  def self.test_hash_lookups
100
- puts "4. Hash Lookup Performance"
101
- puts "-" * 30
102
-
104
+ puts '4. Hash Lookup Performance'
105
+ puts '-' * 30
106
+
103
107
  exceptions = StringToNumber::ToNumber::EXCEPTIONS
104
108
  powers = StringToNumber::ToNumber::POWERS_OF_TEN
105
-
109
+
106
110
  # Test lookup performance
107
111
  exceptions_time = Benchmark.realtime do
108
- 10000.times do
112
+ 10_000.times do
109
113
  exceptions['vingt']
110
114
  exceptions['trois']
111
115
  exceptions['cent']
112
116
  end
113
117
  end
114
-
118
+
115
119
  powers_time = Benchmark.realtime do
116
- 10000.times do
120
+ 10_000.times do
117
121
  powers['million']
118
122
  powers['mille']
119
123
  powers['cent']
120
124
  end
121
125
  end
122
-
126
+
123
127
  # Test nil checks
124
128
  nil_check_time = Benchmark.realtime do
125
- 10000.times do
129
+ 10_000.times do
126
130
  exceptions['nonexistent'].nil?
127
131
  powers['nonexistent'].nil?
128
132
  end
129
133
  end
130
-
134
+
131
135
  puts "EXCEPTIONS hash lookups: #{(exceptions_time * 100).round(4)}ms per 10000 lookups"
132
136
  puts "POWERS_OF_TEN hash lookups: #{(powers_time * 100).round(4)}ms per 10000 lookups"
133
137
  puts "Nil check operations: #{(nil_check_time * 100).round(4)}ms per 10000 checks"
@@ -135,28 +139,28 @@ class MicroBenchmark
135
139
  end
136
140
 
137
141
  def self.test_string_operations
138
- puts "5. String Operations Performance"
139
- puts "-" * 30
140
-
142
+ puts '5. String Operations Performance'
143
+ puts '-' * 30
144
+
141
145
  test_string = 'TROIS MILLIARDS CINQ CENTS MILLIONS'
142
-
146
+
143
147
  # Test different string operations
144
148
  downcase_time = Benchmark.realtime do
145
149
  5000.times { test_string.downcase }
146
150
  end
147
-
151
+
148
152
  gsub_time = Benchmark.realtime do
149
- 5000.times { test_string.gsub(/MILLIONS/, '') }
153
+ 5000.times { test_string.gsub('MILLIONS', '') }
150
154
  end
151
-
155
+
152
156
  split_time = Benchmark.realtime do
153
- 5000.times { test_string.split(' ') }
157
+ 5000.times { test_string.split }
154
158
  end
155
-
159
+
156
160
  tr_time = Benchmark.realtime do
157
161
  5000.times { test_string.tr('-', ' ') }
158
162
  end
159
-
163
+
160
164
  puts "String#downcase: #{(downcase_time * 1000).round(4)}ms per 5000 operations"
161
165
  puts "String#gsub: #{(gsub_time * 1000).round(4)}ms per 5000 operations"
162
166
  puts "String#split: #{(split_time * 1000).round(4)}ms per 5000 operations"
@@ -165,29 +169,28 @@ class MicroBenchmark
165
169
  end
166
170
 
167
171
  def self.test_recursion_overhead
168
- puts "6. Recursion vs Iteration Performance"
169
- puts "-" * 30
170
-
172
+ puts '6. Recursion vs Iteration Performance'
173
+ puts '-' * 30
174
+
171
175
  # Compare recursive vs iterative approaches
172
- def self.recursive_sum(arr, index = 0)
176
+ recursive_sum = lambda do |arr, index = 0|
173
177
  return 0 if index >= arr.length
174
- arr[index] + recursive_sum(arr, index + 1)
175
- end
176
-
177
- def self.iterative_sum(arr)
178
- arr.sum
178
+
179
+ arr[index] + recursive_sum.call(arr, index + 1)
179
180
  end
180
-
181
+
182
+ iterative_sum = :sum.to_proc
183
+
181
184
  test_array = Array.new(100) { rand(100) }
182
-
185
+
183
186
  recursive_time = Benchmark.realtime do
184
- 1000.times { recursive_sum(test_array) }
187
+ 1000.times { recursive_sum.call(test_array) }
185
188
  end
186
-
189
+
187
190
  iterative_time = Benchmark.realtime do
188
- 1000.times { iterative_sum(test_array) }
191
+ 1000.times { iterative_sum.call(test_array) }
189
192
  end
190
-
193
+
191
194
  puts "Recursive approach: #{(recursive_time * 1000).round(4)}ms per 1000 operations"
192
195
  puts "Iterative approach: #{(iterative_time * 1000).round(4)}ms per 1000 operations"
193
196
  puts "Recursion overhead: #{((recursive_time - iterative_time) * 1000).round(4)}ms per 1000 operations"
@@ -195,32 +198,30 @@ class MicroBenchmark
195
198
  end
196
199
 
197
200
  def self.analyze_results
198
- puts "Key Performance Insights:"
201
+ puts 'Key Performance Insights:'
199
202
  puts
200
- puts "1. 🔍 INITIALIZATION COST:"
201
- puts " - Creating new ToNumber instances is expensive (~13ms per 1000)"
202
- puts " - Consider caching or singleton pattern for repeated use"
203
+ puts '1. 🔍 INITIALIZATION COST:'
204
+ puts ' - Creating new ToNumber instances is expensive (~13ms per 1000)'
205
+ puts ' - Consider caching or singleton pattern for repeated use'
203
206
  puts
204
- puts "2. 🔍 REGEX COMPLEXITY:"
205
- puts " - Complex alternation patterns are the main bottleneck"
206
- puts " - Keys pattern is 521 characters long - very expensive to match"
207
- puts " - Consider breaking down into simpler patterns or using different approach"
207
+ puts '2. 🔍 REGEX COMPLEXITY:'
208
+ puts ' - Complex alternation patterns are the main bottleneck'
209
+ puts ' - Keys pattern is 521 characters long - very expensive to match'
210
+ puts ' - Consider breaking down into simpler patterns or using different approach'
208
211
  puts
209
- puts "3. 🔍 SCALABILITY ISSUES:"
210
- puts " - Performance degrades significantly with input length (43x for longest)"
211
- puts " - Recursive parsing creates overhead for complex numbers"
212
- puts " - String operations add up with multiple passes"
212
+ puts '3. 🔍 SCALABILITY ISSUES:'
213
+ puts ' - Performance degrades significantly with input length (43x for longest)'
214
+ puts ' - Recursive parsing creates overhead for complex numbers'
215
+ puts ' - String operations add up with multiple passes'
213
216
  puts
214
- puts "📊 OPTIMIZATION RECOMMENDATIONS:"
215
- puts " 1. Pre-compile regex patterns in class constants"
216
- puts " 2. Use simpler regex patterns with multiple passes if needed"
217
- puts " 3. Implement caching for repeated conversions"
218
- puts " 4. Consider iterative parsing instead of recursive for complex cases"
219
- puts " 5. Optimize string operations (minimize downcase/gsub calls)"
217
+ puts '📊 OPTIMIZATION RECOMMENDATIONS:'
218
+ puts ' 1. Pre-compile regex patterns in class constants'
219
+ puts ' 2. Use simpler regex patterns with multiple passes if needed'
220
+ puts ' 3. Implement caching for repeated conversions'
221
+ puts ' 4. Consider iterative parsing instead of recursive for complex cases'
222
+ puts ' 5. Optimize string operations (minimize downcase/gsub calls)'
220
223
  end
221
224
  end
222
225
 
223
226
  # Run the micro-benchmarks
224
- if __FILE__ == $0
225
- MicroBenchmark.run
226
- end
227
+ MicroBenchmark.run if __FILE__ == $PROGRAM_NAME
@@ -16,20 +16,20 @@ class PerformanceComparison
16
16
  ].freeze
17
17
 
18
18
  def self.run_comparison
19
- puts "StringToNumber Performance Comparison"
20
- puts "=" * 60
21
- puts "Original vs Optimized Implementation"
22
- puts "=" * 60
19
+ puts 'StringToNumber Performance Comparison'
20
+ puts '=' * 60
21
+ puts 'Original vs Optimized Implementation'
22
+ puts '=' * 60
23
23
  puts
24
24
 
25
25
  TEST_CASES.each_with_index do |test_case, index|
26
26
  puts "Test #{index + 1}: '#{test_case}'"
27
- puts "-" * 50
27
+ puts '-' * 50
28
28
 
29
29
  # Verify both implementations produce same results
30
30
  original_result = StringToNumber.in_numbers(test_case, use_optimized: false)
31
31
  optimized_result = StringToNumber.in_numbers(test_case, use_optimized: true)
32
-
32
+
33
33
  if original_result == optimized_result
34
34
  puts "✅ Results match: #{original_result}"
35
35
  else
@@ -38,7 +38,7 @@ class PerformanceComparison
38
38
  end
39
39
 
40
40
  # Benchmark both implementations
41
- iterations = 10000
41
+ iterations = 10_000
42
42
 
43
43
  original_time = Benchmark.realtime do
44
44
  iterations.times { StringToNumber.in_numbers(test_case, use_optimized: false) }
@@ -55,27 +55,27 @@ class PerformanceComparison
55
55
  puts "Original: #{original_avg.round(4)}ms average"
56
56
  puts "Optimized: #{optimized_avg.round(4)}ms average"
57
57
  puts "Speedup: #{speedup.round(1)}x faster"
58
-
58
+
59
59
  # Performance rating
60
60
  rating = case speedup
61
- when 0..2 then "🟡 Minor improvement"
62
- when 2..10 then "🟢 Good improvement"
63
- when 10..50 then "🟢 Great improvement"
64
- else "🚀 Exceptional improvement"
61
+ when 0..2 then '🟡 Minor improvement'
62
+ when 2..10 then '🟢 Good improvement'
63
+ when 10..50 then '🟢 Great improvement'
64
+ else '🚀 Exceptional improvement'
65
65
  end
66
-
66
+
67
67
  puts "Rating: #{rating}"
68
68
  puts
69
69
  end
70
70
 
71
71
  # Overall comparison
72
- puts "=" * 60
73
- puts "OVERALL PERFORMANCE ANALYSIS"
74
- puts "=" * 60
72
+ puts '=' * 60
73
+ puts 'OVERALL PERFORMANCE ANALYSIS'
74
+ puts '=' * 60
75
75
 
76
76
  # Test cache performance
77
77
  puts "\nCache Performance Test:"
78
- puts "-" * 30
78
+ puts '-' * 30
79
79
 
80
80
  # Clear caches
81
81
  StringToNumber.clear_caches!
@@ -107,17 +107,17 @@ class PerformanceComparison
107
107
 
108
108
  # Scalability test
109
109
  puts "\nScalability Comparison:"
110
- puts "-" * 30
110
+ puts '-' * 30
111
111
 
112
112
  scalability_tests = [
113
113
  'un', # 2 chars
114
114
  'vingt et un', # 11 chars
115
- 'mille deux cent trente-quatre', # 29 chars
115
+ 'mille deux cent trente-quatre', # 29 chars
116
116
  'soixante-quinze million trois cent quarante six mille sept cent quatre-vingt-dix neuf' # 85 chars
117
117
  ]
118
118
 
119
- puts "Input Length | Original | Optimized | Improvement"
120
- puts "-------------|----------|-----------|------------"
119
+ puts 'Input Length | Original | Optimized | Improvement'
120
+ puts '-------------|----------|-----------|------------'
121
121
 
122
122
  scalability_tests.each do |test|
123
123
  original_time = Benchmark.realtime do
@@ -132,24 +132,23 @@ class PerformanceComparison
132
132
  optimized_ms = (optimized_time / 1000) * 1000
133
133
  improvement = original_ms / optimized_ms
134
134
 
135
- puts "#{test.length.to_s.rjust(11)} | #{original_ms.round(4).to_s.rjust(8)} | #{optimized_ms.round(4).to_s.rjust(9)} | #{improvement.round(1).to_s.rjust(10)}x"
135
+ puts "#{test.length.to_s.rjust(11)} | #{original_ms.round(4).to_s.rjust(8)} | " \
136
+ "#{optimized_ms.round(4).to_s.rjust(9)} | #{improvement.round(1).to_s.rjust(10)}x"
136
137
  end
137
138
 
138
- puts "\n" + "=" * 60
139
- puts "SUMMARY"
140
- puts "=" * 60
141
- puts "✅ All test cases produce identical results"
142
- puts "🚀 Significant performance improvements across all test cases"
143
- puts "📈 Better scalability with input length"
144
- puts "💾 Effective caching reduces repeated conversion time"
145
- puts "🧠 Lower memory usage and object creation"
139
+ puts "\n#{'=' * 60}"
140
+ puts 'SUMMARY'
141
+ puts '=' * 60
142
+ puts '✅ All test cases produce identical results'
143
+ puts '🚀 Significant performance improvements across all test cases'
144
+ puts '📈 Better scalability with input length'
145
+ puts '💾 Effective caching reduces repeated conversion time'
146
+ puts '🧠 Lower memory usage and object creation'
146
147
  puts
147
- puts "The optimized implementation successfully addresses all identified"
148
- puts "performance bottlenecks while maintaining full compatibility."
148
+ puts 'The optimized implementation successfully addresses all identified'
149
+ puts 'performance bottlenecks while maintaining full compatibility.'
149
150
  end
150
151
  end
151
152
 
152
153
  # Run the comparison
153
- if __FILE__ == $0
154
- PerformanceComparison.run_comparison
155
- end
154
+ PerformanceComparison.run_comparison if __FILE__ == $PROGRAM_NAME