ya_kansuji 1.1.0 → 1.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ae15d72bf1414795e2fc0b0c8b31b292dde3fec64183ad0c8407b561a27dcc0
4
- data.tar.gz: b5a101d4e735075625e4190be2bd6e4a57d2ce419a80312ce256a427fe17dd55
3
+ metadata.gz: 97f2f4c063933b7c86ede7c11d8d34704e612f7eb4e82e2f60f469d8aa8ded4c
4
+ data.tar.gz: 4aa55c66f2d6b5ae168278e0b2b1a096e062ae1a3e96d31bcb118f415c184bb0
5
5
  SHA512:
6
- metadata.gz: bc79795e352c88129045537e093d76fb59169f2424faa0416a2cf9d829e8a6763ba0fa2a06e1e31e8c1032ed04c0fdb96e54e5677216ca355955f622f67e1c76
7
- data.tar.gz: 4fd9683d6c48f51ba18bee9e47fa8e393f150a4f0471ddd0c98e5886dda6a52a99a39d34c9e8383b0e7285465d11fd7f51fc3b7f65b1da3507fcfa7e525c51c3
6
+ metadata.gz: 0203eaef1b77450bd6ea5c9666cf695bfe72fd7fb21d966d18bb177fa38db3ca500dff690841c3f1b5d25b9406c62f7bf38a90be98f6c5983f5df68fe65df8cb
7
+ data.tar.gz: 7a420d832dbd4da1149ac293820dca4f510226c53513bc1f579d2fa889cc8b16708f717406c76be8937f21623090eaf7d073896234296598e40e36a8275091ae
data/ChangeLog CHANGED
@@ -1,3 +1,13 @@
1
+ 2026-07-14 Tatsuki Sugiura <sugi@nemui.org>
2
+
3
+ * Version: 1.2.0
4
+ * Require Ruby 2.3.0 or later
5
+ * Accept formatter and options on Integer#to_kan core extension
6
+ * Accept :kansuji as base symbol on String#to_i core extension
7
+ * Raise RangeError when formatting values outside the supported 72-digit range
8
+ * Avoid circular require warnings between the main and refinement entrypoints
9
+ * Optimize formatter chunk processing (up to ~9x faster, far fewer allocations)
10
+
1
11
  2026-07-13 Tatsuki Sugiura <sugi@nemui.org>
2
12
 
3
13
  * Version: 1.1.0
@@ -19,4 +29,3 @@
19
29
  2019-04-15 Tatsuki Sugiura <sugi@nemui.org>
20
30
 
21
31
  * Version: 0.1.0
22
-
data/README.md CHANGED
@@ -59,6 +59,9 @@ YaKansuji.to_kan(12345) # => 一万二千三百四十五
59
59
  YaKansuji.to_kan(-12345) # => マイナス一万二千三百四十五
60
60
  ```
61
61
 
62
+ 対応する値域は `-(10**72 - 1)` から `10**72 - 1` です。
63
+ 数値として整数化した値がこの範囲を超える場合、`RangeError` が発生します。
64
+
62
65
  このさい、2つめの引数にシンボルを渡すことにより、フォーマッタを切り替えることができます。
63
66
 
64
67
  ```ruby
@@ -113,6 +116,7 @@ using YaKansuji::CoreRefine
113
116
 
114
117
  puts "二万".to_i # => 20000
115
118
  puts 20000.to_kan #= > "二万"
119
+ puts 20000.to_kan(:gov) # => "2万"
116
120
  ```
117
121
 
118
122
  ちなみに、 `to_i` に base が渡された場合は、漢数字が解釈されずにビルトインクラスのものが呼ばれます。
@@ -121,6 +125,7 @@ puts 20000.to_kan #= > "二万"
121
125
  using YaKansuji::CoreRefine
122
126
 
123
127
  puts "12万".to_i # => 120000
128
+ puts "12万".to_i(:kansuji) # => 120000
124
129
  puts "12万".to_i(16) # => 18
125
130
  ```
126
131
 
@@ -4,7 +4,7 @@ require 'ya_kansuji'
4
4
 
5
5
  # Core extension by kansuji
6
6
  class Integer
7
- def to_kan
8
- YaKansuji.to_kan self
7
+ def to_kan(formatter = :simple, options = {})
8
+ YaKansuji.to_kan self, formatter, options
9
9
  end
10
10
  end
@@ -7,7 +7,7 @@ class String
7
7
  alias _to_i_ya_kansuji_orig to_i unless defined?(_to_i_ya_kansuji_orig)
8
8
 
9
9
  def to_i(base = nil)
10
- if base.nil? || base == :kan
10
+ if base.nil? || base == :kan || base == :kansuji
11
11
  YaKansuji.to_i self
12
12
  else
13
13
  _to_i_ya_kansuji_orig(base)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ya_kansuji'
4
-
5
3
  module YaKansuji
6
4
  # String and Integer refinements with YaKansuji
7
5
  module CoreRefine
@@ -16,9 +14,11 @@ module YaKansuji
16
14
  end
17
15
 
18
16
  refine Integer do
19
- def to_kan(formatter = :simple)
20
- YaKansuji.to_kan self, formatter
17
+ def to_kan(formatter = :simple, options = {})
18
+ YaKansuji.to_kan self, formatter, options
21
19
  end
22
20
  end
23
21
  end
24
22
  end
23
+
24
+ require 'ya_kansuji' unless YaKansuji.respond_to?(:to_i) && YaKansuji.respond_to?(:to_kan)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module YaKansuji
2
4
  module Formatter
3
5
  # Formatter for Japan government-style kansuji
@@ -8,10 +10,12 @@ module YaKansuji
8
10
  return '0' if num.zero?
9
11
 
10
12
  parts = []
11
- (UNIT_EXP4.reverse + ['']).each_with_index do |unit4, ridx4|
12
- i4 = (num / (10_000**(UNIT_EXP4.size - ridx4))).to_i % 10_000
13
+ chunks = Formatter.split_by_unit4(num)
14
+ (chunks.size - 1).downto(0) do |idx4|
15
+ i4 = chunks[idx4]
13
16
  next if i4.zero?
14
17
 
18
+ unit4 = Formatter::UNIT4_UNITS[idx4]
15
19
  if i4 == 1
16
20
  parts << "1#{unit4}"
17
21
  next
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Simple kansuji formatter
2
4
  module YaKansuji
3
5
  module Formatter
@@ -8,12 +10,14 @@ module YaKansuji
8
10
  def call(num, _options = {})
9
11
  return '0' if num.zero?
10
12
 
11
- ret = ''
13
+ ret = +''
12
14
  head = true
13
- (UNIT_EXP4.reverse + ['']).each_with_index do |unit4, ridx4|
14
- i4 = (num / (10_000**(UNIT_EXP4.size - ridx4))).to_i % 10_000
15
+ chunks = Formatter.split_by_unit4(num)
16
+ (chunks.size - 1).downto(0) do |idx4|
17
+ i4 = chunks[idx4]
15
18
  next if i4.zero?
16
19
 
20
+ unit4 = Formatter::UNIT4_UNITS[idx4]
17
21
  if head
18
22
  ret << (i4.to_s + unit4)
19
23
  else
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Simple kansuji formatter
2
4
  module YaKansuji
3
5
  module Formatter
@@ -8,12 +10,14 @@ module YaKansuji
8
10
  def call(num, _options = {})
9
11
  return '〇' if num.zero?
10
12
 
11
- ret = ''
13
+ ret = +''
12
14
  head = true
13
- (UNIT_EXP4.reverse + ['']).each_with_index do |unit4, ridx4|
14
- i4 = (num / (10_000**(UNIT_EXP4.size - ridx4))).to_i % 10_000
15
+ chunks = Formatter.split_by_unit4(num)
16
+ (chunks.size - 1).downto(0) do |idx4|
17
+ i4 = chunks[idx4]
15
18
  next if i4.zero?
16
19
 
20
+ unit4 = Formatter::UNIT4_UNITS[idx4]
17
21
  if head
18
22
  ret << (i4.to_s + unit4)
19
23
  else
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Simple kansuji formatter
2
4
  module YaKansuji
3
5
  module Formatter
@@ -8,11 +10,13 @@ module YaKansuji
8
10
  def call(num, _options = {})
9
11
  return '0' if num.zero?
10
12
 
11
- ret = ''
12
- (UNIT_EXP4.reverse + ['']).each_with_index do |unit4, ridx4|
13
- i4 = (num / (10_000**(UNIT_EXP4.size - ridx4))).to_i % 10_000
13
+ ret = +''
14
+ chunks = Formatter.split_by_unit4(num)
15
+ (chunks.size - 1).downto(0) do |idx4|
16
+ i4 = chunks[idx4]
14
17
  next if i4.zero?
15
18
 
19
+ unit4 = Formatter::UNIT4_UNITS[idx4]
16
20
  if i4 == 1
17
21
  ret << "1#{unit4}"
18
22
  next
@@ -4,33 +4,43 @@ module YaKansuji
4
4
  module Formatter
5
5
  # Simple kansuji formatter
6
6
  module Simple
7
+ DIGITS = %w(一 二 三 四 五 六 七 八 九).freeze
8
+ UNITS = ([''] + UNIT_EXP3).freeze
9
+
7
10
  module_function
8
11
 
9
12
  def call(num, _options = {})
10
13
  return '零' if num.zero?
11
14
 
12
- ret = ''
13
- (UNIT_EXP4.reverse + ['']).each_with_index do |unit4, ridx4|
14
- i4 = (num / (10_000**(UNIT_EXP4.size - ridx4))).to_i % 10_000
15
+ ret = nil
16
+ chunks = Formatter.split_by_unit4(num)
17
+ (chunks.size - 1).downto(0) do |idx4|
18
+ i4 = chunks[idx4]
15
19
  next if i4.zero?
16
20
 
21
+ ret ||= +''
22
+ unit4 = Formatter::UNIT4_UNITS[idx4]
17
23
  if i4 == 1
18
- ret += "一#{unit4}"
24
+ ret << '一' << unit4
19
25
  next
20
26
  end
21
- (UNIT_EXP3.reverse + ['']).each_with_index do |unit3, ridx3|
22
- i3 = (i4 / (10**(UNIT_EXP3.size - ridx3))).to_i % 10
27
+
28
+ divisor = 1000
29
+ 3.downto(0) do |idx3|
30
+ i3 = (i4 / divisor) % 10
31
+ divisor /= 10
23
32
  next if i3.zero?
24
33
 
25
- if i3 == 1 && unit3 != ''
26
- ret += unit3
34
+ unit3 = UNITS[idx3]
35
+ if i3 == 1 && !unit3.empty?
36
+ ret << unit3
27
37
  else
28
- ret += i3.to_s.tr('123456789', '一二三四五六七八九') + unit3
38
+ ret << DIGITS[i3 - 1] << unit3
29
39
  end
30
40
  end
31
- ret += unit4
41
+ ret << unit4
32
42
  end
33
- ret
43
+ ret || ''
34
44
  end
35
45
  YaKansuji.register_formatter :simple, self
36
46
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YaKansuji
4
+ # Shared helpers for built-in formatters.
5
+ module Formatter
6
+ UNIT4_BASE = 10_000
7
+ UNIT4_CHUNK_LIMIT = UNIT_EXP4.size + 1
8
+ UNIT4_UNITS = ([''] + UNIT_EXP4).freeze
9
+
10
+ module_function
11
+
12
+ def split_by_unit4(num)
13
+ chunks = []
14
+ UNIT4_CHUNK_LIMIT.times do
15
+ num, chunk = num.divmod(UNIT4_BASE)
16
+ chunks << chunk
17
+ break if num.zero?
18
+ end
19
+ chunks
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module YaKansuji
2
- VERSION = '1.1.0'.freeze
4
+ VERSION = '1.2.0'
3
5
  end
data/lib/ya_kansuji.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'ya_kansuji/version'
4
- require 'ya_kansuji/core_refine'
5
4
 
6
5
  # Yet another Kansuji library for ruby.
7
6
  module YaKansuji
8
7
  UNIT_EXP3 = %w(十 百 千).freeze
9
8
  UNIT_EXP4 = %w(万 億 兆 京 垓 𥝱 穣 溝 澗 正 載 極 恒河沙 阿僧祇 那由他 不可思議 無量大数).freeze
9
+ MAX_VALUE = (10_000**(UNIT_EXP4.size + 1)) - 1
10
10
  NUM_ALT_CHARS = '〇一二三四五六七八九0123456789零壱壹弌弐貳貮参參弎肆伍陸漆質柒捌玖拾什陌佰阡仟萬秭'
11
11
  NUM_NORMALIZED_CHARS = '01234567890123456789011122233345677789十十百百千千万𥝱'
12
12
  # rubocop:disable Lint/DuplicateRegexpCharacterClassElement
@@ -101,6 +101,10 @@ module YaKansuji
101
101
 
102
102
  def to_kan(num, formatter = :simple, options = {})
103
103
  num.respond_to?(:_to_i_ya_kansuji_orig) ? num = num._to_i_ya_kansuji_orig : num = num.to_i
104
+ if num.abs > MAX_VALUE
105
+ raise RangeError, "Value must be between #{-MAX_VALUE} and #{MAX_VALUE}"
106
+ end
107
+
104
108
  return "マイナス#{to_kan(-num, formatter, options)}" if num.negative?
105
109
 
106
110
  if formatter.respond_to? :call
@@ -113,8 +117,10 @@ module YaKansuji
113
117
  end
114
118
  end
115
119
 
120
+ require 'ya_kansuji/formatter'
116
121
  require 'ya_kansuji/formatter/simple'
117
122
  require 'ya_kansuji/formatter/gov'
118
123
  require 'ya_kansuji/formatter/lawyer'
119
124
  require 'ya_kansuji/formatter/judic_v'
120
125
  require 'ya_kansuji/formatter/judic_h'
126
+ require 'ya_kansuji/core_refine' unless defined?(YaKansuji::CoreRefine)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ya_kansuji
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tatsuki Sugiura
@@ -27,6 +27,7 @@ files:
27
27
  - lib/ya_kansuji/core_ext/integer.rb
28
28
  - lib/ya_kansuji/core_ext/string.rb
29
29
  - lib/ya_kansuji/core_refine.rb
30
+ - lib/ya_kansuji/formatter.rb
30
31
  - lib/ya_kansuji/formatter/gov.rb
31
32
  - lib/ya_kansuji/formatter/judic_h.rb
32
33
  - lib/ya_kansuji/formatter/judic_v.rb
@@ -46,7 +47,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
46
47
  requirements:
47
48
  - - ">="
48
49
  - !ruby/object:Gem::Version
49
- version: 2.0.0
50
+ version: 2.3.0
50
51
  required_rubygems_version: !ruby/object:Gem::Requirement
51
52
  requirements:
52
53
  - - ">="