ankit 0.0.2 → 0.0.3

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.
@@ -14,12 +14,14 @@ module Ankit
14
14
  def execute()
15
15
  validate_options
16
16
  each_text do |text|
17
- card = Card.parse(text)
18
- # TODO: gaurd ovewrite
19
- # TODO: guard out-of-path write
20
- filename = to_card_path(dest_dir, card.name)
21
- File.open(filename, "w") { |f| f.write(text) }
22
- runtime.stdout.write("#{filename}\n")
17
+ text.split(/\n\n+/).each do |chunk|
18
+ card = Card.parse(chunk)
19
+ # TODO: gaurd ovewrite
20
+ # TODO: guard out-of-path write
21
+ filename = to_card_path(dest_dir, card.name)
22
+ File.open(filename, "w") { |f| f.write(text) }
23
+ runtime.stdout.write("#{filename}\n")
24
+ end
23
25
  end
24
26
  end
25
27
 
@@ -25,6 +25,8 @@ module Ankit
25
25
  HighLine.color(text, HighLine::GREEN_STYLE)
26
26
  when :wrong
27
27
  HighLine.color(text, HighLine::RED_STYLE)
28
+ when :fyi
29
+ HighLine.color(text, HighLine::DARK)
28
30
  else
29
31
  raise
30
32
  end
@@ -35,7 +37,6 @@ module Ankit
35
37
  def decorated(type)
36
38
  raise
37
39
  decorated = @text.gsub(/\[(.*?)\]/) { |t|
38
- p Regexp::last_match.offset(0)
39
40
  self.class.styled_text($1, type)
40
41
  }
41
42
  decorated != @text ? decorated : self.class.styled_text(@text, type)
@@ -74,23 +75,58 @@ module Ankit
74
75
  end
75
76
  end
76
77
  end
78
+
79
+ def mixed_hilight_for_flash(wrong)
80
+ diff_from_original(wrong) do |ch|
81
+ case ch.action
82
+ when "="
83
+ StylableText.styled_text(ch.old_element, :fyi)
84
+ when "!", "-"
85
+ StylableText.styled_text(ch.old_element, :wrong) + StylableText.styled_text(ch.new_element, :correct)
86
+ when "+"
87
+ StylableText.styled_text(ch.new_element, :correct)
88
+ else
89
+ raise
90
+ end
91
+ end
92
+ end
77
93
  end
78
94
 
79
95
  module Challenge
80
96
  class Slot < Struct.new(:path, :rating, :event)
97
+ BATCH_SIZE = 10
81
98
  def maturity; self.event ? self.event.maturity : 0; end
82
99
  end
83
100
 
84
- class Session < Struct.new(:runtime, :npassed, :nfailed, :mature_names)
85
- def self.make(runtime)
86
- self.new(runtime, 0, 0, [])
101
+ class Session < Struct.new(:runtime, :limit, :npassed, :nfailed, :passed_events)
102
+ def self.make(runtime, limit)
103
+ self.new(runtime, limit, 0, 0, {})
87
104
  end
88
105
 
89
106
  def summary_text
90
- total = self.npassed + self.nfailed
91
- return "" if 0 == total
92
- "#{self.npassed}/#{total} = #{self.npassed.to_f/total.to_f}, #mature: #{mature_names.size}"
107
+ ""
108
+ end
109
+
110
+ def passed_on(event)
111
+ self.passed_events[event.name] = event
112
+ self.npassed += 1
113
+ end
114
+
115
+ def failed_on(event)
116
+ self.nfailed += 1
117
+ end
118
+
119
+ def maturity_triple
120
+ return [0,0,0] if passed_events.empty?
121
+ mats = passed_events.values.map(&:maturity)
122
+ avg = mats.inject(0,:+)/mats.size
123
+ [mats.min, avg, mats.max]
93
124
  end
125
+
126
+ def reached_limit?; limit <= passed_events.size; end
127
+ def limit_reach; passed_events.size ;end
128
+ def ntotal; npassed + nfailed; end
129
+ def hitrate; 0 < ntotal ? npassed.to_f/ntotal : 0; end
94
130
  end
95
131
 
96
132
  class Progress
@@ -103,19 +139,17 @@ module Ankit
103
139
  @this_round = latest_round
104
140
  end
105
141
 
106
- def current_card
107
- # XXX: might be better to cache
108
- Card.parse(open(current_path, "r") { |f| f.read })
109
- end
110
-
111
142
  def round_delta
112
143
  latest_round - this_round
113
144
  end
114
145
 
115
146
  def runtime; @session.runtime; end
116
147
  def last_slot; @slots[@index-1]; end
148
+ def last_path; last_slot.path; end
149
+ def last_card; card_at(last_path); end
117
150
  def current_slot; @slots[@index]; end
118
151
  def current_path; current_slot.path; end
152
+ def current_card; card_at(current_path); end
119
153
  def size; @slots.size; end
120
154
  def over?; @slots.size <= @index; end
121
155
  def npassed; @slots.count { |c| c.rating == :passed }; end
@@ -133,6 +167,7 @@ module Ankit
133
167
  last_slot = current_slot
134
168
  last_slot.rating = :failed
135
169
  last_slot.event = make_happen(FailCommand::EVENT_HAPPENING, to_card_name(current_path), this_round)
170
+ session.failed_on(last_slot.event)
136
171
  end
137
172
 
138
173
  self
@@ -143,6 +178,7 @@ module Ankit
143
178
  last_slot = current_slot
144
179
  last_slot.rating = :passed
145
180
  last_slot.event = make_happen(PassCommand::EVENT_HAPPENING, to_card_name(current_path), this_round)
181
+ session.passed_on(last_slot.event)
146
182
  end
147
183
 
148
184
  @index += 1
@@ -171,13 +207,14 @@ module Ankit
171
207
  end.join
172
208
  end
173
209
 
174
- def update_session
175
- session.npassed += npassed
176
- session.nfailed += nfailed
177
- session.mature_names = (session.mature_names + slots.select{ |s| 1 < s.maturity }.map(&:path)).uniq
178
- end
179
-
180
210
  def maturities; slots.map(&:maturity); end
211
+
212
+
213
+ private
214
+ def card_at(path)
215
+ # XXX: might be better to cache
216
+ Card.parse(open(path, "r") { |f| f.read })
217
+ end
181
218
  end
182
219
 
183
220
  class State
@@ -199,30 +236,21 @@ module Ankit
199
236
  runtime.stdout.print("\033[1A")
200
237
  end
201
238
 
202
- def clear_screen
203
- runtime.stdout.print("\033[2J")
204
- h = HighLine::SystemExtensions.terminal_size[0]
205
- runtime.stdout.print("\033[#{h}A")
206
- end
207
-
208
239
  def say(msg, type=:progress)
209
240
  line.say(message_for(msg, type))
210
241
  end
211
242
 
212
- def show_summary_status
213
- line.say("Round #{progress.this_round}: #{progress.styled_indicator}")
243
+ def show_summary_header
244
+ status = ["P:#{self.session.limit_reach}/#{self.session.limit}",
245
+ "H:#{self.session.hitrate}",
246
+ "M:" + self.session.maturity_triple.map(&:to_s).join(","),
247
+ "R:#{self.progress.this_round.to_s}"
248
+ ]
249
+ line.say(status.join(" "))
214
250
  end
215
251
 
216
252
  def show_breaking_status
217
- show_summary_status
218
- line.say("Maturity: #{progress.maturities.map(&:to_s).join(',')}")
219
- line.say("Session: #{progress.session.summary_text}")
220
- line.say("next round will be +#{progress.round_delta}")
221
- end
222
-
223
- def show_header
224
- show_summary_status
225
- line.say("\n")
253
+ show_summary_header
226
254
  end
227
255
 
228
256
  def show_and_ask_enter(msg, type)
@@ -273,116 +301,149 @@ module Ankit
273
301
  end
274
302
  end
275
303
 
276
- module CommandRecognizing
277
- def may_pump_command(answered)
278
- /^\/(\w+)/.match(answered) ? pump_command($1) : nil
304
+ module SlashRecognizing
305
+ def pump_slash_or(answered, &block)
306
+ if /^\/(\w+)/.match(answered)
307
+ pump_slash($1)
308
+ else
309
+ block.call()
310
+ end
279
311
  end
280
312
 
281
- def pump_command(command)
313
+ def pump_slash(command)
282
314
  case command
283
315
  when "e", "edit"
284
316
  EditState.new(progress)
285
317
  when "z", "zero"
286
318
  QuestionState.new(progress)
287
319
  else
288
- raise
320
+ MessageState.new(progress, "Unknown command: #{command} (Available: /edit, /zero)")
321
+ end
322
+ end
323
+ end
324
+
325
+ class MessageState < State
326
+ include SlashRecognizing
327
+
328
+ def initialize(progress, message)
329
+ super(progress)
330
+ @message = message
331
+ end
332
+
333
+ def pump
334
+ say(@message, :fail) # XXX: should :error
335
+ answered = ask().strip
336
+ pump_slash_or(answered) do
337
+ pump_slash(answered)
289
338
  end
290
339
  end
291
340
  end
292
341
 
293
342
  class QuestionState < State
294
- include CommandRecognizing
343
+ include SlashRecognizing
344
+ attr_reader :flash
295
345
 
296
346
  def pump
297
347
  progress.attack
298
- clear_screen
348
+ runtime.clear_screen
299
349
  show_header
300
350
  card = progress.current_card
301
351
  say("#{card.translation}")
302
352
  say("#{card.hidden_original}", :cont)
303
353
  answered = ask().strip
304
- c = may_pump_command(answered)
305
- return c if c
306
- case card.match?(answered.strip)
307
- when :match
308
- PassedState.new(progress, answered)
309
- when :wrong
310
- FailedState.new(progress, answered)
311
- when :typo
312
- TypoState.new(progress, answered)
354
+ pump_slash_or(answered) do
355
+ case card.match?(answered.strip)
356
+ when :match
357
+ PassedState.new(progress, answered)
358
+ when :wrong
359
+ FailedState.new(progress, answered)
360
+ when :typo
361
+ TypoState.new(progress, answered)
362
+ else
363
+ raise
364
+ end
365
+ end
366
+ end
367
+
368
+ def put_flash(flash)
369
+ @flash = flash
370
+ self
371
+ end
372
+
373
+ private
374
+
375
+ def show_header
376
+ show_summary_header
377
+ if flash
378
+ line.say(flash)
313
379
  else
314
- raise
380
+ line.say("\n")
315
381
  end
382
+ line.say("\n")
316
383
  end
317
384
  end
318
385
 
319
- class FailedStateBase < State
320
- include CommandRecognizing
386
+ class FailedState < State
387
+ include SlashRecognizing
321
388
 
322
389
  def pump
323
390
  original = progress.current_card.corrected_original_over(last_answer)
324
391
  typed = progress.current_card.hilight_against_original(last_answer)
392
+ typed = "\n" if typed.empty?
325
393
  erase_last
326
394
  say("#{typed}", :ask)
327
- say("#{original}", decoration_type)
395
+ say("#{original}", :fail)
328
396
  answered = ask("", :hit_return)
329
- c = may_pump_command(answered)
330
- return c if c
331
- mark_progress
332
- QuestionState.new(progress)
397
+ pump_slash_or(answered) do
398
+ progress.fail
399
+ QuestionState.new(progress)
400
+ end
333
401
  end
334
-
335
402
  end
336
403
 
337
- class FailedState < FailedStateBase
338
- def mark_progress
339
- progress.fail
340
- end
404
+ class PassedStateBase < State
405
+ include SlashRecognizing
341
406
 
342
- def decoration_type
343
- :fail
407
+ def pump
408
+ progress.pass
409
+ last_maturity = progress.last_slot.event.maturity
410
+ progress.over? ? RefillState.new(progress) : QuestionState.new(progress).put_flash(flash)
344
411
  end
345
412
  end
346
413
 
347
- class TypoState < FailedStateBase
348
- def mark_progress
349
-
350
- end
351
-
352
- def decoration_type
353
- :typo
414
+ class TypoState < PassedStateBase
415
+ def flash
416
+ hilited = progress.last_card.mixed_hilight_for_flash(last_answer)
417
+ StylableText.styled_text("last: ", :fyi) + hilited
354
418
  end
355
419
  end
356
420
 
357
- class PassedState < State
358
- include CommandRecognizing
359
-
360
- def pump
361
- progress.pass
362
- last_maturity = progress.last_slot.event.maturity
363
- progress.over? ? BreakingState.new(progress) : QuestionState.new(progress)
421
+ class PassedState < PassedStateBase
422
+ def flash
423
+ StylableText.styled_text("last: #{last_answer}", :fyi)
364
424
  end
365
425
  end
366
426
 
367
- class BreakingState < State
427
+ class RefillState < State
368
428
  def pump
369
- progress.update_session
370
- clear_screen
371
- show_breaking_status
429
+ return initial_state unless session.reached_limit?
372
430
 
373
- case ask_more
431
+ runtime.clear_screen
432
+ show_breaking_status
433
+ case ask_over
374
434
  when :yes
375
- initial_state
376
- when :no
435
+ runtime.clear_screen
377
436
  OverState.new(progress)
437
+ when :no
438
+ initial_state
378
439
  else
379
440
  # TODO: handle help
380
441
  self
381
442
  end
382
443
  end
383
444
 
384
- def ask_more
385
- case line.ask("More(y/n/?) ").strip
445
+ def ask_over
446
+ case line.ask("Over(Y/n/?) ").strip
386
447
  when /^y/, ""
387
448
  :yes
388
449
  when /^n/
@@ -391,10 +452,6 @@ module Ankit
391
452
  :help
392
453
  end
393
454
  end
394
-
395
- def coming_limit
396
- progress.size
397
- end
398
455
  end
399
456
 
400
457
  class OverState < State
@@ -403,11 +460,13 @@ module Ankit
403
460
 
404
461
  module Approaching
405
462
  def initial_state
406
- slots = Coming.coming_paths(self.runtime).take(self.coming_limit).map { |path| Slot.new(path, nil) }
463
+ # XXX: Care the case where |card| < limit
464
+ limit = [self.session.limit, Slot::BATCH_SIZE].min
465
+ slots = Coming.coming_paths(self.runtime).take(limit).map { |path| Slot.new(path, nil) }
407
466
  QuestionState.new(Progress.new(self.session, slots))
408
467
  end
409
468
  end
410
469
 
411
- class BreakingState; include Approaching; end
470
+ class RefillState; include Approaching; end
412
471
  end
413
472
  end
@@ -13,12 +13,13 @@ module Ankit
13
13
  spec.on("-l", "--limit N") { |n| options[:limit] = n.to_i }
14
14
  end
15
15
 
16
- DEFAULT_COUNT = 5
16
+ DEFAULT_COUNT = 50
17
17
 
18
- def session; @session ||= Challenge::Session.make(runtime); end
18
+ def session; @session ||= Challenge::Session.make(runtime, coming_limit); end
19
19
 
20
20
  def execute()
21
21
  Signal.trap("INT") do
22
+ runtime.clear_screen
22
23
  STDERR.print("Quit.\n")
23
24
  exit(0)
24
25
  end
@@ -27,6 +28,8 @@ module Ankit
27
28
  Signal.trap("INT", "DEFAULT")
28
29
  end
29
30
 
31
+ private
32
+
30
33
  def coming_limit
31
34
  options[:limit] or DEFAULT_COUNT
32
35
  end
data/lib/ankit/event.rb CHANGED
@@ -24,6 +24,7 @@ module Ankit
24
24
  def name() @values["name"]; end
25
25
  def type() @values["type"]; end
26
26
  def maturity() @values["maturity"] || 0; end
27
+ def best() @values["best"] || maturity; end
27
28
  def card?() type == "card"; end
28
29
  def round() @envelope.round or 0; end
29
30
  def next_round() round + 2**maturity; end
@@ -39,11 +40,11 @@ module Ankit
39
40
  def to_json(*a) { envelope: @envelope, values: @values }.to_json(*a); end
40
41
 
41
42
  def to_passed(env)
42
- Event.new(env, @values.merge({ "verb" => "passed", "maturity" => maturity + 1 }))
43
+ Event.new(env, Event.sweep(@values.merge({ "verb" => "passed", "maturity" => next_maturity })))
43
44
  end
44
45
 
45
46
  def to_failed(env)
46
- Event.new(env, @values.merge({ "verb" => "failed", "maturity" => 0 }))
47
+ Event.new(env, @values.merge({ "verb" => "failed", "maturity" => 0, "best" => best }))
47
48
  end
48
49
 
49
50
  def self.for_card(name, verb, env)
@@ -52,6 +53,17 @@ module Ankit
52
53
 
53
54
  def self.from_hash(hash) Event.new(Envelope.from_hash(hash["envelope"]), hash["values"]); end
54
55
  def self.parse(text) from_hash(JSON.parse(text)); end
56
+
57
+ def self.sweep(values)
58
+ values.delete("best") if values.include?("best") and values["best"] <= values["maturity"]
59
+ values
60
+ end
61
+
62
+ private
63
+
64
+ def next_maturity
65
+ maturity + [(best - maturity)/2, 1].max
66
+ end
55
67
  end
56
68
 
57
69
  module EventFormatting
data/lib/ankit/runtime.rb CHANGED
@@ -135,6 +135,14 @@ module Ankit
135
135
  saved
136
136
  end
137
137
 
138
+ def clear_screen
139
+ w = HighLine::SystemExtensions.terminal_size[1]
140
+ stdout.print("\033[#{w}D")
141
+ stdout.print("\033[2J")
142
+ h = HighLine::SystemExtensions.terminal_size[0]
143
+ stdout.print("\033[#{h}A")
144
+ end
145
+
138
146
  def unsupress_io(saved)
139
147
  @stdin, @stdout, @stderr = saved
140
148
  end
data/test/command_test.rb CHANGED
@@ -149,7 +149,7 @@ class AddTest < Test::Unit::TestCase
149
149
  end
150
150
  end
151
151
 
152
- def test_hello_two_file
152
+ def test_hello_two_files
153
153
  with_runtime_on_temp_repo do |target|
154
154
  dst_dir = target.config.card_search_paths[1]
155
155
  assert_written(target.dispatch_then(["add", test_data_at("hope.card"), test_data_at("luck.card")]),
@@ -157,6 +157,15 @@ class AddTest < Test::Unit::TestCase
157
157
  File.join(target.config.card_paths[0], "luck-is-not-chance.card")])
158
158
  end
159
159
  end
160
+
161
+ def test_hello_two_chunks
162
+ with_runtime_on_temp_repo do |target|
163
+ dst_dir = target.config.card_search_paths[1]
164
+ assert_written(target.dispatch_then(["add", test_data_at("hope-and-luck.txt")]),
165
+ [File.join(target.config.card_paths[0], "hope-is-the-thing-with-feathers.card"),
166
+ File.join(target.config.card_paths[0], "luck-is-not-chance.card")])
167
+ end
168
+ end
160
169
  end
161
170
 
162
171
  class ComingTest < Test::Unit::TestCase
@@ -264,8 +273,9 @@ class ChallengeTest < Test::Unit::TestCase
264
273
 
265
274
  def test_initial_state_limit_default
266
275
  runtime = make_runtime(NUMBER_REPO)
267
- actual = runtime.make_command(["challenge"]).initial_state
268
- assert_equal(actual.progress.size, ChallengeCommand::DEFAULT_COUNT)
276
+ limit = 5
277
+ actual = runtime.make_command(["challenge", "--limit", limit.to_s]).initial_state
278
+ assert_equal(actual.progress.size, limit)
269
279
  end
270
280
 
271
281
  def test_initial_state_limit_args
@@ -300,6 +310,13 @@ class ChallengeTest < Test::Unit::TestCase
300
310
  state.pump
301
311
  end
302
312
 
313
+ def agree_pump(state, that)
314
+ state.progress.runtime.line = HighLine.new
315
+ state.progress.runtime.line.stubs(:say).at_least(0)
316
+ state.progress.runtime.line.stubs(:ask).once().returns(that)
317
+ state.pump
318
+ end
319
+
303
320
  def test_question_to_fail
304
321
  with_runtime_on_temp_repo do |runtime|
305
322
  actual = ChallengeCommand.new(runtime).initial_state
@@ -312,6 +329,17 @@ class ChallengeTest < Test::Unit::TestCase
312
329
  end
313
330
  end
314
331
 
332
+ def test_question_to_unknown_command
333
+ with_runtime_on_temp_repo do |runtime|
334
+ actual = ChallengeCommand.new(runtime).initial_state
335
+ assert_instance_of(Challenge::QuestionState, actual)
336
+ actual = enter_text_pump(actual, "/unknown")
337
+ assert_instance_of(Challenge::MessageState, actual)
338
+ actual = enter_text_pump(actual, "/zero")
339
+ assert_instance_of(Challenge::QuestionState, actual)
340
+ end
341
+ end
342
+
315
343
  def test_question_to_fail_but_zero_it
316
344
  with_runtime_on_temp_repo do |runtime|
317
345
  actual = ChallengeCommand.new(runtime).initial_state
@@ -329,13 +357,8 @@ class ChallengeTest < Test::Unit::TestCase
329
357
  actual = ChallengeCommand.new(runtime).initial_state
330
358
  actual_next = enter_text_pump(actual, FIRST_TYPO_ANSWER)
331
359
  assert_instance_of(Challenge::TypoState, actual_next)
332
- actual_next = hit_return_pump(actual_next)
360
+ actual_next = actual_next.pump
333
361
  assert_instance_of(Challenge::QuestionState, actual_next)
334
- assert_equal(actual_next.progress.npassed, 0)
335
- assert_equal(actual_next.progress.nfailed, 0)
336
- actual_next = enter_text_pump(actual_next, FIRST_CORRECT_ANSWER)
337
- assert_instance_of(Challenge::PassedState, actual_next)
338
- actual_next.pump
339
362
  assert_equal(actual_next.progress.npassed, 1)
340
363
  assert_equal(actual_next.progress.nfailed, 0)
341
364
  end
@@ -365,38 +388,39 @@ class ChallengeTest < Test::Unit::TestCase
365
388
  state
366
389
  end
367
390
 
368
- def test_to_breaking
391
+ def test_to_refill
369
392
  with_runtime_on_temp_repo do |runtime|
370
393
  actual = ChallengeCommand.new(runtime).initial_state
371
394
  actual_next = pass_two(actual)
372
- assert_instance_of(Challenge::BreakingState, actual_next)
395
+ assert_instance_of(Challenge::RefillState, actual_next)
373
396
  end
374
397
  end
375
398
 
376
- def test_to_breaking_to_over
399
+ def test_to_refill_to_over
377
400
  with_runtime_on_temp_repo do |runtime|
378
- actual = ChallengeCommand.new(runtime).initial_state
401
+ actual = ChallengeCommand.new(runtime, ["--limit", "2"]).initial_state
379
402
  actual = pass_two(actual)
380
- actual = agree_pump(actual, "n")
403
+ actual = agree_pump(actual, "y")
381
404
  assert_instance_of(Challenge::OverState, actual)
382
405
  end
383
406
  end
384
407
 
385
- def test_to_breaking_to_more
408
+ def test_to_refill_to_more
386
409
  with_runtime_on_temp_repo do |runtime|
387
- actual = ChallengeCommand.new(runtime).initial_state
410
+ actual = ChallengeCommand.new(runtime, ["--limit", "2"]).initial_state
388
411
  actual = pass_two(actual)
389
- actual = agree_pump(actual, "y")
412
+ p actual.class
413
+ actual = agree_pump(actual, "n")
390
414
  assert_instance_of(Challenge::QuestionState, actual)
391
415
  end
392
416
  end
393
417
 
394
- def test_to_breaking_to_more
418
+ def test_to_refill_to_more
395
419
  with_runtime_on_temp_repo do |runtime|
396
- actual = ChallengeCommand.new(runtime).initial_state
420
+ actual = ChallengeCommand.new(runtime, ["--limit", "2"]).initial_state
397
421
  actual = pass_two(actual)
398
422
  actual = agree_pump(actual, "?")
399
- assert_instance_of(Challenge::BreakingState, actual)
423
+ assert_instance_of(Challenge::RefillState, actual)
400
424
  end
401
425
  end
402
426
  end
@@ -0,0 +1,4 @@
1
+ O: Hope is the thing with feathers
2
+
3
+
4
+ O: Luck is not chance
data/test/event_test.rb CHANGED
@@ -9,6 +9,7 @@ class EventTest < Test::Unit::TestCase
9
9
  @target = Event.parse('{"envelope":{"at":"2001-02-03T04:05:06+00:00","round":1},' +
10
10
  '"values":{"type":"card","verb":"add","name":"hello","maturity":1}}')
11
11
  @next_envelope = Envelope.parse('{"at":"2002-03-04T05:06:07+00:00","round":2}')
12
+ @another_next_envelope = Envelope.parse('{"at":"2002-03-04T05:06:08+00:00","round":3}')
12
13
  end
13
14
 
14
15
  def test_to_passed
@@ -17,10 +18,30 @@ class EventTest < Test::Unit::TestCase
17
18
  assert_equal(actual, expected)
18
19
  end
19
20
 
21
+ def test_to_passed_recovering
22
+ recovering_target = Event.parse('{"envelope":{"at":"2001-02-03T04:05:06+00:00","round":1},' +
23
+ '"values":{"type":"card","verb":"add","name":"hello","maturity":1,"best":6}}')
24
+ expected = Event.new(@next_envelope, JSON.parse('{"type":"card","verb":"passed","name":"hello","maturity":3,"best":6}'))
25
+ actual = recovering_target.to_passed(@next_envelope)
26
+ assert_equal(actual, expected)
27
+ end
28
+
29
+ def test_to_passed_recovering_to_best
30
+ recovering_target = Event.parse('{"envelope":{"at":"2001-02-03T04:05:06+00:00","round":1},' +
31
+ '"values":{"type":"card","verb":"add","name":"hello","maturity":5,"best":6}}')
32
+ expected = Event.new(@next_envelope, JSON.parse('{"type":"card","verb":"passed","name":"hello","maturity":6}'))
33
+ actual = recovering_target.to_passed(@next_envelope)
34
+ assert_equal(actual, expected)
35
+ end
36
+
20
37
  def test_to_failed
21
- expected = Event.new(@next_envelope, JSON.parse('{"type":"card","verb":"failed","name":"hello","maturity":0}'))
38
+ json = JSON.parse('{"type":"card","verb":"failed","name":"hello","maturity":0,"best":1}')
39
+ expected = Event.new(@next_envelope, json)
22
40
  actual = @target.to_failed(@next_envelope)
23
41
  assert_equal(actual, expected)
42
+ another_expected = Event.new(@another_next_envelope, json)
43
+ actual = @target.to_failed(@another_next_envelope)
44
+ assert_equal(actual, another_expected)
24
45
  end
25
46
 
26
47
  def test_next_round
@@ -8,8 +8,8 @@ class ProgressTest < Test::Unit::TestCase
8
8
  include Ankit::CardNaming
9
9
  include Challenge
10
10
 
11
- def make_target(runtime)
12
- Progress.new(Session.new(runtime), [Slot.new("path1"), Slot.new("path2"), Slot.new("path3")])
11
+ def make_target(runtime, sess=nil)
12
+ Progress.new(sess || Session.make(runtime, 5), [Slot.new("path1"), Slot.new("path2"), Slot.new("path3")])
13
13
  end
14
14
 
15
15
  def first_slot_event_of(progress)
@@ -47,6 +47,32 @@ class ProgressTest < Test::Unit::TestCase
47
47
  end
48
48
  end
49
49
 
50
+ def test_passed_size
51
+ with_runtime_on_temp_repo do |runtime|
52
+ target1 = make_target(runtime)
53
+ session = target1.session
54
+
55
+ target1.pass
56
+ assert_equal(session.limit_reach, 1)
57
+ target1.pass
58
+ assert_equal(session.limit_reach, 2)
59
+ target1.fail
60
+ assert_equal(session.limit_reach, 2)
61
+ target1.pass
62
+ assert_equal(session.limit_reach, 2)
63
+
64
+ target2 = make_target(runtime, session)
65
+ target2.fail
66
+ assert_equal(session.limit_reach, 2)
67
+ target2.pass
68
+ assert_equal(session.limit_reach, 2)
69
+ target2.pass
70
+ assert_equal(session.limit_reach, 2)
71
+ target2.pass
72
+ assert_equal(session.limit_reach, 3)
73
+ end
74
+ end
75
+
50
76
  def test_fail_then_pass
51
77
  with_runtime_on_temp_repo do |runtime|
52
78
  target = make_target(runtime)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ankit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-10 00:00:00.000000000 Z
12
+ date: 2012-03-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: highline
16
- requirement: &20716680 !ruby/object:Gem::Requirement
16
+ requirement: &7184500 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.6.11
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *20716680
24
+ version_requirements: *7184500
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: diff-lcs
27
- requirement: &20716160 !ruby/object:Gem::Requirement
27
+ requirement: &7183860 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.1.3
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *20716160
35
+ version_requirements: *7183860
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: json
38
- requirement: &20715660 !ruby/object:Gem::Requirement
38
+ requirement: &7183300 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.6.5
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *20715660
46
+ version_requirements: *7183300
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: mocha
49
- requirement: &20715080 !ruby/object:Gem::Requirement
49
+ requirement: &7182720 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: 0.10.4
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *20715080
57
+ version_requirements: *7182720
58
58
  description: ! 'Ankit is a CLI and terminal based flashcard program to learn your
59
59
  new language.
60
60
 
@@ -87,6 +87,7 @@ files:
87
87
  - lib/ankit/list_command.rb
88
88
  - lib/ankit.rb
89
89
  - test/data/vanilla_repo/anemone.journal
90
+ - test/data/hope-and-luck.txt
90
91
  - test/data/hello_card.card
91
92
  - test/data/hello_repo/cards/foo/this_is_not_a_card.txt
92
93
  - test/data/hello_repo/cards/foo/vanilla-please.card