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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +83 -0
- data/.rubocop.yml +110 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +32 -1
- data/README.md +9 -5
- data/Rakefile +5 -1
- data/benchmark.rb +41 -40
- data/lib/string_to_number/parser.rb +20 -18
- data/lib/string_to_number/to_number.rb +20 -20
- data/lib/string_to_number/version.rb +3 -1
- data/lib/string_to_number.rb +9 -7
- data/logo.png +0 -0
- data/microbenchmark.rb +81 -80
- data/performance_comparison.rb +34 -35
- data/profile.rb +44 -45
- data/string_to_number.gemspec +5 -6
- metadata +7 -45
data/profile.rb
CHANGED
@@ -8,93 +8,92 @@ require_relative 'lib/string_to_number'
|
|
8
8
|
|
9
9
|
begin
|
10
10
|
require 'ruby-prof'
|
11
|
-
|
11
|
+
|
12
12
|
# Profile the most complex case
|
13
13
|
test_input = 'soixante-quinze million trois cent quarante six mille sept cent quatre-vingt-dix neuf'
|
14
|
-
|
15
|
-
puts
|
14
|
+
|
15
|
+
puts 'Profiling StringToNumber with input:'
|
16
16
|
puts "'#{test_input}'"
|
17
|
-
puts
|
18
|
-
|
17
|
+
puts '=' * 80
|
18
|
+
|
19
19
|
# Start profiling
|
20
20
|
RubyProf.start
|
21
|
-
|
21
|
+
|
22
22
|
# Run the conversion many times
|
23
23
|
5000.times do
|
24
24
|
StringToNumber.in_numbers(test_input)
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
# Stop profiling
|
28
28
|
result = RubyProf.stop
|
29
|
-
|
29
|
+
|
30
30
|
# Print results
|
31
31
|
puts "\nTop 20 methods by total time:"
|
32
|
-
puts
|
33
|
-
|
32
|
+
puts '-' * 80
|
33
|
+
|
34
34
|
printer = RubyProf::FlatPrinter.new(result)
|
35
|
-
printer.print(
|
36
|
-
|
35
|
+
printer.print($stdout, min_percent: 1)
|
36
|
+
|
37
37
|
# Generate call graph
|
38
38
|
puts "\n\nCall Graph Analysis:"
|
39
|
-
puts
|
40
|
-
|
39
|
+
puts '-' * 80
|
40
|
+
|
41
41
|
printer = RubyProf::CallTreePrinter.new(result)
|
42
42
|
File.open('profile_output.txt', 'w') do |file|
|
43
43
|
printer.print(file)
|
44
44
|
end
|
45
|
-
puts
|
46
|
-
|
45
|
+
puts 'Detailed call graph saved to: profile_output.txt'
|
46
|
+
|
47
47
|
# Method-specific analysis
|
48
48
|
puts "\n\nMethod Breakdown:"
|
49
|
-
puts
|
50
|
-
|
49
|
+
puts '-' * 80
|
50
|
+
|
51
51
|
result.threads.each do |thread|
|
52
52
|
thread.methods.sort_by(&:total_time).reverse.first(10).each do |method|
|
53
53
|
next if method.total_time < 0.01
|
54
|
-
|
55
|
-
puts
|
54
|
+
|
55
|
+
puts method.full_name
|
56
56
|
puts " Total time: #{(method.total_time * 1000).round(2)}ms"
|
57
57
|
puts " Calls: #{method.called}"
|
58
58
|
puts " Time per call: #{((method.total_time / method.called) * 1000).round(4)}ms"
|
59
59
|
puts
|
60
60
|
end
|
61
61
|
end
|
62
|
-
|
63
62
|
rescue LoadError
|
64
|
-
puts
|
65
|
-
puts
|
63
|
+
puts 'ruby-prof gem not available. Running basic timing analysis instead.'
|
64
|
+
puts 'Install with: gem install ruby-prof'
|
66
65
|
puts
|
67
|
-
|
66
|
+
|
68
67
|
# Fallback: manual timing analysis
|
69
68
|
require 'benchmark'
|
70
|
-
|
69
|
+
|
71
70
|
test_cases = [
|
72
71
|
'un',
|
73
|
-
'vingt et un',
|
72
|
+
'vingt et un',
|
74
73
|
'mille deux cent',
|
75
74
|
'trois milliards cinq cents millions'
|
76
75
|
]
|
77
|
-
|
78
|
-
puts
|
79
|
-
puts
|
80
|
-
|
76
|
+
|
77
|
+
puts 'Manual Performance Analysis:'
|
78
|
+
puts '=' * 40
|
79
|
+
|
81
80
|
test_cases.each do |input|
|
82
81
|
puts "\nAnalyzing: '#{input}'"
|
83
|
-
|
82
|
+
|
84
83
|
# Time different aspects
|
85
84
|
parser = nil
|
86
85
|
init_time = Benchmark.realtime do
|
87
86
|
1000.times { parser = StringToNumber::ToNumber.new(input) }
|
88
87
|
end
|
89
|
-
|
88
|
+
|
90
89
|
conversion_time = Benchmark.realtime do
|
91
90
|
1000.times { parser.to_number }
|
92
91
|
end
|
93
|
-
|
92
|
+
|
94
93
|
total_time = Benchmark.realtime do
|
95
94
|
1000.times { StringToNumber.in_numbers(input) }
|
96
95
|
end
|
97
|
-
|
96
|
+
|
98
97
|
puts " Initialization: #{(init_time * 1000).round(4)}ms per 1000 calls"
|
99
98
|
puts " Conversion: #{(conversion_time * 1000).round(4)}ms per 1000 calls"
|
100
99
|
puts " Total: #{(total_time * 1000).round(4)}ms per 1000 calls"
|
@@ -103,29 +102,29 @@ rescue LoadError
|
|
103
102
|
|
104
103
|
# Test regex performance specifically
|
105
104
|
puts "\n\nRegex Performance Test:"
|
106
|
-
puts
|
107
|
-
|
108
|
-
sample_input =
|
105
|
+
puts '=' * 40
|
106
|
+
|
107
|
+
sample_input = 'trois milliards cinq cents millions'
|
109
108
|
parser = StringToNumber::ToNumber.new(sample_input)
|
110
109
|
keys = parser.instance_variable_get(:@keys)
|
111
|
-
|
110
|
+
|
112
111
|
puts "Keys pattern length: #{keys.length} characters"
|
113
|
-
|
112
|
+
|
114
113
|
regex_time = Benchmark.realtime do
|
115
|
-
|
114
|
+
10_000.times do
|
116
115
|
/(?<f>.*?)\s?(?<m>#{keys})/.match(sample_input)
|
117
116
|
end
|
118
117
|
end
|
119
|
-
|
118
|
+
|
120
119
|
puts "Regex matching time: #{(regex_time * 100).round(4)}ms per 10000 matches"
|
121
|
-
|
120
|
+
|
122
121
|
# Test hash lookup performance
|
123
122
|
lookup_time = Benchmark.realtime do
|
124
|
-
|
123
|
+
100_000.times do
|
125
124
|
StringToNumber::ToNumber::EXCEPTIONS['vingt']
|
126
125
|
StringToNumber::ToNumber::POWERS_OF_TEN['millions']
|
127
126
|
end
|
128
127
|
end
|
129
|
-
|
128
|
+
|
130
129
|
puts "Hash lookup time: #{(lookup_time * 10).round(4)}ms per 100000 lookups"
|
131
|
-
end
|
130
|
+
end
|
data/string_to_number.gemspec
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
lib = File.expand_path('lib', __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
5
|
require 'string_to_number/version'
|
@@ -18,10 +20,11 @@ Gem::Specification.new do |spec|
|
|
18
20
|
# to allow pushing to a single host or delete
|
19
21
|
# this section to allow pushing to any host.
|
20
22
|
if spec.respond_to?(:metadata)
|
21
|
-
spec.metadata['allowed_push_host'] =
|
23
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
24
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
22
25
|
else
|
23
26
|
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
24
|
-
|
27
|
+
'public gem pushes.'
|
25
28
|
end
|
26
29
|
|
27
30
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
@@ -30,8 +33,4 @@ Gem::Specification.new do |spec|
|
|
30
33
|
spec.bindir = 'exe'
|
31
34
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
35
|
spec.require_paths = ['lib']
|
33
|
-
|
34
|
-
spec.add_development_dependency 'bundler'
|
35
|
-
spec.add_development_dependency 'rake'
|
36
|
-
spec.add_development_dependency 'rspec'
|
37
36
|
end
|
metadata
CHANGED
@@ -1,57 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: string_to_number
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fabien Piette
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-06-
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rspec
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
11
|
+
date: 2025-06-24 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
55
13
|
description: A ruby gem to convert French words into numbers.
|
56
14
|
email:
|
57
15
|
- fab.piette@gmail.com
|
@@ -59,8 +17,10 @@ executables: []
|
|
59
17
|
extensions: []
|
60
18
|
extra_rdoc_files: []
|
61
19
|
files:
|
20
|
+
- ".github/workflows/ci.yml"
|
62
21
|
- ".gitignore"
|
63
22
|
- ".rspec"
|
23
|
+
- ".rubocop.yml"
|
64
24
|
- ".tool-versions"
|
65
25
|
- ".travis.yml"
|
66
26
|
- CLAUDE.md
|
@@ -77,6 +37,7 @@ files:
|
|
77
37
|
- lib/string_to_number/parser.rb
|
78
38
|
- lib/string_to_number/to_number.rb
|
79
39
|
- lib/string_to_number/version.rb
|
40
|
+
- logo.png
|
80
41
|
- microbenchmark.rb
|
81
42
|
- performance_comparison.rb
|
82
43
|
- profile.rb
|
@@ -86,6 +47,7 @@ licenses:
|
|
86
47
|
- MIT
|
87
48
|
metadata:
|
88
49
|
allowed_push_host: https://rubygems.org
|
50
|
+
rubygems_mfa_required: 'true'
|
89
51
|
post_install_message:
|
90
52
|
rdoc_options: []
|
91
53
|
require_paths:
|