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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f22e96585dc1b1e68ac22cdf4c2f3a4952e0c89b
4
- data.tar.gz: ae89a8be6614e9707d4ac400bd1a87535718ae63
2
+ SHA256:
3
+ metadata.gz: 18f1ce1cc9252361375183fcf05ff8f0c53af01f61c8c9b4a361e58265be245f
4
+ data.tar.gz: 6930a65377a3bb2dc4e0d29b897e99e1f85aa8301a352eaeb49771142cbfcc1f
5
5
  SHA512:
6
- metadata.gz: 8ff61fd64bf7e765c593e642799d2a869a47f40cc620fb3b71d27af34f722cbdc548b4861f24cf7b74c5cb7942c2fe374c2600f0a20a62c6f8cf47b17e9019b4
7
- data.tar.gz: 8170a20139eeb403cb5b99b361e0edffb0a64e39788e90100a5f30f55fa6e709c08ed33dde30626e444a63e3b35d6541105acc7138d6ee243b229540197b42ee
6
+ metadata.gz: f418b1fc7567256199684e241d93d76ade1987fdaec463e80ed8105a11bb58f4de9e5a408ddcaa59837c825bea73dc873e1f8bbedcb6fca298eb0c3daa7727a5
7
+ data.tar.gz: 2a6f47d07d483b3401840a840fbba080e21801bd596ad55fb653afa3947d93a4f69b04132ac0d5f04d71e3e7d7c64ac0d8e95ca520cf4a961b0978546739575c
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
  **/*.swp
11
11
  mkmf.log
12
12
  *.gem
13
+ .byebug_history
data/Gemfile CHANGED
@@ -4,3 +4,7 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  gem 'simplecov', :require => false, :group => :test
7
+
8
+ group :development do
9
+ gem 'byebug'
10
+ end
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 lnaguage name and it's okay if that already exists in another file. The entries below that
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 with exactly two entries. The first mapping entry is how the language is being mapped
43
- from key to value (eg "Romaji" => "Hiragana"). The next mapping entry is the representation of how this is to be
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.*
@@ -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: ぐ
@@ -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: ウ
@@ -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.0"
28
+ spec.add_development_dependency "rake", "~> 12.3"
28
29
  spec.add_development_dependency "minitest", "~> 5.10"
29
30
  end
@@ -3,6 +3,7 @@ require 'language_cards/language_cards'
3
3
  require 'yaml'
4
4
  require 'i18n'
5
5
  require 'highline'
6
+ require 'elixirize'
6
7
 
7
8
  ##
8
9
  # TODO:
@@ -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%" % calc_score(correct, incorrect)
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 = ERB.new(IO.read(File.expand_path('../view/game.erb', __dir__)))
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(card_collection, mode)
18
- ic = struct_data.new(card_collection, mode.peek)
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')} #{collection.mapped_as}: #{display}")
35
+ @input ||= CLI.ask("#{I18n.t('Game.TypeThis')}: #{display}")
34
36
  end
35
37
 
36
- def comp_bitz
37
- @comp_bitz ||= collection.rand
38
+ def card
39
+ @card ||= collection.sample
38
40
  end
39
41
 
40
42
  def display
41
- comp_bitz.display
43
+ "#{card}"
42
44
  end
43
45
 
44
46
  def expected
45
- comp_bitz.expected
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
- collection.correct?(input, comp_bitz)
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 :typing then t 'Menu.ModeTyping'
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 = ERB.new(IO.read(File.expand_path('../view/main_menu.erb', __dir__)))
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
@@ -19,6 +19,10 @@ module LanguageCards
19
19
  def clear
20
20
  printf ::LanguageCards::ESC::CLEAR
21
21
  end
22
+
23
+ def humanize string
24
+ "#{string}".split('_').map(&:capitalize).join(' ')
25
+ end
22
26
  end
23
27
  end
24
28
  end
@@ -1,4 +1,4 @@
1
- require_relative 'card_collection'
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
- Dir[File.join(File.expand_path(File.join('..','..','..'), __FILE__), 'cards', '*.yml')].+(
10
- if ENV['HOME']
11
- Dir[File.join(File.expand_path(ENV['HOME']), '.language_cards', 'cards', '*.yml')]
12
- else
13
- []
14
- end
15
- ).
16
- each do |c|
17
- next unless yaml_data = YAML.load(File.open(c).read)
18
- for language in yaml_data.keys do
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
- @CARDS.merge!({language => yaml_data[language]})
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(@CARDS).start
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
@@ -0,0 +1,14 @@
1
+ require 'language_cards/modes/game'
2
+ module LanguageCards
3
+ module Modes
4
+ class Translate < Game
5
+ def match? input
6
+ current.translation == input
7
+ end
8
+
9
+ def mode
10
+ :translate
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'language_cards/modes/game'
2
+ module LanguageCards
3
+ module Modes
4
+ class TypingPractice < Game
5
+ def match? input
6
+ "#{current}" == input
7
+ end
8
+
9
+ def mode
10
+ :typing_practice
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,8 +1,8 @@
1
- require_relative 'timer'
2
- require_relative 'helpers/view_helper'
3
- require_relative 'helpers/game_helper'
4
- require_relative 'controllers/main_menu'
5
- require_relative 'controllers/game'
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.classes
15
- @mode = [:translate, :typing].cycle
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
- clear
20
-
21
- CLI.say SPLASH_SCREEN
22
- sleep 2
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
- collection = cards.select_collection(courses(value))
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: @correct,
44
- incorrect: @incorrect,
45
- title: collection.name,
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,3 +1,3 @@
1
1
  module LanguageCards
2
- VERSION = "0.1.3"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,9 +1,9 @@
1
1
  <%= divider %>
2
2
  <%= draw(_title, nil, 'v' + VERSION) %>
3
3
  <%= divider %>
4
- <%= draw(_select, nil, I18n.t('Menu.GameMode') + _mode) %>
4
+ <%= draw(_select, nil, _mode) %>
5
5
  <% _courses.each do |course| %>
6
6
  <%= course.chomp %><% end %>
7
7
 
8
- <%= draw(_mexit, nil, ("m: " + I18n.t('Menu.ToggleGameMode'))) %>
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.1.3
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: 2017-02-27 00:00:00.000000000 Z
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.0'
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.0'
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/mappings.rb
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.10
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