ankit 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ankit/add_command.rb +8 -6
- data/lib/ankit/challenge.rb +154 -95
- data/lib/ankit/challenge_command.rb +5 -2
- data/lib/ankit/event.rb +14 -2
- data/lib/ankit/runtime.rb +8 -0
- data/test/command_test.rb +44 -20
- data/test/data/hope-and-luck.txt +4 -0
- data/test/event_test.rb +22 -1
- data/test/progress_test.rb +28 -2
- metadata +11 -10
data/lib/ankit/add_command.rb
CHANGED
@@ -14,12 +14,14 @@ module Ankit
|
|
14
14
|
def execute()
|
15
15
|
validate_options
|
16
16
|
each_text do |text|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
|
data/lib/ankit/challenge.rb
CHANGED
@@ -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, :
|
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
|
-
|
91
|
-
|
92
|
-
|
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
|
213
|
-
|
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
|
-
|
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
|
277
|
-
def
|
278
|
-
/^\/(\w+)/.match(answered)
|
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
|
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
|
-
|
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
|
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
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
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
|
-
|
380
|
+
line.say("\n")
|
315
381
|
end
|
382
|
+
line.say("\n")
|
316
383
|
end
|
317
384
|
end
|
318
385
|
|
319
|
-
class
|
320
|
-
include
|
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}",
|
395
|
+
say("#{original}", :fail)
|
328
396
|
answered = ask("", :hit_return)
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
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
|
338
|
-
|
339
|
-
progress.fail
|
340
|
-
end
|
404
|
+
class PassedStateBase < State
|
405
|
+
include SlashRecognizing
|
341
406
|
|
342
|
-
def
|
343
|
-
|
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 <
|
348
|
-
def
|
349
|
-
|
350
|
-
|
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 <
|
358
|
-
|
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
|
427
|
+
class RefillState < State
|
368
428
|
def pump
|
369
|
-
|
370
|
-
clear_screen
|
371
|
-
show_breaking_status
|
429
|
+
return initial_state unless session.reached_limit?
|
372
430
|
|
373
|
-
|
431
|
+
runtime.clear_screen
|
432
|
+
show_breaking_status
|
433
|
+
case ask_over
|
374
434
|
when :yes
|
375
|
-
|
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
|
385
|
-
case line.ask("
|
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
|
-
|
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
|
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 =
|
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" =>
|
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
|
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
|
-
|
268
|
-
|
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 =
|
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
|
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::
|
395
|
+
assert_instance_of(Challenge::RefillState, actual_next)
|
373
396
|
end
|
374
397
|
end
|
375
398
|
|
376
|
-
def
|
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, "
|
403
|
+
actual = agree_pump(actual, "y")
|
381
404
|
assert_instance_of(Challenge::OverState, actual)
|
382
405
|
end
|
383
406
|
end
|
384
407
|
|
385
|
-
def
|
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
|
-
|
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
|
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::
|
423
|
+
assert_instance_of(Challenge::RefillState, actual)
|
400
424
|
end
|
401
425
|
end
|
402
426
|
end
|
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
|
-
|
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
|
data/test/progress_test.rb
CHANGED
@@ -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.
|
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.
|
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-
|
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: &
|
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: *
|
24
|
+
version_requirements: *7184500
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: diff-lcs
|
27
|
-
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: *
|
35
|
+
version_requirements: *7183860
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: json
|
38
|
-
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: *
|
46
|
+
version_requirements: *7183300
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: mocha
|
49
|
-
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: *
|
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
|