base32-url 0.3

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a101ccc7f345bba071066ee065dd335e434fb680
4
+ data.tar.gz: f0a1e95eeec9110ab4604246a3c2f6dca42ce6af
5
+ SHA512:
6
+ metadata.gz: 3d156713e87fa7ff31e62a74b066da157deae6199f857f83bf0bcbab15df14204f1fa4b02590d7f7b5801493b04ce54dc9c1e13e041f0272b50ae89861e31874
7
+ data.tar.gz: 4f8e4d21ea3b6c6aa63b750fc11e6ce17dd5b9c226df5c96466519eea1ee230c131243a4dcfcf3e86dc5625446a36b9d8556f2512db1efa02479a5f7455b2b48
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ doc
3
+ pkg
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ install:
5
+ - travis_retry bundle install
6
+ script: bundle exec rake
7
+ deploy:
8
+ provider: rubygems
9
+ api_key:
10
+ secure: sDQBkoDoHaO4W+HH32585gzQLU9zdfgwm6mT0GgVhD/yODXbFdVgvMkBJ6jocqjq0nKdqEiygMOwWCn60YzuLtFMOTBbqnJkX1FGMsBVU++dr6yQMuROQ9tYqWjBiVFrm4iIOl2dezZdhOCBdwXU43ORXyRmNICmk/V+LWOhSt6HklkJGYmHvw3oOLIDMDllkeKgnnuWGtLX66w2b0Fu42UCZE16Dr12z8V2KoK833yUEjJIoOjC9VKcHsjDv3HzdQXD9yM4gnYxawT0fHUvrRxxA/R/ZWLc8IykUdjDD6CU1fTJxUBwKaxs/Sa3Lv+CyvX86y1c0CYH4FIf39kUg4Dcwdc3+W90t3yUpvIWSBT77oENfS0H3Y4cQXHXQtKC0vox84nR+AMewMOvZ6c4pk65J8ZJjr4hHBV3/kHjeCEGZyDix/QkfwDFEtSPcqtbh8TTn5RLgETCkgrOgppqlXLVkT5qP4kG5shigx1P+g6uNJhWveRKJtVFlyiJvx6mmF4oKkLajnrv58xzqSeUOzyIUyYpkcrqqe5oqzbEhOltD1fxmdsx63PRAHEWPa0afNQIVRboKADL9bGE/8rK3EtKtCHOzdFRWsSVdHOlJK1R4TU9XXzvHEmsNxGgBwvhSt09DpKJPAP/NPw2Z2a25okVldHGQMcPSlQYR/9i5gI=
11
+ gem: base32-url
12
+ on:
13
+ tags: true
14
+ repo: datacite/base32-url
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,36 @@
1
+ [![Gem Version](https://badge.fury.io/rb/base32-url.svg)](https://badge.fury.io/rb/base32-url)
2
+ [![Build Status](https://travis-ci.org/datacite/base32-url.svg?branch=master)](https://travis-ci.org/datacite/base32-url)
3
+
4
+ An implementation of Douglas Crockfords Base32-Encoding in Ruby, with two modifications to make
5
+ the resulting strings more URL friendly:
6
+
7
+ * use lower case characters
8
+ * only use characters that don't need URL encoding for checksum
9
+
10
+ see <http://www.crockford.com/wrmg/base32.html>
11
+
12
+ ## Installation
13
+
14
+ ```
15
+ $ gem install base32-url
16
+ ```
17
+
18
+ ## Changes
19
+
20
+ ```
21
+ 0.3.0 - encode into lower case characters, use * ~ _ ^ u for checksum
22
+ 0.2.0 - added optional checksum
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```
28
+ #!/usr/bin/env ruby
29
+
30
+ require 'base32/url'
31
+
32
+ Base32::Url.encode(1234) # => "16J"
33
+ Base32::Url.encode(100**10, :split=>5, :length=>15) # => "02PQH-TY5NH-H0000"
34
+ Base32::Url.decode("2pqh-ty5nh-hoooo") # => 10**100
35
+ Base32::Url.encode(1234, checksum: true) # => "16JD"
36
+ Base32::Url.decode("16JD", checksum: true) # => 1234
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift './lib'
2
+
3
+ require 'bundler'
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'rake/testtask'
7
+ Rake::TestTask.new(:test)
8
+
9
+ task :default => :test
10
+
@@ -0,0 +1,26 @@
1
+ require "date"
2
+ require File.expand_path("../lib/base32/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.authors = "Martin Fenner"
6
+ s.email = "mfenner@datacite.org"
7
+ s.name = "base32-url"
8
+ s.homepage = "https://github.com/datacite/base32-url"
9
+ s.summary = "Ruby client library for conversion of DOI Metadata"
10
+ s.date = Date.today
11
+ s.description = "32-symbol notation for expressing numbers in a form that can be conveniently and accurately transmitted between humans. URL-friendly version of the base32-crockford gem."
12
+ s.require_paths = ["lib"]
13
+ s.version = Base32::Url::VERSION
14
+ s.extra_rdoc_files = ["README.md"]
15
+ s.license = 'MIT'
16
+ s.required_ruby_version = '~> 2.2'
17
+
18
+ # Declary dependencies here, rather than in the Gemfile
19
+ s.add_development_dependency 'bundler', '~> 1.0'
20
+ s.add_development_dependency 'rake'
21
+ s.add_development_dependency 'test-unit', '~> 3.2.3'
22
+
23
+ s.require_paths = ["lib"]
24
+ s.files = `git ls-files`.split($/)
25
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+ end
@@ -0,0 +1 @@
1
+ require 'base32/url'
@@ -0,0 +1,157 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # (c) 2008, Levin Alexander <http://levinalex.net>
4
+ #
5
+ # This file is released under the same license as ruby.
6
+
7
+ require 'enumerator'
8
+
9
+ module Base32
10
+ end
11
+
12
+ # encode a value with the encoding defined by _Douglas_ _Crockford_ in
13
+ # <http://www.crockford.com/wrmg/base32.html>
14
+ #
15
+ # this is *not* the same as the Base32 encoding defined in RFC 4648
16
+ #
17
+ #
18
+ # The Base32 symbol set is a superset of the Base16 symbol set.
19
+ #
20
+ # We chose a symbol set of 10 digits and 22 letters. We exclude 4 of the 26
21
+ # letters: I L O U.
22
+ #
23
+ # Excluded Letters
24
+ #
25
+ # I:: Can be confused with 1
26
+ # L:: Can be confused with 1
27
+ # O:: Can be confused with 0
28
+ # U:: Accidental obscenity
29
+ #
30
+ # When decoding, upper and lower case letters are accepted, and i and l will
31
+ # be treated as 1 and o will be treated as 0. When encoding, lower upper case
32
+ # letters are used.
33
+ #
34
+ # If the bit-length of the number to be encoded is not a multiple of 5 bits,
35
+ # then zero-extend the number to make its bit-length a multiple of 5.
36
+ #
37
+ # Hyphens (-) can be inserted into symbol strings. This can partition a
38
+ # string into manageable pieces, improving readability by helping to prevent
39
+ # confusion. Hyphens are ignored during decoding. An application may look for
40
+ # hyphens to assure symbol string correctness.
41
+ #
42
+ #
43
+ class Base32::URL
44
+ ENCODE_CHARS =
45
+ %w(0 1 2 3 4 5 6 7 8 9 a b c d e f g h j k m n p q r s t v w x y z ?)
46
+
47
+ DECODE_MAP = ENCODE_CHARS.to_enum(:each_with_index).inject({}) do |h,(c,i)|
48
+ h[c] = i; h
49
+ end.merge({'i' => 1, 'l' => 1, 'o' => 0})
50
+
51
+ CHECKSUM_CHARS = %w(* ~ _ ^ u)
52
+
53
+ CHECKSUM_MAP = { "*" => 32, "~" => 33, "_" => 34, "^" => 35, "u" => 36 }
54
+
55
+ # encodes an integer into a string
56
+ #
57
+ # when +checksum+ is given, a checksum is added at the end of the the string,
58
+ # calculated as modulo 37 of +number+. Five additional checksum symbols are
59
+ # used for symbol values 32-36
60
+ #
61
+ # when +split+ is given a hyphen is inserted every <n> characters to improve
62
+ # readability
63
+ #
64
+ # when +length+ is given, the resulting string is zero-padded to be exactly
65
+ # this number of characters long (hyphens are ignored)
66
+ #
67
+ # Base32::URL.encode(1234) # => "16j"
68
+ # Base32::URL.encode(123456789012345, :split=>5) # => "3g923-0vqvs"
69
+ #
70
+ def self.encode(number, opts = {})
71
+ # verify options
72
+ raise ArgumentError unless (opts.keys - [:length, :split, :checksum] == [])
73
+
74
+ str = number.to_s(2).reverse.scan(/.{1,5}/).map do |bits|
75
+ ENCODE_CHARS[bits.reverse.to_i(2)]
76
+ end.reverse.join
77
+
78
+ str += (ENCODE_CHARS + CHECKSUM_CHARS)[number % 37] if opts[:checksum]
79
+
80
+ str = str.rjust(opts[:length], '0') if opts[:length]
81
+
82
+ if opts[:split]
83
+ str = str.reverse
84
+ str = str.scan(/.{1,#{opts[:split]}}/).map { |x| x.reverse }
85
+ str = str.reverse.join("-")
86
+ end
87
+
88
+ str
89
+ end
90
+
91
+ # decode a string to an integer using Douglas Crockfords Base32 Encoding
92
+ #
93
+ # the string is converted to uppercase and hyphens are stripped before
94
+ # decoding
95
+ #
96
+ # I,i,l,L decodes to 1
97
+ # O,o decodes to 0
98
+ #
99
+ # Base32::Crockford.decode("16J") # => 1234
100
+ # Base32::Crockford.decode("OI") # => 1
101
+ # Base32::Crockford.decode("3G923-0VQVS") # => 123456789012345
102
+ #
103
+ # returns +nil+ if the string contains invalid characters and can't be
104
+ # decoded, or if checksum option is used and checksum is incorrect
105
+ #
106
+ def self.decode(string, opts = {})
107
+ if opts[:checksum]
108
+ checksum_char = string.slice!(-1)
109
+ checksum_number = DECODE_MAP.merge(CHECKSUM_MAP)[checksum_char]
110
+ end
111
+
112
+ number = clean(string).split(//).map { |char|
113
+ DECODE_MAP[char] or return nil
114
+ }.inject(0) { |result,val| (result << 5) + val }
115
+
116
+ return nil if opts[:checksum] && (number % 37 != checksum_number)
117
+
118
+ number
119
+ end
120
+
121
+ # same as decode, but raises ArgumentError when the string can't be decoded
122
+ #
123
+ def self.decode!(string, opts = {})
124
+ decode(string) or raise ArgumentError
125
+ end
126
+
127
+ # return the canonical encoding of a string. converts it to uppercase
128
+ # and removes hyphens
129
+ #
130
+ # replaces invalid characters with a question mark ('?')
131
+ #
132
+ def self.normalize(string, opts = {})
133
+ checksum_char = string.slice!(-1) if opts[:checksum]
134
+
135
+ string = clean(string).split(//).map do |char|
136
+ ENCODE_CHARS[DECODE_MAP[char] || 32]
137
+ end.join
138
+
139
+ string += checksum_char if opts[:checksum]
140
+
141
+ string
142
+ end
143
+
144
+ # returns false if the string contains invalid characters and can't be
145
+ # decoded
146
+ #
147
+ def self.valid?(string, opts = {})
148
+ !(normalize(string, opts) =~ /\?/)
149
+ end
150
+
151
+ class << self
152
+ def clean(string)
153
+ string.gsub(/-/,'').downcase
154
+ end
155
+ private :clean
156
+ end
157
+ end
@@ -0,0 +1,5 @@
1
+ module Base32
2
+ module Url
3
+ VERSION = "0.3"
4
+ end
5
+ end
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+
3
+ require 'test/unit'
4
+ require 'base32/url'
5
+
6
+ class TestBase32Url < Test::Unit::TestCase
7
+
8
+ def test_encoding_and_decoding_single_chars
9
+ from = (0..31).to_a
10
+ to = %w(0 1 2 3 4 5 6 7 8 9 a b c d e f g h j k m n p q r s t v w x y z)
11
+
12
+ from.zip(to) do |symbol_value, encode_symbol|
13
+ assert_equal encode_symbol, Base32::URL.encode(symbol_value)
14
+ assert_equal symbol_value, Base32::URL.decode(encode_symbol)
15
+ end
16
+ end
17
+
18
+ def test_encoding_larger_numbers
19
+ assert_equal("10", Base32::URL.encode(32))
20
+ assert_equal("16j", Base32::URL.encode(1234))
21
+ end
22
+
23
+ def test_decoding_strings
24
+ assert_equal(1234, Base32::URL.decode("16J"))
25
+ end
26
+
27
+ def test_decoding_normalizes_symbols
28
+ assert_equal Base32::URL.decode('11100110'),
29
+ Base32::URL.decode('IL1O0ilo')
30
+ end
31
+
32
+ def test_decoding_lowercase
33
+ assert_equal Base32::URL.decode("abcdefghijklmnopqrstvwxyz"),
34
+ Base32::URL.decode("ABCDEFGHIJKLMNOPQRSTVWXYZ")
35
+ end
36
+
37
+ def test_decoding_invalid_strings
38
+ assert_equal nil, Base32::URL.decode("Ü'+?")
39
+ assert_raises(ArgumentError) { Base32::URL.decode!("'+?") }
40
+ end
41
+
42
+ def test_decode_should_ignore_hyphens
43
+ assert_equal 1234, Base32::URL.decode("1-6-j")
44
+ end
45
+
46
+ def test_normalize
47
+ assert_equal "he110w0r1d", Base32::URL.normalize("hello-world")
48
+ assert_equal "he110w0r1d", Base32::URL.normalize("HELLO-WORLD")
49
+ assert_equal "b?123", Base32::URL.normalize("BU-123")
50
+ end
51
+
52
+ def test_normalize_with_checksum
53
+ assert_equal "b?123", Base32::URL.normalize("BU-123", :checksum => true)
54
+ assert_equal "b123u", Base32::URL.normalize("B123u", :checksum => true)
55
+ end
56
+
57
+ def test_valid
58
+ assert_equal true, Base32::URL.valid?("hello-world")
59
+ assert_equal false, Base32::URL.valid?("BU-123")
60
+ end
61
+
62
+ def test_valid_with_checksum
63
+ assert_equal true, Base32::URL.valid?("b123u", :checksum => true)
64
+ assert_equal false, Base32::URL.valid?("bu-123", :checksum => true)
65
+ end
66
+
67
+ def test_length_and_hyphenization
68
+ assert_equal "0016j", Base32::URL.encode(1234, :length => 5)
69
+ assert_equal "0-01-6j",
70
+ Base32::URL.encode(1234, :length => 5, :split => 2)
71
+ assert_equal "00-010",
72
+ Base32::URL.encode(32, :length => 5, :split => 3)
73
+ end
74
+
75
+ def test_encoding_checksum
76
+ assert_equal "16jd",
77
+ Base32::URL.encode(1234, :checksum => true)
78
+ assert_equal "016jd",
79
+ Base32::URL.encode(1234, :length => 5, :checksum => true)
80
+ assert_equal "0-16-jd",
81
+ Base32::URL.encode(1234, :length => 5, :split => 2, :checksum => true)
82
+ end
83
+
84
+ def test_decoding_checksum
85
+ assert_equal 1234,
86
+ Base32::URL.decode("16jd", :checksum => true)
87
+ assert_equal 1234,
88
+ Base32::URL.decode("016jd", :length => 5, :checksum => true)
89
+ assert_equal 1234,
90
+ Base32::URL.decode("0-16-jd", :length => 5, :split => 2, :checksum => true)
91
+ end
92
+
93
+ def test_decoding_invalid_checksum
94
+ assert_equal nil,
95
+ Base32::URL.decode("16jc", :checksum => true)
96
+ end
97
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: base32-url
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.3'
5
+ platform: ruby
6
+ authors:
7
+ - Martin Fenner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-01-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-unit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.2.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.2.3
55
+ description: 32-symbol notation for expressing numbers in a form that can be conveniently
56
+ and accurately transmitted between humans. URL-friendly version of the base32-crockford
57
+ gem.
58
+ email: mfenner@datacite.org
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files:
62
+ - README.md
63
+ files:
64
+ - ".gitignore"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - README.md
68
+ - Rakefile
69
+ - base32-url.gemspec
70
+ - lib/base32-url.rb
71
+ - lib/base32/url.rb
72
+ - lib/base32/version.rb
73
+ - test/test_base32_url.rb
74
+ homepage: https://github.com/datacite/base32-url
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '2.2'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.6.12
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Ruby client library for conversion of DOI Metadata
98
+ test_files:
99
+ - test/test_base32_url.rb