cw 0.2.2 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -3
- data/.travis.yml +1 -1
- data/README.md +16 -40
- data/Rakefile +4 -0
- data/VERSION +1 -0
- data/bin/cw +44 -0
- data/cw.gemspec +8 -5
- data/data/text/{adv_of_sh_holmes.txt → book.txt} +4 -4
- data/example.rb +17 -17
- data/lib/cw.rb +53 -18
- data/lib/cw/alphabet.rb +37 -0
- data/lib/cw/audio_player.rb +31 -3
- data/lib/cw/book.rb +14 -7
- data/lib/cw/book_details.rb +2 -2
- data/lib/cw/cl.rb +11 -2
- data/lib/cw/config_file.rb +69 -0
- data/lib/cw/cw_dsl.rb +19 -57
- data/lib/cw/monitor_keys.rb +1 -1
- data/lib/cw/params.rb +104 -0
- data/lib/cw/print.rb +19 -23
- data/lib/cw/repeat_word.rb +2 -2
- data/lib/cw/reveal.rb +47 -0
- data/lib/cw/sentence.rb +22 -2
- data/lib/cw/test_words.rb +1 -1
- data/lib/cw/tester.rb +17 -4
- data/lib/cw/timing.rb +1 -1
- data/lib/cw/tone_generator.rb +2 -2
- data/lib/cw/words.rb +20 -1
- data/test/test_cw.rb +8 -11
- data/test/test_tester.rb +62 -0
- metadata +30 -14
- data/classes.svg +0 -145
- data/classes.svg.dot +0 -360
- data/daily.rb +0 -182
- data/data/text/progress.txt +0 -1
- data/lib/cw/cw_params.rb +0 -50
data/lib/cw/alphabet.rb
CHANGED
@@ -4,24 +4,61 @@
|
|
4
4
|
|
5
5
|
class Alphabet
|
6
6
|
|
7
|
+
# initialize class Alphabet
|
8
|
+
# == Parameters:
|
9
|
+
# options::
|
10
|
+
# An optional hash containg options:
|
11
|
+
# :reverse - reverse alphabet
|
12
|
+
# :shuffle - shuffle alphabet
|
13
|
+
# :include - include only these letters of the alphabet
|
14
|
+
# :exclude - exclude these letters from the alphabet
|
15
|
+
|
7
16
|
def initialize(options = {})
|
8
17
|
@options = options
|
9
18
|
end
|
10
19
|
|
20
|
+
# return string containing alphabet
|
21
|
+
|
11
22
|
def alphabet
|
12
23
|
'abcdefghijklmnopqrstuvwxyz'
|
13
24
|
end
|
14
25
|
|
26
|
+
# reverse alphabet if :reverse option defined
|
27
|
+
|
15
28
|
def reverse_alphabet_maybe
|
16
29
|
@letters.reverse! if @options[:reverse]
|
17
30
|
end
|
18
31
|
|
32
|
+
# shuffle alphabet if :shuffle option defined
|
33
|
+
|
19
34
|
def shuffle_alphabet_maybe
|
20
35
|
@letters = @letters.split('').shuffle.join if @options[:shuffle]
|
21
36
|
end
|
22
37
|
|
38
|
+
# include letters passed in as string if :include defined
|
39
|
+
|
40
|
+
def include_letters
|
41
|
+
if @options[:include]
|
42
|
+
@letters = @options[:include]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# exclude letters passed in as string if :exclude defined
|
47
|
+
|
48
|
+
def exclude_letters
|
49
|
+
if @options[:exclude]
|
50
|
+
@letters.tr!(@options[:exclude],'')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# generate alphabet with options acted upon
|
55
|
+
# == Returns:
|
56
|
+
# alphabet or filtered alphabet
|
57
|
+
|
23
58
|
def generate
|
24
59
|
@letters = alphabet
|
60
|
+
include_letters
|
61
|
+
exclude_letters
|
25
62
|
shuffle_alphabet_maybe
|
26
63
|
reverse_alphabet_maybe
|
27
64
|
@letters.split('').join(' ')
|
data/lib/cw/audio_player.rb
CHANGED
@@ -2,16 +2,43 @@
|
|
2
2
|
|
3
3
|
class AudioPlayer
|
4
4
|
|
5
|
+
AFPLAY = '/usr/bin/afplay'
|
6
|
+
|
7
|
+
#todo def initialize
|
8
|
+
#todo if Params.play_command
|
9
|
+
#todo @play_command = Params.play_command
|
10
|
+
#todo end
|
11
|
+
#todo end
|
12
|
+
|
5
13
|
def tone
|
6
14
|
@tone ||= ToneGenerator.new
|
7
15
|
end
|
8
16
|
|
9
17
|
def play_command
|
10
|
-
@play_command ||=
|
18
|
+
@play_command ||= AFPLAY
|
11
19
|
end
|
12
20
|
|
13
21
|
def play_filename_for_ebook2cw
|
14
|
-
@play_filename ||=
|
22
|
+
@play_filename ||= File.expand_path(Params.audio_filename, audio_dir)
|
23
|
+
end
|
24
|
+
|
25
|
+
def audio_dir
|
26
|
+
Params.audio_dir ||= './audio'
|
27
|
+
end
|
28
|
+
|
29
|
+
def temp_filename_for_ebook2cw
|
30
|
+
File.expand_path("tempxxxx.txt", audio_dir)
|
31
|
+
end
|
32
|
+
|
33
|
+
def convert_book words
|
34
|
+
words = words.delete("\n")
|
35
|
+
File.open(temp_filename_for_ebook2cw, 'w') do |file|
|
36
|
+
file.print words
|
37
|
+
end
|
38
|
+
cl = Cl.new.cl_full(temp_filename_for_ebook2cw)
|
39
|
+
! @dry_run ? `#{cl}` : cl
|
40
|
+
File.delete(temp_filename_for_ebook2cw)
|
41
|
+
File.rename(play_filename_for_ebook2cw + '0000.mp3', play_filename_for_ebook2cw)
|
15
42
|
end
|
16
43
|
|
17
44
|
#FIXME dry_run
|
@@ -19,6 +46,7 @@ class AudioPlayer
|
|
19
46
|
words = words.delete("\n")
|
20
47
|
cl = Cl.new.cl_echo(words)
|
21
48
|
! @dry_run ? `#{cl}` : cl
|
49
|
+
File.rename(play_filename + '0000.mp3', play_filename)
|
22
50
|
end
|
23
51
|
|
24
52
|
def convert_words words
|
@@ -42,7 +70,7 @@ class AudioPlayer
|
|
42
70
|
Process.kill(:TERM, @pid)
|
43
71
|
Process.wait(@pid)
|
44
72
|
rescue
|
45
|
-
puts 'Error: Failed to kill pid ' + @pid.to_s
|
73
|
+
# puts 'Error: Failed to kill pid ' + @pid.to_s
|
46
74
|
exit 1
|
47
75
|
end
|
48
76
|
end
|
data/lib/cw/book.rb
CHANGED
@@ -11,7 +11,6 @@ class Book < FileDetails
|
|
11
11
|
super()
|
12
12
|
read_book book_location
|
13
13
|
find_sentences
|
14
|
-
|
15
14
|
# print_book_advice
|
16
15
|
end
|
17
16
|
|
@@ -37,12 +36,22 @@ class Book < FileDetails
|
|
37
36
|
def audio_play_sentence ; audio.play ; end
|
38
37
|
def print_book_advice ; print.print_advice('Play Book') ; end
|
39
38
|
|
39
|
+
def convert
|
40
|
+
book = @sentence.all.join
|
41
|
+
audio.convert_book(book)
|
42
|
+
end
|
43
|
+
|
40
44
|
def change_or_repeat_sentence?
|
41
45
|
sentence.change_or_repeat?
|
42
46
|
end
|
43
47
|
|
44
48
|
def change_repeat_or_quit?
|
45
|
-
change_or_repeat_sentence? || quit?
|
49
|
+
if(change_or_repeat_sentence? || quit?)
|
50
|
+
sentence.index += 1
|
51
|
+
write_book_progress
|
52
|
+
return true
|
53
|
+
end
|
54
|
+
false
|
46
55
|
end
|
47
56
|
|
48
57
|
def check_sentence_navigation chr
|
@@ -102,7 +111,7 @@ class Book < FileDetails
|
|
102
111
|
end
|
103
112
|
|
104
113
|
def compile_sentence
|
105
|
-
audio.convert_words
|
114
|
+
audio.convert_words(add_space(current_sentence))
|
106
115
|
end
|
107
116
|
|
108
117
|
def compile_and_play
|
@@ -118,12 +127,12 @@ class Book < FileDetails
|
|
118
127
|
|
119
128
|
def next_sentence_or_quit?
|
120
129
|
playing = audio_still_playing?
|
130
|
+
sleep 0.01 if playing
|
121
131
|
next_sentence unless playing
|
122
|
-
sleep 0.01 if playing
|
123
132
|
if change_repeat_or_quit?
|
124
133
|
change_and_kill_audio
|
125
134
|
#todo prn.newline unless quit?
|
126
|
-
true
|
135
|
+
return true
|
127
136
|
end
|
128
137
|
end
|
129
138
|
|
@@ -194,13 +203,11 @@ class Book < FileDetails
|
|
194
203
|
sync_with_audio_player
|
195
204
|
print_words_for_current_sentence
|
196
205
|
print.reset
|
197
|
-
puts
|
198
206
|
end
|
199
207
|
end
|
200
208
|
|
201
209
|
def play_sentences_thread
|
202
210
|
play_sentences_until_quit
|
203
|
-
write_book_progress
|
204
211
|
# kill_threads
|
205
212
|
print "\n\rplay has quit " if @debug
|
206
213
|
end
|
data/lib/cw/book_details.rb
CHANGED
@@ -6,7 +6,7 @@ class BookDetails
|
|
6
6
|
|
7
7
|
HERE = File.dirname(__FILE__) + '/'
|
8
8
|
GEM_BOOK_DIRECTORY = HERE + '../../data/text/'
|
9
|
-
GEM_BOOK_NAME = '
|
9
|
+
GEM_BOOK_NAME = 'book.txt'
|
10
10
|
DEFAULT_BOOK_DIRECTORY = 'books'
|
11
11
|
|
12
12
|
def initialize
|
@@ -36,7 +36,7 @@ class BookDetails
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def book_location
|
39
|
-
File.expand_path(
|
39
|
+
File.expand_path(Params.book_name, Params.book_dir)
|
40
40
|
end
|
41
41
|
|
42
42
|
def arguments args
|
data/lib/cw/cl.rb
CHANGED
@@ -63,7 +63,7 @@ class Cl
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def cl_audio_filename
|
66
|
-
"-o \"#{Params.
|
66
|
+
"-o \"#{File.expand_path(Params.audio_filename, Params.audio_dir)}\" "
|
67
67
|
end
|
68
68
|
|
69
69
|
def coarse_quality(quality)
|
@@ -105,8 +105,17 @@ class Cl
|
|
105
105
|
].collect{|param| param}.join
|
106
106
|
end
|
107
107
|
|
108
|
+
def ebook2cw_path
|
109
|
+
Params.ebook2cw_path ||= 'ebook2cw'
|
110
|
+
Params.ebook2cw_path
|
111
|
+
end
|
112
|
+
|
108
113
|
def cl_echo words
|
109
|
-
"echo #{words} |
|
114
|
+
"echo #{words} | #{ebook2cw_path} #{build_command_line}"
|
115
|
+
end
|
116
|
+
|
117
|
+
def cl_full input
|
118
|
+
"#{ebook2cw_path} #{build_command_line} #{input}"
|
110
119
|
end
|
111
120
|
|
112
121
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class ConfigFile
|
2
|
+
|
3
|
+
CONFIG = ".cw_config"
|
4
|
+
HERE = File.dirname(__FILE__) + '/'
|
5
|
+
CONFIGS = ['wpm', 'book_name', 'book_dir',
|
6
|
+
'play_command', 'success_colour', 'fail_colour',
|
7
|
+
'list_colour', 'ebook2cw_path']
|
8
|
+
|
9
|
+
attr_reader :config
|
10
|
+
|
11
|
+
def config
|
12
|
+
@config ||= Hash.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def readlines f
|
16
|
+
f.readlines
|
17
|
+
end
|
18
|
+
|
19
|
+
def write_config(cfg, line)
|
20
|
+
config[cfg.to_sym] = line.gsub(cfg + ':', '').strip
|
21
|
+
end
|
22
|
+
|
23
|
+
def match_config?(line, cfg)
|
24
|
+
if line
|
25
|
+
tmp = line.strip()[0, cfg.length]
|
26
|
+
return true if(tmp == cfg)
|
27
|
+
end
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def extract_config line
|
32
|
+
CONFIGS.each do |cfg|
|
33
|
+
if match_config?(line, cfg + ':')
|
34
|
+
write_config(cfg, line)
|
35
|
+
return
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def read_config
|
41
|
+
File.open(CONFIG,'r') do |f|
|
42
|
+
lines = readlines(f)
|
43
|
+
lines.each do |line|
|
44
|
+
extract_config line
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def read_config_maybe
|
50
|
+
if File.exist?(CONFIG)
|
51
|
+
puts 'Loading config.'
|
52
|
+
read_config
|
53
|
+
config
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def apply_config(sf)
|
58
|
+
cfg = read_config_maybe
|
59
|
+
if cfg
|
60
|
+
cfg.each_pair do |method, arg|
|
61
|
+
begin
|
62
|
+
sf.send("#{method}", arg)
|
63
|
+
rescue
|
64
|
+
end
|
65
|
+
Params.send("#{method}=", arg)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/cw/cw_dsl.rb
CHANGED
@@ -2,8 +2,12 @@
|
|
2
2
|
|
3
3
|
# class Cw_dsl provides CW's commands
|
4
4
|
|
5
|
+
require_relative 'params'
|
6
|
+
|
5
7
|
class CwDsl
|
6
8
|
|
9
|
+
include Params::ParamsSetup
|
10
|
+
|
7
11
|
attr_accessor :cl
|
8
12
|
|
9
13
|
HERE = File.dirname(__FILE__) + '/'
|
@@ -16,55 +20,7 @@ class CwDsl
|
|
16
20
|
def initialize
|
17
21
|
@words, @cl, @str =
|
18
22
|
Words.new, Cl.new, Str.new
|
19
|
-
init_config
|
20
|
-
end
|
21
|
-
|
22
|
-
[:name, :wpm,
|
23
|
-
:effective_wpm, :word_spacing,
|
24
|
-
:command_line, :frequency,
|
25
|
-
:author, :title,
|
26
|
-
:quality, :audio_filename,
|
27
|
-
:pause, :noise,
|
28
|
-
:shuffle, :mark_words,
|
29
|
-
:double_words, :single_words,
|
30
|
-
:audio_dir, :def_word_count,
|
31
|
-
:book_name, :book_dir
|
32
|
-
].each do |method|
|
33
|
-
define_method method do |arg = nil|
|
34
|
-
arg ? Params.send("#{method}=", arg) : Params.send("#{method}")
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
[[:pause, :pause, true],
|
39
|
-
[:un_pause, :pause, nil],
|
40
|
-
[:print_letters, :print_letters, true],
|
41
|
-
[:mark_words, :print_letters, nil],
|
42
|
-
[:noise, :noise, true],
|
43
|
-
[:no_noise, :noise, nil],
|
44
|
-
[:shuffle, :shuffle, true],
|
45
|
-
[:no_shuffle, :shuffle, nil],
|
46
|
-
[:double_words, :double_words, true],
|
47
|
-
[:single_words, :double_words, nil],
|
48
|
-
[:use_ebook2cw, :use_ebook2cw, true],
|
49
|
-
[:use_ruby_tone, :use_ebook2cw, nil],
|
50
|
-
].each do |bool|
|
51
|
-
define_method bool[0] do
|
52
|
-
Params.send("#{bool[1]}=", bool[2])
|
53
|
-
@words.shuffle if((bool[1] == :shuffle) && (bool[2]))
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def init_config
|
58
|
-
Params.config do
|
59
|
-
param :name, :wpm,
|
60
|
-
:dictionary, :command_line, :audio_filename, :tone, :pause,
|
61
|
-
:print_letters, :double_words,
|
62
|
-
:word_filename, :author, :title, :quality, :frequency, :shuffle, :effective_wpm,
|
63
|
-
:max, :min, :word_spacing, :noise, :begin, :end, :word_count, :including,
|
64
|
-
:word_size, :size, :beginning_with, :ending_with, :mark_words, :audio_dir,
|
65
|
-
:use_ebook2cw, :def_word_count, :book_dir, :book_name
|
66
|
-
end
|
67
|
-
|
23
|
+
Params.init_config
|
68
24
|
config_defaults
|
69
25
|
config_files
|
70
26
|
end
|
@@ -75,14 +31,13 @@ class CwDsl
|
|
75
31
|
wpm 25
|
76
32
|
frequency 500
|
77
33
|
dictionary COMMON_WORDS
|
78
|
-
# def_word_count 100
|
79
34
|
}
|
80
35
|
end
|
81
36
|
|
82
37
|
def config_files
|
83
38
|
Params.config {
|
84
39
|
audio_dir 'audio'
|
85
|
-
audio_filename 'audio_output
|
40
|
+
audio_filename 'audio_output'
|
86
41
|
word_filename 'words.txt'
|
87
42
|
}
|
88
43
|
end
|
@@ -123,6 +78,10 @@ class CwDsl
|
|
123
78
|
@words.including letters
|
124
79
|
end
|
125
80
|
|
81
|
+
def containing(* letters)
|
82
|
+
@words.containing letters
|
83
|
+
end
|
84
|
+
|
126
85
|
def no_longer_than(max)
|
127
86
|
Params.max = max
|
128
87
|
@words.no_longer_than max
|
@@ -165,9 +124,9 @@ class CwDsl
|
|
165
124
|
def numbers_spoken()
|
166
125
|
end
|
167
126
|
|
168
|
-
# def add_noise
|
169
|
-
# Params.noise = true
|
170
|
-
# end
|
127
|
+
# def add_noise
|
128
|
+
# Params.noise = true
|
129
|
+
# end
|
171
130
|
|
172
131
|
def reload
|
173
132
|
load_words(Params.dictionary)
|
@@ -191,9 +150,12 @@ class CwDsl
|
|
191
150
|
|
192
151
|
#todo refactor
|
193
152
|
|
194
|
-
def
|
195
|
-
|
196
|
-
end
|
153
|
+
def alpha ; 'a'.upto('z').collect{|ch| ch} ; end
|
154
|
+
|
155
|
+
def vowels ; ['a','e','i','o','u'] ; end
|
156
|
+
def load_vowels ; @words.assign vowels ; end
|
157
|
+
def load_alphabet ; @words.assign alpha ; end
|
158
|
+
def load_consonants ; @words.assign alpha - vowels ; end
|
197
159
|
|
198
160
|
def load_numbers
|
199
161
|
@words.assign '1 2 3 4 5 6 7 8 9 0 '
|
data/lib/cw/monitor_keys.rb
CHANGED
data/lib/cw/params.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Params
|
4
|
+
|
5
|
+
module ParamsSetup
|
6
|
+
|
7
|
+
[:name, :wpm,
|
8
|
+
:effective_wpm, :word_spacing,
|
9
|
+
:command_line, :frequency,
|
10
|
+
:author, :title,
|
11
|
+
:quality, :audio_filename,
|
12
|
+
:pause, :noise,
|
13
|
+
:shuffle, :mark_words,
|
14
|
+
:double_words, :single_words,
|
15
|
+
:audio_dir, :def_word_count,
|
16
|
+
:book_name, :book_dir,
|
17
|
+
:play_command, :success_colour,
|
18
|
+
:fail_colour, :list_colour,
|
19
|
+
:ebook2cw_path
|
20
|
+
].each do |method|
|
21
|
+
define_method method do |arg = nil|
|
22
|
+
arg ? Params.send("#{method}=", arg) : Params.send("#{method}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
[[:pause, :pause, true],
|
27
|
+
[:un_pause, :pause, nil],
|
28
|
+
[:print_letters, :print_letters, true],
|
29
|
+
[:mark_words, :print_letters, nil],
|
30
|
+
[:noise, :noise, true],
|
31
|
+
[:no_noise, :noise, nil],
|
32
|
+
[:shuffle, :shuffle, true],
|
33
|
+
[:no_shuffle, :shuffle, nil],
|
34
|
+
[:double_words, :double_words, true],
|
35
|
+
[:single_words, :double_words, nil],
|
36
|
+
[:use_ebook2cw, :use_ebook2cw, true],
|
37
|
+
[:use_ruby_tone, :use_ebook2cw, nil],
|
38
|
+
].each do |bool|
|
39
|
+
define_method bool[0] do
|
40
|
+
Params.send("#{bool[1]}=", bool[2])
|
41
|
+
@words.shuffle if((bool[1] == :shuffle) && (bool[2]))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
extend self
|
48
|
+
|
49
|
+
def init_config
|
50
|
+
config do
|
51
|
+
param :name, :wpm, :dictionary, :command_line, :audio_filename, :tone, :pause,
|
52
|
+
:print_letters, :double_words, :word_filename, :author, :title, :quality,
|
53
|
+
:frequency, :shuffle, :effective_wpm, :max, :min, :word_spacing, :noise,
|
54
|
+
:begin, :end, :word_count, :including, :word_size, :size, :beginning_with,
|
55
|
+
:ending_with, :mark_words, :audio_dir, :use_ebook2cw, :def_word_count,
|
56
|
+
:book_dir, :book_name, :play_command, :success_colour, :fail_colour,
|
57
|
+
:list_colour, :ebook2cw_path
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def param_method values, name
|
62
|
+
value = values.first
|
63
|
+
value ? self.send("#{name}=", value) : instance_variable_get("@#{name}")
|
64
|
+
end
|
65
|
+
|
66
|
+
def param_internal name
|
67
|
+
attr_accessor name
|
68
|
+
instance_variable_set("@#{name}", nil)
|
69
|
+
define_method name do | * values|
|
70
|
+
param_method values, name
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def param( * names)
|
75
|
+
names.each do |name|
|
76
|
+
param_internal name
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def config( & block)
|
81
|
+
instance_eval( & block)
|
82
|
+
end
|
83
|
+
|
84
|
+
def shuffle_str
|
85
|
+
shuffle ? "Shuffle: #{shuffle ? 'yes' : 'no'}\n" : nil
|
86
|
+
end
|
87
|
+
|
88
|
+
def word_count_str
|
89
|
+
word_count ? "Word count: #{word_count}\n" : nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def wpm_str
|
93
|
+
"WPM: #{wpm}\n"
|
94
|
+
end
|
95
|
+
|
96
|
+
def word_size_str
|
97
|
+
size ? "Word size: #{size}\n" : nil
|
98
|
+
end
|
99
|
+
|
100
|
+
def delim_str
|
101
|
+
"#{'=' * Params.name.size}\n"
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|