language_cards 0.1.3 → 0.2.0
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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/Gemfile +4 -0
- data/README.md +5 -24
- data/cards/japanese-hiragana.yml +2 -18
- data/cards/japanese-katakana.yml +3 -27
- data/language_cards.gemspec +2 -1
- data/lib/language_cards.rb +1 -0
- data/lib/language_cards/controllers/game.rb +19 -10
- data/lib/language_cards/controllers/main_menu.rb +6 -3
- data/lib/language_cards/grapheme_builder.rb +12 -0
- data/lib/language_cards/helpers/view_helper.rb +4 -0
- data/lib/language_cards/language_cards.rb +37 -17
- data/lib/language_cards/menu_node.rb +38 -0
- data/lib/language_cards/models/card_set.rb +38 -0
- data/lib/language_cards/models/grapheme.rb +18 -0
- data/lib/language_cards/modes/game.rb +29 -0
- data/lib/language_cards/modes/translate.rb +14 -0
- data/lib/language_cards/modes/typing_practice.rb +14 -0
- data/lib/language_cards/user_interface.rb +26 -30
- data/lib/language_cards/version.rb +1 -1
- data/lib/language_cards/view/main_menu.erb +2 -2
- metadata +26 -9
- data/lib/language_cards/card_collection.rb +0 -97
- data/lib/language_cards/comp_bitz.rb +0 -12
- data/lib/language_cards/comparator.rb +0 -67
- data/lib/language_cards/mappings.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 18f1ce1cc9252361375183fcf05ff8f0c53af01f61c8c9b4a361e58265be245f
|
4
|
+
data.tar.gz: 6930a65377a3bb2dc4e0d29b897e99e1f85aa8301a352eaeb49771142cbfcc1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f418b1fc7567256199684e241d93d76ade1987fdaec463e80ed8105a11bb58f4de9e5a408ddcaa59837c825bea73dc873e1f8bbedcb6fca298eb0c3daa7727a5
|
7
|
+
data.tar.gz: 2a6f47d07d483b3401840a840fbba080e21801bd596ad55fb653afa3947d93a4f69b04132ac0d5f04d71e3e7d7c64ac0d8e95ca520cf4a961b0978546739575c
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -32,32 +32,21 @@ Or install it yourself as:
|
|
32
32
|
## Usage
|
33
33
|
|
34
34
|
After installing the gem you can run the executable `language_cards`. If you clone the repo then use
|
35
|
-
`bin/language_cards`.
|
35
|
+
`bundle exec bin/language_cards`.
|
36
36
|
|
37
37
|
# Card Format
|
38
38
|
|
39
39
|
The cards are stored in YAML format. You can look in the `cards` directory for existing examples to follow.
|
40
|
-
The first entry is a
|
40
|
+
The first entry is a language name and it's okay if that already exists in another file. The entries below that
|
41
41
|
must be unique for that language (eg: you can't have two Hiragana sub entries on Japanese). The next step in
|
42
|
-
will have a mapping hash
|
43
|
-
|
44
|
-
mapped; the how is for whether you want to do a translation mapping key to value, or keyboard practice mapping
|
45
|
-
value to value. This part of the mapping must be with the symbol entries of :k or :v. Along with the mapping
|
46
|
-
entry you may puts all the keys and values for your cards. Just follow the below outline for a working example.
|
42
|
+
will have a mapping hash on how the language is being mapped in the form of key to value (eg "Romaji" => "Hiragana").
|
43
|
+
Just follow the below outline for a working example.
|
47
44
|
|
48
45
|
```yaml
|
49
46
|
---
|
50
47
|
Japanese:
|
51
48
|
Hiragana:
|
52
|
-
mapping:
|
53
|
-
- Romaji: Hiragana
|
54
|
-
index:
|
55
|
-
- :k
|
56
|
-
- :v
|
57
|
-
- Hiragana: Hiragana
|
58
|
-
index:
|
59
|
-
- :v
|
60
|
-
- :v
|
49
|
+
mapping: { Romaji: Hiragana }
|
61
50
|
a: あ
|
62
51
|
i: い
|
63
52
|
u: う
|
@@ -65,14 +54,6 @@ Japanese:
|
|
65
54
|
o: お
|
66
55
|
```
|
67
56
|
|
68
|
-
In the example above we allow two mappings (game modes as-it-were). The first mapping is a translation mapping
|
69
|
-
for people to write romaji to solve the Hiragana character, and the second is to actually type the Hiragana
|
70
|
-
character in. As you can see the entries for the cards are bellow at the same level as mapping.
|
71
|
-
|
72
|
-
The first entry Japanese can be in any other cards file. The next level in where "Hiragana" is must be unique to
|
73
|
-
the language Japanese and only in one file. If you mess up the mapping the error messages will be very clear
|
74
|
-
about it. You may enter either one mapping, or two.
|
75
|
-
|
76
57
|
## Development
|
77
58
|
|
78
59
|
*Tests required moving forward with this project unless it's translation files.*
|
data/cards/japanese-hiragana.yml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
--- # https://en.wikibooks.org/wiki/Japanese/Kana_chart
|
2
2
|
Japanese:
|
3
3
|
Hiragana:
|
4
|
-
mapping:
|
5
|
-
- Romaji: Hiragana
|
6
|
-
index:
|
7
|
-
- :k
|
8
|
-
- :v
|
9
|
-
- Hiragana: Hiragana
|
10
|
-
index:
|
11
|
-
- :v
|
12
|
-
- :v
|
4
|
+
mapping: { Romaji: Hiragana }
|
13
5
|
a: あ # ✓
|
14
6
|
i: い # ✓
|
15
7
|
u: う # ✓
|
@@ -112,15 +104,7 @@ Japanese:
|
|
112
104
|
ryu: りゅ # ✓
|
113
105
|
ryo: りょ # ✓
|
114
106
|
Hiragana Diacritics: # https://en.wikipedia.org/wiki/Hiragana
|
115
|
-
mapping:
|
116
|
-
- Romaji: Hiragana
|
117
|
-
index:
|
118
|
-
- :k
|
119
|
-
- :v
|
120
|
-
- Hiragana: Hiragana
|
121
|
-
index:
|
122
|
-
- :v
|
123
|
-
- :v
|
107
|
+
mapping: { Romaji: Hiragana }
|
124
108
|
ga: が
|
125
109
|
gi: ぎ
|
126
110
|
gu: ぐ
|
data/cards/japanese-katakana.yml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
--- # https://en.wikibooks.org/wiki/Japanese/Kana_chart
|
2
2
|
Japanese:
|
3
3
|
Katakana:
|
4
|
-
mapping:
|
5
|
-
- Romaji: Katakana
|
6
|
-
index:
|
7
|
-
- :k
|
8
|
-
- :v
|
9
|
-
- Katakana: Katakana
|
10
|
-
index:
|
11
|
-
- :v
|
12
|
-
- :v
|
4
|
+
mapping: { Romaji: Katakana }
|
13
5
|
a: ア # ✓
|
14
6
|
i: イ # ✓
|
15
7
|
u: ウ # ✓
|
@@ -111,15 +103,7 @@ Japanese:
|
|
111
103
|
ryu: リュ # ✓
|
112
104
|
ryo: リョ # ✓
|
113
105
|
Katakana Diacritics: # https://en.wikipedia.org/wiki/Katakana
|
114
|
-
mapping:
|
115
|
-
- Romaji: Katakana
|
116
|
-
index:
|
117
|
-
- :k
|
118
|
-
- :v
|
119
|
-
- Katakana: Katakana
|
120
|
-
index:
|
121
|
-
- :v
|
122
|
-
- :v
|
106
|
+
mapping: { Romaji: Katakana }
|
123
107
|
ga: ガ
|
124
108
|
gi: ギ
|
125
109
|
gu: グ
|
@@ -161,15 +145,7 @@ Japanese:
|
|
161
145
|
pyu: ピュ
|
162
146
|
pyo: ピョ
|
163
147
|
Katakana Keyboard Mappings:
|
164
|
-
mapping:
|
165
|
-
- Romaji: Katakana
|
166
|
-
index:
|
167
|
-
- :k
|
168
|
-
- :v
|
169
|
-
- Katakana: Katakana
|
170
|
-
index:
|
171
|
-
- :v
|
172
|
-
- :v
|
148
|
+
mapping: { Romaji: Katakana }
|
173
149
|
a: ア
|
174
150
|
i: イ
|
175
151
|
u: ウ
|
data/language_cards.gemspec
CHANGED
@@ -23,7 +23,8 @@ Gem::Specification.new do |spec|
|
|
23
23
|
|
24
24
|
spec.add_dependency "highline", "~> 1.7"
|
25
25
|
spec.add_dependency "i18n", "~> 0.7"
|
26
|
+
spec.add_dependency "elixirize", "~> 0.3"
|
26
27
|
spec.add_development_dependency "bundler", "~> 1.13"
|
27
|
-
spec.add_development_dependency "rake", "~> 12.
|
28
|
+
spec.add_development_dependency "rake", "~> 12.3"
|
28
29
|
spec.add_development_dependency "minitest", "~> 5.10"
|
29
30
|
end
|
data/lib/language_cards.rb
CHANGED
@@ -6,16 +6,18 @@ module LanguageCards
|
|
6
6
|
include Helpers::GameHelper
|
7
7
|
|
8
8
|
def render(correct:, incorrect:, title:, timer:, last:)
|
9
|
-
_score = t('Game.ScoreMenu.Score') + ": %0.2d
|
9
|
+
_score = t('Game.ScoreMenu.Score') + ": %0.2d%%" % calc_score(correct, incorrect)
|
10
10
|
_timer = [((t('Timer.Timer') + ": " + timer.ha) if timer.time?), nil, timer.h]
|
11
11
|
_mexit = t 'Menu.Exit'
|
12
12
|
|
13
|
-
view =
|
13
|
+
view = File.expand_path('../view/game.erb', __dir__).
|
14
|
+
ᐅ( IO.method :read ).
|
15
|
+
ᐅ ERB.method :new
|
14
16
|
view.result(binding)
|
15
17
|
end
|
16
18
|
|
17
|
-
def process(
|
18
|
-
ic = struct_data.new(
|
19
|
+
def process(cards, mode)
|
20
|
+
ic = struct_data.new(cards, mode)
|
19
21
|
ic.get_input
|
20
22
|
{
|
21
23
|
correct: ic.valid?,
|
@@ -30,19 +32,26 @@ module LanguageCards
|
|
30
32
|
end
|
31
33
|
|
32
34
|
def get_input
|
33
|
-
@input ||= CLI.ask("#{I18n.t('Game.TypeThis')}
|
35
|
+
@input ||= CLI.ask("#{I18n.t('Game.TypeThis')}: #{display}")
|
34
36
|
end
|
35
37
|
|
36
|
-
def
|
37
|
-
@
|
38
|
+
def card
|
39
|
+
@card ||= collection.sample
|
38
40
|
end
|
39
41
|
|
40
42
|
def display
|
41
|
-
|
43
|
+
"#{card}"
|
42
44
|
end
|
43
45
|
|
44
46
|
def expected
|
45
|
-
|
47
|
+
case mode
|
48
|
+
when :translate
|
49
|
+
card.translation
|
50
|
+
when :typing_practice
|
51
|
+
"#{card}"
|
52
|
+
else
|
53
|
+
raise "Invalid mode in Game Controller!"
|
54
|
+
end
|
46
55
|
end
|
47
56
|
|
48
57
|
def correct_msg
|
@@ -56,7 +65,7 @@ module LanguageCards
|
|
56
65
|
end
|
57
66
|
|
58
67
|
def valid?
|
59
|
-
|
68
|
+
!!(expected == input)
|
60
69
|
end
|
61
70
|
end
|
62
71
|
end
|
@@ -7,14 +7,17 @@ module LanguageCards
|
|
7
7
|
def render(courses:, mode:)
|
8
8
|
_title = t 'Menu.Title'
|
9
9
|
_select = t 'Menu.Choose'
|
10
|
-
_mode = case mode.peek
|
10
|
+
_mode = t('Menu.GameMode') + case mode.peek
|
11
11
|
when :translate then t 'Menu.ModeTranslate'
|
12
|
-
when :
|
12
|
+
when :typing_practice then t 'Menu.ModeTyping'
|
13
13
|
end
|
14
|
+
_toggle = "m: " + t('Menu.ToggleGameMode')
|
14
15
|
_courses = courses.each.with_index.map {|item,index| "#{index + 1}: #{item}" }
|
15
16
|
_mexit = t 'Menu.Exit'
|
16
17
|
|
17
|
-
view =
|
18
|
+
view = File.expand_path('../view/main_menu.erb', __dir__).
|
19
|
+
ᐅ( IO.method :read ).
|
20
|
+
ᐅ ERB.method :new
|
18
21
|
view.result(binding)
|
19
22
|
end
|
20
23
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'language_cards/models/grapheme'
|
2
|
+
|
3
|
+
module LanguageCards
|
4
|
+
module GraphemeBuilder
|
5
|
+
# Hash {translation => grapheme}
|
6
|
+
def self.call(translation_graphemes = {})
|
7
|
+
translation_graphemes.each_with_object([]) do |(key, value), memo|
|
8
|
+
memo << Grapheme.new(value, key)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'language_cards/menu_node'
|
2
2
|
require_relative 'user_interface'
|
3
3
|
|
4
4
|
module LanguageCards
|
@@ -6,30 +6,50 @@ module LanguageCards
|
|
6
6
|
def initialize
|
7
7
|
@CARDS = {}
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
if @CARDS.has_key? language
|
20
|
-
@CARDS[language] = Hash(@CARDS[language]).merge(Hash(yaml_data[language]))
|
9
|
+
# TODO: Extract out YAML file loading behavior to methods via SRP.
|
10
|
+
File.join('..','..').
|
11
|
+
ᐅ(File.method(:expand_path), __dir__ ).
|
12
|
+
ᐅ(File.method(:join), 'cards', '*.yml').
|
13
|
+
ᐅ(Dir.method :[] ).
|
14
|
+
+(
|
15
|
+
if ENV['HOME']
|
16
|
+
File.expand_path(ENV['HOME']).
|
17
|
+
ᐅ(File.method(:join), '.language_cards', 'cards', '*.yml').
|
18
|
+
ᐅ Dir.method :[]
|
21
19
|
else
|
22
|
-
|
20
|
+
[]
|
21
|
+
end
|
22
|
+
).
|
23
|
+
each do |c|
|
24
|
+
next unless yaml_data = c.ᐅ(File.method :open).ᐅ(~:read).ᐅ(YAML.method :load)
|
25
|
+
for language in yaml_data.keys do
|
26
|
+
# Merges sub-items for languages
|
27
|
+
if @CARDS.has_key? language
|
28
|
+
@CARDS[language] = \
|
29
|
+
yaml_data[language].
|
30
|
+
ᐅ(method :Hash).
|
31
|
+
ᐅ @CARDS[language].
|
32
|
+
ᐅ(method :Hash).
|
33
|
+
method(:merge)
|
34
|
+
else
|
35
|
+
# Merges top scope languages
|
36
|
+
{ language => yaml_data[language] }.
|
37
|
+
ᐅ @CARDS.method :merge!
|
38
|
+
end
|
23
39
|
end
|
40
|
+
|
24
41
|
end
|
25
42
|
|
43
|
+
# Builder
|
44
|
+
@CARDS = @CARDS.each_with_object([]) do |(language, values), memo|
|
45
|
+
values.each do |category_with_card_set|
|
46
|
+
memo << MenuNode.new(language, category_with_card_set)
|
47
|
+
end
|
26
48
|
end
|
27
|
-
# Recursive Builder
|
28
|
-
@CARDS = CardCollection.new @CARDS
|
29
49
|
end
|
30
50
|
|
31
51
|
def start
|
32
|
-
UserInterface.new
|
52
|
+
@CARDS.ᐅ(UserInterface.method :new).ᐅ ~:start
|
33
53
|
end
|
34
54
|
end
|
35
55
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'language_cards/models/card_set'
|
2
|
+
module LanguageCards
|
3
|
+
class MenuNode
|
4
|
+
def initialize name, child
|
5
|
+
@name = name
|
6
|
+
|
7
|
+
if child.is_a?(Hash) and child.has_key?("mapping")
|
8
|
+
@mapping = child.delete("mapping") # Extra unused data for the moment
|
9
|
+
@child = CardSet.new(child)
|
10
|
+
else
|
11
|
+
@child = MenuNode.new(*child)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def title(fmt = ' - ', rng = 0..-1)
|
16
|
+
label[rng].delete_if(&:empty?).join(fmt)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return <Mode<CardSet> < Game>
|
20
|
+
def mode(game_mode)
|
21
|
+
child.mode(game_mode)
|
22
|
+
end
|
23
|
+
|
24
|
+
# This is the preferred method for the view as this object shouldn't
|
25
|
+
# care about how it should be displayed in the view.
|
26
|
+
# @return Array<String>
|
27
|
+
def label
|
28
|
+
[@name].push(*child.label)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
label.delete_if(&:empty?).join(' - ')
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
attr_reader :name, :child
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'language_cards/models/grapheme'
|
2
|
+
require 'language_cards/grapheme_builder'
|
3
|
+
require 'language_cards/modes/typing_practice'
|
4
|
+
require 'language_cards/modes/translate'
|
5
|
+
|
6
|
+
module LanguageCards
|
7
|
+
class CardSet
|
8
|
+
attr_reader :graphemes
|
9
|
+
def initialize(grapheme_hash)
|
10
|
+
@graphemes = GraphemeBuilder.(grapheme_hash)
|
11
|
+
end
|
12
|
+
|
13
|
+
def sample
|
14
|
+
@graphemes.sample
|
15
|
+
end
|
16
|
+
|
17
|
+
def mode(mode)
|
18
|
+
case mode
|
19
|
+
when :translate
|
20
|
+
Modes::Translate.new(self)
|
21
|
+
when :typing_practice
|
22
|
+
Modes::TypingPractice.new(self)
|
23
|
+
else
|
24
|
+
raise "Invalid Game Mode!"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# So as to not interfere with menu naming as this is not meant to
|
29
|
+
# be displayed as a string.
|
30
|
+
def to_s
|
31
|
+
""
|
32
|
+
end
|
33
|
+
|
34
|
+
def label
|
35
|
+
[]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
module LanguageCards
|
3
|
+
class Grapheme
|
4
|
+
attr_reader :translation
|
5
|
+
def initialize grapheme, translation
|
6
|
+
@grapheme = grapheme
|
7
|
+
@translation = translation
|
8
|
+
end
|
9
|
+
|
10
|
+
def display
|
11
|
+
@grapheme
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@grapheme
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
module LanguageCards
|
3
|
+
module Modes
|
4
|
+
class Game
|
5
|
+
def initialize card_set
|
6
|
+
@card_set = card_set
|
7
|
+
@index = 0
|
8
|
+
@current = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def current
|
12
|
+
@current or raise "Current grapheme not yet set!"
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return Grapheme Returns a random grapheme
|
16
|
+
def sample
|
17
|
+
@current = @card_set.sample
|
18
|
+
end
|
19
|
+
|
20
|
+
# Iterator for cycling through all translations sequentially.
|
21
|
+
# @return Grapheme Returns a random grapheme
|
22
|
+
def next
|
23
|
+
value = @card_set[@index % @card_set.length]
|
24
|
+
@index += 1
|
25
|
+
@current = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
require 'language_cards/timer'
|
2
|
+
require 'language_cards/helpers/view_helper'
|
3
|
+
require 'language_cards/helpers/game_helper'
|
4
|
+
require 'language_cards/controllers/main_menu'
|
5
|
+
require 'language_cards/controllers/game'
|
6
6
|
require 'erb'
|
7
7
|
|
8
8
|
module LanguageCards
|
@@ -11,15 +11,16 @@ module LanguageCards
|
|
11
11
|
include Controllers
|
12
12
|
def initialize cards
|
13
13
|
@cards = cards
|
14
|
-
@courses = cards.
|
15
|
-
@mode = [:translate, :
|
14
|
+
@courses = cards.flat_map {|i| i.label.join(' - ') }
|
15
|
+
@mode = [:translate, :typing_practice].cycle
|
16
16
|
end
|
17
17
|
|
18
18
|
def start
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
unless ENV['SKIP_SPLASH']
|
20
|
+
clear
|
21
|
+
CLI.say SPLASH_SCREEN
|
22
|
+
sleep 2
|
23
|
+
end
|
23
24
|
|
24
25
|
begin
|
25
26
|
loop do
|
@@ -34,19 +35,23 @@ module LanguageCards
|
|
34
35
|
|
35
36
|
last = nil
|
36
37
|
if (0..courses.length-1).include? value
|
37
|
-
|
38
|
+
|
39
|
+
collection = cards[value] # MenuNode
|
40
|
+
title = "#{collection.title} (#{humanize mode.peek})"
|
41
|
+
collection = collection.mode(mode.peek) # Mode<CardSet> < Game
|
42
|
+
|
38
43
|
timer = Timer.new
|
39
|
-
begin
|
44
|
+
begin # Game Loop
|
40
45
|
loop do
|
41
46
|
clear
|
42
47
|
timer.mark
|
43
|
-
CLI.say Game.render correct:
|
44
|
-
incorrect:
|
45
|
-
title:
|
48
|
+
CLI.say Game.render correct: correct,
|
49
|
+
incorrect: incorrect,
|
50
|
+
title: title,
|
46
51
|
timer: timer,
|
47
52
|
last: last
|
48
|
-
result = Game.process(collection, mode)
|
49
|
-
result[:correct] ? correct : incorrect
|
53
|
+
result = Game.process(collection, collection.mode)
|
54
|
+
result[:correct] ? correct! : incorrect!
|
50
55
|
last = result[:last]
|
51
56
|
end
|
52
57
|
rescue SystemExit, Interrupt
|
@@ -59,23 +64,14 @@ module LanguageCards
|
|
59
64
|
end
|
60
65
|
|
61
66
|
private
|
62
|
-
attr_reader :mode, :cards
|
63
|
-
def correct
|
67
|
+
attr_reader :mode, :cards, :correct, :incorrect, :courses
|
68
|
+
def correct!
|
64
69
|
@correct = @correct.to_i + 1
|
65
70
|
end
|
66
71
|
|
67
|
-
def incorrect
|
72
|
+
def incorrect!
|
68
73
|
@incorrect = @incorrect.to_i + 1
|
69
74
|
end
|
70
|
-
|
71
|
-
def courses(value = nil)
|
72
|
-
courses = @courses.select {|c| detect_course_mode(c) == mode.peek }
|
73
|
-
value ? courses[value] : courses
|
74
|
-
end
|
75
|
-
|
76
|
-
def detect_course_mode str
|
77
|
-
str.split(JOIN).last.split(" => ").inject(:==) ? :typing : :translate
|
78
|
-
end
|
79
75
|
end
|
80
76
|
end
|
81
77
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
<%= divider %>
|
2
2
|
<%= draw(_title, nil, 'v' + VERSION) %>
|
3
3
|
<%= divider %>
|
4
|
-
<%= draw(_select, nil,
|
4
|
+
<%= draw(_select, nil, _mode) %>
|
5
5
|
<% _courses.each do |course| %>
|
6
6
|
<%= course.chomp %><% end %>
|
7
7
|
|
8
|
-
<%= draw(_mexit, nil,
|
8
|
+
<%= draw(_mexit, nil, _toggle) %>
|
9
9
|
<%= divider %>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: language_cards
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel P. Clark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: elixirize
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.3'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +72,14 @@ dependencies:
|
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: '12.
|
75
|
+
version: '12.3'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '12.
|
82
|
+
version: '12.3'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: minitest
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -103,15 +117,18 @@ files:
|
|
103
117
|
- cards/japanese-katakana.yml
|
104
118
|
- language_cards.gemspec
|
105
119
|
- lib/language_cards.rb
|
106
|
-
- lib/language_cards/card_collection.rb
|
107
|
-
- lib/language_cards/comp_bitz.rb
|
108
|
-
- lib/language_cards/comparator.rb
|
109
120
|
- lib/language_cards/controllers/game.rb
|
110
121
|
- lib/language_cards/controllers/main_menu.rb
|
122
|
+
- lib/language_cards/grapheme_builder.rb
|
111
123
|
- lib/language_cards/helpers/game_helper.rb
|
112
124
|
- lib/language_cards/helpers/view_helper.rb
|
113
125
|
- lib/language_cards/language_cards.rb
|
114
|
-
- lib/language_cards/
|
126
|
+
- lib/language_cards/menu_node.rb
|
127
|
+
- lib/language_cards/models/card_set.rb
|
128
|
+
- lib/language_cards/models/grapheme.rb
|
129
|
+
- lib/language_cards/modes/game.rb
|
130
|
+
- lib/language_cards/modes/translate.rb
|
131
|
+
- lib/language_cards/modes/typing_practice.rb
|
115
132
|
- lib/language_cards/timer.rb
|
116
133
|
- lib/language_cards/user_interface.rb
|
117
134
|
- lib/language_cards/version.rb
|
@@ -139,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
156
|
version: '0'
|
140
157
|
requirements: []
|
141
158
|
rubyforge_project:
|
142
|
-
rubygems_version: 2.6
|
159
|
+
rubygems_version: 2.7.6
|
143
160
|
signing_key:
|
144
161
|
specification_version: 4
|
145
162
|
summary: Flashcard game for language learning.
|
@@ -1,97 +0,0 @@
|
|
1
|
-
require_relative 'comparator'
|
2
|
-
require_relative 'mappings'
|
3
|
-
|
4
|
-
module LanguageCards
|
5
|
-
class CardCollection
|
6
|
-
attr_reader :name
|
7
|
-
##
|
8
|
-
# RULE: Always compare by value regardless of key value ordering in mapping.
|
9
|
-
# (This allows for duplicate spellings of the same character translation)
|
10
|
-
def initialize hsh, name=nil
|
11
|
-
@hsh = hsh
|
12
|
-
@name = name ? I18n.t("LanguageName.#{name}") : nil
|
13
|
-
send :_build
|
14
|
-
@mappings = @hsh["mapping"]
|
15
|
-
if @mappings
|
16
|
-
@cards = @hsh.select {|k,v| !v.is_a? Mappings}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
##
|
21
|
-
# Recursively build class course names
|
22
|
-
def classes s=nil
|
23
|
-
s = @name.nil? ? nil : [s, @name].compact.join(JOIN)
|
24
|
-
@hsh.select do |k,v|
|
25
|
-
[CardCollection, Mappings].include? v.class
|
26
|
-
end.flat_map do |k,v|
|
27
|
-
v.send :classes, s
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def [](value)
|
32
|
-
raise EmptyCollection unless collection?
|
33
|
-
@cards[value]
|
34
|
-
end
|
35
|
-
|
36
|
-
def rand
|
37
|
-
raise EmptyCollection unless collection?
|
38
|
-
v = @cards.keys.sample
|
39
|
-
@comparator.given(v, @cards[v])
|
40
|
-
end
|
41
|
-
|
42
|
-
def correct? input, comp_bitz
|
43
|
-
raise EmptyCollection unless collection?
|
44
|
-
@comparator.match? input, comp_bitz
|
45
|
-
end
|
46
|
-
|
47
|
-
def mapped_as
|
48
|
-
raise EmptyCollection unless collection?
|
49
|
-
@comparator.mapped_as
|
50
|
-
end
|
51
|
-
|
52
|
-
def children
|
53
|
-
@hsh.select {|k,v| v.is_a? CardCollection}.values.map do |cc|
|
54
|
-
{cc.name => cc}
|
55
|
-
end.inject(:merge)
|
56
|
-
end
|
57
|
-
|
58
|
-
def select_collection string
|
59
|
-
first, tail = string.split(JOIN, 2)
|
60
|
-
if collection?
|
61
|
-
@comparator = @mappings.select_mapping(first)
|
62
|
-
return self
|
63
|
-
else
|
64
|
-
children[first].select_collection tail
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def collection?
|
69
|
-
!!(@cards ||= nil)
|
70
|
-
end
|
71
|
-
|
72
|
-
def cards
|
73
|
-
@cards || raise(I18n.t 'Errors.UpperCollection')
|
74
|
-
end
|
75
|
-
|
76
|
-
private
|
77
|
-
##
|
78
|
-
# Replace respective raw ruby object with our objects
|
79
|
-
def _build
|
80
|
-
if @hsh.has_key? "mapping"
|
81
|
-
@hsh["mapping"] = Mappings.new(@hsh["mapping"], self)
|
82
|
-
else
|
83
|
-
@hsh.tap do |h|
|
84
|
-
h.select {|k,v| v.is_a? Hash }.each do |k,v|
|
85
|
-
h[k] = self.class.new(v, k)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
class EmptyCollection < StandardError
|
92
|
-
def initialize
|
93
|
-
super(I18n.t 'Errors.EmptyCollection')
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
module LanguageCards
|
2
|
-
class CompBitz
|
3
|
-
attr_reader :display, :collection, :value, :mapping, :expected
|
4
|
-
def initialize options
|
5
|
-
@display = options.fetch(:display)
|
6
|
-
@collection = options.fetch(:collection)
|
7
|
-
@expected = options.fetch(:expected)
|
8
|
-
@value = options.fetch(:value)
|
9
|
-
@mapping = options.fetch(:mapping)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
require_relative 'comp_bitz'
|
2
|
-
|
3
|
-
module LanguageCards
|
4
|
-
class Comparator
|
5
|
-
def initialize mapping_key, mapping, collection
|
6
|
-
##
|
7
|
-
# @title should be a hash like {"Romaji"=>"Katakana"}
|
8
|
-
# @mapping should be an array like [:k, :v]
|
9
|
-
raise I18n.t('Error.MappingNotFound') unless mapping.has_key? mapping_key
|
10
|
-
begin
|
11
|
-
@mapped_as, @mapping = mapping[mapping_key].reduce
|
12
|
-
rescue LocalJumpError
|
13
|
-
raise I18n.t('Errors.InvalidMapping')
|
14
|
-
end
|
15
|
-
|
16
|
-
@collection = collection
|
17
|
-
end
|
18
|
-
|
19
|
-
def mapped_as
|
20
|
-
case @mapping.first
|
21
|
-
when :k
|
22
|
-
@mapped_as.keys.first
|
23
|
-
else
|
24
|
-
@mapped_as.values.first
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def given key, value
|
29
|
-
CompBitz.new(
|
30
|
-
display: choose_display(key, value),
|
31
|
-
collection: @collection,
|
32
|
-
expected: choose_expected(key, value),
|
33
|
-
value: value,
|
34
|
-
mapping: @mapping.first
|
35
|
-
)
|
36
|
-
end
|
37
|
-
|
38
|
-
def match? input, comp_bitz
|
39
|
-
case comp_bitz.mapping
|
40
|
-
when :k
|
41
|
-
comp_bitz.value == comp_bitz.collection[input]
|
42
|
-
when :v
|
43
|
-
comp_bitz.value == input
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
def choose_display key, value
|
49
|
-
case @mapping.last
|
50
|
-
when :k
|
51
|
-
key
|
52
|
-
when :v
|
53
|
-
value
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def choose_expected key, value
|
58
|
-
case @mapping.first
|
59
|
-
when :k
|
60
|
-
key
|
61
|
-
when :v
|
62
|
-
value
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
@@ -1,51 +0,0 @@
|
|
1
|
-
module LanguageCards
|
2
|
-
class Mappings
|
3
|
-
def initialize mapping, collection=nil
|
4
|
-
@collection = collection
|
5
|
-
@mappings = {}
|
6
|
-
mapping.each do |h|
|
7
|
-
index = h.delete("index")
|
8
|
-
begin
|
9
|
-
a,b = h.reduce
|
10
|
-
rescue LocalJumpError
|
11
|
-
raise InvalidMapping
|
12
|
-
end
|
13
|
-
a = I18n.t "LanguageName.#{a}"
|
14
|
-
b = I18n.t "LanguageName.#{b}"
|
15
|
-
|
16
|
-
@mappings["#{a} => #{b}"] = {
|
17
|
-
h => index
|
18
|
-
}
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def select_mapping string
|
23
|
-
Comparator.new string, self, @collection
|
24
|
-
end
|
25
|
-
|
26
|
-
def classes s=nil
|
27
|
-
keys.map do |names|
|
28
|
-
[s, names].compact.join(JOIN)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def [] key
|
33
|
-
@mappings[key]
|
34
|
-
end
|
35
|
-
|
36
|
-
def has_key? key
|
37
|
-
@mappings.has_key? key
|
38
|
-
end
|
39
|
-
|
40
|
-
def keys
|
41
|
-
@mappings.keys
|
42
|
-
end
|
43
|
-
|
44
|
-
class InvalidMapping < StandardError
|
45
|
-
def initialize
|
46
|
-
super(I18n.t 'Errors.InvalidMapping')
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|