tryruby 0.0.1

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