base_convert 6.0.210201 → 7.0.221226

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: 9e29e85eacc7c4fb82ae72be4dec517de21f2e0c1be03a6dc2670fa1296a9b12
4
- data.tar.gz: 999da6376a8025b1c5dedd696b5e5c97fb9423b9dfc6f0c59dbefe270dc72dea
3
+ metadata.gz: '0468363560e386197373265ab15994e9f75b97965f01fd7c7d039ba659fb9e5d'
4
+ data.tar.gz: e22bdb75673cb9e2bedc6edd7c7dd1349234ff8709b77b7e1159e74b79b37975
5
5
  SHA512:
6
- metadata.gz: 52b687612311825f4bc0877d9e5b4483d58006749dd12ec35ae954864a7b091c5c4a20e796a89aff383a1fe7db331446a13fd575924a1129fe29e78db037c24e
7
- data.tar.gz: 768e66ca83303a4d4e36c2310291c480923a8a7758a1d18afc67a0c2dee88c8175b65180cb6dbde46cab71095f9a54302cec170da544f65657cc58f1f2ff0a27
6
+ metadata.gz: 6dfa9704f01b5145bdb9ad4070d59aa4027dafcb8431fd24c42134d861475f33c97a3db30549c606dffd60acdca15768211abac2b648ee6de147481038f405cc
7
+ data.tar.gz: '0948eea3537cc52a521d633c68aa6a4121646bfe20af41e3d11ca902a8cb3f814468ad022c8b5879726de4c24bf4433dbb88b9fc690f53d03d33a0a4bc0c1e52'
data/README.md CHANGED
@@ -1,15 +1,13 @@
1
1
  # BaseConvert
2
2
 
3
- * [VERSION 6.0.210201](https://github.com/carlosjhr64/base_convert/releases)
3
+ * [VERSION 7.0.221226](https://github.com/carlosjhr64/base_convert/releases)
4
4
  * [github](https://www.github.com/carlosjhr64/base_convert)
5
5
  * [rubygems](https://rubygems.org/gems/base_convert)
6
6
 
7
7
  ## INSTALL:
8
-
9
8
  ```shell
10
9
  $ gem install base_convert
11
10
  ```
12
-
13
11
  ## DESCRIPTION:
14
12
 
15
13
  BaseConvert - Number base conversion.
@@ -19,49 +17,45 @@ Binary, octal, hexadecimal, decimal, or any arbitrary base.
19
17
  "Out of the box" handling of up to base 95(:print: characters).
20
18
  Allows for arbitrary choice of alphabet(digits).
21
19
 
22
- See also rosettacode.org's [Non-decimal radices convert](http://rosettacode.org/wiki/Non-decimal_radices/Convert).
23
-
24
20
  ## SYNOPSIS:
25
-
26
21
  ```ruby
27
22
  require 'base_convert'
28
23
 
29
24
  #toi string, base, digits => integer
30
- BaseConvert.toi 'FF', 16, '0123456789ABCDEF' #=> 255
25
+ BaseConvert::Methods.toi 'FF', 16, '0123456789ABCDEF' #=> 255
31
26
 
32
27
  #tos integer, base, digits => string
33
- BaseConvert.tos 255, 16, '0123456789ABCDEF' #=> "FF"
28
+ BaseConvert::Methods.tos 255, 16, '0123456789ABCDEF' #=> "FF"
34
29
 
35
30
  # FromTo
36
- c = BaseConvert::FromTo.new base: 16, digits: '0123456789ABCDEF', to_base: 7, to_digits: 'abcdefg'
37
- c['FFF'] #=> "begea"
38
- c.inspect #=> "16:P95,7:abfg"
31
+ c = BaseConvert::FromTo.new base: 16, digits: '0123456789ABCDEF',
32
+ to_base: 7, to_digits: 'abcdefg'
33
+ c['FFF'] #=> "begea"
34
+ c.inspect #=> "16:P95,7:abfg"
39
35
 
40
36
  # Number
41
37
  n = BaseConvert::Number.new 'FF', base: 16, digits: '0123456789ABCDEF'
42
- n.to_i #=> 255
43
- n.to_s #=> "FF"
38
+ n.to_i #=> 255
39
+ n.to_s #=> "FF"
44
40
  n.inspect #=> FF 16:P95
45
41
  #
46
42
  n = n.to_base 64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
47
- n.to_s #=> "D/"
48
- n.to_i #=> 255
43
+ n.to_s #=> "D/"
44
+ n.to_i #=> 255
49
45
  n.inspect #=> D/ 64:B64
50
46
  ```
51
-
52
47
  ## BUT WAIT, THERE'S MORE:
53
48
 
54
- ### module BaseConvert
49
+ ### module BaseConvert::Methods
55
50
 
56
51
  * `#toi(string=to_s String, base=@base Integer, digits=@digits String) #=> Integer`
57
52
  * `#tos(integer=to_i Integer, base=@base Integer, digits=@digits String) #=> String`
58
- * `#ascii_ordered?(digits=@digits String) #=> TrueClass|FalseClass`
53
+ * `#chars_ordered?(digits=@digits String) #=> TrueClass|FalseClass`
59
54
 
60
55
  Exemplar:
61
-
62
56
  ```ruby
63
57
  class MyClass
64
- include BaseConvert
58
+ include BaseConvert::Methods
65
59
  attr_accessor :to_s, :to_i, :base, :digits
66
60
  end
67
61
 
@@ -75,12 +69,11 @@ obj.toi #=> 1
75
69
  obj.to_i = 3
76
70
  obj.tos #=> "$"
77
71
 
78
- obj.ascii_ordered? #=> false
72
+ obj.chars_ordered? #=> false
79
73
  obj.digits = 'ABCDEFGHIJKLMNOP'
80
- obj.ascii_ordered? #=> true
74
+ obj.chars_ordered? #=> true
81
75
  ```
82
-
83
- ### Hash DIGITS
76
+ ### BaseConvert::DIGITS < Hash
84
77
 
85
78
  #### DIGITS methods
86
79
 
@@ -90,54 +83,51 @@ obj.ascii_ordered? #=> true
90
83
  * `DIGITS.memoize!(key=registry Symbol|Array(Symbol))`
91
84
  * `DIGITS.forget!(key=registry Symbol|Array(Symbol))`
92
85
 
93
-
94
86
  Exemplar:
95
-
96
87
  ```ruby
97
88
  include BaseConvert
98
- DIGITS.get(:P95) #=> :alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers
89
+ DIGITS.get(:P95)
90
+ #=> :alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers
99
91
  DIGITS[:P95]
100
92
  #=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%\"'`_ "
101
- DIGITS.registry #=> [:P95, :B64, :U47, :G94, :Q91, :W63]
102
- DIGITS.registry('347') #=> :U47
103
- DIGITS.registry('0') #=> :P95
104
- DIGITS.registry('AB') #=> :B64
105
- DIGITS.registry('Cukoe') #=> nil
106
- DIGITS.label('Cukoe') #=> :Cuoe
93
+ DIGITS.registry #=> [:P95, :B64, :U47, :G94, :Q91, :W63]
94
+ DIGITS.registry('347') #=> :U47
95
+ DIGITS.registry('0') #=> :P95
96
+ DIGITS.registry('AB') #=> :B64
97
+ DIGITS.registry('Cukoe') #=> nil
98
+ DIGITS.label('Cukoe') #=> :Cuoe
107
99
  DIGITS.label('AaBbCcXxYyZz') #=> :AaZz
108
- DIGITS[:N] #=> "0123456789"
109
- DIGITS.get(:N) #=> nil
100
+ DIGITS[:N] #=> "0123456789"
101
+ DIGITS.get(:N) #=> nil
110
102
  DIGITS.memoize!(:N)
111
- DIGITS.get(:N) #=> "0123456789"
103
+ DIGITS.get(:N) #=> "0123456789"
112
104
  DIGITS.forget!(:N)
113
- DIGITS.get(:N) #=> nil
105
+ DIGITS.get(:N) #=> nil
114
106
  ```
115
-
116
-
117
107
  #### DIGITS constructions
118
108
 
119
109
  `BaseConvert::DIGITS` will take a `Symbol` representation of `Regexp` patterns.
120
110
  See [Ruby-Doc's Regexp](https://ruby-doc.org/core-2.7.0/Regexp.html) documentation
121
111
  for a full list of keys. The following provides an exemplar survey:
122
-
123
112
  ```ruby
124
113
  # Character Classes
125
114
  # Selected from ASCII 32..126
126
115
  DIGITS[:w] #=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
127
116
  DIGITS[:d] #=> "0123456789"
128
117
  # Note: :h was overridden, see :xdigit.
129
- DIGITS[:h] #=> "0123456789ABCDEF"
118
+ DIGITS[:h] #=> "0123456789ABCDEF"
130
119
  DIGITS[:alpha] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
131
120
  DIGITS[:graph]
132
121
  #=> "!\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
133
- DIGITS[:lower] #=> "abcdefghijklmnopqrstuvwxyz"
134
- DIGITS[:punct] #=> "!\"\#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
135
- DIGITS[:upper] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
122
+ DIGITS[:lower] #=> "abcdefghijklmnopqrstuvwxyz"
123
+ DIGITS[:punct] #=> "!\"\#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
124
+ DIGITS[:upper] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
136
125
  DIGITS[:xdigit] #=> "0123456789ABCDEFabcdef"
137
126
 
138
127
  # Character Properties
139
128
  # Selected from ASCII 32..126
140
- DIGITS[:Alnum] #=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
129
+ DIGITS[:Alnum]
130
+ #=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
141
131
  DIGITS[:Any]
142
132
  #=> " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
143
133
 
@@ -149,7 +139,7 @@ DIGITS[:S] #=> "$+<=>^`|~"
149
139
 
150
140
  # Ranged Selections
151
141
  # v<hex>w<hex>_<filter>
152
- DIGITS[:v1d7d8w1d7e1_Any] #=> "𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡"
142
+ DIGITS[:v1d7d8w1d7e1_Any] #=> "𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡"
153
143
  # i<dec>j<dec>_<filter>
154
144
  DIGITS[:i120488j120513_Any] #=> "𝚨𝚩𝚪𝚫𝚬𝚭𝚮𝚯𝚰𝚱𝚲𝚳𝚴𝚵𝚶𝚷𝚸𝚹𝚺𝚻𝚼𝚽𝚾𝚿𝛀𝛁"
155
145
 
@@ -160,19 +150,19 @@ DIGITS[:u61u62] #=> "ab"
160
150
  DIGITS[:k97k98] #=> "ab"
161
151
 
162
152
  # BaseConvert's Custom Sets
163
- DIGITS[:bangs] #=> "!?"
164
- DIGITS[:typers] #=> "$&@"
165
- DIGITS[:operators] #=> "*+-/<=>^~"
153
+ DIGITS[:bangs] #=> "!?"
154
+ DIGITS[:typers] #=> "$&@"
155
+ DIGITS[:operators] #=> "*+-/<=>^~"
166
156
  DIGITS[:separators] #=> ",.:;|"
167
- DIGITS[:scapes] #=> "#\\"
168
- DIGITS[:groupers] #=> "()[]{}"
169
- DIGITS[:quotes] #=> "\"'`"
170
- DIGITS[:quoters] #=> "%\"'`"
171
- DIGITS[:spacers] #=> "_ "
172
- DIGITS[:ambiguous] #=> "012568BDGIOQSZl"
157
+ DIGITS[:scapes] #=> "#\\"
158
+ DIGITS[:groupers] #=> "()[]{}"
159
+ DIGITS[:quotes] #=> "\"'`"
160
+ DIGITS[:quoters] #=> "%\"'`"
161
+ DIGITS[:spacers] #=> "_ "
162
+ DIGITS[:ambiguous] #=> "012568BDGIOQSZl"
173
163
 
174
164
  # Composition, add merge:
175
- DIGITS[:d_ambiguous] #=> "0123456789BDGIOQSZl"
165
+ DIGITS[:d_ambiguous] #=> "0123456789BDGIOQSZl"
176
166
  # Composition, add top:
177
167
  DIGITS[:'d+ambiguous'] #=> "3479012568BDGIOQSZl"
178
168
  # Composition, subtract:
@@ -183,11 +173,12 @@ DIGITS[:'d-ambiguous'] #=> "3479"
183
173
  DIGITS[:alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers]
184
174
  #=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%\"'`_ "
185
175
  # :B64 is:
186
- DIGITS[:LN_k43k47] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
176
+ DIGITS[:LN_k43k47]
177
+ #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
187
178
  # :U47 is:
188
- DIGITS[:'alnum-ambiguous'] #=> "3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz"
179
+ DIGITS[:'alnum-ambiguous']
180
+ #=> "3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz"
189
181
  ```
190
-
191
182
  ### class FromTo
192
183
 
193
184
  * `new(base: 10 Integer|Symbol|String, to_base: base, digits: :P95 String|Symbol|Integer, to_digits: digits) #=> FromTo`
@@ -195,16 +186,14 @@ DIGITS[:'alnum-ambiguous'] #=> "3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz"
195
186
  * `#convert(counter String|Integer) #=> String`
196
187
 
197
188
  Example:
198
-
199
189
  ```ruby
200
190
  h2b = BaseConvert::FromTo.new(base: 16, digits: :P95, to_base: 64, to_digits: :B64)
201
- h2b #=> 16:P95,64:B64
191
+ h2b #=> 16:P95,64:B64
202
192
  h2b['FFF'] #=> "//"
203
193
  b2h = BaseConvert::FromTo.new(base: 64, digits: :B64, to_base: 16, to_digits: :P95)
204
- b2h #=> 64:B64,16:P95
205
- b2h['//'] #=> "FFF"
194
+ b2h #=> 64:B64,16:P95
195
+ b2h['//'] #=> "FFF"
206
196
  ```
207
-
208
197
  ### class Number
209
198
 
210
199
  * `new(counter= 0 Integer|String, base: nil Integer|Symbol|String, digits: nil String|Symbol|Integer, validate: true TrueClass|FalseClass) #=> Number`
@@ -217,24 +206,22 @@ b2h['//'] #=> "FFF"
217
206
  * `#to_digits(digits String|Symbol|Integer, base=@base Integer|Symbol|String, validate=@validate TrueClass|FalseClass) #=> Number`
218
207
 
219
208
  Example:
220
-
221
209
  ```ruby
222
210
  a = BaseConvert::Number.new('FFF', base: 16, digits: :P95)
223
- a #=> FFF 16:P95
211
+ a #=> FFF 16:P95
224
212
  a.to_i #=> 4095
225
213
  b = a.to_digits(:U47)
226
- b #=> RRR 16:U47
214
+ b #=> RRR 16:U47
227
215
  b.to_i #=> 4095
228
216
  c = b.to_base(64, :B64)
229
- c #=> // 64:B64
217
+ c #=> // 64:B64
230
218
  c.to_i #=> 4095
231
219
  ```
232
-
233
220
  ## LICENSE:
234
221
 
235
222
  (The MIT License)
236
223
 
237
- Copyright (c) 2021 CarlosJHR64
224
+ Copyright (c) 2022 CarlosJHR64
238
225
 
239
226
  Permission is hereby granted, free of charge, to any person obtaining
240
227
  a copy of this software and associated documentation files (the
@@ -1,24 +1,65 @@
1
1
  module BaseConvert
2
- class Base < Hash
3
- alias :get :[]
4
- def [](key)
5
- base = super and return base
6
- case key
7
- when String
8
- base = key.length
9
- when Integer
10
- base = key
11
- when /^\D+(\d+)$/
12
- base = $1.to_i
13
- else
14
- begin
15
- base = DIGITS[key].length
16
- rescue
17
- raise 'unrecognized base key'
2
+ class Base < Hash
3
+ alias :get :[]
4
+ def [](key)
5
+ base = super and return base
6
+ case key
7
+ when String
8
+ base = key.length
9
+ when Integer
10
+ base = key
11
+ when /^\D+(\d+)$/
12
+ base = $1.to_i
13
+ else
14
+ begin
15
+ base = DIGITS[key].length
16
+ rescue
17
+ raise 'unrecognized base key'
18
+ end
18
19
  end
20
+ raise 'base must be greater than 1' unless base > 1
21
+ base
19
22
  end
20
- raise 'base must be greater than 1' unless base > 1
21
- base
22
23
  end
23
- end
24
+ BASE = Base[
25
+ # 95
26
+ P95: 95,
27
+ print: 95,
28
+ # 94
29
+ G94: 94, g: 94, graph: 94,
30
+ # 91
31
+ Q91: 91, qgraph: 91, q: 91,
32
+ # 64
33
+ B64: 64, base64: 64, b64: 64,
34
+ # 63
35
+ W63: 63, word: 63, w: 63,
36
+ # 52
37
+ letters: 52, l: 52, L: 52,
38
+ # 47
39
+ U47: 47, unambiguous: 47, u: 47,
40
+ # 16
41
+ hexadecimal: 16, hex: 16, h: 16,
42
+ # 15
43
+ ambiguous: 15,
44
+ # 10
45
+ decimal: 10, dec: 10, d: 10,
46
+ # 9
47
+ operators: 9,
48
+ # 8
49
+ octal: 8, oct: 8, o: 8,
50
+ # 6
51
+ groupers: 6,
52
+ # 5
53
+ separators: 5,
54
+ # 4
55
+ quoters: 4,
56
+ # 3
57
+ typers: 3,
58
+ quotes: 3,
59
+ # 2
60
+ binary: 2, bin: 2, b: 2,
61
+ bangs: 2,
62
+ scapes: 2,
63
+ spacers: 2,
64
+ ]
24
65
  end
@@ -1,33 +1,38 @@
1
1
  module BaseConvert
2
- class Chars < Array
3
- attr_accessor :start,:stop
4
- def initialize(start=32, stop=126)
5
- @start,@stop = start,stop
2
+ # Chars provides ways of populating an ordered(as constructed) set
3
+ # with characters in UTF-8.
4
+ class Chars
5
+ def initialize
6
+ @start,@stop,@a = 32,126,[]
6
7
  end
7
8
 
9
+ attr_accessor :start,:stop
10
+ def to_a = @a
11
+ def to_s = @a.join
12
+
13
+ # Chars can search a range in UTF-8 for character classes.
14
+ # Use Chars#set to set the start and stop of the range.
8
15
  # i<n>: @start=n.to_i
9
16
  # v<n>: @start=n.to_i(16)
10
17
  # j<n>: @stop=n.to_i
11
18
  # w<n>: @stop=n.to_i(16)
12
19
  def set(s)
20
+ unless /^([ij]\d+)|([vw]\h+)$/.match?(s)
21
+ raise 'expected /^([ij]\d+)|([vw]\h+)$/'
22
+ end
13
23
  t,n = s[0],s[1..-1]
14
24
  case t
15
25
  when 'i','v'
16
26
  @start = n.to_i((t=='v')? 16 : 10)
17
27
  when 'j','w'
18
28
  @stop = n.to_i((t=='w')? 16 : 10)
19
- else
20
- raise 'expected /^([ij]\d+)|([vw]\h+)$/'
21
29
  end
22
30
  end
23
31
 
24
32
  def chars_in(x)
25
33
  case x
26
34
  when Regexp
27
- @start.upto(@stop).each do |l|
28
- c = l.chr(Encoding::UTF_8)
29
- yield c if x.match? c
30
- end
35
+ (@start..@stop).each{x.match?(c=_1.chr(Encoding::UTF_8)) && yield(c)}
31
36
  when Symbol
32
37
  yield x[1..-1].to_i((x[0]=='u')? 16: 10).chr(Encoding::UTF_8)
33
38
  when String
@@ -39,21 +44,8 @@ module BaseConvert
39
44
  end
40
45
  end
41
46
 
42
- def add(x)
43
- chars_in(x) do |c|
44
- self.push(c) unless self.include?(c)
45
- end
46
- end
47
-
48
- def top(x)
49
- chars_in(x) do |c|
50
- self.delete(c)
51
- self.push(c)
52
- end
53
- end
54
-
55
- def remove(x)
56
- chars_in(x){|c| self.delete(c)}
57
- end
47
+ def add(x) = chars_in(x){@a.push _1 unless @a.include?_1}
48
+ def top(x) = chars_in(x){@a.delete _1;@a.push _1}
49
+ def remove(x) = chars_in(x){@a.delete _1}
58
50
  end
59
51
  end
@@ -1,96 +1,134 @@
1
1
  module BaseConvert
2
- class Digits < Hash
3
- alias :get :[]
4
- def [](key)
5
- if self.has_key?(key)
6
- d = super(key)
7
- return d.is_a?(Symbol)? self[d]: d
2
+ class Digits < Hash
3
+ def initialize
4
+ @registry = [:P95, :B64, :U47, :G94, :Q91, :W63]
8
5
  end
9
- case key
10
- when Symbol
11
- chars = Chars.new
12
- key.to_s.scan(/[+-]?[[:alnum:]]+/).each do |type|
13
- if self.has_key?(_=type.to_sym)
14
- chars.add super(_)
15
- next
16
- end
17
- case type
18
- when /^((u\h+)|(k\d+))+$/
19
- type.scan(/[uk]\h+/).each{|s| chars.top s.to_sym}
20
- when /^(([ij]\d+)|([vw]\h+))+$/
21
- type.scan(/[ijvw]\h+/).each{|s| chars.set s}
22
- when /^[a-z][a-z]+$/
23
- chars.add Regexp.new "[[:#{type}:]]"
24
- when /^[a-z]$/
25
- chars.add Regexp.new "\\#{type}"
26
- when /^[A-Z]+$/i
27
- type.scan(/[A-Z][a-z]*/).each{|property| chars.add(/\p{#{property}}/)}
28
- when /^([+-])(\w+)/
29
- d = self[$2.to_sym]
30
- case $1
31
- when '+'
32
- chars.top d
33
- when '-'
34
- chars.remove d
6
+
7
+ # Set super's [] definition as get
8
+ alias :get :[]
9
+ def [](key)
10
+ return (_=get key).is_a?(Symbol)?self[_]:_ if self.has_key? key
11
+ case key
12
+ when Symbol
13
+ chars = Chars.new
14
+ key.to_s.scan(/[+-]?[[:alnum:]]+/).each do |type|
15
+ if self.has_key?(_=type.to_sym)
16
+ chars.add super(_)
17
+ next
18
+ end
19
+ case type
20
+ when /^((u\h+)|(k\d+))+$/ # add single char by code
21
+ type.scan(/[uk]\h+/).each{chars.top _1.to_sym}
22
+ when /^(([ij]\d+)|([vw]\h+))+$/ # set start/stop range
23
+ type.scan(/[ijvw]\h+/).each{chars.set _1}
24
+ when /^[a-z][a-z]+$/ # add by POSIX bracket expression
25
+ chars.add Regexp.new "[[:#{type}:]]"
26
+ when /^[a-z]$/ # add by metacharacter
27
+ chars.add Regexp.new "\\#{type}"
28
+ when /^[A-Z]+$/i # add by property
29
+ type.scan(/[A-Z][a-z]*/).each{chars.add(/\p{#{_1}}/)}
30
+ when /^([+-])(\w+)$/ # top or remove chars of key given
31
+ (_=self[$2.to_sym]) and ($1=='+')? chars.top(_): chars.remove(_)
32
+ when /^(\p{L}+)(\d+)$/ # a registered set
33
+ l,m = $1,$2.to_i-1
34
+ n = self.keys.select{_1=~/^#{l}\d+$/}
35
+ .map{_1.to_s.sub(l,'').to_i}.max
36
+ raise "no #{l}<n> digits defined" if n.nil?
37
+ raise "out of range of #{l}#{n}" unless m<n
38
+ chars.add self[:"#{l}#{n}"][0..m]
39
+ else
40
+ raise "unrecognized digits key: #{type}"
35
41
  end
36
- when /^(\p{L}+)(\d+)$/
37
- l,m = $1,$2.to_i-1
38
- n = self.keys.select{|_|_=~/^#{l}\d+$/}.map{|_|_.to_s.sub(l,'').to_i}.max
39
- raise "no #{l}<n> digits defined" if n.nil?
40
- raise "out of range of #{l}#{n}" unless m<n
41
- chars.add self[:"#{l}#{n}"][0..m]
42
- else
43
- raise "unrecognized digits key: #{type}"
44
42
  end
45
- end
46
- return chars.uniq.join.freeze
47
- when String
48
- digits = nil # set as a side effect...
49
- unless registry.detect{|_|(digits=self[_]).start_with? key}
50
- # ...here -------------->^^^^^
43
+ return chars.to_s.freeze
44
+ when String
45
+ _=@registry.lazy.map{self[_1]}.detect{_1.start_with? key} and return _
51
46
  raise 'need at least 2 digits' unless key.length > 1
52
- raise 'digits must not have duplicates' if key.length > key.chars.uniq.length
47
+ if key.length > key.chars.uniq.length
48
+ raise 'digits must not have duplicates'
49
+ end
53
50
  return key
51
+ when Integer
52
+ raise 'need digits to cover base' if key > 95
53
+ return self[:P95] # Defined in configuration.rb
54
54
  end
55
- return digits
56
- when Integer
57
- raise 'need digits to cover base' if key > 95
58
- return self[:P95] # Defined in configuration.rb
55
+ raise 'digits must be String|Symbol|Integer'
59
56
  end
60
- raise 'digits must be String|Symbol|Integer'
61
- end
62
57
 
63
- def registry(d=nil)
64
- # BaseConvert::Number memoizes and uses specifically :P95, :B64, and :U47;
65
- # giving these precedence above the rest. Defined in configuration.rb.
66
- @registry ||= [:P95, :B64, :U47, :G94, :Q91, :W63]
67
- d ? @registry.detect{|_|self[_].start_with? d}: @registry
68
- end
58
+ def registry(d=nil)
59
+ # BaseConvert::Number memoizes and uses specifically :P95, :B64, and :U47;
60
+ # giving these precedence above the rest.
61
+ d ? @registry.detect{|_|self[_].start_with? d}: @registry
62
+ end
69
63
 
70
- def label(d)
71
- registry(d) or (d[0]+d[1]+d[-2]+d[-1]).to_sym
72
- end
64
+ def label(d)
65
+ registry(d) or (d[0..1]+d[-2..-1]).to_sym
66
+ end
73
67
 
74
- def memoize!(keys=registry)
75
- [*keys].each do |k|
76
- while s = get(k)
77
- break if s.is_a? String # links to a constructed String
78
- raise 'expected Symbol' unless s.is_a? Symbol
79
- k = s
68
+ def memoize!(keys=@registry)
69
+ [*keys].each do |k|
70
+ # follow Symbol links 'till nil|String
71
+ while s=get(k) and not s.is_a? String
72
+ raise 'expected Symbol' unless s.is_a? Symbol
73
+ k = s
74
+ end
75
+ self[k]=self[k] unless s # memoize if needed
80
76
  end
81
- self[k]=self[k] if s.nil? # if not memoized, memoize!
82
77
  end
83
- end
84
78
 
85
- def forget!(keys=registry)
86
- [*keys].each do |k|
87
- while s = get(k)
88
- break if s.is_a? String # links to a constructed String
89
- raise 'expected Symbol' unless s.is_a? Symbol
90
- k = s
79
+ def forget!(keys=@registry)
80
+ [*keys].each do |k|
81
+ # follow Symbol links 'till nil|String
82
+ while s = get(k) and not s.is_a? String
83
+ raise 'expected Symbol' unless s.is_a? Symbol
84
+ k = s
85
+ end
86
+ self.delete(k) if s
91
87
  end
92
- self.delete(k) if s.is_a? String
93
88
  end
94
89
  end
95
- end
90
+
91
+ DIGITS = Digits.new
92
+
93
+ # Naming these letter sequences is inpired by
94
+ # (but not the same as)
95
+ # Unicode character’s General Category.
96
+ DIGITS[:bangs] = '!?'.freeze # Used as method name suffix
97
+ DIGITS[:typers] = '$&@'.freeze # Used as variable name prefix
98
+ DIGITS[:operators] = '*+-/<=>^~'.freeze # Used as mathematical operators
99
+ DIGITS[:separators] = ',.:;|'.freeze # Used to separated items
100
+ DIGITS[:scapes] = '#\\'.freeze # Used to escape what's next
101
+ DIGITS[:groupers] = '()[]{}'.freeze # Used to group items
102
+ DIGITS[:quotes] = %("'`).freeze # Quotes
103
+ DIGITS[:quoters] = %(\%"'`).freeze # Used to quote strings('%' not ASCII ordered)
104
+ DIGITS[:spacers] = '_ '.freeze # 1_000 == 1000 #=> true (Not ASCII ordered)
105
+ DIGITS[:ambiguous] = '012568BDGIOQSZl'.freeze # ASCII ordered ambiguous characters
106
+
107
+ ### Recursive string constructors ###
108
+ # 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%"'`_
109
+ DIGITS[:P95] = :alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers
110
+ # 0123456789ABCDEF
111
+ DIGITS[:hexadecimal] = DIGITS[:hex] = DIGITS[:h] = :P16
112
+ # 0123456789
113
+ DIGITS[:decimal] = DIGITS[:dec] = :P10
114
+ # 01234567
115
+ DIGITS[:octal] = DIGITS[:oct] = DIGITS[:o] = :P8
116
+ # 01
117
+ DIGITS[:b] = DIGITS[:bin] = DIGITS[:binary] = :P2
118
+
119
+ # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
120
+ DIGITS[:G94] = DIGITS[:g] = :graph
121
+
122
+ # !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~
123
+ DIGITS[:Q91] = DIGITS[:qgraph] = DIGITS[:q] = :'graph-quotes'
124
+
125
+ # ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
126
+ DIGITS[:base64] = DIGITS[:b64] = DIGITS[:B64] = :LN_k43k47
127
+ DIGITS[:letters] = DIGITS[:l] = :B52 # subset of B64
128
+
129
+ # 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz
130
+ DIGITS[:word] = DIGITS[:W63] = :w
131
+
132
+ # 3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz
133
+ DIGITS[:unambiguous] = DIGITS[:U47] = DIGITS[:u] = :'alnum-ambiguous'
96
134
  end
@@ -1,6 +1,6 @@
1
1
  module BaseConvert
2
2
  class FromTo
3
- include BaseConvert
3
+ include Methods
4
4
 
5
5
  def initialize(base: 10, to_base: base, digits: :P95, to_digits: digits)
6
6
  base = BASE[base]
@@ -1,13 +1,9 @@
1
1
  # http://rosettacode.org/wiki/Non-decimal_radices/Convert#Ruby
2
2
  module BaseConvert
3
+ module Methods
3
4
  def toi(string=to_s, base=@base, digits=@digits)
4
5
  return nil if string.empty?
5
- integer = 0
6
- string.each_char do |c|
7
- index = digits.index(c)
8
- integer = integer * base + index
9
- end
10
- integer
6
+ string.chars.inject(0){_1*base + digits.index(_2)}
11
7
  end
12
8
 
13
9
  def tos(integer=to_i, base=@base, digits=@digits)
@@ -21,9 +17,10 @@ module BaseConvert
21
17
  string
22
18
  end
23
19
 
24
- def ascii_ordered?(digits=@digits)
25
- (1..(digits.length-1)).all?{|i|digits[i-1]<digits[i]}
20
+ def chars_ordered?(digits=@digits)
21
+ digits.chars.each_cons(2).all?{_1<_2}
26
22
  end
27
23
 
28
24
  extend self
29
25
  end
26
+ end
@@ -1,13 +1,14 @@
1
1
  module BaseConvert
2
2
  class Number
3
- include BaseConvert
3
+ include Methods
4
4
  DIGITS.memoize!
5
+ INDEXa = DIGITS[:P95].index('a')
5
6
 
6
- def self.infer(string)
7
+ def self.infer(string, error:'digits not all in P95')
7
8
  p95 = DIGITS[:P95]
8
9
  return 2, p95 if string.empty?
9
10
  chars = string.chars
10
- raise 'need digits to cover string' unless chars.all?{|_|p95.include?_}
11
+ raise error unless chars.all?{|_|p95.include?_}
11
12
  max = chars.map{|_|p95.index(_)}.max
12
13
  return 95, p95 if max == 94 # string has a space digit.
13
14
  return 2, p95 if max < 2
@@ -26,20 +27,16 @@ class Number
26
27
 
27
28
  attr_reader :base, :digits
28
29
  def initialize(counter=0, base: nil, digits: nil, validate: true)
29
- # validate
30
- case validate
31
- when true, false
32
- @validate = validate
33
- else
34
- raise 'validate must be either true or false'
35
- end
30
+ @validate = !!validate # ensure boolean
36
31
 
37
32
  # counter
38
33
  string = nil
39
34
  case counter
40
35
  when String
41
36
  string = counter
42
- base, digits = Number.infer(counter) if base.nil? and digits.nil?
37
+ if base.nil? and digits.nil?
38
+ base, digits = Number.infer(counter, error:'need digits to cover string')
39
+ end
43
40
  when Integer
44
41
  @integer = counter
45
42
  base, digits = 10, DIGITS[:P95] if base.nil? and digits.nil?
@@ -51,21 +48,22 @@ class Number
51
48
  @digits = DIGITS[digits || base]
52
49
 
53
50
  # base
54
- base = digits if base.nil? and digits.is_a? Symbol
51
+ base = digits if base.nil? and digits.is_a? Symbol
55
52
  @base = BASE[base || @digits.length]
56
53
 
57
54
  # validate
58
55
  if @validate
59
56
  raise 'digits must cover base' if @base > @digits.length
60
57
  unless string.nil? or string.empty?
61
- indeces = string.chars.map{|_|@digits.index(_)}
62
- if missing = indeces.any?{|_|_.nil?} or exceeding = indeces.any?{|_|_>=@base}
58
+ indeces = string.chars.map{@digits.index _1}
59
+ if missing = indeces.any?{_1.nil?} or exceeding = indeces.any?{_1>=@base}
63
60
  if @base <= INDEXa and DIGITS[:P95].start_with?(@digits)
61
+ # User ignored case, so fix it...
64
62
  string = string.upcase
65
- indeces = string.chars.map{|_|@digits.index(_)}
66
- missing = indeces.any?{|_|_.nil?} or exceeding = indeces.any?{|_|_>=@base}
63
+ indeces = string.chars.map{@digits.index _1}
64
+ missing = indeces.any?{_1.nil?} or exceeding = indeces.any?{_1>=@base}
67
65
  end
68
- raise 'digits must cover string' if missing
66
+ raise 'digits must cover string' if missing
69
67
  raise 'digits in string must be under base' if exceeding
70
68
  end
71
69
  end
@@ -82,15 +80,9 @@ class Number
82
80
  "#{to_s} #{@base}:#{d}"
83
81
  end
84
82
 
85
- def validate?
86
- @validate
87
- end
88
-
83
+ def validate? = @validate
89
84
  alias to_s tos
90
-
91
- def to_i
92
- @integer
93
- end
85
+ def to_i = @integer
94
86
 
95
87
  def to_base(base, digits=(base.is_a?Symbol)? DIGITS[base] : @digits, validate=@validate)
96
88
  Number.new @integer, base: base, digits: digits, validate: validate
data/lib/base_convert.rb CHANGED
@@ -1,11 +1,10 @@
1
1
  module BaseConvert
2
- VERSION = '6.0.210201'
3
- require 'base_convert/base_convert'
4
- require 'base_convert/chars'
5
- require 'base_convert/digits'
6
- require 'base_convert/base'
7
- require 'base_convert/configuration'
8
- require 'base_convert/from_to'
9
- require 'base_convert/number'
2
+ VERSION = '7.0.221226'
3
+ autoload :Methods, 'base_convert/methods.rb'
4
+ autoload :Chars, 'base_convert/chars.rb'
5
+ autoload :DIGITS, 'base_convert/digits.rb'
6
+ autoload :BASE, 'base_convert/base.rb'
7
+ autoload :FromTo, 'base_convert/from_to.rb'
8
+ autoload :Number, 'base_convert/number.rb'
10
9
  end
11
10
  #`ruby`
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: base_convert
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.210201
4
+ version: 7.0.221226
5
5
  platform: ruby
6
6
  authors:
7
- - carlosjhr64
8
- autorequire:
7
+ - CarlosJHR64
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-01 00:00:00.000000000 Z
11
+ date: 2022-12-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  BaseConvert - Number base conversion.
@@ -25,17 +25,16 @@ files:
25
25
  - README.md
26
26
  - lib/base_convert.rb
27
27
  - lib/base_convert/base.rb
28
- - lib/base_convert/base_convert.rb
29
28
  - lib/base_convert/chars.rb
30
- - lib/base_convert/configuration.rb
31
29
  - lib/base_convert/digits.rb
32
30
  - lib/base_convert/from_to.rb
31
+ - lib/base_convert/methods.rb
33
32
  - lib/base_convert/number.rb
34
33
  homepage: https://github.com/carlosjhr64/base_convert
35
34
  licenses:
36
35
  - MIT
37
36
  metadata: {}
38
- post_install_message:
37
+ post_install_message:
39
38
  rdoc_options: []
40
39
  require_paths:
41
40
  - lib
@@ -50,9 +49,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
49
  - !ruby/object:Gem::Version
51
50
  version: '0'
52
51
  requirements:
53
- - 'ruby: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]'
54
- rubygems_version: 3.2.3
55
- signing_key:
52
+ - 'ruby: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [aarch64-linux]'
53
+ rubygems_version: 3.3.7
54
+ signing_key:
56
55
  specification_version: 4
57
56
  summary: BaseConvert - Number base conversion.
58
57
  test_files: []
@@ -1,88 +0,0 @@
1
- module BaseConvert
2
- DIGITS = Digits.new
3
-
4
- # Naming these letter sequences is inpired by
5
- # (but not the same as)
6
- # Unicode character’s General Category.
7
- DIGITS[:bangs] = '!?'.freeze # Used as method name suffix
8
- DIGITS[:typers] = '$&@'.freeze # Used as variable name prefix
9
- DIGITS[:operators] = '*+-/<=>^~'.freeze # Used as mathematical operators
10
- DIGITS[:separators] = ',.:;|'.freeze # Used to separated items
11
- DIGITS[:scapes] = '#\\'.freeze # Used to escape what's next
12
- DIGITS[:groupers] = '()[]{}'.freeze # Used to group items
13
- DIGITS[:quotes] = %("'`).freeze # Quotes
14
- DIGITS[:quoters] = %(\%"'`).freeze # Used to quote strings('%' not ASCII ordered)
15
- DIGITS[:spacers] = '_ '.freeze # 1_000 == 1000 #=> true (Not ASCII ordered)
16
- DIGITS[:ambiguous] = '012568BDGIOQSZl'.freeze # ASCII ordered ambiguous characters
17
-
18
- ### Recursive string constructors ###
19
- # 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%"'`_
20
- DIGITS[:P95] = :alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers
21
- INDEXa = DIGITS[:P95].index('a')
22
- # 0123456789ABCDEF
23
- DIGITS[:hexadecimal] = DIGITS[:hex] = DIGITS[:h] = :P16
24
- # 0123456789
25
- DIGITS[:decimal] = DIGITS[:dec] = :P10
26
- # 01234567
27
- DIGITS[:octal] = DIGITS[:oct] = DIGITS[:o] = :P8
28
- # 01
29
- DIGITS[:b] = DIGITS[:bin] = DIGITS[:binary] = :P2
30
-
31
- # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
32
- DIGITS[:G94] = DIGITS[:g] = :graph
33
-
34
- # !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~
35
- DIGITS[:Q91] = DIGITS[:qgraph] = DIGITS[:q] = :'graph-quotes'
36
-
37
- # ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
38
- DIGITS[:base64] = DIGITS[:b64] = DIGITS[:B64] = :LN_k43k47
39
- DIGITS[:letters] = DIGITS[:l] = :B52 # subset of B64
40
-
41
- # 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz
42
- DIGITS[:word] = DIGITS[:W63] = :w
43
-
44
- # 3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz
45
- DIGITS[:unambiguous] = DIGITS[:U47] = DIGITS[:u] = :'alnum-ambiguous'
46
-
47
- BASE = Base[
48
- # 95
49
- P95: 95,
50
- print: 95,
51
- # 94
52
- G94: 94, g: 94, graph: 94,
53
- # 91
54
- Q91: 91, qgraph: 91, q: 91,
55
- # 64
56
- B64: 64, base64: 64, b64: 64,
57
- # 63
58
- W63: 63, word: 63, w: 63,
59
- # 52
60
- letters: 52, l: 52, L: 52,
61
- # 47
62
- U47: 47, unambiguous: 47, u: 47,
63
- # 16
64
- hexadecimal: 16, hex: 16, h: 16,
65
- # 15
66
- ambiguous: 15,
67
- # 10
68
- decimal: 10, dec: 10, d: 10,
69
- # 9
70
- operators: 9,
71
- # 8
72
- octal: 8, oct: 8, o: 8,
73
- # 6
74
- groupers: 6,
75
- # 5
76
- separators: 5,
77
- # 4
78
- quoters: 4,
79
- # 3
80
- typers: 3,
81
- quotes: 3,
82
- # 2
83
- binary: 2, bin: 2, b: 2,
84
- bangs: 2,
85
- scapes: 2,
86
- spacers: 2,
87
- ]
88
- end