user_friendly_id 1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9cf76745e7b09f8d74ec33802bdb3e4ce3cd854b
4
+ data.tar.gz: 215888ec2be67489940feb426807a2bc9ee8eeb8
5
+ SHA512:
6
+ metadata.gz: 89976bd39fce604428b45c02269f4c8ccfd7f996224a27c3d9d5445c0d628af70678cdd2691bcb694d2e7eed031322a1bc563936866524b60ba11b1c120f11e1
7
+ data.tar.gz: 650d7d09da855c6c8d78dcdaa7bcb85b46d53ef57f0e48d704578e27acaa78559e05708e0dc486ff87a6841cd8067ce8ac892ffbe9bbd26827c67d59bfd24c75
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2009 Alex Agranov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,54 @@
1
+ user_friendly_id
2
+ ======
3
+ Add methods to Integer and String to convert between base10 and base34 representations of a number.
4
+
5
+ Base34 rocks!!!
6
+ - shorter than decimal
7
+ - shorter than hexadecimal
8
+ - case insensitive when compared with base64
9
+ - avoids user input confusion associated with 1/I and 0/O
10
+
11
+ Base34 is represented with the following characters: [0-9] and [A-Z, minus I & O to avoid any readability issues]
12
+
13
+ Applications of user_friendly_id could include, but are not limited to:
14
+ - gift/promotion/discount/redemption code generation
15
+ - much shorter string representation of long decimal strings, such as a UUID or MongoDB object id
16
+
17
+ Example Usage:
18
+ ==============
19
+
20
+ ```ruby
21
+ >> 33.to_base34
22
+ => "Z"
23
+
24
+ >> 34.to_base34
25
+ => "10"
26
+
27
+ >> "10".to_base10
28
+ => 34
29
+
30
+ >> 1155.to_base34
31
+ => "ZZ"
32
+
33
+ >> "ZZ".from_base34
34
+ => 1155
35
+
36
+ >> "0000000000ZZ".from_base34
37
+ => 1155
38
+
39
+ >> " 00ZZ ".from_base34
40
+ => 1155
41
+
42
+ # you can represent 10^24 - one septillion - with just 16 base34 digits, aka, a string of length 16
43
+ >> (10 ** 24).to_base34
44
+ => "ANGMLFL5UA0AW72G"
45
+
46
+ # typical MongoDB ObjectId
47
+ >> "507f191e810c19729de860ea".hex.to_base34
48
+ => "6RRUV0LLDJG0N6MAYBL"
49
+
50
+ # typical UUID
51
+ >> "6948DF80-14BD-4E04-8842-7668D9C001F5".gsub(/-/,'').hex.to_base34
52
+ => "QKH6RDPUM5ACPE8GWKWB2PSMB"
53
+
54
+ ```
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
@@ -0,0 +1,4 @@
1
+ require "user_friendly_id/version"
2
+ require "user_friendly_id/digits"
3
+ require "user_friendly_id/integer"
4
+ require "user_friendly_id/string"
@@ -0,0 +1,8 @@
1
+ module UserFriendlyId
2
+
3
+ BASE34_DIGITS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
4
+ 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
5
+
6
+
7
+
8
+ end
@@ -0,0 +1,43 @@
1
+ class Integer
2
+
3
+ =begin rdoc
4
+ Turn a base10 integer into a base34 string representation.
5
+ The basic methodology is to decompose work into multiples of 34 - we create the base34 number by taking base34 chunks away from the base10 number.
6
+ =end
7
+ def to_base34
8
+ # our storage string...
9
+ base34_str = String.new
10
+
11
+ # the zero case...
12
+ if self == 0
13
+ base34_str << UserFriendlyId::BASE34_DIGITS[0]
14
+ return base34_str
15
+ end
16
+
17
+ # get sign...
18
+ sign = self/(self.abs)
19
+
20
+ # make a working copy of self...
21
+ work = self.abs
22
+
23
+ # we build the base34 number from right to left...
24
+ place = 0
25
+ while work > 0 do
26
+ # grab the portion that is representable in our 'place' before we have to increment up to the next 'place'
27
+ remainder = work % (34**(place+1))
28
+ # build the base34 number from right to left (i.e, tack on at the front)...
29
+ base34_str.insert(0, UserFriendlyId::BASE34_DIGITS[remainder/(34**place)])
30
+ # remove the portion we just represented...
31
+ work = work - remainder
32
+ # keep going...
33
+ place += 1
34
+ end
35
+
36
+ # append a negative sign if negative...
37
+ if sign < 0
38
+ base34_str.insert(0,'-')
39
+ end
40
+
41
+ return base34_str
42
+ end
43
+ end
@@ -0,0 +1,37 @@
1
+ class String
2
+
3
+ =begin rdoc
4
+ Turn a base34 string representation into a base10 integer.
5
+ =end
6
+ def from_base34
7
+ raise ArgumentError.new("Invalid characters for a base34 number found") unless self.valid_base34?
8
+ # strip whitespace, negative sign, and upcase
9
+ kleen = self.kleened.upcase
10
+ total = 0
11
+ size = kleen.length
12
+ for i in 0..size-1
13
+ total += UserFriendlyId::BASE34_DIGITS.index(kleen[i,1]) * 34**(size-(i+1))
14
+ end
15
+ total *= -1 if is_negative?
16
+ return total
17
+ end
18
+
19
+ def valid_base34?
20
+ # only the alpha minus I & O is what we want...
21
+ not /[^0-9a-zA-Z&&[^ioIO]]/.match(self.kleened)
22
+ end
23
+
24
+ def is_negative?
25
+ self.chr == '-'
26
+ end
27
+
28
+ protected
29
+
30
+ def kleened
31
+ # get rid of leading/trailing whitespace...
32
+ kleen = self.strip
33
+ # strip any leading negative sign...
34
+ kleen = kleen[1..-1] if is_negative?
35
+ kleen
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module UserFriendlyId
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1 @@
1
+ require 'user_friendly_id'
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+
3
+ describe UserFriendlyId do
4
+ subject { UserFriendlyId.new }
5
+
6
+ describe '#to_base34' do
7
+ context 'method existence' do
8
+ it 'is callable on any Integer' do
9
+ expect(Integer(45)).to respond_to :to_base34
10
+ expect(45).to respond_to :to_base34
11
+ expect(456789012345678901234567).to respond_to :to_base34
12
+ end
13
+ end
14
+
15
+ context 'correct conversion' do
16
+ it 'handles 0 just fine' do
17
+ expect(0.to_base34).to eq "0"
18
+ end
19
+
20
+ it 'handles conversion to base34 as expected' do
21
+ expect((34 ** 1).to_base34).to eq "10"
22
+ expect((34 ** 5).to_base34).to eq "100000"
23
+ expect((34 ** 10).to_base34).to eq "10000000000"
24
+ expect(1155.to_base34).to eq "ZZ"
25
+ end
26
+
27
+ it 'handles negative integer as expected' do
28
+ expect((-34 ** 1).to_base34).to eq "-10"
29
+ expect((-34 ** 5).to_base34).to eq "-100000"
30
+ expect((-34 ** 10).to_base34).to eq "-10000000000"
31
+ expect(-1155.to_base34).to eq "-ZZ"
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '#valid_base34?' do
37
+ context 'method existence' do
38
+ it 'is callable on any String' do
39
+ expect(String.new("sdfasdfasdf")).to respond_to :valid_base34?
40
+ expect("45").to respond_to :valid_base34?
41
+ expect("45AU34KFH567").to respond_to :valid_base34?
42
+ end
43
+ end
44
+
45
+ context 'valid base34 characters' do
46
+ it "should handle any base34 character" do
47
+ expect("0123456789".valid_base34?).to eq true
48
+ expect("abcdefghjklmnpqrstuvwxyz".valid_base34?).to eq true
49
+ expect("ABCDEFGHJKLMNPQRSTUVWXYZ".valid_base34?).to eq true
50
+ end
51
+
52
+ it "should handle any base34 character beginning with negative sign" do
53
+ expect("-0123456789".valid_base34?).to eq true
54
+ expect("-abcdefghjklmnpqrstuvwxyz".valid_base34?).to eq true
55
+ expect("-ABCDEFGHJKLMNPQRSTUVWXYZ".valid_base34?).to eq true
56
+ end
57
+
58
+ it "should not like negative sign embedded within string" do
59
+ expect("-01234-56789".valid_base34?).to eq false
60
+ expect("-abcdefghj-klmnpqrstuvwxyz".valid_base34?).to eq false
61
+ expect("-ABCDEFGHJK-LMNPQRSTUVWXYZ".valid_base34?).to eq false
62
+ end
63
+
64
+ it "should not like I or O within string" do
65
+ expect("io".valid_base34?).to eq false
66
+ expect("IO".valid_base34?).to eq false
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+ describe '#from_base34' do
73
+ context 'method existence' do
74
+ it 'is callable on any String' do
75
+ expect(String.new("sdfasdfasdf")).to respond_to :from_base34
76
+ expect("45").to respond_to :from_base34
77
+ expect("45AU34KFH567").to respond_to :from_base34
78
+ end
79
+ end
80
+
81
+ context 'correct conversion' do
82
+ it 'handles 0 just fine' do
83
+ expect("0".from_base34).to eq 0
84
+ end
85
+
86
+ it 'handles whitespace at front/back just fine' do
87
+ expect(" 10 ".from_base34).to eq 34
88
+ end
89
+
90
+ it 'handles conversion from base34 as expected' do
91
+ expect("10".from_base34).to eq (34 ** 1)
92
+ expect("100000".from_base34).to eq (34 ** 5)
93
+ expect("10000000000".from_base34).to eq (34 ** 10)
94
+ expect("ZZ".from_base34).to eq 1155
95
+ end
96
+
97
+ it 'handles negative integer as expected' do
98
+ expect("-10".from_base34).to eq (-34 ** 1)
99
+ expect("-100000".from_base34).to eq (-34 ** 5)
100
+ expect("-10000000000".from_base34).to eq (-34 ** 10)
101
+ expect("-ZZ".from_base34).to eq -1155
102
+ end
103
+ end
104
+
105
+ context 'bad strings' do
106
+ it 'should raise ArgumentError' do
107
+ expect{"-90 0453".from_base34}.to raise_error(ArgumentError)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/user_friendly_id/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Alex Agranov"]
6
+ gem.email = ["alex@morphogenic.net"]
7
+ gem.description = %q{Make long integer ids pretty, short and less confusing by shortening via conversion to base34}
8
+ gem.summary = %q{By leveraging base34 - [0-9, A-Z minus I & O] - we can significantly reduce the number of characters used to represent a number. For instance, a 24-digit base10 number can be represented with just 16 digits in base34.}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "user_friendly_id"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = UserFriendlyId::VERSION
17
+
18
+ gem.add_development_dependency 'bundler', '~> 1.3'
19
+ gem.add_development_dependency 'rake'
20
+ gem.add_development_dependency 'rspec'
21
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: user_friendly_id
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Alex Agranov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-25 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.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
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: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Make long integer ids pretty, short and less confusing by shortening
56
+ via conversion to base34
57
+ email:
58
+ - alex@morphogenic.net
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE
66
+ - README.md
67
+ - Rakefile
68
+ - lib/user_friendly_id.rb
69
+ - lib/user_friendly_id/digits.rb
70
+ - lib/user_friendly_id/integer.rb
71
+ - lib/user_friendly_id/string.rb
72
+ - lib/user_friendly_id/version.rb
73
+ - spec/spec_helper.rb
74
+ - spec/user_friendly_id_spec.rb
75
+ - user_friendly_id.gemspec
76
+ homepage: ''
77
+ licenses: []
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.4.2
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: By leveraging base34 - [0-9, A-Z minus I & O] - we can significantly reduce
99
+ the number of characters used to represent a number. For instance, a 24-digit base10
100
+ number can be represented with just 16 digits in base34.
101
+ test_files:
102
+ - spec/spec_helper.rb
103
+ - spec/user_friendly_id_spec.rb