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,23 @@
|
|
1
|
+
module Tryruby
|
2
|
+
# Single tutorial level
|
3
|
+
class Level
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize(*challenges)
|
7
|
+
@challenges = challenges
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](n)
|
11
|
+
@challenges[n]
|
12
|
+
end
|
13
|
+
|
14
|
+
def each(&block)
|
15
|
+
@challenges.each(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Number of challenges in level
|
19
|
+
def length
|
20
|
+
@challenges.length
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'level'
|
2
|
+
require_relative 'challenge_builder'
|
3
|
+
|
4
|
+
module Tryruby
|
5
|
+
# Single tutorial level builder
|
6
|
+
class LevelBuilder
|
7
|
+
def initialize
|
8
|
+
@challenges = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def challenge(&block)
|
12
|
+
builder = ChallengeBuilder.new
|
13
|
+
builder.instance_eval(&block)
|
14
|
+
@challenges << builder.challenge
|
15
|
+
end
|
16
|
+
|
17
|
+
def level
|
18
|
+
Level.new(*@challenges)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'ripl'
|
2
|
+
require 'ripl/multi_line'
|
3
|
+
require_relative 'shell'
|
4
|
+
require_relative 'commands'
|
5
|
+
|
6
|
+
module Tryruby
|
7
|
+
# Startup class of the shell
|
8
|
+
class Runner
|
9
|
+
def self.start(tutorials)
|
10
|
+
Ripl::Shell.include Tryruby::Shell
|
11
|
+
Ripl::Commands.include Tryruby::Commands
|
12
|
+
tutorials.each do |tutorial|
|
13
|
+
tutorial.each { |level| Ripl.shell.levels << level }
|
14
|
+
Ripl::Commands.include tutorial.commands
|
15
|
+
end
|
16
|
+
Ripl.start
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require_relative 'colors'
|
3
|
+
require_relative 'next_fix'
|
4
|
+
|
5
|
+
module Tryruby
|
6
|
+
# Shell extension
|
7
|
+
module Shell
|
8
|
+
include Tryruby::NextFix
|
9
|
+
attr_writer :levels
|
10
|
+
|
11
|
+
def before_loop
|
12
|
+
super
|
13
|
+
@level, @challenge = 0, -1
|
14
|
+
next_challenge
|
15
|
+
setup_challenge if @challenge_changed
|
16
|
+
@challenge_changed = false
|
17
|
+
@output = ''
|
18
|
+
end
|
19
|
+
|
20
|
+
def loop_once
|
21
|
+
throw :ripl_exit unless challenge
|
22
|
+
super
|
23
|
+
result = @error_raised ? @error : @result
|
24
|
+
if challenge && \
|
25
|
+
challenge.test(repl_self, result, read_variables, @output)
|
26
|
+
puts Colors.success('Success!')
|
27
|
+
next_challenge
|
28
|
+
end
|
29
|
+
setup_challenge if @challenge_changed
|
30
|
+
@challenge_changed = false
|
31
|
+
end
|
32
|
+
|
33
|
+
def loop_eval(str)
|
34
|
+
stdout_saved = $stdout
|
35
|
+
$stdout = StringIO.new
|
36
|
+
begin
|
37
|
+
super(str)
|
38
|
+
ensure
|
39
|
+
@output = $stdout.string
|
40
|
+
$stdout = stdout_saved
|
41
|
+
puts @output if @output != ''
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def print_eval_error(error)
|
46
|
+
@error = error
|
47
|
+
super(error)
|
48
|
+
end
|
49
|
+
|
50
|
+
def format_error(error)
|
51
|
+
Colors.error(super(error))
|
52
|
+
end
|
53
|
+
|
54
|
+
def format_result(result)
|
55
|
+
Colors.result(super(result))
|
56
|
+
end
|
57
|
+
|
58
|
+
def levels
|
59
|
+
@levels ||= []
|
60
|
+
end
|
61
|
+
|
62
|
+
def level
|
63
|
+
levels[@level] if @level >= 0
|
64
|
+
end
|
65
|
+
|
66
|
+
def challenge
|
67
|
+
level[@challenge] if level && @challenge >= 0
|
68
|
+
end
|
69
|
+
|
70
|
+
def next_challenge
|
71
|
+
@challenge += 1
|
72
|
+
while level && !challenge
|
73
|
+
@challenge = 0
|
74
|
+
@level += 1
|
75
|
+
end
|
76
|
+
@challenge_changed = true if challenge
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
|
80
|
+
def prev_challenge
|
81
|
+
lvl, chall = @level, @challenge - 1
|
82
|
+
while lvl > 0 && chall < 0
|
83
|
+
lvl -= 1
|
84
|
+
chall = levels[lvl].length - 1
|
85
|
+
end
|
86
|
+
return if chall < 0
|
87
|
+
@level, @challenge = lvl, chall
|
88
|
+
@challenge_changed = true
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def help_challenge
|
93
|
+
puts challenge.help if challenge
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def repl_self
|
99
|
+
eval('self', @binding)
|
100
|
+
end
|
101
|
+
|
102
|
+
def read_variables
|
103
|
+
vars = eval('local_variables', @binding).map do |var|
|
104
|
+
[var, @binding.local_variable_get(var)]
|
105
|
+
end
|
106
|
+
Hash[vars]
|
107
|
+
end
|
108
|
+
|
109
|
+
def write_variables(vars)
|
110
|
+
vars.each { |sym, value| @binding.local_variable_set(sym, value) }
|
111
|
+
end
|
112
|
+
|
113
|
+
def setup_challenge
|
114
|
+
return unless challenge
|
115
|
+
vars = read_variables
|
116
|
+
challenge.setup(repl_self, vars)
|
117
|
+
write_variables(vars)
|
118
|
+
puts challenge.setup_source if challenge.display_setup
|
119
|
+
help_challenge
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'level_builder'
|
2
|
+
|
3
|
+
module Tryruby
|
4
|
+
# Base module for level DSL
|
5
|
+
class Tutorial
|
6
|
+
extend Enumerable
|
7
|
+
|
8
|
+
# Commands to be imported
|
9
|
+
module Commands
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@levels = []
|
14
|
+
self.class.each do |block|
|
15
|
+
builder = LevelBuilder.new
|
16
|
+
builder.instance_eval(&block)
|
17
|
+
@levels << builder.level
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](i)
|
22
|
+
@levels[i]
|
23
|
+
end
|
24
|
+
|
25
|
+
def each(&block)
|
26
|
+
@levels.each(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def length
|
30
|
+
@levels.length
|
31
|
+
end
|
32
|
+
|
33
|
+
def commands
|
34
|
+
self.class::Commands
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.each(&block)
|
38
|
+
levels.each(&block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.level(&block)
|
42
|
+
levels << block
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.levels
|
46
|
+
@levels ||= []
|
47
|
+
end
|
48
|
+
|
49
|
+
class << self
|
50
|
+
private :level, :levels
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/tryruby/challenge_builder'
|
3
|
+
|
4
|
+
describe Tryruby::ChallengeBuilder do
|
5
|
+
subject { described_class.new }
|
6
|
+
|
7
|
+
it 'passes help' do
|
8
|
+
subject.help <<-EOF
|
9
|
+
HELP! HELP!
|
10
|
+
I'm being oppressed!
|
11
|
+
EOF
|
12
|
+
expect(subject.challenge.help).to eq "HELP! HELP!\nI'm being oppressed!\n"
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'passes test' do
|
16
|
+
called = []
|
17
|
+
subject.test do |result, vars, out|
|
18
|
+
called << [self, result, vars, out]
|
19
|
+
true
|
20
|
+
end
|
21
|
+
expect(subject.challenge.test('self', 42, { foo: 'bar' }, '')).to eq true
|
22
|
+
expect(called).to eq [['self', 42, { foo: 'bar' }, '']]
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'passes setup' do
|
26
|
+
called = []
|
27
|
+
subject.setup do |vars|
|
28
|
+
called << [self, vars]
|
29
|
+
true
|
30
|
+
end
|
31
|
+
expect(subject.challenge.setup('self', foo: 'bar')).to eq true
|
32
|
+
expect(called).to eq [['self', foo: 'bar']]
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'passes display_setup' do
|
36
|
+
subject.display_setup true
|
37
|
+
expect(subject.challenge.display_setup).to eq true
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/tryruby/challenge'
|
3
|
+
|
4
|
+
describe Tryruby::Challenge do
|
5
|
+
let(:help) { '' }
|
6
|
+
let(:test) { nil }
|
7
|
+
let(:setup) { nil }
|
8
|
+
let(:display_setup) { false }
|
9
|
+
|
10
|
+
subject { described_class.new(help, test, setup, display_setup) }
|
11
|
+
|
12
|
+
describe '#help' do
|
13
|
+
let(:help) { 'This is help' }
|
14
|
+
it 'returns help' do
|
15
|
+
expect(subject.help).to eq 'This is help'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#test' do
|
20
|
+
context 'non-empty test' do
|
21
|
+
called = []
|
22
|
+
let(:test) do
|
23
|
+
proc do |res, vars, out|
|
24
|
+
called << self << res << vars.clone << out
|
25
|
+
vars[:foobar] = 24
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'runs the test' do
|
31
|
+
expect(subject.test('self', 42, vars = { foo: 'bar' }, '')).to eq true
|
32
|
+
expect(called).to eq ['self', 42, { foo: 'bar' }, '']
|
33
|
+
expect(vars[:foobar]).to eq 24
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'empty test' do
|
38
|
+
it 'returns nil' do
|
39
|
+
expect(subject.test(nil, nil, {}, '')).to eq nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#setup' do
|
45
|
+
context 'non-empty setup' do
|
46
|
+
called = []
|
47
|
+
let(:setup) do
|
48
|
+
proc do |vars|
|
49
|
+
called << self << vars.clone
|
50
|
+
vars[:foobar] = 24
|
51
|
+
true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'runs the setup' do
|
56
|
+
expect(subject.setup('self', vars = { foo: 'bar' })).to eq true
|
57
|
+
expect(called).to eq ['self', { foo: 'bar' }]
|
58
|
+
expect(vars[:foobar]).to eq 24
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'empty setup' do
|
63
|
+
it 'returns nil' do
|
64
|
+
expect(subject.setup(nil, {})).to eq nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#setup_source' do
|
70
|
+
let(:setup) do
|
71
|
+
proc do |vars|
|
72
|
+
puts 42
|
73
|
+
vars[:foo] = vars[:bar]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'formats setup source' do
|
78
|
+
expect(subject.setup_source).to eq <<-EOS
|
79
|
+
puts(42)
|
80
|
+
foo = bar
|
81
|
+
EOS
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#display_setup' do
|
86
|
+
let(:display_setup) { true }
|
87
|
+
it 'returns display_setup' do
|
88
|
+
expect(subject.display_setup).to eq true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/spec/colors_spec.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/tryruby/colors'
|
3
|
+
require 'paint'
|
4
|
+
|
5
|
+
describe Tryruby::Colors do
|
6
|
+
let(:string) { 'test' }
|
7
|
+
subject { described_class }
|
8
|
+
|
9
|
+
context 'module' do
|
10
|
+
it 'formats strings' do
|
11
|
+
expect(subject.black(string)).to eq Paint[string, :black]
|
12
|
+
expect(subject.red(string)).to eq Paint[string, :red]
|
13
|
+
expect(subject.green(string)).to eq Paint[string, :green]
|
14
|
+
expect(subject.yellow(string)).to eq Paint[string, :yellow]
|
15
|
+
expect(subject.blue(string)).to eq Paint[string, :blue]
|
16
|
+
expect(subject.magenta(string)).to eq Paint[string, :magenta]
|
17
|
+
expect(subject.cyan(string)).to eq Paint[string, :cyan]
|
18
|
+
expect(subject.white(string)).to eq Paint[string, :white]
|
19
|
+
expect(subject.bg_black(string)).to eq Paint[string, nil, :black]
|
20
|
+
expect(subject.bg_red(string)).to eq Paint[string, nil, :red]
|
21
|
+
expect(subject.bg_green(string)).to eq Paint[string, nil, :green]
|
22
|
+
expect(subject.bg_yellow(string)).to eq Paint[string, nil, :yellow]
|
23
|
+
expect(subject.bg_blue(string)).to eq Paint[string, nil, :blue]
|
24
|
+
expect(subject.bg_magenta(string)).to eq Paint[string, nil, :magenta]
|
25
|
+
expect(subject.bg_cyan(string)).to eq Paint[string, nil, :cyan]
|
26
|
+
expect(subject.bg_white(string)).to eq Paint[string, nil, :white]
|
27
|
+
expect(subject.reset(string)).to eq Paint[string, :reset]
|
28
|
+
expect(subject.bold(string)).to eq Paint[string, :bold]
|
29
|
+
expect(subject.underline(string)).to eq Paint[string, :underline]
|
30
|
+
expect(subject.inverse(string)).to eq Paint[string, :inverse]
|
31
|
+
expect(subject.hide(string)).to eq Paint[string, :hide]
|
32
|
+
expect(subject.title(string)).to eq Paint[string, :bold, :underline]
|
33
|
+
expect(subject.result(string)).to eq Paint[string, :blue]
|
34
|
+
expect(subject.error(string)).to eq Paint[string, :red, :bold]
|
35
|
+
expect(subject.success(string)).to eq Paint[string, :green, :bold]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'included' do
|
40
|
+
include described_class
|
41
|
+
it 'formats strings' do
|
42
|
+
expect(black(string)).to eq Paint[string, :black]
|
43
|
+
expect(red(string)).to eq Paint[string, :red]
|
44
|
+
expect(green(string)).to eq Paint[string, :green]
|
45
|
+
expect(yellow(string)).to eq Paint[string, :yellow]
|
46
|
+
expect(blue(string)).to eq Paint[string, :blue]
|
47
|
+
expect(magenta(string)).to eq Paint[string, :magenta]
|
48
|
+
expect(cyan(string)).to eq Paint[string, :cyan]
|
49
|
+
expect(white(string)).to eq Paint[string, :white]
|
50
|
+
expect(bg_black(string)).to eq Paint[string, nil, :black]
|
51
|
+
expect(bg_red(string)).to eq Paint[string, nil, :red]
|
52
|
+
expect(bg_green(string)).to eq Paint[string, nil, :green]
|
53
|
+
expect(bg_yellow(string)).to eq Paint[string, nil, :yellow]
|
54
|
+
expect(bg_blue(string)).to eq Paint[string, nil, :blue]
|
55
|
+
expect(bg_magenta(string)).to eq Paint[string, nil, :magenta]
|
56
|
+
expect(bg_cyan(string)).to eq Paint[string, nil, :cyan]
|
57
|
+
expect(bg_white(string)).to eq Paint[string, nil, :white]
|
58
|
+
expect(reset(string)).to eq Paint[string, :reset]
|
59
|
+
expect(bold(string)).to eq Paint[string, :bold]
|
60
|
+
expect(underline(string)).to eq Paint[string, :underline]
|
61
|
+
expect(inverse(string)).to eq Paint[string, :inverse]
|
62
|
+
expect(hide(string)).to eq Paint[string, :hide]
|
63
|
+
expect(title(string)).to eq Paint[string, :bold, :underline]
|
64
|
+
expect(result(string)).to eq Paint[string, :blue]
|
65
|
+
expect(error(string)).to eq Paint[string, :red, :bold]
|
66
|
+
expect(success(string)).to eq Paint[string, :green, :bold]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|