language_cards 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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