multibases 0.1.0

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