├── .gitignore ├── .travis.yml ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── friendly_code.gemspec ├── lib └── friendly_code.rb └── spec └── friendly_code_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | cache: bundler 2 | language: ruby 3 | rvm: 4 | - 1.9.3 5 | - 2.0.0 6 | - 2.1.0 7 | - 2.2.0 -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | friendly_code (2.0.1) 5 | 6 | GEM 7 | remote: https://rubygems.org/ 8 | specs: 9 | minitest (5.8.2) 10 | rake (10.4.2) 11 | 12 | PLATFORMS 13 | ruby 14 | 15 | DEPENDENCIES 16 | friendly_code! 17 | minitest (~> 5.8) 18 | rake (~> 10.4) 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Matt Swanson 2 | 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Friendly Code 2 | Generate user-friendly, pseudo-random codes without ambiguous letters or numbers (e.g. 0 vs O vs o). 3 | 4 | ### Why not just use `SecureRandom.guid`? 5 | For scenarios where only computers will be interacting, this is probably the way to go. But when the interaction involves a human, we want to remove ambiguity to improve accessibility and improve ease of reading and entering data. 6 | 7 | Use cases: 8 | * Entering code sent via SMS into a web page or app 9 | * Entering code from printed material into a web page or app 10 | * Easy to read coupon codes, promo codes, or access tokens 11 | 12 | ## Installation 13 | [![Gem Version](https://badge.fury.io/rb/friendly_code.svg)](https://badge.fury.io/rb/friendly_code) 14 | 15 | Add it to your Gemfile: 16 | 17 | ```ruby 18 | gem 'friendly_code' 19 | ``` 20 | 21 | Run the following command to install it: 22 | 23 | ```console 24 | bundle install 25 | ``` 26 | 27 | ## Usage 28 | 29 | Generate codes in your application: 30 | 31 | ```ruby 32 | require 'friendly_code' 33 | 34 | FriendlyCode.generate 35 | => "QQ6C46" 36 | 37 | FriendlyCode.generate(8) 38 | => "TRRT47W4" 39 | ``` 40 | 41 | ## Guidelines 42 | This gem generates codes that are all UPPERCASE. However, your application should allow the user to enter the code with any casing (including mixed casing). 43 | 44 | By default, the gem will return codes that are 6 characters in length. 45 | 46 | Based on the available characters (below) and length of 6, there are 17^6 unique permutations (~24 Million). It is still recommended that you check for and handle the possibility of duplicates in your application. 47 | 48 | You should try to strike a balance between length of the code and how many unique combinations you need. It will be tedious to make your users enter a 35 character code so make this decision with forethought. You can always increase the code length if you are starting to run out of codes or generate collisions. 49 | 50 | ## Character Set Considerations 51 | Valid character set: 52 | `3 6 7 C D F G H J K M N P R T W X` 53 | 54 | Ambiguous characters are characters that could be confused with another character. Vowels are removed to reduce the chance of generating actual words. 55 | 56 | ``` 57 | 0 => Ambiguous (O, Q) 58 | 1 => Ambiguous (I, l) 59 | 2 => Ambiguous (Z) 60 | 3 61 | 4 => Ambiguous (A) 62 | 5 => Ambiguous (S) 63 | 6 64 | 7 65 | 8 => Ambiguous (B) 66 | 9 => Ambiguous (g) 67 | A => Ambiguous (4), Vowel 68 | B => Ambiguous (8) 69 | C 70 | D 71 | E => Vowel 72 | F 73 | G 74 | H 75 | I => Ambiguous (1, l), Vowel 76 | J 77 | K 78 | L => Ambiguous (1, I) 79 | M 80 | N 81 | O => Ambiguous (0, Q) 82 | P 83 | Q => Ambiguous (0, O) 84 | R 85 | S => Ambiguous (5) 86 | T 87 | U => Ambiguous (V), Vowel 88 | V => Ambiguous (U, Y) 89 | W 90 | X 91 | Y => Vowel, Ambiguous (V) 92 | Z => Ambiguous (2) 93 | ``` 94 | 95 | ## Development Instructions 96 | [![Build Status](https://api.travis-ci.org/swanson/friendly_code.svg?style=flat)](https://travis-ci.org/swanson/friendly_code) 97 | 98 | Install development dependencies: 99 | 100 | ```console 101 | bundle install 102 | ``` 103 | 104 | Run the tests: 105 | ```console 106 | rake 107 | ``` -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | 3 | task :default => [:test] 4 | 5 | Rake::TestTask.new do |t| 6 | t.pattern = 'spec/*_spec.rb' 7 | end -------------------------------------------------------------------------------- /friendly_code.gemspec: -------------------------------------------------------------------------------- 1 | require File.expand_path('../lib/friendly_code', __FILE__) 2 | 3 | Gem::Specification.new do |s| 4 | s.name = 'friendly_code' 5 | s.version = FriendlyCode::VERSION 6 | s.summary = <<-EOF 7 | Generate user-friendly, pseudo-random codes without ambiguous letters 8 | or numbers (e.g. 0 vs O vs o). 9 | EOF 10 | s.description = <<-EOF 11 | Generate user-friendly, pseudo-random codes without ambiguous letters 12 | or numbers (e.g. 0 vs O vs o). 13 | 14 | For scenarios where only computers will be interacting, this is probably 15 | the way to go. But when the interaction involves a human, we want to remove 16 | ambigouity to improve accessibility and ease of reading and entering data. 17 | 18 | Use cases: 19 | * Entering code sent via SMS into a web page or app 20 | * Entering code from printed material into a web page or app 21 | EOF 22 | s.authors = ['Matt Swanson'] 23 | s.email = 'matt@mdswanson.com' 24 | s.files = ['lib/friendly_code.rb'] 25 | s.homepage = 'https://github.com/swanson/friendly_code' 26 | s.license = 'MIT' 27 | 28 | s.add_development_dependency 'minitest', '~> 5.8' 29 | s.add_development_dependency 'rake', '~> 10.4' 30 | end -------------------------------------------------------------------------------- /lib/friendly_code.rb: -------------------------------------------------------------------------------- 1 | require 'securerandom' 2 | 3 | class FriendlyCode 4 | VERSION = '2.0.1' 5 | 6 | CHARACTER_SET = %w{ 3 6 7 C D F G H J K M N P R T W X } 7 | DEFAULT_SIZE = 6 8 | 9 | def self.generate(size = DEFAULT_SIZE) 10 | size.times.map{ CHARACTER_SET[SecureRandom.random_number(CHARACTER_SET.length)] }.join 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/friendly_code_spec.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | describe FriendlyCode do 4 | describe '#generate' do 5 | it 'generates UPPER_CASE codes' do 6 | code = FriendlyCode.generate 7 | assert_equal code, code.upcase 8 | end 9 | 10 | it 'defaults codes to six characters in length' do 11 | code = FriendlyCode.generate 12 | assert_equal code.length, 6 13 | end 14 | 15 | it 'accepts a size parameter to change the default' do 16 | code = FriendlyCode.generate(18) 17 | assert_equal code.length, 18 18 | 19 | code = FriendlyCode.generate(4) 20 | assert_equal code.length, 4 21 | end 22 | end 23 | 24 | describe '::CHARACTER_SET' do 25 | it 'only contains unambiguous characters' do 26 | %w{ 3 6 7 C D F G H J K M N P R T W X }.each do |valid_char| 27 | assert_includes FriendlyCode::CHARACTER_SET, valid_char 28 | end 29 | end 30 | 31 | it 'does not contain any ambiguous characters' do 32 | %w{ 0 1 2 4 5 8 9 A B E I L O Q S U V Y Z }.each do |invalid_char| 33 | refute_includes FriendlyCode::CHARACTER_SET, invalid_char 34 | end 35 | end 36 | end 37 | end --------------------------------------------------------------------------------