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.
- 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
|