chrad 1.1.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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +23 -0
- data/LICENSE.txt +21 -0
- data/README.md +188 -0
- data/Rakefile +13 -0
- data/certs/pdkl95.pem +25 -0
- data/chrad.gemspec +32 -0
- data/exe/chrad +5 -0
- data/lib/chrad/algorithms.rb +18 -0
- data/lib/chrad/alphabet.rb +95 -0
- data/lib/chrad/cli.rb +183 -0
- data/lib/chrad/io_manager.rb +136 -0
- data/lib/chrad/version.rb +3 -0
- data/lib/chrad.rb +20 -0
- data.tar.gz.sig +0 -0
- metadata +86 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b2496ecbaa44e120f9be12f8850bafcbc91cb6be85fde1d89afe392260829fd7
|
4
|
+
data.tar.gz: b86d3009434f1ac3007fbda668d3c671d56e98227896ee66a3c4576b896b9367
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 74a95665031363af6adb52cd4daf79f1564864164479055b60906e01d60474eac2ca9c50803447cb34b71ea62b4c2bb3409363b8ae5c22ff0d3a422c8533c62a
|
7
|
+
data.tar.gz: d7c89246f637683d07b8166d5f681688323514105d8adc7b0db69864e3288a05b8489492254cd33ab5434c25a5c45f44232432f1160f5024a0688491367d0407
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
chrad (1.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
byebug (11.1.3)
|
10
|
+
minitest (5.16.2)
|
11
|
+
rake (12.3.3)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
x86_64-linux
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
byebug (~> 11.1)
|
18
|
+
chrad!
|
19
|
+
minitest (~> 5.0)
|
20
|
+
rake (~> 12.0)
|
21
|
+
|
22
|
+
BUNDLED WITH
|
23
|
+
2.3.9
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2022 Brent Sanders
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# ChRad
|
2
|
+
|
3
|
+
Change Radix. A command line utility to convert integer bases.
|
4
|
+
|
5
|
+
Arbitrarily large numbers are supported thanks to ruby's built-in
|
6
|
+
support for bignums. Conversion to or from any positive integer fixed
|
7
|
+
base system is supported.
|
8
|
+
|
9
|
+
Mixed-radix systems are not supported. For converting numbers in the factoradic
|
10
|
+
(factorial base) system, use my [factoradic gem][fact_gem] or [faster c utility][c_util].
|
11
|
+
|
12
|
+
[fact_gem]: https://github.com/pdkl95/factoradic
|
13
|
+
|
14
|
+
[c_util]: https://github.com/pdkl95/factoradic_c_utils
|
15
|
+
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Run:
|
20
|
+
|
21
|
+
gem install chrad
|
22
|
+
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
### The command line utility
|
27
|
+
|
28
|
+
#### Options
|
29
|
+
|
30
|
+
```
|
31
|
+
Usage: chrad [options] -i <input_base> -o <output_base> <number> [...]
|
32
|
+
|
33
|
+
REQUIRED OPTIONS
|
34
|
+
|
35
|
+
-i, --input=BASE Interpret input strings integers in base <BASE>
|
36
|
+
-o, --output=BASE Print converted numbers as integers in base <BASE>
|
37
|
+
|
38
|
+
INPUT/OUTPUT FORMAT
|
39
|
+
|
40
|
+
--input-list Input values as delimiter separated lists
|
41
|
+
--output-list Output values as delimiter separated lists
|
42
|
+
-l, --list Both input and output values as delimiter separated lists
|
43
|
+
(Shorthand for using both --input-list and --output-list)
|
44
|
+
--input-sep=CHAR Use <CHAR> as the delimiter between places
|
45
|
+
in input vales when using --input-list mode
|
46
|
+
--output-sep=CHAR Use <CHAR> as the delimiter between places
|
47
|
+
in output vales when using --output-list mode
|
48
|
+
-s, --separator=CHAR Use <CHAR> as the delimiter between places in both
|
49
|
+
input and output list modes. (shorthand for using
|
50
|
+
both --input-separator=CHAR and --output-separator=CHAR)
|
51
|
+
|
52
|
+
DIGIT ALPHABET
|
53
|
+
|
54
|
+
--input-digits=STR Use the given <STR> as the set of chars to use
|
55
|
+
when interpreting input integers.
|
56
|
+
(Ignored when using--input-list mode.)
|
57
|
+
--output-digits=STR Use the given <STR> as the set of chars to use
|
58
|
+
when printing number in the output base.
|
59
|
+
(Ignored when using--input-list mode.)
|
60
|
+
-d, --digits=STR Use the given <STR> as the set of chars to use
|
61
|
+
for both input and output. (shorthand for using
|
62
|
+
both --input-digits=STR and --output-digits=STR)
|
63
|
+
|
64
|
+
--list-named-digits List the built-in named digit sets. These names
|
65
|
+
can be passed to any of --digits, --input-digits,
|
66
|
+
or --output-digits using the \"name:\" prefix.
|
67
|
+
(example: \"--digits=base64\")
|
68
|
+
-h, --help Show this help message
|
69
|
+
--version Show version
|
70
|
+
```
|
71
|
+
|
72
|
+
|
73
|
+
#### Examples
|
74
|
+
|
75
|
+
```
|
76
|
+
$ chrad -i 10 -o 16 255
|
77
|
+
ff
|
78
|
+
|
79
|
+
$ chrad -i 16 -o 2 c9
|
80
|
+
11001001
|
81
|
+
|
82
|
+
$ chrad -i 10 -o 64 --output-digits=name:base64 129633344153503
|
83
|
+
deadbeef
|
84
|
+
|
85
|
+
$ chrad -i 10 -o 64 --output-list 129633344153503
|
86
|
+
29,30,26,29,27,30,30,31
|
87
|
+
|
88
|
+
$ chrad -i 64 -o 64 --input-list --output-digits=name:base64 29,30,26,29,27,30,30,31
|
89
|
+
deadbeef
|
90
|
+
|
91
|
+
$ chrad -i 10 -o 4 --output-digits='♠♡♢♣' 4321
|
92
|
+
♡♠♠♣♢♠♡
|
93
|
+
|
94
|
+
$ print3nums() { echo 255 ; echo 65535 ; echo 16777215 ; }
|
95
|
+
$ print3nums | chrad -i 10 -o 16 --stdin
|
96
|
+
ff
|
97
|
+
ffff
|
98
|
+
ffffff
|
99
|
+
```
|
100
|
+
|
101
|
+
|
102
|
+
### Input/Output
|
103
|
+
|
104
|
+
To represent a number in a given base, a set of digits must be available
|
105
|
+
that is at least as large as that base. To support this, chrad allows
|
106
|
+
you to provide a string of characters to use for input, output, or
|
107
|
+
both (with `--input-digits`, `--output-digits`, and `--digits`
|
108
|
+
respectively).
|
109
|
+
|
110
|
+
```
|
111
|
+
$ chrad -i 16 -o 3 --output-digits .-/ 5717063
|
112
|
+
/.-../---/...-/./
|
113
|
+
```
|
114
|
+
|
115
|
+
|
116
|
+
#### Built-in Digit Sets
|
117
|
+
|
118
|
+
Several commonly used sets of digits are built-in. To use a built-in
|
119
|
+
set, use the name of the wet with the `--digits` options and a `name:`
|
120
|
+
prefix.
|
121
|
+
|
122
|
+
```
|
123
|
+
$ chrad -i 16 -o 64 --output-digits=name:base64 dea
|
124
|
+
```
|
125
|
+
|
126
|
+
The built-in digit sets are:
|
127
|
+
```
|
128
|
+
$ chrad --list-named-digits
|
129
|
+
name:base62 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
|
130
|
+
name:base64 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
|
131
|
+
name:base64url ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_
|
132
|
+
name:base32rfc ABCDEFGHIJKLMNOPQRSTUVWXYZ234567
|
133
|
+
name:base32 0123456789abcdefghijklmnopqrstuv
|
134
|
+
name:base16 0123456789abcdef
|
135
|
+
```
|
136
|
+
|
137
|
+
The sets `base16` and `base32` are the common hexadecimal-style
|
138
|
+
extension of the base 10 digits. The sets `base64`, `base64url`, and
|
139
|
+
`base32rfc` are from [RFC 3548][rfc3548].
|
140
|
+
|
141
|
+
[rfc3548]: https://datatracker.ietf.org/doc/html/rfc3548
|
142
|
+
|
143
|
+
|
144
|
+
#### List Mode
|
145
|
+
|
146
|
+
When converting numbers in very large bases, finding appropriate
|
147
|
+
characters to use becomes difficult. To avoid this problem, use list
|
148
|
+
mode. List mode can also make integration easier because it is a
|
149
|
+
base-independent representation.
|
150
|
+
|
151
|
+
List mode can be enabled for input, output, or both with
|
152
|
+
`--input-list`, `--output-list`, and `-l/--list` respectively. When
|
153
|
+
list mode is enabled, numbers are represented as a comma (`","`)
|
154
|
+
separated list of base 10 integers.
|
155
|
+
|
156
|
+
```
|
157
|
+
$ chrad -i 10 -o 64 --output-list 16772988
|
158
|
+
63,62,61,60
|
159
|
+
|
160
|
+
$ chrad -i 64 -o 16 --input-list 3,30,43,27,59,47
|
161
|
+
deadbeef
|
162
|
+
|
163
|
+
$ chrad -i 8 -o 16 --list 5,4,3,2,1
|
164
|
+
5,8,13,1
|
165
|
+
```
|
166
|
+
|
167
|
+
The comma separator can be changed to any character with the
|
168
|
+
`--input-sep`, `--output-sep`, and `-s/--separator` options.
|
169
|
+
|
170
|
+
```
|
171
|
+
$ chrad -i 10 -o 64 --output-list --output-sep=: 16772988
|
172
|
+
63:62:61:60
|
173
|
+
```
|
174
|
+
|
175
|
+
|
176
|
+
## Development
|
177
|
+
|
178
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
179
|
+
|
180
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
181
|
+
|
182
|
+
## Contributing
|
183
|
+
|
184
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/pdkl95/chrad.
|
185
|
+
|
186
|
+
## License
|
187
|
+
|
188
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "minitest/test_task"
|
5
|
+
|
6
|
+
Minitest::TestTask.create(:test) do |t|
|
7
|
+
t.libs << "test"
|
8
|
+
t.libs << "lib"
|
9
|
+
t.warning = false
|
10
|
+
t.test_globs = ["test/**/*_test.rb"]
|
11
|
+
end
|
12
|
+
|
13
|
+
task default: :test
|
data/certs/pdkl95.pem
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIEMDCCApigAwIBAgIBATANBgkqhkiG9w0BAQsFADAhMR8wHQYDVQQDDBZwZGts
|
3
|
+
OTUvREM9Z21haWwvREM9Y29tMB4XDTIyMDIwMTIxNDQxMFoXDTIzMDIwMTIxNDQx
|
4
|
+
MFowITEfMB0GA1UEAwwWcGRrbDk1L0RDPWdtYWlsL0RDPWNvbTCCAaIwDQYJKoZI
|
5
|
+
hvcNAQEBBQADggGPADCCAYoCggGBAJrJqYa1q3ckmQ6L0v5r2KpJLFrks7L9cmpO
|
6
|
+
qdo3QdUZqnBbIIuhkUOy+rzUM//lCvZeT2Rym8zysJWslATnjhqoKdC6HhAnM7u8
|
7
|
+
puI1Xgr0vy84YCc4Ec0iRyrUQkwRB0flQ1XzmH4CJzMD9HafjF0JbCakoawxYsWu
|
8
|
+
A8DJ4mZn8sdz0BjGF5nHaLtt/cTx4FQpHLcU6AJSep0BP+fn87HGsrvhLEcITx5v
|
9
|
+
8KYnWAdCEiSVCprmANn0rEeD/vCONotRdUBGSmx6aYV/ijujS+ND7a0hk8d3lhkk
|
10
|
+
yvW9L4GM6i3lDsM/wlNBG/HwJuuI06Nve/FC53XYUbh6oyszHiwf8F3jpd9LVHiz
|
11
|
+
hO05+X59sJfbC26k8HdsI8/hodDJfgJ4VM5sOqqg3yKV8h6kySiGFSr1XeWddblg
|
12
|
+
Zz5jRp85cQsLQWUKWBfxGG3Jnqe8h+aflTaUqnU1EWkEyS0BsotZAFD5t5yX55WD
|
13
|
+
dlaJPfF7IyJABxsY+L9LvmWUPFx4RwIDAQABo3MwcTAJBgNVHRMEAjAAMAsGA1Ud
|
14
|
+
DwQEAwIEsDAdBgNVHQ4EFgQUsdOGedmK14HgEtn36tJY4fFiPyUwGwYDVR0RBBQw
|
15
|
+
EoEQcGRrbDk1QGdtYWlsLmNvbTAbBgNVHRIEFDASgRBwZGtsOTVAZ21haWwuY29t
|
16
|
+
MA0GCSqGSIb3DQEBCwUAA4IBgQA481LIo+nYP69SRZgo6Okpii2kO3URi+aR5TLC
|
17
|
+
8BZI/z5/NuYZivMuaMenL90NmeF3LYjmKrOhQD0JmW48YmWQB19b2kIbExBqmu3V
|
18
|
+
JomVhCTLZ+oU3NhzQ5fL70DUhOz7CUCKpLV5lsUyUEGjebDFN21j4GjyeDFqkphj
|
19
|
+
/d2Qe2I5NLzga3tB1AOBqH0EAf3GSWDp1KkWDSUpUCbhjI+CAu4tpUj74HuCBG4g
|
20
|
+
QSTyCS7bp79NUcLmDGJ/43ZgPpJwo6wdV5uo3BQMq8AzRDnTXW1EeGlBOTaDCCvp
|
21
|
+
N7ImUU63/qmLKyPskr53EKYR6bzvF4V+w5+Lq/JxWIbaB5UxY1kCxGrOubzQLvwE
|
22
|
+
tf/k74CEmUNN71A4MXGVuydmgrlok/LBZO8Lqa9Dt+95nBdqKz5vIcO6szPGZIid
|
23
|
+
NMwK52EhsO4bDuwRB7r1zYTj42O24s0o0yJQPzqhfQEGssdLDNkEr147K0symobj
|
24
|
+
l35DiP6VyFMH/Y0JWgs65E5bGzk=
|
25
|
+
-----END CERTIFICATE-----
|
data/chrad.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative "lib/chrad/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "chrad"
|
5
|
+
spec.version = ChRad::VERSION
|
6
|
+
spec.authors = ["Brent Sanders"]
|
7
|
+
spec.email = ["git@gmail.com"]
|
8
|
+
|
9
|
+
spec.summary = %q{Command line util to convert integer base}
|
10
|
+
spec.description = %q{A commsnd line utility to convert integers into arbitrary bases.}
|
11
|
+
|
12
|
+
spec.homepage = "https://github.com/pdkl95/chrad"
|
13
|
+
spec.license = "MIT"
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
15
|
+
|
16
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
17
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
18
|
+
|
19
|
+
spec.cert_chain = ['certs/pdkl95.pem']
|
20
|
+
spec.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
26
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
spec.bindir = "exe"
|
30
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ["lib"]
|
32
|
+
end
|
data/exe/chrad
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module ChRad
|
2
|
+
module Algorithms
|
3
|
+
def self.number_to_base(number, base)
|
4
|
+
if number == 0
|
5
|
+
return [0]
|
6
|
+
end
|
7
|
+
|
8
|
+
digits = []
|
9
|
+
while number > 0
|
10
|
+
div, mod = number.divmod(base)
|
11
|
+
digits.push(mod)
|
12
|
+
number = div
|
13
|
+
end
|
14
|
+
|
15
|
+
digits
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module ChRad
|
2
|
+
class Alphabet
|
3
|
+
B62 = (
|
4
|
+
('A'..'Z').to_a +
|
5
|
+
('a'..'z').to_a +
|
6
|
+
(0..9).to_a.map(&:to_s)
|
7
|
+
)
|
8
|
+
|
9
|
+
B32rfc = (
|
10
|
+
('A'..'Z').to_a +
|
11
|
+
('2'..'7').to_a
|
12
|
+
)
|
13
|
+
|
14
|
+
B32 = (
|
15
|
+
('0'..'9').to_a +
|
16
|
+
('a'..'v').to_a
|
17
|
+
)
|
18
|
+
|
19
|
+
B16 = (
|
20
|
+
('0'..'9').to_a +
|
21
|
+
('a'..'f').to_a
|
22
|
+
)
|
23
|
+
|
24
|
+
def self.all
|
25
|
+
@all ||= Hash.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.add(name, digits)
|
29
|
+
all[name.to_s] = digits
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.find(name)
|
33
|
+
all[name.to_s]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.[](name)
|
37
|
+
find(name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.names
|
41
|
+
all.keys
|
42
|
+
end
|
43
|
+
|
44
|
+
add :base62, B62
|
45
|
+
add :base64, B62 + %w(+ /)
|
46
|
+
add :base64url, B62 + %w(- _)
|
47
|
+
add :base32rfc, B32rfc
|
48
|
+
add :base32, B32
|
49
|
+
add :base16, B16
|
50
|
+
|
51
|
+
|
52
|
+
attr_reader :name, :digits
|
53
|
+
|
54
|
+
def initialize(name, digit_chars)
|
55
|
+
@name = name
|
56
|
+
|
57
|
+
self.digits = digit_chars
|
58
|
+
end
|
59
|
+
|
60
|
+
def digits=(value)
|
61
|
+
new_digits = []
|
62
|
+
case value
|
63
|
+
when String
|
64
|
+
self.digits = value.each_char.to_a
|
65
|
+
|
66
|
+
when Array
|
67
|
+
value.each do |ch|
|
68
|
+
if new_digits.include?(ch)
|
69
|
+
raise InvalidInputError,
|
70
|
+
"Cannot add duplicate characters (\"#{ch}\")"
|
71
|
+
else
|
72
|
+
new_digits.push ch.to_s
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@digits = new_digits
|
77
|
+
|
78
|
+
else
|
79
|
+
raise Error, "Cannot set digits from a \"${value}\". Expected a list of digits as a String or Array"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def [](*args)
|
84
|
+
digits[*args]
|
85
|
+
end
|
86
|
+
|
87
|
+
def length
|
88
|
+
digits.length
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_s
|
92
|
+
digits.join('')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/chrad/cli.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'chrad'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
module ChRad
|
5
|
+
class CLI
|
6
|
+
attr_reader :argv
|
7
|
+
|
8
|
+
def initialize(argv = ARGV)
|
9
|
+
@argv = argv.map do |x|
|
10
|
+
x.to_s
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def input
|
15
|
+
@input ||= ChRad::InputManager.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def output
|
19
|
+
@output ||= ChRad::OutputManager.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def optparse
|
23
|
+
@optparse ||= OptionParser.new do |opts|
|
24
|
+
opts.banner = "Converts integers into a different base (radix)."
|
25
|
+
opts.define_head "Usage: #{$0} [options] -i <input_base> -o <output_base> <number> [...]"
|
26
|
+
opts.summary_width = 24
|
27
|
+
opts.summary_indent = ' '
|
28
|
+
|
29
|
+
opts.separator ''
|
30
|
+
opts.separator 'REQUIRED OPTIONS'
|
31
|
+
opts.separator ''
|
32
|
+
|
33
|
+
opts.on('-iBASE', '--input=BASE',
|
34
|
+
'Interpret input strings integers in base <BASE>'
|
35
|
+
) do |base|
|
36
|
+
input.base = base
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on('-oBASE', '--output=BASE',
|
40
|
+
'Print converted numbers as integers in base <BASE>'
|
41
|
+
) do |base|
|
42
|
+
output.base = base
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
opts.separator ''
|
47
|
+
opts.separator 'INPUT/OUTPUT FORMAT'
|
48
|
+
opts.separator ''
|
49
|
+
|
50
|
+
opts.on('--input-list',
|
51
|
+
'Input values as delimiter separated lists'
|
52
|
+
) do
|
53
|
+
input.mode = :list
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.on('--output-list',
|
57
|
+
'Output values as delimiter separated lists'
|
58
|
+
) do
|
59
|
+
output.mode = :list
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on('-l', '--list',
|
63
|
+
'Both input and output values as delimiter separated lists',
|
64
|
+
'(Shorthand for using both --input-list and --output-list)'
|
65
|
+
) do
|
66
|
+
input.mode = :list
|
67
|
+
output.mode = :list
|
68
|
+
end
|
69
|
+
|
70
|
+
opts.on('--input-sep=CHAR',
|
71
|
+
'Use <CHAR> as the delimiter between places',
|
72
|
+
'in input vales when using --input-list mode'
|
73
|
+
) do |sep|
|
74
|
+
input.separator = sep
|
75
|
+
end
|
76
|
+
|
77
|
+
opts.on('--output-sep=CHAR',
|
78
|
+
'Use <CHAR> as the delimiter between places',
|
79
|
+
'in output vales when using --output-list mode'
|
80
|
+
) do |sep|
|
81
|
+
output.separator = sep
|
82
|
+
end
|
83
|
+
|
84
|
+
opts.on('-s', '--separator=CHAR',
|
85
|
+
'Use <CHAR> as the delimiter between places in both',
|
86
|
+
'input and output list modes. (shothand for using',
|
87
|
+
'both --input-separator=CHAR and --output-separator=CHAR)'
|
88
|
+
) do |sep|
|
89
|
+
input.separator = sep
|
90
|
+
output.separator = sep
|
91
|
+
end
|
92
|
+
|
93
|
+
opts.separator ''
|
94
|
+
opts.separator 'DIGIT ALPHABET'
|
95
|
+
opts.separator ''
|
96
|
+
|
97
|
+
opts.on('--input-digits=STR',
|
98
|
+
'Use the given <STR> as the set of chars to use',
|
99
|
+
'when interpreting input integers.',
|
100
|
+
'(Ignored when using--input-list mode.)'
|
101
|
+
) do |str|
|
102
|
+
input.alphabet = str
|
103
|
+
end
|
104
|
+
|
105
|
+
opts.on('--output-digits=STR',
|
106
|
+
'Use the given <STR> as the set of chars to use',
|
107
|
+
'when printing number in the output base.',
|
108
|
+
'(Ignored when using--input-list mode.)'
|
109
|
+
) do |str|
|
110
|
+
output.alphabet = str
|
111
|
+
end
|
112
|
+
|
113
|
+
opts.on('-d', '--digits=STR',
|
114
|
+
'Use the given <STR> as the set of chars to use',
|
115
|
+
'for both input and output. (shorthand for using',
|
116
|
+
'both --input-digits=STR and --output-digits=STR)'
|
117
|
+
) do |str|
|
118
|
+
input.alphabet = str
|
119
|
+
output.alphabet = str
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
opts.separator ''
|
124
|
+
|
125
|
+
opts.on('--stdin',
|
126
|
+
'Read one number per line from STDIN instead',
|
127
|
+
'of ARGV. Equivalent to using the single',
|
128
|
+
'character "-" as the first arg.'
|
129
|
+
) do
|
130
|
+
input.force_stdin = true
|
131
|
+
end
|
132
|
+
|
133
|
+
opts.on('--list-named-digits',
|
134
|
+
'List the built-in named digit sets. These names',
|
135
|
+
'can be passed to any of --digits, --input-digits,',
|
136
|
+
'or --output-digits using the \"name:\" prefix.',
|
137
|
+
'(example: \"--digits=base64\")'
|
138
|
+
) do
|
139
|
+
Alphabet.all.each_pair do |name, digits|
|
140
|
+
puts "name:#{name}\t#{digits.join('')}"
|
141
|
+
end
|
142
|
+
exit
|
143
|
+
end
|
144
|
+
|
145
|
+
opts.on('-h', '--help', 'Show this help message') do
|
146
|
+
puts opts
|
147
|
+
exit
|
148
|
+
end
|
149
|
+
|
150
|
+
opts.on('--version', 'Show version') do
|
151
|
+
puts ChRad::VERSION
|
152
|
+
exit
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def run!
|
158
|
+
optparse.parse!(argv)
|
159
|
+
|
160
|
+
if argv.length > 0
|
161
|
+
unless argv.first == '-'
|
162
|
+
unless input.force_stdin
|
163
|
+
input.stream = argv
|
164
|
+
end
|
165
|
+
end
|
166
|
+
else
|
167
|
+
unless input.force_stdin
|
168
|
+
puts optparse
|
169
|
+
exit 1
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
input.setup_base_digits!
|
174
|
+
output.setup_base_digits!
|
175
|
+
|
176
|
+
input.stream.each do |arg|
|
177
|
+
arg = arg.chomp
|
178
|
+
number = input.parse(arg)
|
179
|
+
output.stream_puts(number)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require_relative 'algorithms'
|
2
|
+
|
3
|
+
module ChRad
|
4
|
+
class IOManager
|
5
|
+
attr_accessor :stream, :base
|
6
|
+
attr_writer :mode, :separator
|
7
|
+
attr_reader :digits
|
8
|
+
|
9
|
+
def mode
|
10
|
+
@mode ||= DEFAULT_MODE
|
11
|
+
end
|
12
|
+
|
13
|
+
def base=(value)
|
14
|
+
case value
|
15
|
+
when Integer
|
16
|
+
@base = value
|
17
|
+
when /\A[0-9]+\Z/
|
18
|
+
@base = value.to_i
|
19
|
+
else
|
20
|
+
raise Error, "Trying to set #{name} base to #{value.inspect} (expected an Integer or a string matching /[0-9]+/"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def separator
|
25
|
+
@separator ||= DEFAULT_SEPARATOR
|
26
|
+
end
|
27
|
+
|
28
|
+
def alphabet
|
29
|
+
@alphabet ||= DEFAULT_ALPHABET
|
30
|
+
end
|
31
|
+
|
32
|
+
def alphabet=(str)
|
33
|
+
@alphabet = automagic_find_alphabet(str)
|
34
|
+
end
|
35
|
+
|
36
|
+
def automagic_find_alphabet(str)
|
37
|
+
case str
|
38
|
+
when /\Aname:(\w+)\Z/
|
39
|
+
Alphabet.find($1) or raise Error, "No digit alphabet named \"#{$1}\""
|
40
|
+
else
|
41
|
+
Alphabet.new("custom_#{name}", str)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def setup_base_digits!
|
46
|
+
case mode
|
47
|
+
when :alphabet
|
48
|
+
if base > alphabet.length
|
49
|
+
raise Error, "Trying to use base #{base}, but the input alphabet only has #{alphabet.length} characters."
|
50
|
+
end
|
51
|
+
|
52
|
+
@digits = alphabet[0, base]
|
53
|
+
|
54
|
+
when :list
|
55
|
+
# not needed in :list mode
|
56
|
+
|
57
|
+
else
|
58
|
+
raise Error, "Invalid mode #{mode.inspect}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def value_to_digit(value)
|
63
|
+
raise Error, '@digits == nil' if @digits.nil?
|
64
|
+
@digits[value]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class InputManager < IOManager
|
69
|
+
attr_accessor :force_stdin
|
70
|
+
|
71
|
+
def initialize
|
72
|
+
@base = DEFAULT_INPUT_BASE
|
73
|
+
@stream = $stdin
|
74
|
+
@force_stdin = false
|
75
|
+
end
|
76
|
+
|
77
|
+
def name
|
78
|
+
'input'
|
79
|
+
end
|
80
|
+
|
81
|
+
def parse(str)
|
82
|
+
case mode
|
83
|
+
when :alphabet
|
84
|
+
str.reverse.each_char.map.with_index do |c, idx|
|
85
|
+
value = digits.index(c)
|
86
|
+
if value.nil?
|
87
|
+
raise Error, "Input digit #{c.inspect} is not a valid input digit (expected: #{digits.join('')})"
|
88
|
+
end
|
89
|
+
value * (base ** idx)
|
90
|
+
end.reduce(&:+)
|
91
|
+
|
92
|
+
when :list
|
93
|
+
digits = str.split(separator).reverse
|
94
|
+
digits.map.with_index do |x,idx|
|
95
|
+
x.to_i * (base ** idx)
|
96
|
+
end.reduce(&:+)
|
97
|
+
|
98
|
+
else
|
99
|
+
raise Error, "Invalid mode #{mode.inspect}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class OutputManager < IOManager
|
105
|
+
def initialize
|
106
|
+
@base = DEFAULT_OUTPUT_BASE
|
107
|
+
@stream = $stdout
|
108
|
+
end
|
109
|
+
|
110
|
+
def name
|
111
|
+
'output'
|
112
|
+
end
|
113
|
+
|
114
|
+
def number_to_string(number)
|
115
|
+
list = Algorithms.number_to_base(number, base)
|
116
|
+
list.reverse!
|
117
|
+
|
118
|
+
case mode
|
119
|
+
when :alphabet
|
120
|
+
list.map do |value|
|
121
|
+
value_to_digit(value)
|
122
|
+
end.join('')
|
123
|
+
|
124
|
+
when :list
|
125
|
+
list.join(separator)
|
126
|
+
|
127
|
+
else
|
128
|
+
raise Error, "Invalid mode #{mode.inspect}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def stream_puts(number)
|
133
|
+
stream.puts number_to_string(number)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/lib/chrad.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative "chrad/version"
|
2
|
+
|
3
|
+
module ChRad
|
4
|
+
class Error < StandardError; end
|
5
|
+
class InvalidInputError < Error; end
|
6
|
+
|
7
|
+
DEFAULT_BASE = 10
|
8
|
+
DEFAULT_INPUT_BASE = DEFAULT_BASE
|
9
|
+
DEFAULT_OUTPUT_BASE = DEFAULT_BASE
|
10
|
+
|
11
|
+
DEFAULT_MODE = :alphabet
|
12
|
+
DEFAULT_SEPARATOR = ','
|
13
|
+
end
|
14
|
+
|
15
|
+
require_relative 'chrad/alphabet'
|
16
|
+
require_relative 'chrad/io_manager'
|
17
|
+
|
18
|
+
module ChRad
|
19
|
+
DEFAULT_ALPHABET = Alphabet[:base16]
|
20
|
+
end
|
data.tar.gz.sig
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chrad
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brent Sanders
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIEMDCCApigAwIBAgIBATANBgkqhkiG9w0BAQsFADAhMR8wHQYDVQQDDBZwZGts
|
14
|
+
OTUvREM9Z21haWwvREM9Y29tMB4XDTIyMDIwMTIxNDQxMFoXDTIzMDIwMTIxNDQx
|
15
|
+
MFowITEfMB0GA1UEAwwWcGRrbDk1L0RDPWdtYWlsL0RDPWNvbTCCAaIwDQYJKoZI
|
16
|
+
hvcNAQEBBQADggGPADCCAYoCggGBAJrJqYa1q3ckmQ6L0v5r2KpJLFrks7L9cmpO
|
17
|
+
qdo3QdUZqnBbIIuhkUOy+rzUM//lCvZeT2Rym8zysJWslATnjhqoKdC6HhAnM7u8
|
18
|
+
puI1Xgr0vy84YCc4Ec0iRyrUQkwRB0flQ1XzmH4CJzMD9HafjF0JbCakoawxYsWu
|
19
|
+
A8DJ4mZn8sdz0BjGF5nHaLtt/cTx4FQpHLcU6AJSep0BP+fn87HGsrvhLEcITx5v
|
20
|
+
8KYnWAdCEiSVCprmANn0rEeD/vCONotRdUBGSmx6aYV/ijujS+ND7a0hk8d3lhkk
|
21
|
+
yvW9L4GM6i3lDsM/wlNBG/HwJuuI06Nve/FC53XYUbh6oyszHiwf8F3jpd9LVHiz
|
22
|
+
hO05+X59sJfbC26k8HdsI8/hodDJfgJ4VM5sOqqg3yKV8h6kySiGFSr1XeWddblg
|
23
|
+
Zz5jRp85cQsLQWUKWBfxGG3Jnqe8h+aflTaUqnU1EWkEyS0BsotZAFD5t5yX55WD
|
24
|
+
dlaJPfF7IyJABxsY+L9LvmWUPFx4RwIDAQABo3MwcTAJBgNVHRMEAjAAMAsGA1Ud
|
25
|
+
DwQEAwIEsDAdBgNVHQ4EFgQUsdOGedmK14HgEtn36tJY4fFiPyUwGwYDVR0RBBQw
|
26
|
+
EoEQcGRrbDk1QGdtYWlsLmNvbTAbBgNVHRIEFDASgRBwZGtsOTVAZ21haWwuY29t
|
27
|
+
MA0GCSqGSIb3DQEBCwUAA4IBgQA481LIo+nYP69SRZgo6Okpii2kO3URi+aR5TLC
|
28
|
+
8BZI/z5/NuYZivMuaMenL90NmeF3LYjmKrOhQD0JmW48YmWQB19b2kIbExBqmu3V
|
29
|
+
JomVhCTLZ+oU3NhzQ5fL70DUhOz7CUCKpLV5lsUyUEGjebDFN21j4GjyeDFqkphj
|
30
|
+
/d2Qe2I5NLzga3tB1AOBqH0EAf3GSWDp1KkWDSUpUCbhjI+CAu4tpUj74HuCBG4g
|
31
|
+
QSTyCS7bp79NUcLmDGJ/43ZgPpJwo6wdV5uo3BQMq8AzRDnTXW1EeGlBOTaDCCvp
|
32
|
+
N7ImUU63/qmLKyPskr53EKYR6bzvF4V+w5+Lq/JxWIbaB5UxY1kCxGrOubzQLvwE
|
33
|
+
tf/k74CEmUNN71A4MXGVuydmgrlok/LBZO8Lqa9Dt+95nBdqKz5vIcO6szPGZIid
|
34
|
+
NMwK52EhsO4bDuwRB7r1zYTj42O24s0o0yJQPzqhfQEGssdLDNkEr147K0symobj
|
35
|
+
l35DiP6VyFMH/Y0JWgs65E5bGzk=
|
36
|
+
-----END CERTIFICATE-----
|
37
|
+
date: 2022-07-12 00:00:00.000000000 Z
|
38
|
+
dependencies: []
|
39
|
+
description: A commsnd line utility to convert integers into arbitrary bases.
|
40
|
+
email:
|
41
|
+
- git@gmail.com
|
42
|
+
executables:
|
43
|
+
- chrad
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- Gemfile
|
48
|
+
- Gemfile.lock
|
49
|
+
- LICENSE.txt
|
50
|
+
- README.md
|
51
|
+
- Rakefile
|
52
|
+
- certs/pdkl95.pem
|
53
|
+
- chrad.gemspec
|
54
|
+
- exe/chrad
|
55
|
+
- lib/chrad.rb
|
56
|
+
- lib/chrad/algorithms.rb
|
57
|
+
- lib/chrad/alphabet.rb
|
58
|
+
- lib/chrad/cli.rb
|
59
|
+
- lib/chrad/io_manager.rb
|
60
|
+
- lib/chrad/version.rb
|
61
|
+
homepage: https://github.com/pdkl95/chrad
|
62
|
+
licenses:
|
63
|
+
- MIT
|
64
|
+
metadata:
|
65
|
+
homepage_uri: https://github.com/pdkl95/chrad
|
66
|
+
source_code_uri: https://github.com/pdkl95/chrad
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.3.0
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubygems_version: 3.1.4
|
83
|
+
signing_key:
|
84
|
+
specification_version: 4
|
85
|
+
summary: Command line util to convert integer base
|
86
|
+
test_files: []
|
metadata.gz.sig
ADDED
Binary file
|