rexpl 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Rakefile +24 -0
- data/Readme.md +67 -0
- data/bin/rexpl +3 -0
- data/lib/rexpl.rb +15 -0
- data/lib/rexpl/environment.rb +31 -0
- data/lib/rexpl/generator_methods.rb +43 -0
- data/lib/rexpl/generator_proxy.rb +116 -0
- data/lib/rexpl/output.rb +72 -0
- data/lib/rexpl/version.rb +4 -0
- data/rexpl.gemspec +27 -0
- data/test/rexpl/environment_test.rb +23 -0
- data/test/rexpl/generator_methods_test.rb +38 -0
- data/test/rexpl/generator_proxy_test.rb +64 -0
- data/test/rexpl/output_test.rb +63 -0
- data/test/test_helper.rb +7 -0
- metadata +158 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create use rbx-2.0.0pre@rexpl
|
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake/testtask'
|
5
|
+
desc "Run Rexpl tests"
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.libs << "test"
|
8
|
+
t.test_files = FileList['test/**/*_test.rb']
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'yard'
|
13
|
+
YARD::Rake::YardocTask.new(:docs) do |t|
|
14
|
+
t.files = ['lib/**/*.rb']
|
15
|
+
t.options = ['-m', 'markdown', '--no-private', '-r', 'Readme.md', '--title', 'Rexpl documentation']
|
16
|
+
end
|
17
|
+
task :doc => [:docs]
|
18
|
+
|
19
|
+
desc "Generate and open class diagram (needs Graphviz installed)"
|
20
|
+
task :graph do |t|
|
21
|
+
`bundle exec yard graph -d --full --no-private | dot -Tpng -o graph.png && open graph.png`
|
22
|
+
end
|
23
|
+
|
24
|
+
task :default => [:test]
|
data/Readme.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# rexpl
|
2
|
+
|
3
|
+
**rexpl** is a sandbox to experiment and play with the [Rubinius](http:://rubini.us)
|
4
|
+
Virtual Machine and its bytecode instructions. It comes wrapped in a REPL
|
5
|
+
(Read-Eval-Print Loop) à la IRB, so that anytime you can open a terminal,
|
6
|
+
fire up **rexpl**, and start playing with instant feedback.
|
7
|
+
|
8
|
+
This intends to be a fun tool to use when learning how to use Rubinius
|
9
|
+
bytecode instructions, for example when bootstraping a new language targeting
|
10
|
+
the Rubinius VM for the first time.
|
11
|
+
|
12
|
+
Its main feature is **stack introspection**, which means you can inspect
|
13
|
+
what the stack looks like after each step of your instruction set.
|
14
|
+
|
15
|
+
## How to use it?
|
16
|
+
|
17
|
+
Needless to say, **rexpl** runs only on Rubinius. Thus, your first step is to
|
18
|
+
install it. Go to the [Rubinius website](http://rubini.us) to find how, or if
|
19
|
+
you are using RVM, just follow [this instructions](http://beginrescueend.com/interpreters/rbx/).
|
20
|
+
|
21
|
+
$ gem install rexpl
|
22
|
+
$ rexpl
|
23
|
+
|
24
|
+
Now you should see a welcome banner and an IRB-like prompt, and you're good to
|
25
|
+
go! Just start typing some [VM instructions](http://rubini.us/doc/en/virtual-machine/instructions/)
|
26
|
+
and see what happens!
|
27
|
+
|
28
|
+
There are three extra commands to take advantage of the stack introspection:
|
29
|
+
|
30
|
+
* `list` lists the instruction set of the current program.
|
31
|
+
* `reset` empties the instruction set and starts a new program.
|
32
|
+
* `draw` prints a visual representation of the stack after each instruction of
|
33
|
+
your program.
|
34
|
+
|
35
|
+
## When to use it?
|
36
|
+
|
37
|
+
Imagine you are bootstrapping a new language targeting the Rubinius VM and you
|
38
|
+
just implemented a particular AST node, but when you try to run the tests, you
|
39
|
+
keep getting nasty stack validation errors. Net stack underflow? What the heck
|
40
|
+
does this even mean? Where the hell is that extra `pop`? Did this or that
|
41
|
+
instruction consume stack? Or maybe produce it? Oh fuck it, let's go fishing.
|
42
|
+
|
43
|
+
Don't panic. You always have your friends pen and paper ready to help you out,
|
44
|
+
Read through the source code, and knowing what each instruction does, try to
|
45
|
+
follow along and draw what the stack looks like at each step (does that sound
|
46
|
+
familiar to you?). Or just fire up **rexpl**.
|
47
|
+
|
48
|
+
## Resources
|
49
|
+
|
50
|
+
Documentation is online here:
|
51
|
+
|
52
|
+
* [Rexpl documentation](http://rdoc.info/github/txus/rexpl/master/frames)
|
53
|
+
|
54
|
+
##Note on Patches/Pull Requests
|
55
|
+
|
56
|
+
* Fork the project.
|
57
|
+
* Make your feature addition or bug fix.
|
58
|
+
* Add tests for it. This is important so I don't break it in a
|
59
|
+
future version unintentionally.
|
60
|
+
* Commit, do not mess with rakefile, version, or history.
|
61
|
+
If you want to have your own version, that is fine but bump version
|
62
|
+
in a commit by itself I can ignore when I pull.
|
63
|
+
* Send me a pull request. Bonus points for topic branches.
|
64
|
+
|
65
|
+
## Copyright
|
66
|
+
|
67
|
+
Copyright (c) 2010 Josep M. Bach. See LICENSE for details.
|
data/bin/rexpl
ADDED
data/lib/rexpl.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# rexpl is an interactive bytecode console for the Rubinius VM.
|
2
|
+
#
|
3
|
+
# **rexpl** is a sandbox to experiment and play with the [Rubinius](http://rubini.us)
|
4
|
+
# Virtual Machine and its bytecode instructions. It comes wrapped in a REPL
|
5
|
+
# (Read-Eval-Print Loop) à la IRB, so that anytime you can open a terminal,
|
6
|
+
# fire up **rexpl**, and start playing with instant feedback.
|
7
|
+
#
|
8
|
+
module Rexpl
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'rexpl/version'
|
12
|
+
require 'rexpl/generator_proxy'
|
13
|
+
require 'rexpl/generator_methods'
|
14
|
+
require 'rexpl/output'
|
15
|
+
require 'rexpl/environment'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rexpl
|
2
|
+
# This class represents the Environment holding a {GeneratorProxy} instance
|
3
|
+
# exposing the main entry point as a class method.
|
4
|
+
#
|
5
|
+
class Environment
|
6
|
+
@@generator = GeneratorProxy.new
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# Fires up the REPL. This is the program's main entry point.
|
10
|
+
def run
|
11
|
+
Output.print_banner
|
12
|
+
|
13
|
+
while (Output.print_prompt; input = gets)
|
14
|
+
@@generator.instance_eval input.chomp
|
15
|
+
|
16
|
+
# After each new instruction, evaluate all of them.
|
17
|
+
dynamic_method(:run) do |g|
|
18
|
+
@@generator.visit(g)
|
19
|
+
if g.size == 0
|
20
|
+
g.push_nil
|
21
|
+
else
|
22
|
+
g.print_debug_info
|
23
|
+
end
|
24
|
+
g.ret
|
25
|
+
end
|
26
|
+
new.run
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Rexpl
|
2
|
+
# Extends the Rubinius::Generator class with some utility methods used by
|
3
|
+
# Replx.
|
4
|
+
#
|
5
|
+
module GeneratorMethods
|
6
|
+
# Prints the topmost element on the stack and the stack's current size.
|
7
|
+
#
|
8
|
+
# Calling this method neither consumes nor produces stack, it's just used
|
9
|
+
# for debugging the current state.
|
10
|
+
def print_debug_info
|
11
|
+
initial_size = size
|
12
|
+
dup
|
13
|
+
push_const :Rexpl
|
14
|
+
find_const :Output
|
15
|
+
swap_stack
|
16
|
+
send :inspect, 0, true
|
17
|
+
push_literal initial_size
|
18
|
+
swap_stack
|
19
|
+
send :print_debug_info, 2, true
|
20
|
+
pop
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns an array with all the elements currently in the stack.
|
24
|
+
#
|
25
|
+
# Calling #return_stack increases by 1 the stack size (being the topmost
|
26
|
+
# element an array containing a duplicate of every other element in the
|
27
|
+
# stack).
|
28
|
+
def return_stack
|
29
|
+
initial_size = size
|
30
|
+
dup_many initial_size
|
31
|
+
make_array initial_size
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the current size of the stack.
|
35
|
+
#
|
36
|
+
# @return [Fixnum] the current size of the stack.
|
37
|
+
def size
|
38
|
+
@current_block.instance_eval { @stack }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Rubinius::Generator.__send__ :include, Rexpl::GeneratorMethods
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Rexpl
|
2
|
+
# This class acts as a Proxy between the user and an actual Generator.
|
3
|
+
#
|
4
|
+
class GeneratorProxy
|
5
|
+
protected_methods = %w(class to_s inspect instance_eval tainted?)
|
6
|
+
# Undefine every method so that this class acts as an actual proxy.
|
7
|
+
instance_methods.each do |method|
|
8
|
+
unless method.to_s =~ /^_/ || protected_methods.include?(method.to_s)
|
9
|
+
undef_method method
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :instructions
|
14
|
+
|
15
|
+
# Initializes a new {GeneratorProxy} instance with an empty instruction
|
16
|
+
# set.
|
17
|
+
def initialize
|
18
|
+
@instructions = []
|
19
|
+
end
|
20
|
+
|
21
|
+
# Swallows every message passed onto the instance and stores it in the
|
22
|
+
# instruction set.
|
23
|
+
def method_missing(method, *args)
|
24
|
+
@instructions << [method, *args]
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# Applies the set of instructions to an actual generator.
|
29
|
+
#
|
30
|
+
# It captures errors in case an instruction is unknown or called with wrong
|
31
|
+
# arguments.
|
32
|
+
#
|
33
|
+
# @param [Rubinius::Generator] generator the generator onto which apply the
|
34
|
+
# instructions.
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
#
|
38
|
+
# proxy = Rexpl::GeneratorProxy.new
|
39
|
+
# proxy.push 83
|
40
|
+
# proxy.push_literal 'bar'
|
41
|
+
#
|
42
|
+
# dynamic_method(:foo) do |g|
|
43
|
+
# proxy.visit(g)
|
44
|
+
# g.ret
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
def visit(generator)
|
48
|
+
last_instruction = nil
|
49
|
+
begin
|
50
|
+
@instructions.each do |instruction|
|
51
|
+
last_instruction = instruction
|
52
|
+
generator.__send__ *instruction
|
53
|
+
end
|
54
|
+
rescue NameError, ArgumentError=>e
|
55
|
+
puts "[ERROR]: #{e}"
|
56
|
+
@instructions.delete(last_instruction)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Empties the instruction set.
|
61
|
+
def reset
|
62
|
+
Output.print_reset
|
63
|
+
initialize
|
64
|
+
end
|
65
|
+
|
66
|
+
# Prints a list of the current instruction set.
|
67
|
+
def list
|
68
|
+
puts
|
69
|
+
@instructions.each_with_index do |instruction, idx|
|
70
|
+
Output.print_instruction instruction, idx
|
71
|
+
end
|
72
|
+
puts
|
73
|
+
end
|
74
|
+
|
75
|
+
# Visually represents the state of the stack after each instruction is ran.
|
76
|
+
def draw
|
77
|
+
instructions = @instructions.dup
|
78
|
+
klass = Class.new do
|
79
|
+
dynamic_method(:draw) do |g|
|
80
|
+
|
81
|
+
instructions.each_with_index do |instruction, idx|
|
82
|
+
# Execute the instruction
|
83
|
+
before = g.size
|
84
|
+
g.__send__ *instruction
|
85
|
+
after = g.size
|
86
|
+
|
87
|
+
# Print the instruction header
|
88
|
+
produced = after - before
|
89
|
+
verb = 'produced'
|
90
|
+
if produced < 0
|
91
|
+
verb = 'consumed'
|
92
|
+
produced = produced.abs
|
93
|
+
end
|
94
|
+
g.push_self
|
95
|
+
g.push_literal "[#{idx}] [#{instruction.first} #{instruction[1..-1].map(&:inspect).join(', ')}] #{verb} #{produced} stack, size is now #{after}"
|
96
|
+
g.send :puts, 1, true
|
97
|
+
g.pop
|
98
|
+
|
99
|
+
# Visually print the entire stack
|
100
|
+
g.return_stack
|
101
|
+
g.push_const :Rexpl
|
102
|
+
g.find_const :Output
|
103
|
+
g.swap_stack
|
104
|
+
g.send :print_stack, 1, true
|
105
|
+
g.pop
|
106
|
+
end
|
107
|
+
|
108
|
+
g.push_nil
|
109
|
+
g.ret
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
klass.new.draw
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/rexpl/output.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'ansi'
|
2
|
+
|
3
|
+
module Rexpl
|
4
|
+
# Utility module to abstract output-related stuff, like printing banners or
|
5
|
+
# graphically representing stacks.
|
6
|
+
class Output
|
7
|
+
extend ANSI::Code
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# Prints the welcome banner and a bit of instructions on how to use the
|
11
|
+
# interactive console.
|
12
|
+
def print_banner
|
13
|
+
puts
|
14
|
+
puts bold { red { "rexpl" } } + bold { " v#{Rexpl::VERSION}" } + " - interactive bytecode console for Rubinius"
|
15
|
+
puts bold { "--------------------------------------------------------" }
|
16
|
+
puts
|
17
|
+
print_rationale
|
18
|
+
end
|
19
|
+
|
20
|
+
# Prints the console prompt.
|
21
|
+
def print_prompt
|
22
|
+
print bold { '> ' }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Prints a message indicating that the instruction set has been resetted.
|
26
|
+
def print_reset
|
27
|
+
puts "Reseted!"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Prints the current size of the stack and the topmost value.
|
31
|
+
def print_debug_info(size, value)
|
32
|
+
puts "=> [" + bold { "Stack size: #{size}"} + "] " + "[" + bold { "Topmost value: #{value}" } + "]"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Prints an instruction in a single row.
|
36
|
+
def print_instruction(instruction, idx)
|
37
|
+
puts bold { "[" } + blue { idx.to_s } + bold { "]" } + ": " + green { instruction.first } + " " + bold { instruction[1..-1].map(&:inspect) }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Prints a stack out of an array of stack cells.
|
41
|
+
#
|
42
|
+
# @param [Array] cells the cells of the stack containing its values.
|
43
|
+
def print_stack(cells)
|
44
|
+
puts
|
45
|
+
puts "\t#{bold { 'Current stack' }.center(33, ' ')}"
|
46
|
+
puts "\t" + blue { "-------------------------" }
|
47
|
+
cells.reverse.each do |element|
|
48
|
+
puts "\t#{blue {"|"} }#{bold { element.inspect.center(23, ' ') }}#{blue {"|"}}"
|
49
|
+
puts "\t" + blue { "-------------------------" }
|
50
|
+
end
|
51
|
+
puts
|
52
|
+
end
|
53
|
+
|
54
|
+
# Prints a little readme to get people started when firing up the
|
55
|
+
# interactive console.
|
56
|
+
def print_rationale
|
57
|
+
puts "To start playing, just start typing some Rubinius VM instructions."
|
58
|
+
puts "You can find a complete list with documentation here:"
|
59
|
+
puts
|
60
|
+
puts "\thttp://rubini.us/doc/en/virtual-machine/instructions/"
|
61
|
+
puts
|
62
|
+
puts "To introspect the program you are writing, use the following commands,"
|
63
|
+
puts "or type " + bold { "exit" } + " to exit:"
|
64
|
+
puts
|
65
|
+
puts " " + bold { "list" } + " lists the instruction set of the current program."
|
66
|
+
puts " " + bold { "reset" } + " empties the instruction set and starts a new program."
|
67
|
+
puts " " + bold { "draw" } + " prints a visual representation of the stack after each instruction."
|
68
|
+
puts
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/rexpl.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "rexpl/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rexpl"
|
7
|
+
s.version = Rexpl::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Josep M. Bach"]
|
10
|
+
s.email = ["josep.m.bach@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/txus/rexpl"
|
12
|
+
s.summary = %q{Rexpl is an interactive bytecode console for Rubinius}
|
13
|
+
s.description = %q{Rexpl is an interactive bytecode console for Rubinius}
|
14
|
+
|
15
|
+
s.rubyforge_project = "rexpl"
|
16
|
+
|
17
|
+
s.add_runtime_dependency "ansi"
|
18
|
+
s.add_development_dependency "minitest"
|
19
|
+
s.add_development_dependency "mocha"
|
20
|
+
s.add_development_dependency 'yard'
|
21
|
+
s.add_development_dependency 'bluecloth'
|
22
|
+
|
23
|
+
s.files = `git ls-files`.split("\n")
|
24
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
25
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EnvironmentTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_run
|
6
|
+
Rexpl::Output.stubs(:print_banner)
|
7
|
+
Rexpl::Output.stubs(:print_prompt)
|
8
|
+
|
9
|
+
Rexpl::Environment.expects(:gets).times(3).returns('noop', 'push 3', nil)
|
10
|
+
|
11
|
+
proxy = mock
|
12
|
+
Rexpl::Environment.class_variable_set(:@@generator, proxy)
|
13
|
+
|
14
|
+
proxy.expects(:instance_eval).with('noop')
|
15
|
+
proxy.expects(:instance_eval).with('push 3')
|
16
|
+
proxy.expects(:visit).with do |g|
|
17
|
+
assert_kind_of Rubinius::Generator, g
|
18
|
+
end.twice
|
19
|
+
|
20
|
+
Rexpl::Environment.run
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class GeneratorMethodsTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_print_debug_info
|
6
|
+
klass = Class.new do
|
7
|
+
dynamic_method :foo do |g|
|
8
|
+
g.push 5
|
9
|
+
g.push 6
|
10
|
+
g.print_debug_info
|
11
|
+
g.ret
|
12
|
+
end
|
13
|
+
end
|
14
|
+
Rexpl::Output.expects(:print_debug_info).with(2, '6')
|
15
|
+
result = klass.new.foo
|
16
|
+
assert_equal result, 6
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_return_stack_returns_an_array_with_stack_cells
|
20
|
+
klass = Class.new do
|
21
|
+
dynamic_method :foo do |g|
|
22
|
+
g.push 3
|
23
|
+
g.push 6
|
24
|
+
g.return_stack
|
25
|
+
g.ret
|
26
|
+
end
|
27
|
+
end
|
28
|
+
assert_equal klass.new.foo, [3, 6]
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_size_returns_size_of_the_stack
|
32
|
+
g = Rubinius::Generator.new
|
33
|
+
g.push 3
|
34
|
+
g.push 5
|
35
|
+
assert_equal 2, g.size
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class GeneratorProxyTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@proxy = Rexpl::GeneratorProxy.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_swallows_everything_with_its_args
|
10
|
+
@proxy.push 3
|
11
|
+
@proxy.foo
|
12
|
+
@proxy.bar
|
13
|
+
@proxy.whatever
|
14
|
+
@proxy.biwinning
|
15
|
+
|
16
|
+
assert_equal 5, @proxy.instructions.size
|
17
|
+
assert_equal [:push, 3], @proxy.instructions.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_visit_executes_the_instructions
|
21
|
+
@proxy.push 3
|
22
|
+
@proxy.push_literal 'hey'
|
23
|
+
|
24
|
+
g = Rubinius::Generator.new
|
25
|
+
g.expects(:push).with(3)
|
26
|
+
g.expects(:push_literal).with('hey')
|
27
|
+
|
28
|
+
@proxy.visit(g)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_reset
|
32
|
+
@proxy.push 3
|
33
|
+
@proxy.push 5
|
34
|
+
|
35
|
+
Rexpl::Output.expects(:print_reset)
|
36
|
+
|
37
|
+
@proxy.reset
|
38
|
+
|
39
|
+
assert_equal 0, @proxy.instructions.size
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_list
|
43
|
+
@proxy.push 3
|
44
|
+
@proxy.push 5
|
45
|
+
|
46
|
+
Rexpl::Output.expects(:print_instruction).with([:push, 3], 0)
|
47
|
+
Rexpl::Output.expects(:print_instruction).with([:push, 5], 1)
|
48
|
+
|
49
|
+
@proxy.list
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_draw
|
53
|
+
@proxy.push 3
|
54
|
+
@proxy.push 5
|
55
|
+
@proxy.meta_send_op_plus 2
|
56
|
+
|
57
|
+
Rexpl::Output.expects(:print_stack).with([3])
|
58
|
+
Rexpl::Output.expects(:print_stack).with([3, 5])
|
59
|
+
Rexpl::Output.expects(:print_stack).with([8])
|
60
|
+
|
61
|
+
@proxy.draw
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
class OutputTest < MiniTest::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
$stdout = StringIO.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_print_banner
|
10
|
+
Rexpl::Output.print_banner
|
11
|
+
assert_match /rexpl/, $stdout.string
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_print_prompt
|
15
|
+
Rexpl::Output.print_prompt
|
16
|
+
assert_match />/, $stdout.string
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_print_reset
|
20
|
+
Rexpl::Output.print_reset
|
21
|
+
assert_match /Reseted!/, $stdout.string
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_print_debug_info
|
25
|
+
Rexpl::Output.print_debug_info("3", '"some_value"')
|
26
|
+
assert_match /Stack size: 3/, $stdout.string
|
27
|
+
assert_match /Topmost value: "some_value"/, $stdout.string
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_print_instruction
|
31
|
+
instruction = ['send', ':puts', '1', 'true']
|
32
|
+
|
33
|
+
Rexpl::Output.print_instruction(instruction, 3)
|
34
|
+
assert_match /send/, $stdout.string
|
35
|
+
assert_match /:puts/, $stdout.string
|
36
|
+
assert_match /1/, $stdout.string
|
37
|
+
assert_match /true/, $stdout.string
|
38
|
+
assert_match /3/, $stdout.string
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_print_stack
|
42
|
+
cells = %w(Rubinius 23)
|
43
|
+
Rexpl::Output.print_stack(cells)
|
44
|
+
assert_match /Current stack/, $stdout.string
|
45
|
+
assert_match /23/, $stdout.string
|
46
|
+
assert_match /Rubinius/, $stdout.string
|
47
|
+
|
48
|
+
# Rubinius should appear after 23, since cells are reversed
|
49
|
+
refute_match /Rubinius/, $stdout.string.split('23').first
|
50
|
+
assert_match /Rubinius/, $stdout.string.split('23').last
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_print_rationale
|
54
|
+
Rexpl::Output.print_rationale
|
55
|
+
assert_match /list/, $stdout.string
|
56
|
+
assert_match /reset/, $stdout.string
|
57
|
+
assert_match /draw/, $stdout.string
|
58
|
+
end
|
59
|
+
|
60
|
+
def teardown
|
61
|
+
$stdout = STDOUT
|
62
|
+
end
|
63
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rexpl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Josep M. Bach
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-06-17 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: ansi
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: minitest
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: mocha
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: yard
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :development
|
76
|
+
version_requirements: *id004
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: bluecloth
|
79
|
+
prerelease: false
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
type: :development
|
90
|
+
version_requirements: *id005
|
91
|
+
description: Rexpl is an interactive bytecode console for Rubinius
|
92
|
+
email:
|
93
|
+
- josep.m.bach@gmail.com
|
94
|
+
executables:
|
95
|
+
- rexpl
|
96
|
+
extensions: []
|
97
|
+
|
98
|
+
extra_rdoc_files: []
|
99
|
+
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- .rvmrc
|
103
|
+
- Gemfile
|
104
|
+
- Rakefile
|
105
|
+
- Readme.md
|
106
|
+
- bin/rexpl
|
107
|
+
- lib/rexpl.rb
|
108
|
+
- lib/rexpl/environment.rb
|
109
|
+
- lib/rexpl/generator_methods.rb
|
110
|
+
- lib/rexpl/generator_proxy.rb
|
111
|
+
- lib/rexpl/output.rb
|
112
|
+
- lib/rexpl/version.rb
|
113
|
+
- rexpl.gemspec
|
114
|
+
- test/rexpl/environment_test.rb
|
115
|
+
- test/rexpl/generator_methods_test.rb
|
116
|
+
- test/rexpl/generator_proxy_test.rb
|
117
|
+
- test/rexpl/output_test.rb
|
118
|
+
- test/test_helper.rb
|
119
|
+
has_rdoc: true
|
120
|
+
homepage: http://github.com/txus/rexpl
|
121
|
+
licenses: []
|
122
|
+
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
hash: 3
|
134
|
+
segments:
|
135
|
+
- 0
|
136
|
+
version: "0"
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
hash: 3
|
143
|
+
segments:
|
144
|
+
- 0
|
145
|
+
version: "0"
|
146
|
+
requirements: []
|
147
|
+
|
148
|
+
rubyforge_project: rexpl
|
149
|
+
rubygems_version: 1.5.2
|
150
|
+
signing_key:
|
151
|
+
specification_version: 3
|
152
|
+
summary: Rexpl is an interactive bytecode console for Rubinius
|
153
|
+
test_files:
|
154
|
+
- test/rexpl/environment_test.rb
|
155
|
+
- test/rexpl/generator_methods_test.rb
|
156
|
+
- test/rexpl/generator_proxy_test.rb
|
157
|
+
- test/rexpl/output_test.rb
|
158
|
+
- test/test_helper.rb
|