├── VERSION ├── bin └── alphadecimal ├── init.rb ├── rails └── init.rb ├── History.txt ├── Manifest.txt ├── Rakefile ├── LICENSE ├── alphadecimal.gemspec ├── README.txt ├── lib └── alphadecimal.rb └── test └── test_alphadecimal.rb /VERSION: -------------------------------------------------------------------------------- 1 | 1.1.2 -------------------------------------------------------------------------------- /bin/alphadecimal: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | require 'alphadecimal' 2 | -------------------------------------------------------------------------------- /rails/init.rb: -------------------------------------------------------------------------------- 1 | require 'alphadecimal' 2 | -------------------------------------------------------------------------------- /History.txt: -------------------------------------------------------------------------------- 1 | ### 1.0.0 / 2008-03-11 2 | 3 | * added rails/init.rb to allow loading as a gem into a Rails app 4 | 5 | ### 1.0.0 / 2008-03-11 6 | 7 | * 1 major enhancement 8 | 9 | * Birthday! 10 | 11 | -------------------------------------------------------------------------------- /Manifest.txt: -------------------------------------------------------------------------------- 1 | History.txt 2 | Manifest.txt 3 | README.txt 4 | Rakefile 5 | alphadecimal.gemspec 6 | bin/alphadecimal 7 | init.rb 8 | lib/alphadecimal.rb 9 | rails/init.rb 10 | test/test_alphadecimal.rb 11 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | begin 2 | require 'jeweler' 3 | Jeweler::Tasks.new do |gem| 4 | gem.name = "alphadecimal" 5 | gem.summary = %Q{Convert integers to base62 strings (A-Za-z0-9) and back. A handy way to shorten long numbers.} 6 | gem.description = %Q{Convert integers to base62 strings (A-Za-z0-9) and back. Ideal for url shorteners like Shawty-server.} 7 | gem.email = "rubygems@6brand.com" 8 | gem.homepage = "http://github.com/JackDanger/alphadecimal" 9 | gem.authors = ["Mike Mondragon", "Jack Danger Canty"] 10 | # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings 11 | end 12 | Jeweler::GemcutterTasks.new 13 | rescue LoadError 14 | puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler" 15 | end 16 | 17 | 18 | 19 | task :default => :test 20 | 21 | require 'rake/testtask' 22 | Rake::TestTask.new(:test) do |test| 23 | test.libs << '.' 24 | test.pattern = 'test/test_*.rb' 25 | test.verbose = true 26 | end 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Jack Danger Canty 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /alphadecimal.gemspec: -------------------------------------------------------------------------------- 1 | # Generated by jeweler 2 | # DO NOT EDIT THIS FILE DIRECTLY 3 | # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' 4 | # -*- encoding: utf-8 -*- 5 | 6 | Gem::Specification.new do |s| 7 | s.name = %q{alphadecimal} 8 | s.version = "1.1.2" 9 | 10 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= 11 | s.authors = ["Mike Mondragon", "Jack Danger Canty"] 12 | s.date = %q{2011-06-21} 13 | s.default_executable = %q{alphadecimal} 14 | s.description = %q{Convert integers to base62 strings (A-Za-z0-9) and back. Ideal for url shorteners like Shawty-server.} 15 | s.email = %q{rubygems@6brand.com} 16 | s.executables = ["alphadecimal"] 17 | s.extra_rdoc_files = [ 18 | "LICENSE", 19 | "README.txt" 20 | ] 21 | s.files = [ 22 | "History.txt", 23 | "LICENSE", 24 | "Manifest.txt", 25 | "README.txt", 26 | "Rakefile", 27 | "VERSION", 28 | "alphadecimal.gemspec", 29 | "bin/alphadecimal", 30 | "init.rb", 31 | "lib/alphadecimal.rb", 32 | "rails/init.rb", 33 | "test/test_alphadecimal.rb" 34 | ] 35 | s.homepage = %q{http://github.com/JackDanger/alphadecimal} 36 | s.require_paths = ["lib"] 37 | s.rubygems_version = %q{1.6.2} 38 | s.summary = %q{Convert integers to base62 strings (A-Za-z0-9) and back. A handy way to shorten long numbers.} 39 | 40 | if s.respond_to? :specification_version then 41 | s.specification_version = 3 42 | 43 | if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then 44 | else 45 | end 46 | else 47 | end 48 | end 49 | 50 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | = alphadecimal 2 | 3 | * http://github.com/JackDanger/alphadecimal 4 | 5 | == DESCRIPTION: 6 | 7 | Convert integers to base62 strings (A-Za-z0-9) and back. A handy 8 | way to shorten long numbers. 9 | 10 | == SYNOPSIS: 11 | 12 | # 45.alphadecimal 13 | # => 'j' 14 | # 5234233.alphadecimal 15 | # 'Lxf7' 16 | # 'yH783Xx3Ajz99'.alphadecimal 17 | # => 194466611442340388130115 18 | # 194466611442340388130115.alphadecimal 19 | # => 'yH783Xx3Ajz99' 20 | 21 | 22 | == INSTALL: 23 | 24 | * sudo gem install alphadecimal 25 | 26 | == LICENSE: 27 | 28 | (The MIT License) 29 | 30 | Copyright (c) 2008 Jack Danger Canty, Mike Mondragon 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining 33 | a copy of this software and associated documentation files (the 34 | 'Software'), to deal in the Software without restriction, including 35 | without limitation the rights to use, copy, modify, merge, publish, 36 | distribute, sublicense, and/or sell copies of the Software, and to 37 | permit persons to whom the Software is furnished to do so, subject to 38 | the following conditions: 39 | 40 | The above copyright notice and this permission notice shall be 41 | included in all copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 44 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 45 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 46 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 47 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 48 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 49 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 50 | -------------------------------------------------------------------------------- /lib/alphadecimal.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | module Alphadecimal 4 | def self.char(str) 5 | str.respond_to?(:ord) ? str.ord : str[0] 6 | end 7 | 8 | B62_0, B62_9 = char('0'), char('9') 9 | B62_A, B62_Z = char('A'), char('Z') 10 | B62_a, B62_z = char('a'), char('z') 11 | B62_CHRS = [(B62_0..B62_9).map{|i|i}, (B62_A..B62_Z).map{|i|i}, (B62_a..B62_z).map{|i|i}].flatten 12 | 13 | module Number 14 | def alphadecimal 15 | return self if nil? || self < 0 16 | return to_s if self == 0 17 | string = "" 18 | value = self 19 | until value == 0 20 | case mod = value % 62 21 | when 0..9 then string << (mod + B62_0) 22 | when 10..35 then string << (mod - 10 + B62_A) 23 | when 36...62 then string << (mod - 36 + B62_a) 24 | end 25 | value = value / 62 26 | end 27 | string.reverse 28 | end 29 | end 30 | 31 | module String 32 | def alphadecimal 33 | return self unless is_alphadecimal? 34 | val = 0 35 | key = reverse 36 | key.bytes.each_with_index do |char, i| 37 | case 38 | when (B62_0..B62_9).include?(char) then norm = char - B62_0 39 | when (B62_A..B62_Z).include?(char) then norm = char - B62_A + 10 40 | when (B62_a..B62_z).include?(char) then norm = char - B62_a + 36 41 | end 42 | val = val + (norm * (62 ** i)) 43 | end 44 | val 45 | end 46 | 47 | def is_alphadecimal? 48 | return false if nil? 49 | string = dup 50 | return false if string.length <= 0 51 | string.bytes.to_a.each do |b| 52 | return false unless B62_CHRS.include?(b) 53 | end 54 | true 55 | end 56 | end 57 | end 58 | 59 | class String 60 | include Alphadecimal::String 61 | end 62 | class Fixnum 63 | include Alphadecimal::Number 64 | end 65 | class Bignum 66 | include Alphadecimal::Number 67 | end 68 | -------------------------------------------------------------------------------- /test/test_alphadecimal.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | require 'test/unit' 4 | require File.dirname(__FILE__) + "/../lib/alphadecimal" 5 | 6 | class TestAlphadecimal < Test::Unit::TestCase 7 | 8 | include Alphadecimal 9 | 10 | def test_fixnum_becomes_string 11 | assert_kind_of String, 45.alphadecimal 12 | end 13 | 14 | def test_bignum_becomes_string 15 | assert_kind_of String, 231087934571049032.alphadecimal 16 | end 17 | 18 | def test_string_becomes_bignum 19 | assert_kind_of Bignum, 'aHealk43JZy'.alphadecimal 20 | end 21 | 22 | def test_string_becomes_fixnum 23 | assert_kind_of Fixnum, 'j'.alphadecimal 24 | end 25 | 26 | def test_invalid_string_returns_self 27 | string = 'Whoah there!' 28 | assert_equal string, string.alphadecimal 29 | end 30 | 31 | def test_identities 32 | [123, 90000008, 733, '12331', 'abYzj', '0', 'A', 'z', 33 | 79823898923232, 'ZZZZZZZZZZZZZZZZZZZ', 'Yz82J3Ng5Nj9M1', 34 | '!!!', '@$%!^', 'abc ', 'HP', 4, 'ǟ'].each do |object| 35 | assert_equal object, object.alphadecimal.alphadecimal 36 | end 37 | end 38 | 39 | def test_alphabet_characters_should_only_validate 40 | alphabet = (('0'.bytes.first..'9'.bytes.first).map{|i|i} + 41 | ('A'.bytes.first..'Z'.bytes.first).map{|i|i} + 42 | ('a'.bytes.first..'z'.bytes.first).map{|i|i}).flatten 43 | (0..255).each do |i| 44 | if alphabet.include?(i) 45 | assert i.chr.is_alphadecimal?, "char #{i} is not valid as string #{i.chr}" 46 | else 47 | assert !i.chr.is_alphadecimal?, "char #{i} is valid as string #{i.chr}" 48 | end 49 | end 50 | end 51 | 52 | def test_edge_62_to_the_0_convertions_should_be_valid 53 | (0...62).each do |i| 54 | encode = i.alphadecimal 55 | decode = encode.alphadecimal 56 | assert_equal i, decode, "integer #{i.inspect} was encoded as #{encode.inspect} and was decoded to #{decode.inspect}" 57 | end 58 | end 59 | 60 | def test_edge_62_to_the_n_convertions_should_be_valid 61 | (0...3).each do |p| 62 | n = 62 ** p 63 | (0...62).each do |i| 64 | encode = (i+n).alphadecimal 65 | decode = encode.alphadecimal 66 | assert_equal i+n, decode, "interger #{i+n} was encoded as #{encode} and was decoded to #{decode}" 67 | end 68 | end 69 | end 70 | end 71 | --------------------------------------------------------------------------------