multibases 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 57c641bb941bf22ba1e15624ec2f798ccfdbda9c349f8abaa18bc6ef39275008
4
+ data.tar.gz: 5dd0cbd27ac8ee91362505fa0ab64b021856109ce61ca8d1815242d21a2f347e
5
+ SHA512:
6
+ metadata.gz: 4ebd6b9d19633242cf696170912d7897c2ebc40321b92a3f717d918d1adad0d65ab2cbd9c50dca09497917221236c6110ffcf65f2be93fa690b6df9c658018d6
7
+ data.tar.gz: 59e4ddce0a22b82771c695e7f50e9da0653af855cd09e6be53329539a0115ac85329606ce15ff03ca28c0eb1cf07fbda45c4005975cbaf633c84d4763d729b74
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ Gemfile.lock
data/.rubocop.yml ADDED
@@ -0,0 +1,7 @@
1
+ # inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 2.5
5
+
6
+ Style/Documentation:
7
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.1
7
+ before_install: gem install bundler -v 2.0.1
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in multibases.gemspec
8
+ gemspec
data/README.md ADDED
@@ -0,0 +1,326 @@
1
+ # Multibases
2
+
3
+ [![Build Status: master](https://travis-ci.com/SleeplessByte/ruby-multibase.svg?branch=master)](https://travis-ci.com/SleeplessByte/ruby-multibase)
4
+ [![Gem Version](https://badge.fury.io/rb/ruby-multibase.svg)](https://badge.fury.io/rb/ruby-multibase)
5
+ [![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
6
+ [![Maintainability](https://api.codeclimate.com/v1/badges/1e5600a4be90eec063e0/maintainability)](https://codeclimate.com/repos/5d094b036bd112014f005f98/maintainability)
7
+
8
+ > Multibase is a protocol for disambiguating the encoding of base-encoded
9
+ > (e.g., base32, base64, base58, etc.) binary appearing in text.
10
+
11
+ `Multibases` is the ruby implementation of [multiformats/multibase][spec].
12
+
13
+ This gem can be used _both_ for encoding into or decoding from multibase packed
14
+ strings, as well as serve as a _general purpose_ library to do `BaseX` encoding
15
+ and decoding _without_ adding the prefix.
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```Ruby
22
+ gem 'multibases'
23
+ ```
24
+
25
+ or alternatively if you would like to bring your own engines and not load any
26
+ of the built-in ones:
27
+
28
+ ```Ruby
29
+ gem 'multibases', require: 'multibases/bare'
30
+ ```
31
+
32
+ And then execute:
33
+
34
+ $ bundle
35
+
36
+ Or install it yourself as:
37
+
38
+ $ gem install multibases
39
+
40
+ ## Usage
41
+
42
+ This is a low-level library, but high level implementations are provided.
43
+ You can also bring your own encoder/decoder. The most important methods are:
44
+
45
+ - `Multibases.encode(encoding, data, engine?)`: encodes the given data with a
46
+ built-in engine for encoding, or engine if it's given. Returns an `Encoded`
47
+ PORO that has `pack`.
48
+ - `Multibases.unpack(packed)`: decodes a multibase packed string into an
49
+ `Encoded` PORO that has `decode`.
50
+ - `Multibases::Encoded.pack`: packs the multihash into a single string
51
+ - `Multibases::Encoded.decode(engine?)`: decodes the PORO's data using a
52
+ built-in engine, or engine if it's given. Returns a decoded `ByteArray`.
53
+
54
+ ```ruby
55
+ encoded = Multibases.encode('base2', 'mb')
56
+ # => #<struct Multibases::Encoded
57
+ # code="0", encoding="base2", length=16,
58
+ # data=[Multibases::EncodedByteArray "0110110101100010"]>
59
+
60
+ encoded.pack
61
+ # => [Multibases::EncodedByteArray "00110110101100010"]
62
+
63
+
64
+ encoded = Multibases.unpack('766542')
65
+ # => #<struct Multibases::Encoded
66
+ # code="7", encoding="base8", length=5,
67
+ # data=[Multibases::EncodedByteArray "66542"]>
68
+
69
+ encoded.decode
70
+ # => [Multibases::DecodedByteArray "mb"]
71
+ ```
72
+
73
+ This means that the flow of calls is as follows:
74
+
75
+ ```text
76
+ data ➡️ (encode) ➡️ encoded data
77
+ encoded data ➡️ (pack) ➡️ multibasestr
78
+
79
+ multibasestr ➡️ (unpack) ➡️ encoded data
80
+ encoded data ➡️ (decode) ➡️ data
81
+ ```
82
+
83
+ Convenience methods are provided:
84
+
85
+ - `Multibases.pack(encoding, data, engine?)`: calls `encode` and then `pack`
86
+ - `Multibases.decode(packed, engine?)`: calls `unpack` and then `decode`
87
+
88
+ ```ruby
89
+ Multibases.pack('base2', 'mb')
90
+ # => [Multibases::EncodedByteArray "00110110101100010"]
91
+ ```
92
+
93
+ ### ByteArrays and encoding
94
+
95
+ As you can see, the "final" methods output a `ByteArray`. These are simple
96
+ `DelegateClass` wrappers around the array with bytes, which means that the `hex`
97
+ encoding of `hello` is not actually stored as `"f68656c6c6f"`:
98
+
99
+ ```ruby
100
+ packed = Multibases.pack('base16', 'hello')
101
+ # => [Multibases::EncodedByteArray "f68656c6c6f"]
102
+
103
+ packed.to_a # .__getobj__.dup
104
+ # => [102, 54, 56, 54, 53, 54, 99, 54, 99, 54, 102]
105
+ ```
106
+
107
+ They override `inspect` and _force_ the encoding to `UTF-8` (in inspect), but
108
+ you can use the convenience methods to use the correct encoding:
109
+
110
+ > **Note**: If you're using `pry` and have not changed the printer, you
111
+ > naturally won't see the output as described above, but instead see the inner
112
+ > Array of bytes, always.
113
+
114
+ ```ruby
115
+ data = 'hello'.encode('UTF-16LE')
116
+ data.encoding
117
+ # => #<Encoding:UTF-16LE>
118
+
119
+ data.bytes
120
+ # => [104, 0, 101, 0, 108, 0, 108, 0, 111, 0]
121
+
122
+ packed = Multibases.pack('base16', data)
123
+ # => [Multibases::EncodedByteArray "f680065006c006c006f00"]
124
+
125
+ decoded = Multibases.decode(packed)
126
+ # => [Multibases::DecodedByteArray "h e l l o "]
127
+
128
+ decoded.to_s('UTF-16LE')
129
+ # => "hello"
130
+ ```
131
+
132
+ ### Implementations
133
+
134
+ You can find the _current_ multibase table [here][git-multibase-table]. At this
135
+ moment, built-in engines are provided as follows:
136
+
137
+ | encoding | code | description | implementation |
138
+ |-------------------|------|-----------------------------------|----------------|
139
+ | identity | 0x00 | 8-bit binary | `bare` |
140
+ | base1 | 1 | unary (1111) | ❌ |
141
+ | base2 | 0 | binary (0101) | `base2` 💨 |
142
+ | base8 | 7 | octal | `base_x` |
143
+ | base10 | 9 | decimal | `base_x` |
144
+ | base16 | f | hexadecimal | `base16` 💨 |
145
+ | base16upper | F | hexadecimal | `base16` 💨 |
146
+ | base32hex | v | rfc4648 no padding - highest char | `base32` ✨ |
147
+ | base32hexupper | V | rfc4648 no padding - highest char | `base32` ✨ |
148
+ | base32hexpad | t | rfc4648 with padding | `base32` ✨ |
149
+ | base32hexpadupper | T | rfc4648 with padding | `base32` ✨ |
150
+ | base32 | b | rfc4648 no padding | `base32` ✨ |
151
+ | base32upper | B | rfc4648 no padding | `base32` ✨ |
152
+ | base32pad | c | rfc4648 with padding | `base32` ✨ |
153
+ | base32padupper | C | rfc4648 with padding | `base32` ✨ |
154
+ | base32z | h | z-base-32 (used by Tahoe-LAFS) | `base32` ✨ |
155
+ | base58flickr | Z | base58 flicker | `base_x` |
156
+ | base58btc | z | base58 bitcoin | `base_x` |
157
+ | base64 | m | rfc4648 no padding | `base64` 💨 |
158
+ | base64pad | M | rfc4648 with padding - MIME enc | `base64` 💨 |
159
+ | base64url | u | rfc4648 no padding | `base64` 💨 |
160
+ | base64urlpad | U | rfc4648 with padding | `base64` 💨 |
161
+
162
+ Those with a 💨 are marked because they are backed by a C implementation (using
163
+ `pack` and `unpack`) and are therefore suposed to be blazingly fast. Those with
164
+ a ✨ are marked because they have a custom implementation over the generic
165
+ `base_x` implementation. It should be faster.
166
+
167
+ The version of the spec that this repository was last updated for is available
168
+ via `Multibases.multibase_version`:
169
+
170
+ ```ruby
171
+ Multibases.multibase_version
172
+ # => "1.0.0"
173
+ ```
174
+
175
+ ### Bring your own engine
176
+
177
+ The methods of `multibases` allow you to bring your own engine, and you can safe
178
+ additional memory by only loading `multibases/bare`.
179
+
180
+ ```ruby
181
+ # Note: This is not how multibase was meant to work. It's supposed to only
182
+ # convert the input from one base to another, and denote what that base
183
+ # is, stored in the output. However, the system is _so_ flexible that this
184
+ # works perfectly for any reversible transformation!
185
+ class EngineKlazz
186
+ def initialize(*_)
187
+ end
188
+
189
+ def encode(plain)
190
+ plain = plain.bytes unless plain.is_a?(Array)
191
+ Multibases::EncodedByteArray.new(plain.reverse)
192
+ end
193
+
194
+ def decode(encoded)
195
+ encoded = encoded.bytes unless encoded.is_a?(Array)
196
+ Multibases::DecodedByteArray.new(encoded.reverse)
197
+ end
198
+ end
199
+
200
+ Multibases.implement 'reverse', 'r', EngineKlazz, 'alphabet'
201
+ # => Initializes EngineKlazz with 'alphabet'
202
+
203
+ Multibases.pack('reverse', 'md')
204
+ # => [Multibases::EncodedByteArray "rdm"]
205
+
206
+ Multibases.decode('dm')
207
+ # => [Multibases::DecodedByteArray "md"]
208
+
209
+ # Alternatively, you can pass the instantiated engine to the appropriate
210
+ # function.
211
+ engine = EngineKlazz.new
212
+
213
+ # Mark the encoding as "existing" and attach a code
214
+ Multibases.implement 'reverse', 'r'
215
+
216
+ # Pack, using a custom engine
217
+ Multibases.pack('reverse', 'md', engine)
218
+ # => [Multibases::EncodedByteArray "rdm"]
219
+
220
+ Multibases.decode('rdm', engine)
221
+ # => [Multibases::DecodedByteArray "md"]
222
+ ```
223
+
224
+ ### Using the built-in encoders/decoders
225
+
226
+ You can use the built-in encoders and decoders.
227
+
228
+ ```ruby
229
+ require 'multibases/base16'
230
+
231
+ Multibases::Base16.encode('foobar')
232
+ # => [Multibases::EncodedByteArray "666f6f626172"]
233
+
234
+ Multibases::Base16.decode('666f6f626172')
235
+ # => [Multibases::DecodedByteArray "foobar"]
236
+ ```
237
+
238
+ These don't add the `multibase` prefix to the output and they use the canonical
239
+ `encode` and `decode` nomenclature.
240
+
241
+ The `base_x` / `BaseX` encoder does not have a module function. You _must_
242
+ instantiate it first. The result is an encoder that uses the base alphabet to
243
+ determine its base. Currently padding is ❌ not supported for `BaseX`, but
244
+ might be in a future update using a second argument or key.
245
+
246
+ ```ruby
247
+ require 'multibases/base_x'
248
+
249
+ Base3 = Multibases::BaseX.new('012')
250
+ # => [Multibases::Base3 alphabet="012" strict]
251
+
252
+ Base3.encode('foobar')
253
+ # => [Multibases::EncodedByteArray "112202210012121110020020001100"]
254
+ ```
255
+
256
+ You can use the same technique to inject a custom alphabet. This can be used on
257
+ the built-in encoders, even the ones that are not `BaseX`:
258
+
259
+ ```ruby
260
+ base = Multibases::Base2.new('.!')
261
+ # => [Multibases::Base2 alphabet=".!"]
262
+
263
+ base.encode('foo')
264
+ # [Multibases::EncodedByteArray ".!!..!!..!!.!!!!.!!.!!!!"]
265
+
266
+ base.decode('.!!...!..!!....!.!!!..!.')
267
+ # => [Multibases::DecodedByteArray "bar"]
268
+ ```
269
+
270
+ All the built-in encoder/decoders take strings, arrays or byte-arrays as input.
271
+
272
+ ```ruby
273
+ expected = Multibases::Base16.encode("abc")
274
+ # => [Multibases::EncodedByteArray "616263"]
275
+
276
+ expected == Multibases::Base16.encode([97, 98, 99])
277
+ # => true
278
+
279
+ expected == Multibases::Base16.encode(Multibases::ByteArray.new("abc".bytes))
280
+ # => true
281
+ ```
282
+
283
+ ## Related
284
+
285
+ - [`multiformats/multibase`][git-multibase]: the spec repository
286
+ - [`multiformats/ruby-multihash`][git-ruby-multihash]: the ruby implementation of [`multiformats/multihash`][git-multihash]
287
+
288
+ ## Development
289
+
290
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
291
+ `rake test` to run the tests. You can also run `bin/console` for an interactive
292
+ prompt that will allow you to experiment.
293
+
294
+ To install this gem onto your local machine, run `bundle exec rake install`.
295
+ To release a new version, update the version number in `version.rb`, and then
296
+ run `bundle exec rake release`, which will create a git tag for the version,
297
+ push git commits and tags, and push the `.gem` file to [rubygems.org][web-rubygems].
298
+
299
+ ## Contributing
300
+
301
+ Bug reports and pull requests are welcome on GitHub at [SleeplessByte/commmand][git-self].
302
+ This project is intended to be a safe, welcoming space for collaboration, and
303
+ contributors are expected to adhere to the [Contributor Covenant][web-coc] code
304
+ of conduct.
305
+
306
+ ## License
307
+
308
+ The gem is available as open source under the terms of the [MIT License][web-mit].
309
+
310
+ ## Code of Conduct
311
+
312
+ Everyone interacting in the Shrine::ConfigurableStorage project’s codebases,
313
+ issue trackers, chat rooms and mailing lists is expected to follow the
314
+ [code of conduct][git-self-coc].
315
+
316
+ [spec]: https://github.com/multiformats/multibase
317
+ [git-self-coc]: https://github.com/SleeplessByte/ruby-multibase/blob/master/CODE_OF_CONDUCT.md
318
+ [git-self]: https://github.com/SleeplessByte/ruby-multibase
319
+ [git-multibase]: https://github.com/multiformats/multibase
320
+ [git-multibase-table]: https://github.com/multiformats/multibase/blob/master/multibase.csv
321
+ [git-ruby-multihash]: https://github.com/multiformats/ruby-multihash
322
+ [git-multihash]: https://github.com/multiformats/multihash
323
+ [web-coc]: http://contributor-covenant.org
324
+ [web-mit]: https://opensource.org/licenses/MIT
325
+ [web-rubygems]: https://rubygems.org
326
+
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'multibases'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/multibases.rb ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'multibases/bare'
4
+
5
+ require 'multibases/registry'
6
+
7
+ require 'multibases/base_x'
8
+ require 'multibases/base2'
9
+ require 'multibases/base16'
10
+ require 'multibases/base32'
11
+ require 'multibases/base64'
12
+
13
+ module Multibases
14
+ class Error < StandardError; end
15
+
16
+ # https://github.com/multiformats/multibase#multibase-table-v100-rc-semver
17
+ multibase_version '1.0.0'
18
+
19
+ # rubocop:disable Metrics/LineLength
20
+ implement 'base1', '1', nil, '1'
21
+ implement 'base2', '0', Base2, '01'
22
+ implement 'base8', '7', BaseX, '01234567'
23
+ implement 'base10', '9', BaseX, '0123456789'
24
+ implement 'base16', 'f', Base16, '0123456789abcdef'
25
+ implement 'base16upper', 'F', Base16, '0123456789ABCDEF'
26
+ implement 'base32', 'b', Base32, 'abcdefghijklmnopqrstuvwxyz234567'
27
+ implement 'base32upper', 'B', Base32, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
28
+ implement 'base32pad', 'c', Base32, 'abcdefghijklmnopqrstuvwxyz234567='
29
+ implement 'base32padupper', 'C', Base32, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567='
30
+ implement 'base32hex', 'v', Base32, '0123456789abcdefghijklmnopqrstuv'
31
+ implement 'base32hexupper', 'V', Base32, '0123456789ABCDEFGHIJKLMNOPQRSTUV'
32
+ implement 'base32hexpad', 't', Base32, '0123456789abcdefghijklmnopqrstuv='
33
+ implement 'base32hexpadupper', 'T', Base32, '0123456789ABCDEFGHIJKLMNOPQRSTUV='
34
+ implement 'base32z', 'h', Base32, 'ybndrfg8ejkmcpqxot1uwisza345h769'
35
+ implement 'base58flickr', 'Z', BaseX, '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
36
+ implement 'base58btc', 'z', BaseX, '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
37
+ implement 'base64', 'm', Base64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
38
+ implement 'base64pad', 'M', Base64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
39
+ implement 'base64url', 'u', Base64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
40
+ implement 'base64urlpad', 'U', Base64, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_='
41
+ # rubocop:enable Metrics/LineLength
42
+ end