tryruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,9 @@
1
+ module Tryruby
2
+ # evals 'next' as 'self.next' instead of keyword
3
+ module NextFix
4
+ def loop_eval(str)
5
+ str = 'self.' + str if str == 'next'
6
+ super(str)
7
+ end
8
+ end
9
+ 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,4 @@
1
+ # Version
2
+ module Tryruby
3
+ VERSION = '0.0.1'
4
+ 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
@@ -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