user_friendly_id 1.0.0

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