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