tryruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +25 -0
- data/Rakefile +1 -0
- data/bin/tryruby +21 -0
- data/lib/tryruby.rb +5 -0
- data/lib/tryruby/challenge.rb +28 -0
- data/lib/tryruby/challenge_builder.rb +32 -0
- data/lib/tryruby/colors.rb +43 -0
- data/lib/tryruby/commands.rb +18 -0
- data/lib/tryruby/default_levels.rb +858 -0
- data/lib/tryruby/level.rb +23 -0
- data/lib/tryruby/level_builder.rb +21 -0
- data/lib/tryruby/next_fix.rb +9 -0
- data/lib/tryruby/runner.rb +19 -0
- data/lib/tryruby/shell.rb +122 -0
- data/lib/tryruby/tutorial.rb +53 -0
- data/lib/tryruby/version.rb +4 -0
- data/spec/challenge_buider_spec.rb +39 -0
- data/spec/challenge_spec.rb +91 -0
- data/spec/colors_spec.rb +69 -0
- data/spec/commands_spec.rb +50 -0
- data/spec/level_builder_spec.rb +21 -0
- data/spec/level_spec.rb +30 -0
- data/spec/next_fix_spec.rb +22 -0
- data/spec/shell_spec.rb +205 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/tutorial_spec.rb +74 -0
- data/tryruby.gemspec +27 -0
- metadata +173 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'ripl'
|
3
|
+
require_relative '../lib/tryruby/commands'
|
4
|
+
require_relative '../lib/tryruby/next_fix'
|
5
|
+
|
6
|
+
# mocking shell
|
7
|
+
module TestShellModule
|
8
|
+
class << self; attr_reader :called; end
|
9
|
+
@called = {}
|
10
|
+
|
11
|
+
def next_challenge
|
12
|
+
TestShellModule.called[:next_challenge] = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def prev_challenge
|
16
|
+
TestShellModule.called[:prev_challenge] = true
|
17
|
+
end
|
18
|
+
|
19
|
+
def help_challenge
|
20
|
+
TestShellModule.called[:help_challenge] = true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Ripl::Shell.include TestShellModule
|
25
|
+
Ripl::Shell.include Tryruby::NextFix
|
26
|
+
Ripl::Commands.include Tryruby::Commands
|
27
|
+
Ripl.shell.before_loop
|
28
|
+
|
29
|
+
describe Tryruby::Commands do
|
30
|
+
let(:input) { nil }
|
31
|
+
before(:each) do
|
32
|
+
TestShellModule.called.clear
|
33
|
+
Ripl.shell.eval_input(input)
|
34
|
+
end
|
35
|
+
subject { TestShellModule.called }
|
36
|
+
describe '#next' do
|
37
|
+
let(:input) { 'next' }
|
38
|
+
it { is_expected.to eq next_challenge: true }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#back' do
|
42
|
+
let(:input) { 'back' }
|
43
|
+
it { is_expected.to eq prev_challenge: true }
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#help' do
|
47
|
+
let(:input) { 'help' }
|
48
|
+
it { is_expected.to eq help_challenge: true }
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/tryruby/level_builder'
|
3
|
+
|
4
|
+
describe Tryruby::LevelBuilder do
|
5
|
+
subject { described_class.new }
|
6
|
+
|
7
|
+
describe '#challenge' do
|
8
|
+
it 'adds challenges' do
|
9
|
+
subject.challenge do
|
10
|
+
help 'first'
|
11
|
+
end
|
12
|
+
subject.challenge do
|
13
|
+
help 'second'
|
14
|
+
end
|
15
|
+
level = subject.level
|
16
|
+
expect(level[0].help).to eq 'first'
|
17
|
+
expect(level[1].help).to eq 'second'
|
18
|
+
expect(level.length).to eq 2
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/spec/level_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/tryruby/level'
|
3
|
+
require_relative '../lib/tryruby/challenge'
|
4
|
+
|
5
|
+
describe Tryruby::Level do
|
6
|
+
let(:a) { Tryruby::Challenge.new('a') }
|
7
|
+
let(:b) { Tryruby::Challenge.new('b') }
|
8
|
+
subject { described_class.new(a, b) }
|
9
|
+
|
10
|
+
describe '#[]' do
|
11
|
+
it 'returns proper item' do
|
12
|
+
expect(subject[0]).to eq a
|
13
|
+
expect(subject[1]).to eq b
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#each' do
|
18
|
+
it 'iterates through items' do
|
19
|
+
yielded = []
|
20
|
+
subject.each { |i| yielded << i }
|
21
|
+
expect(yielded).to eq [a, b]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#length' do
|
26
|
+
it 'returns number of items' do
|
27
|
+
expect(subject.length).to eq 2
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/tryruby/next_fix'
|
3
|
+
|
4
|
+
describe Tryruby::NextFix do
|
5
|
+
# mocking module to properly inherit
|
6
|
+
module API
|
7
|
+
def loop_eval(str)
|
8
|
+
str
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
include API
|
13
|
+
include described_class
|
14
|
+
|
15
|
+
it 'converts next to self.next' do
|
16
|
+
expect(loop_eval('next')).to eq 'self.next'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'does not convert "next"' do
|
20
|
+
expect(loop_eval('"next"')).to eq '"next"'
|
21
|
+
end
|
22
|
+
end
|
data/spec/shell_spec.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/tryruby/shell'
|
3
|
+
require_relative '../lib/tryruby/challenge'
|
4
|
+
|
5
|
+
# mocking shell
|
6
|
+
class TestShell
|
7
|
+
class << self; public :include; end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@binding = create_binding
|
11
|
+
@result = false
|
12
|
+
end
|
13
|
+
|
14
|
+
# mocking module to properly inherit
|
15
|
+
module API
|
16
|
+
def before_loop
|
17
|
+
end
|
18
|
+
|
19
|
+
def loop_once
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_binding
|
24
|
+
foo = 42
|
25
|
+
bar = 24
|
26
|
+
binding
|
27
|
+
end
|
28
|
+
|
29
|
+
include API
|
30
|
+
end
|
31
|
+
|
32
|
+
TestShell.include Tryruby::Shell
|
33
|
+
|
34
|
+
describe Tryruby::Shell do
|
35
|
+
called = []
|
36
|
+
let(:test) do
|
37
|
+
proc do |result, vars, output|
|
38
|
+
called << [:test, self, result, vars.dup, output]
|
39
|
+
result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
let(:setup) do
|
43
|
+
proc do |vars|
|
44
|
+
called << [:setup, self, vars.dup]
|
45
|
+
vars[:test_var] ||= 0
|
46
|
+
vars[:test_var] += 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
let(:a) { Tryruby::Challenge.new('a', test, setup) }
|
50
|
+
let(:b) { Tryruby::Challenge.new('b', nil, setup) }
|
51
|
+
let(:c) { Tryruby::Challenge.new('c', test) }
|
52
|
+
let(:levels) { [[a, b], [], [c]] }
|
53
|
+
let(:shell) { TestShell.new.tap { |sh| sh.levels = levels } }
|
54
|
+
|
55
|
+
def test_var
|
56
|
+
eval('test_var', shell.instance_eval('@binding'))
|
57
|
+
end
|
58
|
+
|
59
|
+
subject { shell.challenge }
|
60
|
+
|
61
|
+
before(:each) do
|
62
|
+
called = []
|
63
|
+
shell.before_loop
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#before_loop' do
|
67
|
+
it 'prints help and calls setup' do
|
68
|
+
is_expected.to eq a
|
69
|
+
expect(called).to eq [[:setup, shell, { foo: 42, bar: 24 }]]
|
70
|
+
expect(test_var).to eq 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#next_challenge' do
|
75
|
+
let(:test) {}
|
76
|
+
it 'prints helps and calls setups' do
|
77
|
+
expect do
|
78
|
+
shell.next_challenge
|
79
|
+
shell.loop_once
|
80
|
+
end.to match_stdout('b')
|
81
|
+
expect(shell.challenge).to eq b
|
82
|
+
expect(test_var).to eq 2
|
83
|
+
expect do
|
84
|
+
shell.next_challenge
|
85
|
+
shell.loop_once
|
86
|
+
end.to match_stdout('c')
|
87
|
+
expect(shell.challenge).to eq c
|
88
|
+
expect(test_var).to eq 2
|
89
|
+
expect do
|
90
|
+
shell.next_challenge
|
91
|
+
shell.loop_once
|
92
|
+
end.to throw_symbol(:ripl_exit)
|
93
|
+
expect(shell.challenge).to eq nil
|
94
|
+
expect(test_var).to eq 2
|
95
|
+
expect(called).to eq [
|
96
|
+
[:setup, shell, { foo: 42, bar: 24 }],
|
97
|
+
[:setup, shell, { foo: 42, bar: 24, test_var: 1 }]
|
98
|
+
]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#prev_challenge' do
|
103
|
+
let(:test) {}
|
104
|
+
it 'prints helps and calls setups' do
|
105
|
+
2.times do
|
106
|
+
shell.next_challenge
|
107
|
+
shell.loop_once
|
108
|
+
end
|
109
|
+
expect(shell.challenge).to eq c
|
110
|
+
expect(test_var).to eq 2
|
111
|
+
expect do
|
112
|
+
shell.prev_challenge
|
113
|
+
shell.loop_once
|
114
|
+
end.to match_stdout('b')
|
115
|
+
expect(shell.challenge).to eq b
|
116
|
+
expect(test_var).to eq 3
|
117
|
+
expect do
|
118
|
+
shell.prev_challenge
|
119
|
+
shell.loop_once
|
120
|
+
end.to match_stdout('a')
|
121
|
+
expect(shell.challenge).to eq a
|
122
|
+
expect(test_var).to eq 4
|
123
|
+
expect do
|
124
|
+
shell.prev_challenge
|
125
|
+
shell.loop_once
|
126
|
+
end.to match_stdout('')
|
127
|
+
expect(shell.challenge).to eq a
|
128
|
+
expect(test_var).to eq 4
|
129
|
+
expect(called).to eq [
|
130
|
+
[:setup, shell, { foo: 42, bar: 24 }],
|
131
|
+
[:setup, shell, { foo: 42, bar: 24, test_var: 1 }],
|
132
|
+
[:setup, shell, { foo: 42, bar: 24, test_var: 2 }],
|
133
|
+
[:setup, shell, { foo: 42, bar: 24, test_var: 3 }]
|
134
|
+
]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe '#loop_once' do
|
139
|
+
context 'with fulfilled test' do
|
140
|
+
let(:test) do
|
141
|
+
proc do |result, vars, output|
|
142
|
+
called << [:test, self, result, vars, output]
|
143
|
+
!result
|
144
|
+
end
|
145
|
+
end
|
146
|
+
it 'goes to next challenge' do
|
147
|
+
expect { shell.loop_once }.to match_stdout('Success!')
|
148
|
+
expect(called).to eq [
|
149
|
+
[:setup, shell, { foo: 42, bar: 24 }],
|
150
|
+
[:test, shell, false, { foo: 42, bar: 24, test_var: 1 }, ''],
|
151
|
+
[:setup, shell, { foo: 42, bar: 24, test_var: 1 }]
|
152
|
+
]
|
153
|
+
expect(shell.challenge).to eq b
|
154
|
+
end
|
155
|
+
end
|
156
|
+
context 'with failed test' do
|
157
|
+
it 'does not go to next challenge' do
|
158
|
+
expect { shell.loop_once }.to match_stdout('')
|
159
|
+
expect(called).to eq [
|
160
|
+
[:setup, shell, { foo: 42, bar: 24 }],
|
161
|
+
[:test, shell, false, { foo: 42, bar: 24, test_var: 1 }, '']
|
162
|
+
]
|
163
|
+
expect(shell.challenge).to eq a
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#level' do
|
169
|
+
it 'returns current level\'s challenges' do
|
170
|
+
expect(shell.level).to eq [a, b]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe '#challenge' do
|
175
|
+
it 'returns current challenge' do
|
176
|
+
is_expected.to eq a
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe '#help_challenge' do
|
181
|
+
it 'prints help' do
|
182
|
+
expect { shell.help_challenge }.to match_stdout('a')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context 'without challenge' do
|
187
|
+
let(:levels) { [] }
|
188
|
+
|
189
|
+
describe '#loop_once' do
|
190
|
+
it { expect { shell.loop_once }.to throw_symbol(:ripl_exit) }
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '#level' do
|
194
|
+
it { expect(shell.level).to eq nil }
|
195
|
+
end
|
196
|
+
|
197
|
+
describe '#challenge' do
|
198
|
+
it { is_expected.to eq nil }
|
199
|
+
end
|
200
|
+
|
201
|
+
describe '#help_challenge' do
|
202
|
+
it { expect { shell.help_challenge }.to match_stdout('') }
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
$LOAD_PATH << '../lib/tryruby'
|
5
|
+
|
6
|
+
RSpec.configure do |c|
|
7
|
+
c.color = true
|
8
|
+
c.formatter = :documentation
|
9
|
+
c.tty = true
|
10
|
+
end
|
11
|
+
|
12
|
+
# mtm @ http://stackoverflow.com/questions/6372763/rspec-how-do-i-write-a-test-that-expects-certain-output-but-doesnt-care-about
|
13
|
+
RSpec::Matchers.define :match_stdout do |check|
|
14
|
+
@capture = nil
|
15
|
+
|
16
|
+
match do |block|
|
17
|
+
begin
|
18
|
+
stdout_saved = $stdout
|
19
|
+
$stdout = StringIO.new
|
20
|
+
block.call
|
21
|
+
ensure
|
22
|
+
@capture = $stdout
|
23
|
+
$stdout = stdout_saved
|
24
|
+
end
|
25
|
+
|
26
|
+
@capture.string.match check
|
27
|
+
end
|
28
|
+
|
29
|
+
failure_message do
|
30
|
+
"expected to #{description}"
|
31
|
+
end
|
32
|
+
failure_message_when_negated do
|
33
|
+
"expected not to #{description}"
|
34
|
+
end
|
35
|
+
description do
|
36
|
+
"match [#{check}] on stdout [#{@capture.string}]"
|
37
|
+
end
|
38
|
+
|
39
|
+
def supports_block_expectations?
|
40
|
+
true
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/tryruby/tutorial'
|
3
|
+
|
4
|
+
describe Tryruby::Tutorial do
|
5
|
+
subject { described_class.new }
|
6
|
+
|
7
|
+
describe '#[]' do
|
8
|
+
it { expect(subject[0]).to eq nil }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#each' do
|
12
|
+
it 'returns Enumerator without block' do
|
13
|
+
expect(subject.each.class).to be Enumerator
|
14
|
+
end
|
15
|
+
it 'iterates through levels' do
|
16
|
+
yielded = []
|
17
|
+
subject.each { |i| yielded << i }
|
18
|
+
expect(yielded).to eq []
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#length' do
|
23
|
+
it { expect(subject.length).to eq 0 }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#commands' do
|
27
|
+
it 'return Commands module' do
|
28
|
+
expect(subject.commands).to eq described_class::Commands
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'subclass' do
|
33
|
+
# Tutorial subclass
|
34
|
+
class TestTutorial < described_class
|
35
|
+
# Test commands
|
36
|
+
module Commands
|
37
|
+
def test
|
38
|
+
'test'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
level do
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
subject { TestTutorial.new }
|
46
|
+
|
47
|
+
describe '#[]' do
|
48
|
+
it { expect(subject[0].class).to eq Tryruby::Level }
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#each' do
|
52
|
+
it 'returns Enumerator without block' do
|
53
|
+
expect(subject.each.class).to be Enumerator
|
54
|
+
end
|
55
|
+
it 'iterates through levels' do
|
56
|
+
yielded = []
|
57
|
+
subject.each { |i| yielded << i.class }
|
58
|
+
expect(yielded).to eq [Tryruby::Level]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#length' do
|
63
|
+
it { expect(subject.length).to eq 1 }
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#commands' do
|
67
|
+
it 'return Commands module' do
|
68
|
+
expect(subject.commands).to eq TestTutorial::Commands
|
69
|
+
expect(subject.commands.instance_methods).to eq [:test]
|
70
|
+
expect(described_class.new.commands.instance_methods).to eq []
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|