Last active
August 25, 2020 15:37
-
-
Save esquinas/5c4e139689fd3bf1f99ae57d606b5b60 to your computer and use it in GitHub Desktop.
Convert integers (or hex ids) into url-safe base64 strings saving space compared to hexadecimal (like Mongo) IE: "b380d04df5a7ea1d22cc4a54" could be passed as "s4DQTfWn6h0izEpU" in an url param saving 8 characters.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require 'base64' | |
def number_to_base64(number, base: nil) | |
valid_base = ->(b) { | |
b.is_a?(Integer) && b > 1 | |
} | |
hex2int = ->(hex_chars) { | |
hex_chars.to_i(16) | |
} | |
case number | |
when NilClass | |
warn 'nil passed as number, was coerced to 0' | |
return '' | |
when String | |
base = 10 if base.nil? | |
raise ArgumentError, 'Specify a base when passing numbers as string' unless valid_base.call(base) | |
hex_n = base == 16 ? number : number.to_i(base).to_s(16) | |
when Integer | |
hex_n = number.to_s(16) | |
else | |
raise ArgumentError, "Invalid number #{number.inspect}" | |
end | |
Base64.urlsafe_encode64( | |
hex_n.reverse.scan(/[0-9a-z]{1,2}/i).map(&:reverse).reverse.map(&hex2int).pack('C*'), | |
padding: false | |
) | |
end | |
def base64_to_number(string) | |
return nil unless string&.is_a?(String) | |
number = 0 | |
Base64.urlsafe_decode64(string).chars.reverse.each_with_index do |char, position| | |
char_value = char.unpack1('C') * (256**position) | |
number += char_value | |
end | |
number | |
end | |
# Following are the "tests", copy/paste and save into a new file `test_number_to_base64.rb` | |
# then run `ruby test_number_to_base64.rb`: | |
=begin | |
#!/usr/local/bin/ruby -w | |
# frozen_string_literal: true | |
require_relative './number2base64' | |
def assert(something) | |
return true if something == true | |
puts "#{something.inspect} FAILED!" | |
false | |
end | |
def assert_nil(something) | |
return true if assert(something.nil?) | |
puts "#{something.inspect} is not nil." | |
false | |
end | |
def assert_equal(something, other_thing) | |
return true if assert(something == other_thing) | |
puts "#{something.inspect} doesn't equal #{other_thing.inspect}" | |
false | |
end | |
puts 'START' | |
puts '-----------' | |
success = true | |
success &&= assert_equal('', number_to_base64(nil)) | |
success &&= assert_nil(base64_to_number(nil)) | |
success &&= assert_equal(0, base64_to_number('')) | |
success &&= | |
success &&= assert_equal(number_to_base64(1), number_to_base64("1")) | |
success &&= assert_equal(number_to_base64(10), number_to_base64("10")) | |
success &&= assert_equal(number_to_base64(10), number_to_base64("a", base: 16)) | |
success &&= assert_equal(base64_to_number(number_to_base64(10)), 10) | |
success &&= assert_equal(base64_to_number(number_to_base64(0)), 0) | |
success &&= assert_equal(base64_to_number(number_to_base64(1234567890)), 1234567890) | |
success &&= assert_equal('abcdef'.to_i(16), base64_to_number(number_to_base64('abcdef'.to_i(16)))) | |
success &&= assert_equal('abcdef'.to_i(16), base64_to_number(number_to_base64('abcdef', base: 16))) | |
success &&= assert_equal('5f4510717c9cfa441df2df51'.to_i(16), base64_to_number(number_to_base64('5f4510717c9cfa441df2df51', base: 16))) | |
32.times do |digits| | |
random_number = rand(10**(digits+1)) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(2), base: 2))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(3), base: 3))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(8), base: 8))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(10), base: 10))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(16), base: 16))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(32), base: 32))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(36), base: 36))) | |
end | |
puts '-----------' | |
print 'FINISHED... ' | |
puts 'OK' if success | |
puts 'WITH ERRORS' unless success | |
=end | |
# Following are the "tests", copy/paste and save into a new file `test_number_to_base64.rb` | |
# then run `ruby test_number_to_base64.rb`: | |
=begin | |
#!/usr/local/bin/ruby -w | |
# frozen_string_literal: true | |
require_relative './number2base64' | |
def assert(something) | |
return true if something == true | |
puts "#{something.inspect} FAILED!" | |
false | |
end | |
def assert_nil(something) | |
return true if assert(something.nil?) | |
puts "#{something.inspect} is not nil." | |
false | |
end | |
def assert_equal(something, other_thing) | |
return true if assert(something == other_thing) | |
puts "#{something.inspect} doesn't equal #{other_thing.inspect}" | |
false | |
end | |
puts 'START' | |
puts '-----------' | |
success = true | |
success &&= assert_equal('', number_to_base64(nil)) | |
success &&= assert_nil(base64_to_number(nil)) | |
success &&= assert_equal(0, base64_to_number('')) | |
success &&= | |
success &&= assert_equal(number_to_base64(1), number_to_base64("1")) | |
success &&= assert_equal(number_to_base64(10), number_to_base64("10")) | |
success &&= assert_equal(number_to_base64(10), number_to_base64("a", base: 16)) | |
success &&= assert_equal(base64_to_number(number_to_base64(10)), 10) | |
success &&= assert_equal(base64_to_number(number_to_base64(0)), 0) | |
success &&= assert_equal(base64_to_number(number_to_base64(1234567890)), 1234567890) | |
success &&= assert_equal('abcdef'.to_i(16), base64_to_number(number_to_base64('abcdef'.to_i(16)))) | |
success &&= assert_equal('abcdef'.to_i(16), base64_to_number(number_to_base64('abcdef', base: 16))) | |
success &&= assert_equal('b380d04df5a7ea1d22cc4a54'.to_i(16), base64_to_number(number_to_base64('b380d04df5a7ea1d22cc4a54', base: 16))) | |
success &&= assert_equal('b380d04df5a7ea1d22cc4a549a45aee0'.to_i(16), base64_to_number(number_to_base64('b380d04df5a7ea1d22cc4a549a45aee0', base: 16))) | |
32.times do |digits| | |
random_number = rand(10**(digits+1)) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(2), base: 2))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(3), base: 3))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(8), base: 8))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(10), base: 10))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(16), base: 16))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(32), base: 32))) | |
success &&= assert_equal(random_number, base64_to_number(number_to_base64(random_number.to_s(36), base: 36))) | |
end | |
puts '-----------' | |
print 'FINISHED... ' | |
puts 'OK' if success | |
puts 'WITH ERRORS' unless success | |
=end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment