base_convert 6.0.210201 → 7.0.221226

Sign up to get free protection for your applications and to get access to all the features.
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