ruby2ruby 1.1.3 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +13 -0
- data/Rakefile +5 -0
- data/lib/ruby2ruby.rb +107 -74
- data/test/test_ruby2ruby.rb +43 -1
- metadata +9 -9
data/History.txt
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
== 1.1.4 / 2007-01-15
|
2
|
+
|
3
|
+
* 4 minor enhancements:
|
4
|
+
* Added some extra rewriting code and tests for various bmethods. Ugh.
|
5
|
+
* Added support for splatted block args.
|
6
|
+
* Refactored class/module and dsym/dstr.
|
7
|
+
* Short if/unless statements are now post-conditional expressions.
|
8
|
+
* 4 bug fixes:
|
9
|
+
* Finally fixed eric's nebulous proc code-in-goalposts bug.
|
10
|
+
* Fixed dasgn_curr so block's dasgn vars decl goes away (bug 7420).
|
11
|
+
* Fixed dmethod. I think the tests were bogus before.
|
12
|
+
* Fixed improper end in method rescues (bug 7396).
|
13
|
+
|
1
14
|
== 1.1.3 / 2006-12-20
|
2
15
|
|
3
16
|
* 1 minor enhancement
|
data/Rakefile
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
|
3
|
+
dirs = %w(../../ParseTree/dev/lib ../../ParseTree/dev/test:lib)
|
4
|
+
$:.push(*dirs)
|
5
|
+
ENV['RUBY_FLAGS'] = "-I" + dirs.join(":")
|
6
|
+
|
3
7
|
require 'rubygems'
|
4
8
|
require 'hoe'
|
5
9
|
require './lib/ruby2ruby.rb'
|
@@ -10,6 +14,7 @@ Hoe.new('ruby2ruby', RubyToRuby::VERSION) do |p|
|
|
10
14
|
p.description = p.paragraphs_of('README.txt', 2).join
|
11
15
|
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1].map {|u| u.strip }
|
12
16
|
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
17
|
+
p.clean_globs << File.expand_path("~/.ruby_inline")
|
13
18
|
p.extra_deps << "ParseTree"
|
14
19
|
end
|
15
20
|
|
data/lib/ruby2ruby.rb
CHANGED
@@ -11,7 +11,7 @@ class NilClass # Objective-C trick
|
|
11
11
|
end
|
12
12
|
|
13
13
|
class RubyToRuby < SexpProcessor
|
14
|
-
VERSION = '1.1.
|
14
|
+
VERSION = '1.1.4'
|
15
15
|
|
16
16
|
def self.translate(klass_or_str, method = nil)
|
17
17
|
self.new.process(ParseTree.translate(klass_or_str, method))
|
@@ -148,18 +148,11 @@ class RubyToRuby < SexpProcessor
|
|
148
148
|
result = []
|
149
149
|
|
150
150
|
until exp.empty? do
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
raise "wtf"
|
155
|
-
result[-1] = result[-1][0..-2] + ", #{process(exp.shift)})"
|
151
|
+
code = exp.shift
|
152
|
+
if code.nil? or code.first == :nil then
|
153
|
+
result << "# do nothing"
|
156
154
|
else
|
157
|
-
|
158
|
-
if code.nil? or code.first == :nil then
|
159
|
-
result << "# do nothing"
|
160
|
-
else
|
161
|
-
result << process(code)
|
162
|
-
end
|
155
|
+
result << process(code)
|
163
156
|
end
|
164
157
|
end
|
165
158
|
|
@@ -236,23 +229,7 @@ class RubyToRuby < SexpProcessor
|
|
236
229
|
end
|
237
230
|
|
238
231
|
def process_class(exp)
|
239
|
-
|
240
|
-
superk = process(exp.shift)
|
241
|
-
|
242
|
-
s << " < #{superk}" if superk
|
243
|
-
s << "\n"
|
244
|
-
|
245
|
-
body = []
|
246
|
-
begin
|
247
|
-
code = process(exp.shift).chomp
|
248
|
-
body << code unless code.nil? or code.empty?
|
249
|
-
end until exp.empty?
|
250
|
-
unless body.empty? then
|
251
|
-
body = indent(body.join("\n\n")) + "\n"
|
252
|
-
else
|
253
|
-
body = ""
|
254
|
-
end
|
255
|
-
s + body + "end"
|
232
|
+
"class #{util_module_or_class(exp, true)}"
|
256
233
|
end
|
257
234
|
|
258
235
|
def process_colon2(exp)
|
@@ -279,10 +256,23 @@ class RubyToRuby < SexpProcessor
|
|
279
256
|
"#{exp.shift} = #{process(exp.shift)}"
|
280
257
|
end
|
281
258
|
|
259
|
+
# (a, lit1) => "a = 1"
|
260
|
+
# (a, (b, lit2)) => "a = b = 2"
|
261
|
+
# (a, (b)) => ""
|
262
|
+
|
282
263
|
def process_dasgn_curr(exp)
|
283
|
-
|
284
|
-
|
285
|
-
|
264
|
+
lhs = exp.shift.to_s
|
265
|
+
rhs = exp.shift
|
266
|
+
return lhs if rhs.nil?
|
267
|
+
return "#{lhs} = #{process rhs}" unless rhs.first == :dasgn_curr
|
268
|
+
|
269
|
+
# keep recursing. ensure that the leaf node assigns to _something_
|
270
|
+
rhs = process rhs
|
271
|
+
if rhs =~ /=/ then
|
272
|
+
"#{lhs} = #{rhs}"
|
273
|
+
else
|
274
|
+
""
|
275
|
+
end
|
286
276
|
end
|
287
277
|
|
288
278
|
def process_dasgn(exp)
|
@@ -374,16 +364,7 @@ class RubyToRuby < SexpProcessor
|
|
374
364
|
end
|
375
365
|
|
376
366
|
def process_dsym(exp)
|
377
|
-
|
378
|
-
until exp.empty?
|
379
|
-
pt = exp.shift
|
380
|
-
if pt.first == :str
|
381
|
-
s << process(pt)[1..-2]
|
382
|
-
else
|
383
|
-
s << '#{' + process(pt) + '}'
|
384
|
-
end
|
385
|
-
end
|
386
|
-
s + '"'
|
367
|
+
":" + process_dstr(exp)
|
387
368
|
end
|
388
369
|
|
389
370
|
def process_dvar(exp)
|
@@ -466,11 +447,17 @@ class RubyToRuby < SexpProcessor
|
|
466
447
|
f = process exp.shift
|
467
448
|
|
468
449
|
if t then
|
450
|
+
unless f then
|
451
|
+
r = "#{t} if #{c}"
|
452
|
+
return r if (@indent+r).size < 78 and r !~ /\n/
|
453
|
+
end
|
469
454
|
r = "if #{c} then\n#{indent(t)}\n"
|
470
455
|
r << "else\n#{indent(f)}\n" if f
|
471
456
|
r << "end"
|
472
457
|
r
|
473
458
|
else
|
459
|
+
r = "#{f} unless #{c}"
|
460
|
+
return r if (@indent+r).size < 78 and r !~ /\n/
|
474
461
|
"unless #{c} then\n#{indent(f)}\nend"
|
475
462
|
end
|
476
463
|
end
|
@@ -493,7 +480,7 @@ class RubyToRuby < SexpProcessor
|
|
493
480
|
result << " |#{args}|" if args
|
494
481
|
if body then
|
495
482
|
result << "\n"
|
496
|
-
result << indent(body)
|
483
|
+
result << indent(body.strip)
|
497
484
|
result << "\n"
|
498
485
|
else
|
499
486
|
result << ' '
|
@@ -561,18 +548,7 @@ class RubyToRuby < SexpProcessor
|
|
561
548
|
end
|
562
549
|
|
563
550
|
def process_module(exp)
|
564
|
-
|
565
|
-
body = []
|
566
|
-
begin
|
567
|
-
code = process exp.shift
|
568
|
-
body << code unless code.nil? or code.empty?
|
569
|
-
end until exp.empty?
|
570
|
-
unless body.empty? then
|
571
|
-
body = indent(body.join("\n\n")) + "\n"
|
572
|
-
else
|
573
|
-
body = ""
|
574
|
-
end
|
575
|
-
s + body + "end"
|
551
|
+
"module #{util_module_or_class(exp)}"
|
576
552
|
end
|
577
553
|
|
578
554
|
def process_next(exp)
|
@@ -697,7 +673,7 @@ class RubyToRuby < SexpProcessor
|
|
697
673
|
code << "else"
|
698
674
|
code << indent(els)
|
699
675
|
else
|
700
|
-
code << "end\n"
|
676
|
+
code << "end\n" unless stack.first == "process_block"
|
701
677
|
end
|
702
678
|
code.join("\n")
|
703
679
|
else # a rescue b and others
|
@@ -845,6 +821,12 @@ class RubyToRuby < SexpProcessor
|
|
845
821
|
rewrite_defn(exp)
|
846
822
|
end
|
847
823
|
|
824
|
+
# s(:defn, :name, s(:scope, s(:block, s(:args, ...), ...)))
|
825
|
+
# s(:defn, :name, s(:bmethod, s(:masgn, s(:dasgn_curr, :args)), s(:block, ...)))
|
826
|
+
# s(:defn, :name, s(:fbody, s(:bmethod, s(:masgn, s(:dasgn_curr, :params)), s(:block, ...))))
|
827
|
+
# =>
|
828
|
+
# s(:defn, :name, s(:args, ...), s(:scope, s:(block, ...)))
|
829
|
+
|
848
830
|
def rewrite_defn(exp)
|
849
831
|
# REFACTOR this needs help now
|
850
832
|
exp.shift # :defn
|
@@ -861,18 +843,38 @@ class RubyToRuby < SexpProcessor
|
|
861
843
|
assert_type body[1], :block
|
862
844
|
when :scope, :fbody then
|
863
845
|
body = body[1] if body.first == :fbody
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
846
|
+
case body.first
|
847
|
+
when :scope then
|
848
|
+
args = body.block.args(true)
|
849
|
+
assert_type body, :scope
|
850
|
+
assert_type body[1], :block
|
851
|
+
|
852
|
+
if body[1][1].first == :block_arg then
|
853
|
+
block_arg = body[1].delete_at 1
|
854
|
+
args << block_arg
|
855
|
+
end
|
856
|
+
when :bmethod then
|
857
|
+
body[0] = :scope
|
858
|
+
body.block.delete_at(1) # nuke the decl # REFACTOR
|
859
|
+
masgn = body.masgn(true)
|
860
|
+
if masgn then
|
861
|
+
splat = :"*#{masgn[-1][-1]}"
|
862
|
+
args.push(splat)
|
863
|
+
else
|
864
|
+
dasgn_curr = body.dasgn_curr(true)
|
865
|
+
if dasgn_curr then
|
866
|
+
arg = :"*#{dasgn_curr[-1]}"
|
867
|
+
args.push(arg)
|
868
|
+
end
|
869
|
+
end
|
870
|
+
body.find_and_replace_all(:dvar, :lvar)
|
871
|
+
else
|
872
|
+
raise "no: #{body.first} / #{body.inspect}"
|
872
873
|
end
|
873
874
|
when :bmethod then
|
874
875
|
body.shift # :bmethod
|
875
|
-
|
876
|
+
case body.first.first
|
877
|
+
when :dasgn_curr then
|
876
878
|
# WARN: there are some implications here of having an empty
|
877
879
|
# :args below namely, "proc { || " does not allow extra args
|
878
880
|
# passed in.
|
@@ -881,7 +883,15 @@ class RubyToRuby < SexpProcessor
|
|
881
883
|
dasgn.shift # type
|
882
884
|
args.push(*dasgn)
|
883
885
|
body.find_and_replace_all(:dvar, :lvar)
|
886
|
+
when :masgn then
|
887
|
+
dasgn = body.masgn(true)
|
888
|
+
# DAMNIT body.block.dasgn_curr(true) - multiple values so can't use
|
889
|
+
body.block.delete_at(1) # nuke the decl
|
890
|
+
splat = :"*#{dasgn[-1][-1]}"
|
891
|
+
args.push(splat)
|
892
|
+
body.find_and_replace_all(:dvar, :lvar)
|
884
893
|
end
|
894
|
+
|
885
895
|
if body.first.first == :block then
|
886
896
|
body = s(:scope, body.shift)
|
887
897
|
else
|
@@ -890,12 +900,9 @@ class RubyToRuby < SexpProcessor
|
|
890
900
|
when :dmethod
|
891
901
|
# BEFORE: [:defn, :dmethod_added, [:dmethod, :bmethod_maker, ...]]
|
892
902
|
# AFTER: [:defn, :dmethod_added, ...]
|
893
|
-
|
894
|
-
|
895
|
-
args =
|
896
|
-
iter.delete_at 1 # args
|
897
|
-
iter[0] = :block
|
898
|
-
body = s(:scope, iter.find_and_replace_all(:dvar, :lvar))
|
903
|
+
body[0] = :scope
|
904
|
+
body.delete_at 1 # method name
|
905
|
+
args = body.scope.block.args(true)
|
899
906
|
when :ivar, :attrset then
|
900
907
|
# do nothing
|
901
908
|
else
|
@@ -943,6 +950,29 @@ class RubyToRuby < SexpProcessor
|
|
943
950
|
############################################################
|
944
951
|
# Utility Methods:
|
945
952
|
|
953
|
+
def util_module_or_class(exp, is_class=false)
|
954
|
+
s = "#{exp.shift}"
|
955
|
+
|
956
|
+
if is_class then
|
957
|
+
superk = process(exp.shift)
|
958
|
+
s << " < #{superk}" if superk
|
959
|
+
end
|
960
|
+
|
961
|
+
s << "\n"
|
962
|
+
|
963
|
+
body = []
|
964
|
+
begin
|
965
|
+
code = process(exp.shift).chomp
|
966
|
+
body << code unless code.nil? or code.empty?
|
967
|
+
end until exp.empty?
|
968
|
+
unless body.empty? then
|
969
|
+
body = indent(body.join("\n\n")) + "\n"
|
970
|
+
else
|
971
|
+
body = ""
|
972
|
+
end
|
973
|
+
s + body + "end"
|
974
|
+
end
|
975
|
+
|
946
976
|
def indent(s)
|
947
977
|
s.to_s.map{|line| @indent + line}.join
|
948
978
|
end
|
@@ -1003,8 +1033,11 @@ class Proc
|
|
1003
1033
|
end
|
1004
1034
|
|
1005
1035
|
def to_ruby
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1036
|
+
ruby = self.to_method.to_ruby
|
1037
|
+
ruby.sub!(/\A(def \S+)\(([^\)]*)\)/, '\1 |\2|') # move args
|
1038
|
+
ruby.sub!(/\Adef[^\n\|]+/, 'proc { ') # strip def name
|
1039
|
+
ruby.sub!(/end\Z/, '}') # strip end
|
1040
|
+
ruby.gsub!(/\s+$/, '') # trailing WS bugs me
|
1041
|
+
ruby
|
1009
1042
|
end
|
1010
1043
|
end
|
data/test/test_ruby2ruby.rb
CHANGED
@@ -10,6 +10,40 @@ class TestRubyToRuby < Test::Unit::TestCase
|
|
10
10
|
@processor = RubyToRuby.new
|
11
11
|
end
|
12
12
|
|
13
|
+
def test_rewrite_defn_define_method
|
14
|
+
inn = s(:defn, :splatted,
|
15
|
+
s(:bmethod,
|
16
|
+
s(:masgn, s(:dasgn_curr, :args)),
|
17
|
+
s(:block,
|
18
|
+
s(:dasgn_curr, :y),
|
19
|
+
s(:dasgn_curr, :y, s(:call, s(:dvar, :args), :first)),
|
20
|
+
s(:call, s(:dvar, :y), :+, s(:array, s(:lit, 42))))))
|
21
|
+
out = s(:defn, :splatted,
|
22
|
+
s(:args, :"*args"),
|
23
|
+
s(:scope,
|
24
|
+
s(:block,
|
25
|
+
s(:dasgn_curr, :y, s(:call, s(:lvar, :args), :first)),
|
26
|
+
s(:call, s(:lvar, :y), :+, s(:array, s(:lit, 42))))))
|
27
|
+
|
28
|
+
assert_equal out, @processor.rewrite_defn(inn)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_rewrite_defn_bmethod
|
32
|
+
inn = s(:defn, :group,
|
33
|
+
s(:fbody,
|
34
|
+
s(:bmethod,
|
35
|
+
s(:masgn, s(:dasgn_curr, :params)),
|
36
|
+
s(:block,
|
37
|
+
s(:dasgn_curr, :force_reload, s(:dasgn_curr, :association, s(:dasgn_curr, :retval))),
|
38
|
+
s(:lit, 42)))))
|
39
|
+
out = s(:defn, :group,
|
40
|
+
s(:args, :"*params"),
|
41
|
+
s(:scope,
|
42
|
+
s(:block, s(:lit, 42))))
|
43
|
+
|
44
|
+
assert_equal out, @processor.rewrite_defn(inn)
|
45
|
+
end
|
46
|
+
|
13
47
|
def test_rewrite_resbody
|
14
48
|
inn = [:resbody,
|
15
49
|
[:array, [:const, :SyntaxError]],
|
@@ -60,7 +94,15 @@ class TestRubyToRuby < Test::Unit::TestCase
|
|
60
94
|
end
|
61
95
|
|
62
96
|
# Self-Translation: 1st Generation
|
63
|
-
|
97
|
+
ruby = RubyToRuby.translate(RubyToRuby).sub("RubyToRuby", "RubyToRuby2")
|
98
|
+
begin
|
99
|
+
eval ruby
|
100
|
+
rescue SyntaxError => e
|
101
|
+
puts "SyntaxError: #{e.message}"
|
102
|
+
puts
|
103
|
+
puts ruby
|
104
|
+
exit 1
|
105
|
+
end
|
64
106
|
|
65
107
|
class TestRubyToRuby2 < TestRubyToRuby
|
66
108
|
def setup
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.0
|
2
|
+
rubygems_version: 0.9.0.9
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby2ruby
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.1.
|
7
|
-
date:
|
6
|
+
version: 1.1.4
|
7
|
+
date: 2007-01-15 00:00:00 -08:00
|
8
8
|
summary: ruby2ruby provides a means of generating pure ruby code easily from ParseTree's Sexps.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -49,20 +49,20 @@ requirements: []
|
|
49
49
|
|
50
50
|
dependencies:
|
51
51
|
- !ruby/object:Gem::Dependency
|
52
|
-
name:
|
52
|
+
name: ParseTree
|
53
53
|
version_requirement:
|
54
54
|
version_requirements: !ruby/object:Gem::Version::Requirement
|
55
55
|
requirements:
|
56
|
-
- - "
|
56
|
+
- - ">"
|
57
57
|
- !ruby/object:Gem::Version
|
58
|
-
version:
|
58
|
+
version: 0.0.0
|
59
59
|
version:
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
|
-
name:
|
61
|
+
name: hoe
|
62
62
|
version_requirement:
|
63
63
|
version_requirements: !ruby/object:Gem::Version::Requirement
|
64
64
|
requirements:
|
65
|
-
- - "
|
65
|
+
- - ">="
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
67
|
+
version: 1.1.7
|
68
68
|
version:
|