rspec 0.6.4 → 0.7.0
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/CHANGES +90 -1
- data/EXAMPLES.rd +28 -6
- data/MIT-LICENSE +20 -0
- data/README +18 -12
- data/Rakefile +60 -54
- data/examples/custom_formatter.rb +4 -4
- data/examples/helper_method_example.rb +11 -0
- data/examples/mocking_example.rb +19 -2
- data/examples/partial_mock_example.rb +28 -0
- data/examples/stack_spec.rb +8 -8
- data/examples/stubbing_example.rb +50 -9
- data/examples/test_case_spec.rb +6 -6
- data/lib/spec.rb +1 -2
- data/lib/spec/callback.rb +0 -0
- data/lib/spec/expectations.rb +3 -6
- data/lib/spec/expectations/diff.rb +23 -47
- data/lib/spec/expectations/differs/default.rb +62 -0
- data/lib/spec/expectations/{exceptions.rb → errors.rb} +0 -0
- data/lib/spec/expectations/extensions.rb +4 -0
- data/lib/spec/expectations/extensions/inspect_for_expectation_not_met_error.rb +14 -0
- data/lib/spec/expectations/extensions/numeric.rb +5 -0
- data/lib/spec/expectations/{expectations.rb → extensions/object.rb} +3 -6
- data/lib/spec/expectations/extensions/symbol.rb +5 -0
- data/lib/spec/expectations/should.rb +4 -0
- data/lib/spec/expectations/should/base.rb +42 -0
- data/lib/spec/expectations/should/have.rb +79 -0
- data/lib/spec/expectations/should/not.rb +72 -0
- data/lib/spec/expectations/should/should.rb +83 -0
- data/lib/spec/expectations/sugar.rb +6 -25
- data/lib/spec/mocks.rb +5 -1
- data/lib/spec/mocks/argument_expectation.rb +15 -1
- data/lib/spec/mocks/error_generator.rb +72 -0
- data/lib/spec/mocks/{exceptions.rb → errors.rb} +0 -0
- data/lib/spec/mocks/extensions/object.rb +3 -0
- data/lib/spec/mocks/message_expectation.rb +80 -73
- data/lib/spec/mocks/mock.rb +4 -69
- data/lib/spec/mocks/mock_handler.rb +158 -0
- data/lib/spec/mocks/mock_methods.rb +44 -0
- data/lib/spec/mocks/order_group.rb +10 -2
- data/lib/spec/rake/spectask.rb +20 -18
- data/lib/spec/rake/{rcov_verify.rb → verify_rcov.rb} +2 -2
- data/lib/spec/runner.rb +3 -1
- data/lib/spec/runner/backtrace_tweaker.rb +2 -1
- data/lib/spec/runner/context.rb +10 -16
- data/lib/spec/runner/context_eval.rb +40 -40
- data/lib/spec/runner/execution_context.rb +1 -12
- data/lib/spec/runner/{kernel_ext.rb → extensions/kernel.rb} +2 -2
- data/lib/spec/runner/{instance_exec.rb → extensions/object.rb} +0 -0
- data/lib/spec/runner/formatter/base_text_formatter.rb +25 -18
- data/lib/spec/runner/formatter/html_formatter.rb +81 -101
- data/lib/spec/runner/formatter/progress_bar_formatter.rb +9 -9
- data/lib/spec/runner/formatter/rdoc_formatter.rb +6 -6
- data/lib/spec/runner/formatter/specdoc_formatter.rb +7 -6
- data/lib/spec/runner/option_parser.rb +41 -5
- data/lib/spec/runner/reporter.rb +3 -15
- data/lib/spec/runner/spec_should_raise_handler.rb +74 -0
- data/lib/spec/runner/specification.rb +33 -14
- data/lib/spec/version.rb +6 -3
- data/vendor/watir/README.txt +1 -1
- metadata +34 -68
- data/bin/test2spec +0 -112
- data/examples/helper_method_spec.rb +0 -12
- data/lib/spec/expectations/have_helper.rb +0 -41
- data/lib/spec/expectations/helper.rb +0 -4
- data/lib/spec/expectations/should_base.rb +0 -52
- data/lib/spec/expectations/should_helper.rb +0 -93
- data/lib/spec/expectations/should_negator.rb +0 -71
- data/lib/spec/test_to_spec/ruby2ruby.rb +0 -492
- data/lib/spec/test_to_spec/sexp_transformer.rb +0 -196
- data/lib/spec/test_to_spec/test_case_ext.rb +0 -22
- data/lib/spec/test_to_spec/translation_test_runner.rb +0 -147
- data/test/spec/expectations/arbitrary_operator_test.rb +0 -55
- data/test/spec/expectations/arbitrary_predicate_test.rb +0 -163
- data/test/spec/expectations/containment_test.rb +0 -129
- data/test/spec/expectations/diff_test.rb +0 -62
- data/test/spec/expectations/identity_test.rb +0 -75
- data/test/spec/expectations/object_equality_test.rb +0 -65
- data/test/spec/expectations/raising_test.rb +0 -106
- data/test/spec/expectations/regex_matching_test.rb +0 -36
- data/test/spec/expectations/should_have_test.rb +0 -169
- data/test/spec/expectations/should_satisfy_test.rb +0 -37
- data/test/spec/expectations/sugar_test.rb +0 -93
- data/test/spec/expectations/supported_symbols_test.rb +0 -33
- data/test/spec/expectations/throwing_test.rb +0 -55
- data/test/spec/expectations/true_false_special_case_test.rb +0 -85
- data/test/spec/expectations/typing_test.rb +0 -108
- data/test/spec/mocks/mock_arg_constraints_test.rb +0 -113
- data/test/spec/mocks/mock_counts_test.rb +0 -431
- data/test/spec/mocks/mock_ordering_test.rb +0 -109
- data/test/spec/mocks/mock_test.rb +0 -220
- data/test/spec/mocks/null_object_test.rb +0 -37
- data/test/spec/runner/backtrace_tweaker_test.rb +0 -90
- data/test/spec/runner/context_matching_test.rb +0 -35
- data/test/spec/runner/context_runner_test.rb +0 -62
- data/test/spec/runner/context_test.rb +0 -191
- data/test/spec/runner/execution_context_test.rb +0 -45
- data/test/spec/runner/formatter/failure_dump_test.rb +0 -94
- data/test/spec/runner/formatter/html_formatter_test.rb +0 -48
- data/test/spec/runner/formatter/progress_bar_formatter_test.rb +0 -56
- data/test/spec/runner/formatter/rdoc_formatter_test.rb +0 -51
- data/test/spec/runner/formatter/specdoc_formatter_test.rb +0 -57
- data/test/spec/runner/kernel_ext_test.rb +0 -13
- data/test/spec/runner/option_parser_test.rb +0 -141
- data/test/spec/runner/reporter_test.rb +0 -128
- data/test/spec/runner/spec_matcher_test.rb +0 -47
- data/test/spec/runner/specification_test.rb +0 -121
- data/test/spec/test_to_spec/ruby_to_ruby_test.rb +0 -79
- data/test/spec/test_to_spec/sexp_transformer_assertion_test.rb +0 -207
- data/test/spec/test_to_spec/sexp_transformer_test.rb +0 -303
- data/test/spec/test_to_spec/test_case_ext_test.rb +0 -25
- data/test/spec/test_to_spec/testfiles/test_unit_api_spec.rb +0 -75
- data/test/spec/test_to_spec/testfiles/test_unit_api_test.rb +0 -70
- data/test/test_classes.rb +0 -102
- data/test/test_helper.rb +0 -32
data/bin/test2spec
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'test/unit/ui/console/testrunner'
|
5
|
-
require 'test/unit/ui/testrunnerutilities'
|
6
|
-
require 'test/unit/ui/testrunnermediator'
|
7
|
-
require 'test/unit/autorunner'
|
8
|
-
require 'optparse'
|
9
|
-
|
10
|
-
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
11
|
-
|
12
|
-
require 'rubygems'
|
13
|
-
require 'spec/test_to_spec/translation_test_runner'
|
14
|
-
require 'spec/version'
|
15
|
-
|
16
|
-
$test2spec_options = {
|
17
|
-
:collision => :ask,
|
18
|
-
:verbose => false
|
19
|
-
}
|
20
|
-
|
21
|
-
opts = OptionParser.new do |opts|
|
22
|
-
opts.banner = "Usage: test2spec [options] (FILE|DIRECTORY|GLOB)+"
|
23
|
-
opts.separator ""
|
24
|
-
|
25
|
-
opts.on("-s", "--specdir DIRECTORY", "Directory where specs will be written") do |dir|
|
26
|
-
$test2spec_options[:specdir] = dir
|
27
|
-
end
|
28
|
-
|
29
|
-
opts.on("-t", "--template FILE",
|
30
|
-
"ERB template that will be used to decorate each translated file.",
|
31
|
-
"The template has access to the following variables:",
|
32
|
-
" translation : the translated source code",
|
33
|
-
" depth : the directory depth of the file to be written",
|
34
|
-
" relative_path : the relative name of the file to be written"
|
35
|
-
) do |file|
|
36
|
-
$test2spec_options[:template] = file
|
37
|
-
end
|
38
|
-
|
39
|
-
opts.on("-c", "--chmod MODIFIERS", Integer, "Change file modifiers on written files (POSIX only)") do |mods|
|
40
|
-
$test2spec_options[:chmod] = mods
|
41
|
-
end
|
42
|
-
|
43
|
-
opts.on("--svn", "Add written files to subversion") do
|
44
|
-
$test2spec_options[:svn] = true
|
45
|
-
end
|
46
|
-
|
47
|
-
opts.on("-f", "--force", "Forcefully overwrite existing specs") do
|
48
|
-
$test2spec_options[:collision] = :force
|
49
|
-
end
|
50
|
-
|
51
|
-
opts.on("-q", "--quiet", "Don't print anything to stdout") do
|
52
|
-
$test2spec_options[:quiet] = true
|
53
|
-
end
|
54
|
-
|
55
|
-
opts.on("--verbose", "Be extra verbose (printing backtraces when classes can't be translated)") do
|
56
|
-
$test2spec_options[:verbose] = true
|
57
|
-
end
|
58
|
-
|
59
|
-
opts.on("-v", "--version", "Show version") do
|
60
|
-
puts "test2spec #{Spec::VERSION::DESCRIPTION}"
|
61
|
-
exit
|
62
|
-
end
|
63
|
-
|
64
|
-
opts.on("-d", "--dry-run", "Don't write anything - just verify that translation works") do
|
65
|
-
$test2spec_options[:dry_run] = true
|
66
|
-
end
|
67
|
-
|
68
|
-
opts.on_tail("-h", "--help", "You're looking at it") do
|
69
|
-
puts opts
|
70
|
-
exit
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
opts.parse! ARGV
|
75
|
-
|
76
|
-
if($test2spec_options[:specdir].nil?)
|
77
|
-
STDERR.puts "ERROR: --specdir must be specified"
|
78
|
-
puts opts
|
79
|
-
exit 1
|
80
|
-
end
|
81
|
-
|
82
|
-
if(ARGV.empty?)
|
83
|
-
STDERR.puts "ERROR: At least one directory, file or glob must be specified"
|
84
|
-
puts opts
|
85
|
-
exit 1
|
86
|
-
end
|
87
|
-
|
88
|
-
module Test
|
89
|
-
module Unit
|
90
|
-
class AutoRunner
|
91
|
-
def initialize(standalone)
|
92
|
-
@standalone = standalone
|
93
|
-
@runner = proc { |r| Spec::TestToSpec::TranslationTestRunner }
|
94
|
-
@collector = COLLECTORS[(standalone ? :dir : :objectspace)]
|
95
|
-
@filters = []
|
96
|
-
@to_run = []
|
97
|
-
yield(self) if(block_given?)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# If ARGV is a glob, it will actually each over each one of the matching files.
|
104
|
-
ARGV.each do |arg|
|
105
|
-
if File.directory?(arg)
|
106
|
-
Dir["#{arg}/**/*.rb"].each do |file|
|
107
|
-
require "#{file}"
|
108
|
-
end
|
109
|
-
else
|
110
|
-
require arg
|
111
|
-
end
|
112
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module Spec
|
2
|
-
module Expectations
|
3
|
-
class HaveHelper < ShouldBase
|
4
|
-
|
5
|
-
def initialize(target, relativity=:exactly, expected=nil)
|
6
|
-
@target = target
|
7
|
-
@expected = expected == :no ? 0 : expected
|
8
|
-
@at_least = (relativity == :at_least)
|
9
|
-
@at_most = (relativity == :at_most)
|
10
|
-
end
|
11
|
-
|
12
|
-
def method_missing(sym, *args)
|
13
|
-
fail_with_message(build_message(sym, args)) unless as_specified?(sym, args)
|
14
|
-
end
|
15
|
-
|
16
|
-
def collection(sym, args)
|
17
|
-
@target.send(sym, *args)
|
18
|
-
end
|
19
|
-
|
20
|
-
def actual_size(collection)
|
21
|
-
return collection.length if collection.respond_to? :length
|
22
|
-
return collection.size if collection.respond_to? :size
|
23
|
-
end
|
24
|
-
|
25
|
-
def build_message(sym, args)
|
26
|
-
message = "#{@target.inspect_for_expectation_not_met_error} should have"
|
27
|
-
message += " at least" if @at_least
|
28
|
-
message += " at most" if @at_most
|
29
|
-
message += " #{@expected} #{sym} (has #{actual_size(collection(sym, args))})"
|
30
|
-
end
|
31
|
-
|
32
|
-
def as_specified?(sym, args)
|
33
|
-
return actual_size(collection(sym, args)) >= @expected if @at_least
|
34
|
-
return actual_size(collection(sym, args)) <= @expected if @at_most
|
35
|
-
return actual_size(collection(sym, args)) == @expected
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
class Symbol
|
2
|
-
def supported_by_rspec?
|
3
|
-
return ["<","<=",">=",">","==","=~"].include?(to_s)
|
4
|
-
end
|
5
|
-
end
|
6
|
-
class Object
|
7
|
-
def inspect_for_expectation_not_met_error
|
8
|
-
return "#{inspect}" if inspect.include? "<"
|
9
|
-
return "<#{inspect}>" unless inspect.include? "<"
|
10
|
-
end
|
11
|
-
end
|
12
|
-
class TrueClass; def inspect_for_expectation_not_met_error; "true" end end
|
13
|
-
class FalseClass; def inspect_for_expectation_not_met_error; "false" end end
|
14
|
-
class NilClass; def inspect_for_expectation_not_met_error; "nil" end end
|
15
|
-
class Class; def inspect_for_expectation_not_met_error; "<#{name}>" end end
|
16
|
-
class Proc; def inspect_for_expectation_not_met_error; "<Proc>" end end
|
17
|
-
class Array; def inspect_for_expectation_not_met_error; inspect end end
|
18
|
-
class String; def inspect_for_expectation_not_met_error; inspect end end
|
19
|
-
class Numeric; def inspect_for_expectation_not_met_error; inspect end end
|
20
|
-
|
21
|
-
module Spec
|
22
|
-
module Expectations
|
23
|
-
class ShouldBase
|
24
|
-
|
25
|
-
instance_methods.each { |m| undef_method m unless m =~ /^(__|\w)/ }
|
26
|
-
|
27
|
-
def default_message(expectation, expected=:no_expectation_specified)
|
28
|
-
message = "#{@target.inspect_for_expectation_not_met_error} #{expectation}"
|
29
|
-
if (expected != :no_expectation_specified)
|
30
|
-
message << " " << expected.inspect_for_expectation_not_met_error
|
31
|
-
end
|
32
|
-
message
|
33
|
-
end
|
34
|
-
|
35
|
-
def fail_with_message(message)
|
36
|
-
Kernel::raise(Spec::Expectations::ExpectationNotMetError.new(message))
|
37
|
-
end
|
38
|
-
|
39
|
-
def respond_to? sym
|
40
|
-
return true if super
|
41
|
-
return true if @target.respond_to? "#{sym.to_s}?"
|
42
|
-
end
|
43
|
-
|
44
|
-
def find_supported_sym(original_sym)
|
45
|
-
["#{original_sym}?", "#{original_sym}s?"].each do |alternate_sym|
|
46
|
-
return alternate_sym.to_s if @target.respond_to?(alternate_sym.to_s)
|
47
|
-
end
|
48
|
-
return original_sym.supported_by_rspec? ? original_sym : "#{original_sym}?"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,93 +0,0 @@
|
|
1
|
-
module Spec
|
2
|
-
module Expectations
|
3
|
-
class ShouldHelper < ShouldBase
|
4
|
-
|
5
|
-
def initialize(target)
|
6
|
-
@target = target
|
7
|
-
@be_seen = false
|
8
|
-
end
|
9
|
-
|
10
|
-
def not
|
11
|
-
ShouldNegator.new(@target)
|
12
|
-
end
|
13
|
-
|
14
|
-
def have(expected_number=nil)
|
15
|
-
HaveHelper.new(@target, :exactly, expected_number)
|
16
|
-
end
|
17
|
-
|
18
|
-
def have_exactly(expected_number=nil)
|
19
|
-
HaveHelper.new(@target, :exactly, expected_number)
|
20
|
-
end
|
21
|
-
|
22
|
-
def have_at_least(expected_number=nil)
|
23
|
-
HaveHelper.new(@target, :at_least, expected_number)
|
24
|
-
end
|
25
|
-
|
26
|
-
def have_at_most(expected_number=nil)
|
27
|
-
HaveHelper.new(@target, :at_most, expected_number)
|
28
|
-
end
|
29
|
-
|
30
|
-
def satisfy(&block)
|
31
|
-
return if block.call(@target)
|
32
|
-
fail_with_message "Supplied expectation was not satisfied"
|
33
|
-
end
|
34
|
-
|
35
|
-
def equal(expected)
|
36
|
-
fail_with_message(default_message("should equal", expected)) unless (@target == expected)
|
37
|
-
end
|
38
|
-
|
39
|
-
def be(expected = :___no_arg)
|
40
|
-
@be_seen = true
|
41
|
-
return self if (expected == :___no_arg)
|
42
|
-
return if (expected == false and @target.nil?)
|
43
|
-
return if (expected == true and (!@target.nil?) and (@target != false))
|
44
|
-
fail_with_message(default_message("should be", expected)) unless (@target.equal?(expected))
|
45
|
-
end
|
46
|
-
|
47
|
-
def an_instance_of expected_class
|
48
|
-
fail_with_message(default_message("should be an instance of", expected_class)) unless @target.instance_of? expected_class
|
49
|
-
end
|
50
|
-
|
51
|
-
def a_kind_of expected_class
|
52
|
-
fail_with_message(default_message("should be a kind of", expected_class)) unless @target.kind_of? expected_class
|
53
|
-
end
|
54
|
-
|
55
|
-
def respond_to message
|
56
|
-
fail_with_message(default_message("should respond to", message)) unless @target.respond_to? message
|
57
|
-
end
|
58
|
-
|
59
|
-
def method_missing(original_sym, *args)
|
60
|
-
actual_sym = find_supported_sym(original_sym)
|
61
|
-
return if @target.send(actual_sym, *args)
|
62
|
-
fail_with_message(default_message("should#{@be_seen ? ' be' : ''} #{original_sym}" + (args.empty? ? '' : (' ' + args.join(', ')))))
|
63
|
-
end
|
64
|
-
|
65
|
-
def match(expected)
|
66
|
-
fail_with_message(default_message("should match", expected)) unless (@target =~ expected)
|
67
|
-
end
|
68
|
-
|
69
|
-
def raise(exception=Exception, message=nil)
|
70
|
-
begin
|
71
|
-
@target.call
|
72
|
-
rescue exception => e
|
73
|
-
e.message.should_equal message unless message.nil?
|
74
|
-
return
|
75
|
-
rescue => e
|
76
|
-
fail_with_message("#{default_message("should raise", exception)} but raised #{e.inspect}")
|
77
|
-
end
|
78
|
-
fail_with_message("#{default_message("should raise", exception)} but raised nothing")
|
79
|
-
end
|
80
|
-
|
81
|
-
def throw(symbol)
|
82
|
-
begin
|
83
|
-
catch symbol do
|
84
|
-
@target.call
|
85
|
-
fail_with_message(default_message("should throw", symbol.inspect))
|
86
|
-
end
|
87
|
-
rescue NameError
|
88
|
-
fail_with_message(default_message("should throw", symbol.inspect))
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
module Spec
|
2
|
-
module Expectations
|
3
|
-
class ShouldNegator < ShouldBase
|
4
|
-
|
5
|
-
def initialize(target)
|
6
|
-
@target = target
|
7
|
-
@be_seen = false
|
8
|
-
end
|
9
|
-
|
10
|
-
def satisfy
|
11
|
-
fail_with_message "Supplied expectation was satisfied, but should not have been" if (yield @target)
|
12
|
-
end
|
13
|
-
|
14
|
-
def equal(expected)
|
15
|
-
fail_with_message(default_message("should not equal", expected)) if (@target == expected)
|
16
|
-
end
|
17
|
-
|
18
|
-
def be(expected = :no_arg)
|
19
|
-
@be_seen = true
|
20
|
-
return self if (expected == :no_arg)
|
21
|
-
fail_with_message(default_message("should not be", expected)) if (@target.equal?(expected))
|
22
|
-
end
|
23
|
-
|
24
|
-
def an_instance_of expected_class
|
25
|
-
fail_with_message(default_message("should not be an instance of", expected_class)) if @target.instance_of? expected_class
|
26
|
-
end
|
27
|
-
|
28
|
-
def a_kind_of expected_class
|
29
|
-
fail_with_message(default_message("should not be a kind of", expected_class)) if @target.kind_of? expected_class
|
30
|
-
end
|
31
|
-
|
32
|
-
def respond_to message
|
33
|
-
fail_with_message(default_message("should not respond to", message)) if @target.respond_to? message
|
34
|
-
end
|
35
|
-
|
36
|
-
def match(expected)
|
37
|
-
fail_with_message(default_message("should not match", expected)) if (@target =~ expected)
|
38
|
-
end
|
39
|
-
|
40
|
-
def raise(exception=Exception, message=nil)
|
41
|
-
begin
|
42
|
-
@target.call
|
43
|
-
rescue exception => e
|
44
|
-
return unless message.nil? || e.message == message
|
45
|
-
fail_with_message("#{default_message("should not raise", exception)}") if e.instance_of? exception
|
46
|
-
fail_with_message("#{default_message("should not raise", exception)} but raised #{e.inspect}") unless e.instance_of? exception
|
47
|
-
rescue
|
48
|
-
true
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def throw(symbol=:___this_is_a_symbol_that_will_likely_never_occur___)
|
53
|
-
begin
|
54
|
-
catch symbol do
|
55
|
-
@target.call
|
56
|
-
return true
|
57
|
-
end
|
58
|
-
fail_with_message(default_message("should not throw", symbol.inspect))
|
59
|
-
rescue NameError
|
60
|
-
true
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def method_missing(original_sym, *args)
|
65
|
-
actual_sym = find_supported_sym(original_sym)
|
66
|
-
return unless @target.__send__(actual_sym, *args)
|
67
|
-
fail_with_message(default_message("should not#{@be_seen ? ' be' : ''} #{original_sym}" + (args.empty? ? '' : (' ' + args.join(', ')))))
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,492 +0,0 @@
|
|
1
|
-
# Taken from http://dark.fhtr.org/ruby2ruby.rb
|
2
|
-
|
3
|
-
require 'pp'
|
4
|
-
require 'rubygems'
|
5
|
-
begin
|
6
|
-
require 'parse_tree'
|
7
|
-
require 'sexp_processor'
|
8
|
-
rescue LoadError
|
9
|
-
raise "You must gem install ParseTree (and RubyInline)"
|
10
|
-
end
|
11
|
-
|
12
|
-
class RubySource < String
|
13
|
-
|
14
|
-
def inspect
|
15
|
-
"\n"+to_s
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
class Object
|
22
|
-
|
23
|
-
def parse_tree(method_name=nil)
|
24
|
-
if method_name
|
25
|
-
m = method(method_name)
|
26
|
-
klass = m.defined_in
|
27
|
-
method_name = m.name
|
28
|
-
return ParseTree.new.parse_tree_for_method(klass, method_name)
|
29
|
-
elsif is_a?(Class)
|
30
|
-
klass = self
|
31
|
-
else
|
32
|
-
klass = self.class
|
33
|
-
end
|
34
|
-
ParseTree.new.parse_tree(klass).first
|
35
|
-
end
|
36
|
-
|
37
|
-
def source(method_name=nil)
|
38
|
-
RubySource.new RubyToRuby.new.process(parse_tree(method_name))
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
class Method
|
45
|
-
|
46
|
-
def defined_in
|
47
|
-
full_name = to_s.split(" ").last.chop
|
48
|
-
klass_name = full_name.split(/[\#\.]/).first
|
49
|
-
if klass_name.include?("(")
|
50
|
-
klass_name = klass_name.split("(").last.chop
|
51
|
-
end
|
52
|
-
klass = klass_name.split("::").inject(Object){|o,n| o.const_get(n)}
|
53
|
-
klass
|
54
|
-
end
|
55
|
-
|
56
|
-
def name
|
57
|
-
full_name = to_s.split(" ").last.chop
|
58
|
-
full_name.split(/[\#\.]/).last
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
class RubyToRuby < SexpProcessor
|
64
|
-
|
65
|
-
def self.translate(klass, method=nil)
|
66
|
-
RubySource.new(
|
67
|
-
unless method.nil? then
|
68
|
-
self.new.process(ParseTree.new.parse_tree_for_method(klass, method))
|
69
|
-
else
|
70
|
-
self.new.process(ParseTree.new.parse_tree(klass).first) # huh? why is the :class node wrapped?
|
71
|
-
end
|
72
|
-
)
|
73
|
-
end
|
74
|
-
|
75
|
-
def initialize
|
76
|
-
super
|
77
|
-
@block_params = false
|
78
|
-
@indent = " "
|
79
|
-
self.auto_shift_type = true
|
80
|
-
self.strict = true
|
81
|
-
self.expected = String
|
82
|
-
end
|
83
|
-
|
84
|
-
def indent(s)
|
85
|
-
s.to_s.map{|line| @indent + line}.join
|
86
|
-
end
|
87
|
-
|
88
|
-
def process_and(exp)
|
89
|
-
"(#{process exp.shift} and #{process exp.shift})"
|
90
|
-
end
|
91
|
-
|
92
|
-
def process_args(exp)
|
93
|
-
args = []
|
94
|
-
|
95
|
-
until exp.empty? do
|
96
|
-
arg = exp.shift
|
97
|
-
if arg.is_a? Array
|
98
|
-
args[-(arg.size-1)..-1] = arg[1..-1].map{|a| process a}
|
99
|
-
else
|
100
|
-
args << arg
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
args.empty? ? "" : "(#{args.join ', '})"
|
105
|
-
end
|
106
|
-
|
107
|
-
def process_array(exp)
|
108
|
-
code = []
|
109
|
-
until exp.empty? do
|
110
|
-
code << process(exp.shift)
|
111
|
-
end
|
112
|
-
return "[" + code.join(", ") + "]"
|
113
|
-
end
|
114
|
-
|
115
|
-
def process_attrasgn(exp)
|
116
|
-
process_call(exp)
|
117
|
-
end
|
118
|
-
|
119
|
-
def process_begin(exp)
|
120
|
-
s = "begin\n"
|
121
|
-
s << (process(exp.shift).to_s + "\n") until exp.empty?
|
122
|
-
s + "\nend"
|
123
|
-
end
|
124
|
-
|
125
|
-
def process_block(exp)
|
126
|
-
code = []
|
127
|
-
catch_block_arg = false
|
128
|
-
until exp.empty? do
|
129
|
-
if catch_block_arg
|
130
|
-
if exp.first and exp.first.first == :block_arg
|
131
|
-
code[-1] = code[-1][0..-2] + ", #{process(exp.shift)})"
|
132
|
-
end
|
133
|
-
catch_block_arg = false
|
134
|
-
else
|
135
|
-
if exp.first.first == :args
|
136
|
-
catch_block_arg = true
|
137
|
-
end
|
138
|
-
if [:ensure, :rescue].include? exp.first.first
|
139
|
-
code << process(exp.shift)
|
140
|
-
else
|
141
|
-
code << indent(process(exp.shift))
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
body = code.join("\n")
|
147
|
-
body += "\n"
|
148
|
-
|
149
|
-
return body
|
150
|
-
end
|
151
|
-
|
152
|
-
def process_block_arg(exp)
|
153
|
-
"&#{exp.shift}"
|
154
|
-
end
|
155
|
-
|
156
|
-
def process_block_pass(exp)
|
157
|
-
bname = process(exp.shift)
|
158
|
-
fcall = process(exp.shift)
|
159
|
-
if fcall[-1,1] == ')'
|
160
|
-
"#{fcall[0..-2]}, &(#{bname}))"
|
161
|
-
else
|
162
|
-
"#{fcall}(&(#{bname}))"
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
def process_call(exp)
|
167
|
-
receiver = process exp.shift
|
168
|
-
name = exp.shift
|
169
|
-
args_exp = exp.shift
|
170
|
-
if args_exp && args_exp.first == :array
|
171
|
-
args = "#{process(args_exp)[1..-2]}"
|
172
|
-
else
|
173
|
-
args = process args_exp
|
174
|
-
end
|
175
|
-
|
176
|
-
case name
|
177
|
-
when :<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :% then #
|
178
|
-
"(#{receiver} #{name} #{args})"
|
179
|
-
when :[] then
|
180
|
-
"#{receiver}[#{args}]"
|
181
|
-
else
|
182
|
-
"#{receiver}.#{name}#{args ? "(#{args})" : args}"
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
def process_case(exp)
|
187
|
-
s = "case #{process exp.shift}\n"
|
188
|
-
until exp.empty?
|
189
|
-
pt = exp.shift
|
190
|
-
if pt and pt.first == :when
|
191
|
-
s << "#{process(pt)}\n"
|
192
|
-
else
|
193
|
-
s << "else\n#{indent(process(pt))}\n"
|
194
|
-
end
|
195
|
-
end
|
196
|
-
s + "\nend"
|
197
|
-
end
|
198
|
-
|
199
|
-
def process_class(exp)
|
200
|
-
s = "class #{exp.shift} < #{exp.shift}\n"
|
201
|
-
body = ""
|
202
|
-
body << "#{process exp.shift}\n\n" until exp.empty?
|
203
|
-
s + indent(body) + "end"
|
204
|
-
end
|
205
|
-
|
206
|
-
def process_colon2(exp)
|
207
|
-
"#{process(exp.shift)}::#{exp.shift}"
|
208
|
-
end
|
209
|
-
|
210
|
-
def process_const(exp)
|
211
|
-
exp.shift.to_s
|
212
|
-
end
|
213
|
-
|
214
|
-
def process_dasgn_curr(exp)
|
215
|
-
s = exp.shift.to_s
|
216
|
-
unless exp.empty?
|
217
|
-
s += "=" + process(exp.shift)
|
218
|
-
else
|
219
|
-
if(@block_params)
|
220
|
-
s
|
221
|
-
else
|
222
|
-
""
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def process_defn(exp)
|
228
|
-
if exp[1].first == :cfunc
|
229
|
-
s = "# method '#{exp.shift}' defined in a C function"
|
230
|
-
exp.shift
|
231
|
-
return s
|
232
|
-
else
|
233
|
-
name = exp.shift
|
234
|
-
args = process(exp.shift)
|
235
|
-
return "def #{name}#{args}end".gsub(/\n\s*\n+/, "\n")
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
def process_dot2(exp)
|
240
|
-
"(#{process exp.shift}..#{process exp.shift})"
|
241
|
-
end
|
242
|
-
|
243
|
-
def process_dot3(exp)
|
244
|
-
"(#{process exp.shift}...#{process exp.shift})"
|
245
|
-
end
|
246
|
-
|
247
|
-
def process_dstr(exp)
|
248
|
-
s = exp.shift.dump[0..-2]
|
249
|
-
until exp.empty?
|
250
|
-
pt = exp.shift
|
251
|
-
if pt.first == :str
|
252
|
-
s << process(pt)[1..-2]
|
253
|
-
else
|
254
|
-
s << '#{' + process(pt) + '}'
|
255
|
-
end
|
256
|
-
end
|
257
|
-
s + '"'
|
258
|
-
end
|
259
|
-
|
260
|
-
def process_dvar(exp)
|
261
|
-
exp.shift.to_s
|
262
|
-
end
|
263
|
-
|
264
|
-
def process_ensure(exp)
|
265
|
-
process(exp.shift) + "\n" +
|
266
|
-
"ensure\n" +
|
267
|
-
indent(process(exp.shift))
|
268
|
-
end
|
269
|
-
|
270
|
-
def process_false(exp)
|
271
|
-
"false"
|
272
|
-
end
|
273
|
-
|
274
|
-
def process_fbody(exp)
|
275
|
-
process(exp.shift)
|
276
|
-
end
|
277
|
-
|
278
|
-
def process_fcall(exp)
|
279
|
-
exp_orig = exp.deep_clone
|
280
|
-
# [:fcall, :puts, [:array, [:str, "This is a weird loop"]]]
|
281
|
-
name = exp.shift.to_s
|
282
|
-
args = exp.shift
|
283
|
-
code = []
|
284
|
-
unless args.nil? then
|
285
|
-
assert_type args, :array
|
286
|
-
args.shift # :array
|
287
|
-
until args.empty? do
|
288
|
-
code << process(args.shift)
|
289
|
-
end
|
290
|
-
end
|
291
|
-
return "#{name}(#{code.join(', ')})"
|
292
|
-
end
|
293
|
-
|
294
|
-
def process_for(exp)
|
295
|
-
s = "for #{process(exp[1])} in #{process(exp[0])}\n"
|
296
|
-
2.times{ exp.shift }
|
297
|
-
s += indent("#{process(exp.shift)}\n")
|
298
|
-
s += "end"
|
299
|
-
end
|
300
|
-
|
301
|
-
def process_gvar(exp)
|
302
|
-
exp.shift.to_s
|
303
|
-
end
|
304
|
-
|
305
|
-
def process_hash(exp)
|
306
|
-
body = []
|
307
|
-
body << "#{process(exp.shift)} => #{process(exp.shift)}" until exp.empty?
|
308
|
-
body_str = ""
|
309
|
-
body_str = "\n"+indent(body.join(",\n"))+"\n" unless body.empty?
|
310
|
-
"{" + body_str + "}"
|
311
|
-
end
|
312
|
-
|
313
|
-
def process_iasgn(exp)
|
314
|
-
"#{exp.shift} = #{process exp.shift}"
|
315
|
-
end
|
316
|
-
|
317
|
-
def cond_indent_process(pt)
|
318
|
-
(pt and pt.first == :block) ? process(pt) : indent(process(pt))
|
319
|
-
end
|
320
|
-
|
321
|
-
def process_if(exp)
|
322
|
-
s = ["if (#{process exp.shift})"]
|
323
|
-
s << "#{cond_indent_process(exp.shift)}"
|
324
|
-
s << "else\n#{cond_indent_process(exp.shift)}" until exp.empty?
|
325
|
-
s << "end"
|
326
|
-
s.join("\n")
|
327
|
-
end
|
328
|
-
|
329
|
-
def process_iter(exp)
|
330
|
-
owner = exp.shift
|
331
|
-
args = exp.shift
|
332
|
-
if !args.nil?
|
333
|
-
@block_params = true
|
334
|
-
end
|
335
|
-
processed_args = process args
|
336
|
-
block_args = processed_args.nil? ? "" : "|#{processed_args}|"
|
337
|
-
|
338
|
-
result = "#{process owner} {#{block_args}\n" +
|
339
|
-
indent("#{process exp.shift}\n") +
|
340
|
-
"}"
|
341
|
-
@block_params = false
|
342
|
-
result
|
343
|
-
end
|
344
|
-
|
345
|
-
def process_ivar(exp)
|
346
|
-
exp.shift.to_s
|
347
|
-
end
|
348
|
-
|
349
|
-
def process_lasgn(exp)
|
350
|
-
s = "#{exp.shift}"
|
351
|
-
s += " = #{process exp.shift}" unless exp.empty?
|
352
|
-
s
|
353
|
-
end
|
354
|
-
|
355
|
-
def process_lit(exp)
|
356
|
-
obj = exp.shift
|
357
|
-
if obj.is_a? Range # to get around how parsed ranges turn into lits and lose parens
|
358
|
-
"(" + obj.inspect + ")"
|
359
|
-
else
|
360
|
-
obj.inspect
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
|
-
def process_lvar(exp)
|
365
|
-
exp.shift.to_s
|
366
|
-
end
|
367
|
-
|
368
|
-
def process_masgn(exp)
|
369
|
-
process(exp.shift)[1..-2]
|
370
|
-
end
|
371
|
-
|
372
|
-
def process_module(exp)
|
373
|
-
s = "module #{exp.shift}\n"
|
374
|
-
body = ""
|
375
|
-
body << "#{process exp.shift}\n\n" until exp.empty?
|
376
|
-
s + indent(body) + "end"
|
377
|
-
end
|
378
|
-
|
379
|
-
def process_nil(exp)
|
380
|
-
"nil"
|
381
|
-
end
|
382
|
-
|
383
|
-
def process_not(exp)
|
384
|
-
"(not #{process exp.shift})"
|
385
|
-
end
|
386
|
-
|
387
|
-
def process_or(exp)
|
388
|
-
"(#{process exp.shift} or #{process exp.shift})"
|
389
|
-
end
|
390
|
-
|
391
|
-
def process_resbody(exp)
|
392
|
-
s = "rescue "
|
393
|
-
unless exp.empty?
|
394
|
-
if exp.first.first == :array
|
395
|
-
s << process(exp.shift)[1..-2]
|
396
|
-
end
|
397
|
-
s << "\n"
|
398
|
-
end
|
399
|
-
s << (process(exp.shift).to_s + "\n") until exp.empty?
|
400
|
-
s
|
401
|
-
end
|
402
|
-
|
403
|
-
def process_rescue(exp)
|
404
|
-
s = ""
|
405
|
-
s << (process(exp.shift).to_s + "\n") until exp.empty?
|
406
|
-
s
|
407
|
-
end
|
408
|
-
|
409
|
-
def process_retry(exp)
|
410
|
-
"retry"
|
411
|
-
end
|
412
|
-
|
413
|
-
def process_return(exp)
|
414
|
-
return "return #{process exp.shift}"
|
415
|
-
end
|
416
|
-
|
417
|
-
def process_scope(exp)
|
418
|
-
return process(exp.shift)
|
419
|
-
end
|
420
|
-
|
421
|
-
def process_self(exp)
|
422
|
-
"self"
|
423
|
-
end
|
424
|
-
def process_str(exp)
|
425
|
-
return exp.shift.dump
|
426
|
-
end
|
427
|
-
|
428
|
-
def process_super(exp)
|
429
|
-
"super(#{process(exp.shift)})"
|
430
|
-
end
|
431
|
-
|
432
|
-
def process_true(exp)
|
433
|
-
"true"
|
434
|
-
end
|
435
|
-
|
436
|
-
def process_until(exp)
|
437
|
-
cond_loop(exp, 'until')
|
438
|
-
end
|
439
|
-
|
440
|
-
def process_vcall(exp)
|
441
|
-
return exp.shift.to_s
|
442
|
-
end
|
443
|
-
|
444
|
-
def process_when(exp)
|
445
|
-
"when #{process(exp.shift).to_s[1..-2]}\n#{indent(process(exp.shift))}"
|
446
|
-
end
|
447
|
-
|
448
|
-
def process_while(exp)
|
449
|
-
cond_loop(exp, 'while')
|
450
|
-
end
|
451
|
-
|
452
|
-
def process_yield(exp)
|
453
|
-
body = process(exp.shift)[1..-2] unless exp.empty?
|
454
|
-
"yield#{body and "(#{body})"}"
|
455
|
-
end
|
456
|
-
|
457
|
-
def process_zarray(exp)
|
458
|
-
"[]"
|
459
|
-
end
|
460
|
-
|
461
|
-
def process_zsuper(exp)
|
462
|
-
"super"
|
463
|
-
end
|
464
|
-
|
465
|
-
# def process_dxstr(exp)
|
466
|
-
# puts "DXSTR:#{exp.shift}"
|
467
|
-
# end
|
468
|
-
|
469
|
-
def cond_loop(exp, name)
|
470
|
-
cond = process(exp.shift)
|
471
|
-
body = cond_indent_process(exp.shift)
|
472
|
-
head_controlled = exp.empty? ? false : exp.shift
|
473
|
-
|
474
|
-
code = []
|
475
|
-
if head_controlled then
|
476
|
-
code << "#{name} (#{cond}) do"
|
477
|
-
code << body
|
478
|
-
code << "end"
|
479
|
-
else
|
480
|
-
code << "begin"
|
481
|
-
code << body
|
482
|
-
code << "end #{name} (#{cond})"
|
483
|
-
end
|
484
|
-
code.join("\n")
|
485
|
-
end
|
486
|
-
|
487
|
-
def process_bmethod(exp)
|
488
|
-
exp.clear
|
489
|
-
""
|
490
|
-
end
|
491
|
-
|
492
|
-
end
|