mnemonicker 0.0.1
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.
- data/HISTORY.md +5 -0
- data/README.md +71 -0
- data/bin/mnemonicker +7 -0
- data/lib/mnemonicker.rb +2 -0
- data/lib/mnemonicker/cli.rb +100 -0
- data/lib/mnemonicker/major_system.rb +43 -0
- data/lib/mnemonicker/version.rb +3 -0
- data/lib/mnemonicker/word_list.rb +46 -0
- data/mnemonicker.gemspec +29 -0
- data/test/major_system_test.rb +29 -0
- metadata +73 -0
data/HISTORY.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
Mnemonicker
|
2
|
+
===========
|
3
|
+
|
4
|
+
An encoder and decoder for the [mnemonic major system][major-system] for
|
5
|
+
remembering numbers.
|
6
|
+
|
7
|
+
[major-system]: https://en.wikipedia.org/wiki/Mnemonic_major_system
|
8
|
+
|
9
|
+
Usage
|
10
|
+
-----
|
11
|
+
|
12
|
+
```
|
13
|
+
> gem install mnemonicker
|
14
|
+
> mnemonicker
|
15
|
+
|
16
|
+
Commands
|
17
|
+
|
18
|
+
encode [number] - Suggest words that can represent the number
|
19
|
+
decode [*words] - Convert words to numbers
|
20
|
+
update - Download latest wordlist
|
21
|
+
help - This output
|
22
|
+
|
23
|
+
System
|
24
|
+
|
25
|
+
Each number maps to a group of similar sounds, which you can then make
|
26
|
+
a sentence out of that is easier to remember than the numbers themself.
|
27
|
+
|
28
|
+
# | Sound | Way to remember
|
29
|
+
--+-----------+---------------------------
|
30
|
+
0 | s, z | z is the first letter of zero
|
31
|
+
1 | t, th, t | t & d have one downstroke
|
32
|
+
2 | n | n has two downstrokes
|
33
|
+
3 | m | m has three downstrokes
|
34
|
+
4 | r | r is the last character of four
|
35
|
+
5 | l | L is the roman numeral for 50
|
36
|
+
6 | sh, ch, j | I just remember this one
|
37
|
+
7 | k | K contains two sevens back to back
|
38
|
+
8 | f, v | Script f looks like an 8
|
39
|
+
9 | p, b | p and b both very similar shape to 9
|
40
|
+
|
41
|
+
Any sounds not in this list (vowels, "w", "h", "x") are "free" and do not
|
42
|
+
represent anything.
|
43
|
+
|
44
|
+
> mnemonicker encode 314
|
45
|
+
emitter
|
46
|
+
matter
|
47
|
+
meter
|
48
|
+
mother
|
49
|
+
motor
|
50
|
+
> mnemonicker decode mother
|
51
|
+
314
|
52
|
+
> mnemonicker decode a man a plan a canal panama
|
53
|
+
32952725923
|
54
|
+
```
|
55
|
+
|
56
|
+
Known Issues
|
57
|
+
------------
|
58
|
+
|
59
|
+
Mnemonicker uses the [Double Metaphone][double-metaphone] phonetic encoding algorithm, which causes some limitations:
|
60
|
+
|
61
|
+
* Does not decode long words correctly. For instance, "hindquarters" and
|
62
|
+
"manufacturing" are both a number of digits short.
|
63
|
+
* Certain words with odd pronunciation (such as "enough") are incorrectly
|
64
|
+
decoded.
|
65
|
+
|
66
|
+
Additionally, the current word list is somewhat anemic.
|
67
|
+
|
68
|
+
That said, the goal of this project is to spark your imagination. Only you can
|
69
|
+
combine words in a way that is memorable to you!
|
70
|
+
|
71
|
+
[double-metaphone]: https://en.wikipedia.org/wiki/Metaphone
|
data/bin/mnemonicker
ADDED
data/lib/mnemonicker.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
require 'rubyfish'
|
6
|
+
|
7
|
+
require 'mnemonicker/major_system'
|
8
|
+
require 'mnemonicker/word_list'
|
9
|
+
|
10
|
+
module Mnemonicker
|
11
|
+
class CLI
|
12
|
+
def self.run(*args)
|
13
|
+
cmd = args.shift
|
14
|
+
cmd ||= 'help'
|
15
|
+
cmd = cmd[0].upcase + cmd[1..-1]
|
16
|
+
handler = Commands.const_get(cmd)
|
17
|
+
handler.new.process(*args)
|
18
|
+
rescue NameError
|
19
|
+
Commands::Help.new.process
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Commands
|
24
|
+
class Update
|
25
|
+
def process
|
26
|
+
Mnemonicker::WordList.new('cli').update do |file, count|
|
27
|
+
puts "%s...%i words" % [file, count]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Encode
|
33
|
+
def process(number)
|
34
|
+
tried = false
|
35
|
+
list = WordList.new('cli')
|
36
|
+
wordlist = begin
|
37
|
+
list.fetch
|
38
|
+
rescue WordList::ListNotFound
|
39
|
+
if tried
|
40
|
+
raise
|
41
|
+
else
|
42
|
+
tried = true
|
43
|
+
$stderr.puts "No word list found, downloading..."
|
44
|
+
list.update
|
45
|
+
retry
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
candidates = wordlist['words'][number]
|
50
|
+
|
51
|
+
puts candidates.sort if candidates
|
52
|
+
true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Decode
|
57
|
+
def process(*words)
|
58
|
+
words.each do |word|
|
59
|
+
puts MajorSystem.word_to_number(word)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Help
|
65
|
+
def process
|
66
|
+
$stderr.puts <<-EOS
|
67
|
+
|
68
|
+
Commands
|
69
|
+
|
70
|
+
encode [number] - Suggest words that can represent the number
|
71
|
+
decode [*words] - Convert words to numbers
|
72
|
+
update - Download latest wordlist
|
73
|
+
help - This output
|
74
|
+
|
75
|
+
System
|
76
|
+
|
77
|
+
Each number maps to a group of similar sounds, which you can then make
|
78
|
+
a sentence out of that is easier to remember than the numbers themself.
|
79
|
+
|
80
|
+
# | Sound | Way to remember
|
81
|
+
--+-----------+---------------------------
|
82
|
+
0 | s, z | z is the first letter of zero
|
83
|
+
1 | t, th, t | t & d have one downstroke
|
84
|
+
2 | n | n has two downstrokes
|
85
|
+
3 | m | m has three downstrokes
|
86
|
+
4 | r | r is the last character of four
|
87
|
+
5 | l | L is the roman numeral for 50
|
88
|
+
6 | sh, ch, j | I just remember this one
|
89
|
+
7 | k | K contains two sevens back to back
|
90
|
+
8 | f, v | Script f looks like an 8
|
91
|
+
9 | p, b | p and b both very similar shape to 9
|
92
|
+
|
93
|
+
Any sounds not in this list (vowels, "w", "h", "x") are "free" and do not
|
94
|
+
represent anything.
|
95
|
+
|
96
|
+
EOS
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Mnemonicker
|
2
|
+
class MajorSystem
|
3
|
+
MAPPINGS = {
|
4
|
+
'S' => 0,
|
5
|
+
'0' => 1,
|
6
|
+
'T' => 1,
|
7
|
+
'D' => 1,
|
8
|
+
'N' => 2,
|
9
|
+
'M' => 3,
|
10
|
+
'R' => 4,
|
11
|
+
'L' => 5,
|
12
|
+
'J' => 6,
|
13
|
+
'K' => 7,
|
14
|
+
'F' => 8,
|
15
|
+
'V' => 8,
|
16
|
+
'P' => 9,
|
17
|
+
'B' => 9,
|
18
|
+
'X' => 6,
|
19
|
+
'A' => nil,
|
20
|
+
'W' => nil,
|
21
|
+
'H' => nil
|
22
|
+
}
|
23
|
+
|
24
|
+
def self.word_to_number(word)
|
25
|
+
# Metaphone is insufficient since it has a maximum length of six, which
|
26
|
+
# does not work for long words like "hindquarters" or "manufacturing".
|
27
|
+
#
|
28
|
+
# Best phonetic algorithm I have found though.
|
29
|
+
metaphone = RubyFish::DoubleMetaphone.phonetic_code(word)[0]
|
30
|
+
metaphone.gsub!(/KS$/, "") # fox => FKS => F
|
31
|
+
metaphone.gsub!(/RNK$/, "RK") # turing => TRNK => TRK
|
32
|
+
n = ""
|
33
|
+
metaphone.each_char do |c|
|
34
|
+
if MAPPINGS.has_key?(c)
|
35
|
+
n << MAPPINGS[c].to_s if MAPPINGS[c]
|
36
|
+
else
|
37
|
+
raise "No mapping for #{c}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
n
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Mnemonicker
|
2
|
+
class WordList < Struct.new(:key)
|
3
|
+
class ListNotFound < RuntimeError; end
|
4
|
+
|
5
|
+
def fetch
|
6
|
+
JSON.parse(File.read(cache_file))
|
7
|
+
rescue
|
8
|
+
raise ListNotFound
|
9
|
+
end
|
10
|
+
|
11
|
+
def update(&block)
|
12
|
+
wordlist = {
|
13
|
+
version: 1,
|
14
|
+
fetched_at: Time.now.utc,
|
15
|
+
'words' => {}
|
16
|
+
}
|
17
|
+
index = fetch_url('index.html')
|
18
|
+
index.lines.each do |line|
|
19
|
+
line = line.chomp
|
20
|
+
words = fetch_url(line)
|
21
|
+
words.lines.each do |word|
|
22
|
+
word = word.chomp
|
23
|
+
number = MajorSystem.word_to_number(word)
|
24
|
+
wordlist['words'][number] ||= []
|
25
|
+
wordlist['words'][number] << word
|
26
|
+
end
|
27
|
+
if block
|
28
|
+
block.call(line, words.lines.count)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
FileUtils.mkdir_p(File.dirname(cache_file))
|
33
|
+
File.open(cache_file, "w") {|f| f.write wordlist.to_json }
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def cache_file
|
39
|
+
File.expand_path("~/.mnemonicker/#{key}.json")
|
40
|
+
end
|
41
|
+
|
42
|
+
def fetch_url(file)
|
43
|
+
Net::HTTP.get('xaviershay.github.io', '/mnemonicker-wordlist/' + file)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/mnemonicker.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/mnemonicker/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Xavier Shay"]
|
6
|
+
gem.email = ["contact@xaviershay.com"]
|
7
|
+
gem.description =
|
8
|
+
%q{An aid for remembering numbers}
|
9
|
+
gem.summary = %q{
|
10
|
+
Encoder and decoder for the mnemonic major system for remembering numbers.
|
11
|
+
}
|
12
|
+
gem.homepage = "http://github.com/xaviershay/mnemonicker"
|
13
|
+
|
14
|
+
gem.executables = []
|
15
|
+
gem.required_ruby_version = '>= 1.9.0'
|
16
|
+
gem.files = Dir.glob("{test,lib}/**/*.rb") + %w(
|
17
|
+
README.md
|
18
|
+
HISTORY.md
|
19
|
+
mnemonicker.gemspec
|
20
|
+
)
|
21
|
+
gem.test_files = Dir.glob("test/**/*.rb")
|
22
|
+
gem.name = "mnemonicker"
|
23
|
+
gem.require_paths = ["lib"]
|
24
|
+
gem.bindir = "bin"
|
25
|
+
gem.executables << "mnemonicker"
|
26
|
+
gem.version = Mnemonicker::VERSION
|
27
|
+
gem.has_rdoc = false
|
28
|
+
gem.add_dependency 'rubyfish'
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
require 'mnemonicker/cli'
|
4
|
+
|
5
|
+
class MajorSystemTest < MiniTest::Unit::TestCase
|
6
|
+
{
|
7
|
+
wikipedia: { # From https://en.wikipedia.org/wiki/Mnemonic_major_system
|
8
|
+
"action" => '762',
|
9
|
+
"ghost" => '701',
|
10
|
+
'missile' => '305',
|
11
|
+
'mossy' => '30',
|
12
|
+
'sail' => '05',
|
13
|
+
},
|
14
|
+
exceptions: {
|
15
|
+
"fox" => '8',
|
16
|
+
"turing" => '147',
|
17
|
+
},
|
18
|
+
known_bugs: {
|
19
|
+
"enough" => '27', # Should be 28
|
20
|
+
'hindquarters' => '217' # Should be 2174140
|
21
|
+
}
|
22
|
+
}.each do |label, examples|
|
23
|
+
examples.each do |word, number|
|
24
|
+
define_method("test_#{label}_#{word}") do
|
25
|
+
assert_equal number, Mnemonicker::MajorSystem.word_to_number(word)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mnemonicker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Xavier Shay
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rubyfish
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: An aid for remembering numbers
|
31
|
+
email:
|
32
|
+
- contact@xaviershay.com
|
33
|
+
executables:
|
34
|
+
- mnemonicker
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- test/major_system_test.rb
|
39
|
+
- lib/mnemonicker/cli.rb
|
40
|
+
- lib/mnemonicker/major_system.rb
|
41
|
+
- lib/mnemonicker/version.rb
|
42
|
+
- lib/mnemonicker/word_list.rb
|
43
|
+
- lib/mnemonicker.rb
|
44
|
+
- README.md
|
45
|
+
- HISTORY.md
|
46
|
+
- mnemonicker.gemspec
|
47
|
+
- bin/mnemonicker
|
48
|
+
homepage: http://github.com/xaviershay/mnemonicker
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 1.9.0
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.8.23
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Encoder and decoder for the mnemonic major system for remembering numbers.
|
72
|
+
test_files:
|
73
|
+
- test/major_system_test.rb
|