Module: Proquint

Extended by:
Proquint
Included in:
Proquint
Defined in:
lib/proquint.rb,
lib/proquint/version.rb

Overview

A Proquint is a readable, spellable, pronouncable representation of a number. In Ruby, a proquint is a string, such as “badab-lufiv”, which represents the number 0x407d92 (or 4226450 in decimal).

See arxiv.org/html/0901.4016 for more details.

The main API is provided by ‘encode` and `decode`, the former of which takes a number, or an array of words (unsigned 16-bit integers) to make a proquint, and the latter of which takes a proquint and returns an array of words. There are also some convenience methods for getting a complete number from an array of words, for getting an array of words from a number, and for converting between dotted-decimal IP-addresses and hex IP addresses.

Constant Summary collapse

CONSONANTS =
%w[b d f g h j k l m n p r s t v z]
VOWELS =
%w[a i o u]
REVERSE =
{}
DQUAD_PATTERN =
/^(\d{1,3}).(\d{1,3}).(\d{1,3}).(\d{1,3})$/
HEX_PATTERN =
/^x(\h+)$/
VERSION =
"0.0.1"

Instance Method Summary collapse

Instance Method Details

#decode(s, sep = "-") ⇒ Object

Convert a proquint to an array of numbers (between 0 and 0xffff)



79
80
81
82
83
84
85
86
87
88
89
# File 'lib/proquint.rb', line 79

def decode(s, sep = "-")
  s.split(sep).map do |p|
    p = p.downcase
    raise ArgumentError.new("Invalid proquint") unless p.bytes.length == 5
    (REVERSE[p[0]]   << 12) +
      (REVERSE[p[1]] << 10) +
      (REVERSE[p[2]] << 6) +
      (REVERSE[p[3]] << 4) +
      (REVERSE[p[4]])
  end
end

#dquad2hex(dquad) ⇒ Object



24
25
26
27
28
29
30
31
# File 'lib/proquint.rb', line 24

def dquad2hex(dquad)
  if dquad =~ DQUAD_PATTERN
    i = (($1.to_i << 24) + ($2.to_i << 16) + ($3.to_i << 8) + $4.to_i)
    "x#{i.to_s(16)}"
  else
    raise ArgumentError.new("Invalid dotted quad")
  end
end

#encode(i, sep = "-") ⇒ Object

Convert a string, number or array of uint16s to a proquint



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/proquint.rb', line 61

def encode(i, sep = "-")
  case i
    when Fixnum
      raise ArgumentError.new("Can't encode negative numbers") if i < 0
      return encode(num2words(i)) if i > 0xffff
      CONSONANTS[(i & 0xf000) >> 12] +
        VOWELS[(i & 0xc00) >> 10] +
        CONSONANTS[(i & 0x3c0) >> 6] +
        VOWELS[(i & 0x30) >> 4] +
        CONSONANTS[i & 0xf]
    when Array then i.map { |x| encode(x) }.join(sep)
    when DQUAD_PATTERN then encode(dquad2hex(i)[1..-1].to_i(16))
    when String then encode(str2words(i))
    else raise ArgumentError.new("Can't encode #{i}")
  end
end

#hex2dquad(hex) ⇒ Object



33
34
35
36
37
38
39
40
# File 'lib/proquint.rb', line 33

def hex2dquad(hex)
  if hex =~ HEX_PATTERN
    i = $1.to_i(16)
    [(i & 0xff000000) >> 24, (i & 0xff0000) >> 16, (i & 0xff00) >> 8, i & 0xff].join('.')
  else
    raise ArgumentError.new("Invalid hex address")
  end
end

#num2words(num) ⇒ Object



42
43
44
45
46
47
48
49
# File 'lib/proquint.rb', line 42

def num2words(num)
  words = [num & 0xffff]
  while num > 0xffff
    num >>= 16
    words.unshift(num & 0xffff)
  end
  words
end

#quint2num(s, sep = "-") ⇒ Object

Convert a proquint to a number



92
93
94
# File 'lib/proquint.rb', line 92

def quint2num(s, sep = "-")
  words2num(decode(s))
end

#words2num(words) ⇒ Object



51
52
53
54
55
56
57
58
# File 'lib/proquint.rb', line 51

def words2num(words)
  num = words.shift || 0
  until words.empty?
    num <<= 16
    num += words.shift
  end
  num
end