ruby2ruby 1.1.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/History.txt +7 -0
- data/Manifest.txt +6 -0
- data/README.txt +50 -0
- data/Rakefile +16 -0
- data/lib/ruby2ruby.rb +954 -0
- data/test/test_ruby2ruby.rb +134 -0
- metadata +69 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
ruby2ruby
|
2
|
+
http://seattlerb.rubyforge.org/
|
3
|
+
http://rubyforge.org/projects/seattlerb
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
ruby2ruby provides a means of generating pure ruby code easily from
|
8
|
+
ParseTree's Sexps. This makes making dynamic language processors much
|
9
|
+
easier in ruby than ever before.
|
10
|
+
|
11
|
+
== FEATURES/PROBLEMS:
|
12
|
+
|
13
|
+
* Clean, simple SexpProcessor generates ruby code from ParseTree's output.
|
14
|
+
|
15
|
+
== SYNOPSYS:
|
16
|
+
|
17
|
+
RubyToRuby.translate(MyClass, :mymethod) # => "def mymethod..."
|
18
|
+
|
19
|
+
== REQUIREMENTS:
|
20
|
+
|
21
|
+
+ ParseTree
|
22
|
+
|
23
|
+
== INSTALL:
|
24
|
+
|
25
|
+
+ sudo gem install ruby2ruby
|
26
|
+
|
27
|
+
== LICENSE:
|
28
|
+
|
29
|
+
(The MIT License)
|
30
|
+
|
31
|
+
Copyright (c) 2006 Ryan Davis
|
32
|
+
|
33
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
34
|
+
a copy of this software and associated documentation files (the
|
35
|
+
'Software'), to deal in the Software without restriction, including
|
36
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
37
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
38
|
+
permit persons to whom the Software is furnished to do so, subject to
|
39
|
+
the following conditions:
|
40
|
+
|
41
|
+
The above copyright notice and this permission notice shall be
|
42
|
+
included in all copies or substantial portions of the Software.
|
43
|
+
|
44
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
45
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
46
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
47
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
48
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
49
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
50
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/ruby2ruby.rb'
|
6
|
+
|
7
|
+
Hoe.new('ruby2ruby', RubyToRuby::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'seattlerb'
|
9
|
+
p.summary = 'ruby2ruby provides a means of generating pure ruby code easily from ParseTree\'s Sexps.'
|
10
|
+
p.description = p.paragraphs_of('README.txt', 2).join
|
11
|
+
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1].map {|u| u.strip }
|
12
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
13
|
+
p.extra_deps << "ParseTree"
|
14
|
+
end
|
15
|
+
|
16
|
+
# vim: syntax=Ruby
|
data/lib/ruby2ruby.rb
ADDED
@@ -0,0 +1,954 @@
|
|
1
|
+
# begin require 'rubygems'; rescue LoadError; end
|
2
|
+
require 'parse_tree'
|
3
|
+
require 'sexp_processor'
|
4
|
+
|
5
|
+
class NilClass
|
6
|
+
def method_missing(msg, *args, &block)
|
7
|
+
nil
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class RubyToRuby < SexpProcessor
|
12
|
+
VERSION = '1.1.0'
|
13
|
+
|
14
|
+
def self.translate(klass_or_str, method=nil)
|
15
|
+
self.new.process(ParseTree.translate(klass_or_str, method))
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
super
|
20
|
+
@indent = " "
|
21
|
+
self.auto_shift_type = true
|
22
|
+
self.strict = true
|
23
|
+
self.expected = String
|
24
|
+
end
|
25
|
+
|
26
|
+
############################################################
|
27
|
+
# Processors (rewriters at bottom)
|
28
|
+
|
29
|
+
def process_alias(exp)
|
30
|
+
"alias_method #{process(exp.shift)}, #{process(exp.shift)}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def process_and(exp)
|
34
|
+
"(#{process exp.shift} and #{process exp.shift})"
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_args(exp)
|
38
|
+
args = []
|
39
|
+
|
40
|
+
until exp.empty? do
|
41
|
+
arg = exp.shift
|
42
|
+
case arg
|
43
|
+
when Symbol then
|
44
|
+
args << arg
|
45
|
+
when Array then
|
46
|
+
case arg.first
|
47
|
+
when :block then
|
48
|
+
asgns = {}
|
49
|
+
arg[1..-1].each do |lasgn|
|
50
|
+
asgns[lasgn[1]] = process(lasgn)
|
51
|
+
end
|
52
|
+
|
53
|
+
args.each_with_index do |name, index|
|
54
|
+
args[index] = asgns[name] if asgns.has_key? name
|
55
|
+
end
|
56
|
+
when :block_arg then
|
57
|
+
args << "&#{arg.last}"
|
58
|
+
when :array then
|
59
|
+
names = arg
|
60
|
+
vals = exp.shift
|
61
|
+
names.shift
|
62
|
+
vals.shift
|
63
|
+
v_size = vals.size
|
64
|
+
|
65
|
+
args << process(names.shift) until names.size == v_size
|
66
|
+
names.zip(vals) do |name, val|
|
67
|
+
args << "#{process name} = #{process val}"
|
68
|
+
end
|
69
|
+
else
|
70
|
+
raise "unknown arg type #{arg.first.inspect}"
|
71
|
+
end
|
72
|
+
else
|
73
|
+
raise "unknown arg type #{arg.inspect}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
return "(#{args.join ', '})"
|
78
|
+
end
|
79
|
+
|
80
|
+
def process_arglist(exp) # custom made node
|
81
|
+
code = []
|
82
|
+
until exp.empty? do
|
83
|
+
code << process(exp.shift)
|
84
|
+
end
|
85
|
+
code.join ', '
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_argscat(exp)
|
89
|
+
args = []
|
90
|
+
ary = exp.shift
|
91
|
+
ary.shift # :array
|
92
|
+
until ary.empty? do
|
93
|
+
args << process(ary.shift)
|
94
|
+
end
|
95
|
+
args << "*#{process(exp.shift)}"
|
96
|
+
args.join ', '
|
97
|
+
end
|
98
|
+
|
99
|
+
def process_argspush(exp)
|
100
|
+
args = []
|
101
|
+
|
102
|
+
until exp.empty? do
|
103
|
+
args << process(exp.shift)
|
104
|
+
end
|
105
|
+
|
106
|
+
"#{args.join ', '}"
|
107
|
+
end
|
108
|
+
|
109
|
+
def process_array(exp)
|
110
|
+
"[#{process_arglist(exp)}]"
|
111
|
+
end
|
112
|
+
|
113
|
+
def process_attrasgn(exp)
|
114
|
+
process_call(exp)
|
115
|
+
end
|
116
|
+
|
117
|
+
def process_back_ref(exp)
|
118
|
+
"$#{exp.shift}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def process_begin(exp)
|
122
|
+
is_rescue = exp.first.first == :rescue rescue false
|
123
|
+
code = []
|
124
|
+
code << "begin"
|
125
|
+
until exp.empty?
|
126
|
+
src = process(exp.shift)
|
127
|
+
src = indent(src) unless src =~ /\nrescue/ # ensures no level 0 rescues
|
128
|
+
code << src
|
129
|
+
end
|
130
|
+
code << "end" unless is_rescue
|
131
|
+
return code.join("\n")
|
132
|
+
end
|
133
|
+
|
134
|
+
def process_block(exp)
|
135
|
+
result = []
|
136
|
+
|
137
|
+
until exp.empty? do
|
138
|
+
found = exp.first.first == :block_arg rescue false
|
139
|
+
if found then
|
140
|
+
raise "wtf"
|
141
|
+
result[-1] = result[-1][0..-2] + ", #{process(exp.shift)})"
|
142
|
+
else
|
143
|
+
code = exp.shift
|
144
|
+
if code.nil? or code.first == :nil then
|
145
|
+
result << "# do nothing"
|
146
|
+
else
|
147
|
+
result << process(code)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
return result.join("\n") + "\n"
|
153
|
+
end
|
154
|
+
|
155
|
+
def process_block_arg(exp)
|
156
|
+
"&#{exp.shift}"
|
157
|
+
end
|
158
|
+
|
159
|
+
def process_block_pass(exp)
|
160
|
+
bname = [:lvar, "&" + process(exp.shift)]
|
161
|
+
call = exp.shift
|
162
|
+
has_args = Array === call.last and call.last.first == :array
|
163
|
+
call << [:array] unless has_args
|
164
|
+
call.last << bname
|
165
|
+
|
166
|
+
process(call)
|
167
|
+
end
|
168
|
+
|
169
|
+
def process_break(exp)
|
170
|
+
val = process(exp.shift)
|
171
|
+
"break" + (val ? " #{val}" : "")
|
172
|
+
end
|
173
|
+
|
174
|
+
def process_call(exp)
|
175
|
+
receiver = process exp.shift
|
176
|
+
name = exp.shift
|
177
|
+
args_exp = exp.shift
|
178
|
+
if args_exp && args_exp.first == :array
|
179
|
+
args = "#{process(args_exp)[1..-2]}"
|
180
|
+
else
|
181
|
+
args = process args_exp
|
182
|
+
end
|
183
|
+
|
184
|
+
case name
|
185
|
+
when :<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :%, :<<, :>> then #
|
186
|
+
"(#{receiver} #{name} #{args})"
|
187
|
+
when :[] then
|
188
|
+
"#{receiver}[#{args}]"
|
189
|
+
else
|
190
|
+
unless receiver.nil? then
|
191
|
+
"#{receiver}.#{name}#{args ? "(#{args})" : args}"
|
192
|
+
else
|
193
|
+
"#{name}#{args ? "(#{args})" : args}"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def process_case(exp)
|
199
|
+
result = []
|
200
|
+
result << "case #{process exp.shift}"
|
201
|
+
until exp.empty?
|
202
|
+
pt = exp.shift
|
203
|
+
if pt and pt.first == :when
|
204
|
+
result << "#{process(pt)}"
|
205
|
+
else
|
206
|
+
code = indent(process(pt))
|
207
|
+
code = indent("# do nothing") if code =~ /^\s*$/
|
208
|
+
result << "else\n#{code}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
result << "end"
|
212
|
+
result.join("\n")
|
213
|
+
end
|
214
|
+
|
215
|
+
def process_cdecl(exp)
|
216
|
+
"#{exp.shift} = #{process(exp.shift)}"
|
217
|
+
end
|
218
|
+
|
219
|
+
def process_class(exp)
|
220
|
+
s = "class #{exp.shift}"
|
221
|
+
superk = process(exp.shift)
|
222
|
+
|
223
|
+
s << " < #{superk}" if superk
|
224
|
+
s << "\n"
|
225
|
+
|
226
|
+
body = ""
|
227
|
+
body << "#{process exp.shift}\n\n" until exp.empty?
|
228
|
+
s + indent(body) + "end"
|
229
|
+
end
|
230
|
+
|
231
|
+
def process_colon2(exp)
|
232
|
+
"#{process(exp.shift)}::#{exp.shift}"
|
233
|
+
end
|
234
|
+
|
235
|
+
def process_colon3(exp)
|
236
|
+
"::#{exp.shift}"
|
237
|
+
end
|
238
|
+
|
239
|
+
def process_const(exp)
|
240
|
+
exp.shift.to_s
|
241
|
+
end
|
242
|
+
|
243
|
+
def process_cvar(exp)
|
244
|
+
"#{exp.shift}"
|
245
|
+
end
|
246
|
+
|
247
|
+
def process_cvasgn(exp)
|
248
|
+
"#{exp.shift} = #{process(exp.shift)}"
|
249
|
+
end
|
250
|
+
|
251
|
+
def process_cvdecl(exp)
|
252
|
+
"#{exp.shift} = #{process(exp.shift)}"
|
253
|
+
end
|
254
|
+
|
255
|
+
def process_dasgn_curr(exp)
|
256
|
+
s = exp.shift.to_s
|
257
|
+
s += "=" + process(exp.shift) unless exp.empty?
|
258
|
+
s
|
259
|
+
end
|
260
|
+
|
261
|
+
def process_dasgn(exp)
|
262
|
+
"#{exp.shift.to_s} = #{process(exp.shift)}"
|
263
|
+
end
|
264
|
+
|
265
|
+
def process_defined(exp)
|
266
|
+
"defined? #{process(exp.shift)}"
|
267
|
+
end
|
268
|
+
|
269
|
+
def process_defs(exp)
|
270
|
+
process_defn(exp)
|
271
|
+
end
|
272
|
+
|
273
|
+
def process_defn(exp)
|
274
|
+
t = exp[1].first
|
275
|
+
t2 = exp[2].first rescue nil
|
276
|
+
if t == :args and [:ivar, :attrset].include? t2 then
|
277
|
+
name = exp.shift
|
278
|
+
case t2
|
279
|
+
when :ivar then
|
280
|
+
exp.clear
|
281
|
+
return "attr_reader #{name.inspect}"
|
282
|
+
when :attrset then
|
283
|
+
exp.clear
|
284
|
+
return "attr_writer :#{name.to_s[0..-2]}"
|
285
|
+
else
|
286
|
+
raise "Unknown defn type: #{exp.inspect}"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
case t
|
291
|
+
when :cfunc then
|
292
|
+
s = "# method '#{exp.shift}' defined in a C function"
|
293
|
+
exp.shift
|
294
|
+
return s
|
295
|
+
when :scope, :args then
|
296
|
+
name = exp.shift
|
297
|
+
args = process(exp.shift)
|
298
|
+
args = "" if args == "()"
|
299
|
+
body = indent(process(exp.shift))
|
300
|
+
return "def #{name}#{args}\n#{body}\nend".gsub(/\n\s*\n+/, "\n")
|
301
|
+
when :fcall then
|
302
|
+
# skip the fcall (to define_method and such) and grab the body
|
303
|
+
name = exp.shift
|
304
|
+
exp.shift # :fcall to define_method
|
305
|
+
body = process(exp.shift)
|
306
|
+
p name, body
|
307
|
+
raise "no"
|
308
|
+
else
|
309
|
+
raise "Unknown defn type: #{t} for #{exp.inspect}"
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def process_defx(exp) # custom node type - TODO why in r2r?
|
314
|
+
name = exp.shift
|
315
|
+
args = process(exp.shift)
|
316
|
+
body = indent(process(exp.shift))
|
317
|
+
return "defx #{name}#{args}\n#{body}end".gsub(/\n\s*\n+/, "\n")
|
318
|
+
end
|
319
|
+
|
320
|
+
def process_dot2(exp)
|
321
|
+
"(#{process exp.shift}..#{process exp.shift})"
|
322
|
+
end
|
323
|
+
|
324
|
+
def process_dot3(exp)
|
325
|
+
"(#{process exp.shift}...#{process exp.shift})"
|
326
|
+
end
|
327
|
+
|
328
|
+
def process_dregx(exp)
|
329
|
+
"/#{process_dstr(exp)[1..-2]}/"
|
330
|
+
end
|
331
|
+
|
332
|
+
def process_dregx_once(exp)
|
333
|
+
process_dregx(exp) + "o"
|
334
|
+
end
|
335
|
+
|
336
|
+
def process_dstr(exp)
|
337
|
+
s = exp.shift.dump[0..-2]
|
338
|
+
until exp.empty?
|
339
|
+
pt = exp.shift
|
340
|
+
if pt.first == :str
|
341
|
+
s << process(pt)[1..-2]
|
342
|
+
else
|
343
|
+
s << '#{' + process(pt) + '}'
|
344
|
+
end
|
345
|
+
end
|
346
|
+
s + '"'
|
347
|
+
end
|
348
|
+
|
349
|
+
def process_dsym(exp)
|
350
|
+
s = ":" + exp.shift.dump[0..-2]
|
351
|
+
until exp.empty?
|
352
|
+
pt = exp.shift
|
353
|
+
if pt.first == :str
|
354
|
+
s << process(pt)[1..-2]
|
355
|
+
else
|
356
|
+
s << '#{' + process(pt) + '}'
|
357
|
+
end
|
358
|
+
end
|
359
|
+
s + '"'
|
360
|
+
end
|
361
|
+
|
362
|
+
def process_dvar(exp)
|
363
|
+
exp.shift.to_s
|
364
|
+
end
|
365
|
+
|
366
|
+
def process_dxstr(exp)
|
367
|
+
"`#{process_dstr(exp)[1..-2]}`"
|
368
|
+
end
|
369
|
+
|
370
|
+
def process_ensure(exp)
|
371
|
+
body = process exp.shift
|
372
|
+
ens = process exp.shift
|
373
|
+
return "#{body}\nensure\n#{indent ens}"
|
374
|
+
end
|
375
|
+
|
376
|
+
def process_false(exp)
|
377
|
+
"false"
|
378
|
+
end
|
379
|
+
|
380
|
+
def process_fcall(exp)
|
381
|
+
exp_orig = exp.deep_clone
|
382
|
+
name = exp.shift.to_s
|
383
|
+
args = exp.shift
|
384
|
+
code = []
|
385
|
+
unless args.nil? then
|
386
|
+
args[0] = :arglist if args.first == :array
|
387
|
+
code << process(args)
|
388
|
+
end
|
389
|
+
return "#{name}(#{code.join(', ')})"
|
390
|
+
end
|
391
|
+
|
392
|
+
def process_flip2(exp)
|
393
|
+
"#{process(exp.shift)}..#{process(exp.shift)}"
|
394
|
+
end
|
395
|
+
|
396
|
+
def process_flip3(exp)
|
397
|
+
"#{process(exp.shift)}...#{process(exp.shift)}"
|
398
|
+
end
|
399
|
+
|
400
|
+
def process_for(exp)
|
401
|
+
recv = process exp.shift
|
402
|
+
iter = process exp.shift
|
403
|
+
body = process exp.shift
|
404
|
+
return "for #{iter} in #{recv}\n#{indent body}\nend\n"
|
405
|
+
end
|
406
|
+
|
407
|
+
def process_gasgn(exp)
|
408
|
+
process_iasgn(exp)
|
409
|
+
end
|
410
|
+
|
411
|
+
def process_gvar(exp)
|
412
|
+
return exp.shift.to_s
|
413
|
+
end
|
414
|
+
|
415
|
+
def process_hash(exp)
|
416
|
+
result = []
|
417
|
+
until exp.empty?
|
418
|
+
result << "#{process(exp.shift)} => #{process(exp.shift)}"
|
419
|
+
end
|
420
|
+
return "{ #{result.join(', ')} }"
|
421
|
+
end
|
422
|
+
|
423
|
+
def process_iasgn(exp)
|
424
|
+
"#{exp.shift} = #{process exp.shift}"
|
425
|
+
end
|
426
|
+
|
427
|
+
def cond_indent_process(pt)
|
428
|
+
(pt and pt.first == :block) ? process(pt) : indent(process(pt))
|
429
|
+
end
|
430
|
+
|
431
|
+
def process_if(exp)
|
432
|
+
cond = process exp.shift
|
433
|
+
t = process exp.shift
|
434
|
+
|
435
|
+
type = t ? "if" : "unless"
|
436
|
+
|
437
|
+
s = ["#{type} #{cond} then"]
|
438
|
+
s << indent(t) if t
|
439
|
+
|
440
|
+
until exp.empty?
|
441
|
+
code = exp.shift
|
442
|
+
case code.first
|
443
|
+
when nil
|
444
|
+
# do nothing
|
445
|
+
when :if then
|
446
|
+
s << "els#{process(code).sub(/\nend\Z/, '')}"
|
447
|
+
else
|
448
|
+
s << "else\n#{cond_indent_process(code)}"
|
449
|
+
end
|
450
|
+
|
451
|
+
if t.nil? then
|
452
|
+
s[-1] = s[-1][5..-1] # remove else\n
|
453
|
+
t = true
|
454
|
+
end
|
455
|
+
end
|
456
|
+
s << "end"
|
457
|
+
|
458
|
+
s.join("\n")
|
459
|
+
end
|
460
|
+
|
461
|
+
def process_iter(exp)
|
462
|
+
iter = process exp.shift
|
463
|
+
args = process exp.shift
|
464
|
+
body = process exp.shift
|
465
|
+
|
466
|
+
b, e = if iter == "END" then
|
467
|
+
[ "{", "}" ]
|
468
|
+
else
|
469
|
+
[ "do", "end" ]
|
470
|
+
end
|
471
|
+
|
472
|
+
iter.sub!(/\(\)$/, '')
|
473
|
+
|
474
|
+
result = []
|
475
|
+
result << "#{iter} #{b}"
|
476
|
+
result << " |#{args}|" if args
|
477
|
+
if body then
|
478
|
+
result << "\n"
|
479
|
+
result << indent(body).chomp
|
480
|
+
result << "\n"
|
481
|
+
else
|
482
|
+
result << ' '
|
483
|
+
end
|
484
|
+
result << e
|
485
|
+
result.join
|
486
|
+
end
|
487
|
+
|
488
|
+
def process_ivar(exp)
|
489
|
+
exp.shift.to_s
|
490
|
+
end
|
491
|
+
|
492
|
+
def process_lasgn(exp)
|
493
|
+
s = "#{exp.shift}"
|
494
|
+
s += " = #{process exp.shift}" unless exp.empty?
|
495
|
+
s
|
496
|
+
end
|
497
|
+
|
498
|
+
def process_lit(exp)
|
499
|
+
obj = exp.shift
|
500
|
+
if obj.is_a? Range # to get around how parsed ranges turn into lits and lose parens
|
501
|
+
"(" + obj.inspect + ")"
|
502
|
+
else
|
503
|
+
obj.inspect
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
def process_lvar(exp)
|
508
|
+
exp.shift.to_s
|
509
|
+
end
|
510
|
+
|
511
|
+
def process_masgn(exp)
|
512
|
+
lhs = exp.shift
|
513
|
+
rhs = exp.shift
|
514
|
+
|
515
|
+
assert_type lhs, :array
|
516
|
+
lhs.shift
|
517
|
+
lhs = lhs.map { |l| process(l) }
|
518
|
+
|
519
|
+
unless rhs.nil? then
|
520
|
+
# HACK - but seems to work (see to_ary test) assert_type rhs, :array
|
521
|
+
rhs.shift
|
522
|
+
rhs = rhs.map { |r| process(r) }
|
523
|
+
return "#{lhs.join(", ")} = #{rhs.join(", ")}"
|
524
|
+
else
|
525
|
+
return lhs.join(", ")
|
526
|
+
end
|
527
|
+
|
528
|
+
end
|
529
|
+
|
530
|
+
def process_match(exp)
|
531
|
+
"#{process(exp.shift)}"
|
532
|
+
end
|
533
|
+
|
534
|
+
def process_match2(exp)
|
535
|
+
lhs = process(exp.shift)
|
536
|
+
rhs = process(exp.shift)
|
537
|
+
"#{lhs} =~ #{rhs}"
|
538
|
+
end
|
539
|
+
|
540
|
+
def process_match3(exp)
|
541
|
+
rhs = process(exp.shift)
|
542
|
+
lhs = process(exp.shift)
|
543
|
+
"#{lhs} =~ #{rhs}"
|
544
|
+
end
|
545
|
+
|
546
|
+
def process_module(exp)
|
547
|
+
s = "module #{exp.shift}\n"
|
548
|
+
body = ""
|
549
|
+
body << "#{process exp.shift}\n\n" until exp.empty?
|
550
|
+
s + indent(body) + "end"
|
551
|
+
end
|
552
|
+
|
553
|
+
def process_next(exp)
|
554
|
+
"next"
|
555
|
+
end
|
556
|
+
|
557
|
+
def process_nil(exp)
|
558
|
+
"nil"
|
559
|
+
end
|
560
|
+
|
561
|
+
def process_not(exp)
|
562
|
+
"(not #{process exp.shift})"
|
563
|
+
end
|
564
|
+
|
565
|
+
def process_nth_ref(exp)
|
566
|
+
"$#{exp.shift}"
|
567
|
+
end
|
568
|
+
|
569
|
+
def process_op_asgn1(exp)
|
570
|
+
# [[:lvar, :b], [:array, [:lit, 1]], :"||", [:lit, 10]]
|
571
|
+
lhs = process(exp.shift)
|
572
|
+
index = process(exp.shift)
|
573
|
+
msg = exp.shift
|
574
|
+
rhs = process(exp.shift)
|
575
|
+
|
576
|
+
"#{lhs}#{index} #{msg}= #{rhs}"
|
577
|
+
end
|
578
|
+
|
579
|
+
def process_op_asgn2(exp)
|
580
|
+
# [[:lvar, :c], :var=, :"||", [:lit, 20]]
|
581
|
+
lhs = process(exp.shift)
|
582
|
+
index = exp.shift.to_s[0..-2]
|
583
|
+
msg = exp.shift
|
584
|
+
|
585
|
+
rhs = process(exp.shift)
|
586
|
+
|
587
|
+
"#{lhs}.#{index} #{msg}= #{rhs}"
|
588
|
+
end
|
589
|
+
|
590
|
+
def process_op_asgn_or(exp)
|
591
|
+
# a ||= 1
|
592
|
+
# [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
|
593
|
+
exp.shift
|
594
|
+
process(exp.shift).sub(/=/, '||=')
|
595
|
+
end
|
596
|
+
|
597
|
+
def process_op_asgn_and(exp)
|
598
|
+
# a &&= 1
|
599
|
+
# [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
|
600
|
+
exp.shift
|
601
|
+
process(exp.shift).sub(/=/, '&&=')
|
602
|
+
end
|
603
|
+
|
604
|
+
def process_or(exp)
|
605
|
+
"(#{process exp.shift} or #{process exp.shift})"
|
606
|
+
end
|
607
|
+
|
608
|
+
def process_postexe(exp)
|
609
|
+
"END"
|
610
|
+
end
|
611
|
+
|
612
|
+
def process_redo(exp)
|
613
|
+
"redo"
|
614
|
+
end
|
615
|
+
|
616
|
+
def process_resbody(exp) # TODO: rewrite this fucker
|
617
|
+
code = []
|
618
|
+
|
619
|
+
until exp.nil? or exp.empty?
|
620
|
+
list = exp.shift
|
621
|
+
body = exp.shift
|
622
|
+
|
623
|
+
var = if list.last.first == :lasgn then
|
624
|
+
list.pop[1]
|
625
|
+
else
|
626
|
+
nil
|
627
|
+
end
|
628
|
+
|
629
|
+
list[0] = :arglist
|
630
|
+
|
631
|
+
if list then
|
632
|
+
code << "rescue #{process(list)}"
|
633
|
+
else
|
634
|
+
code << "rescue"
|
635
|
+
end
|
636
|
+
code.last << " => #{var}" if var
|
637
|
+
|
638
|
+
if body then
|
639
|
+
code << indent(process(body))
|
640
|
+
else
|
641
|
+
code << indent("# do nothing")
|
642
|
+
end
|
643
|
+
|
644
|
+
exp = exp.shift
|
645
|
+
exp.shift if exp
|
646
|
+
end
|
647
|
+
|
648
|
+
code.join("\n")
|
649
|
+
end
|
650
|
+
|
651
|
+
def process_rescue(exp)
|
652
|
+
# TODO: proper formatting depends on knowing the context
|
653
|
+
#
|
654
|
+
# a = b rescue c => [lasgn a [rescue b c]]
|
655
|
+
# begin; a = b; rescue c => [begin [rescue [lasgn a b] c]]
|
656
|
+
body = process exp.shift
|
657
|
+
resbody = process exp.shift
|
658
|
+
els = process exp.shift
|
659
|
+
|
660
|
+
code = []
|
661
|
+
code << indent(body)
|
662
|
+
code << resbody
|
663
|
+
if els then
|
664
|
+
code << "else"
|
665
|
+
code << indent(els)
|
666
|
+
else
|
667
|
+
code << "end\n"
|
668
|
+
end
|
669
|
+
code.join("\n")
|
670
|
+
end
|
671
|
+
|
672
|
+
def process_retry(exp)
|
673
|
+
"retry"
|
674
|
+
end
|
675
|
+
|
676
|
+
def process_return(exp)
|
677
|
+
return "return #{process exp.shift}"
|
678
|
+
end
|
679
|
+
|
680
|
+
def process_sclass(exp)
|
681
|
+
"class << #{process(exp.shift)}\n#{indent(process(exp.shift))}\nend"
|
682
|
+
end
|
683
|
+
|
684
|
+
def process_scope(exp)
|
685
|
+
return process(exp.shift)
|
686
|
+
end
|
687
|
+
|
688
|
+
def process_self(exp)
|
689
|
+
"self"
|
690
|
+
end
|
691
|
+
|
692
|
+
def process_splat(exp)
|
693
|
+
"*#{process(exp.shift)}"
|
694
|
+
end
|
695
|
+
|
696
|
+
def process_str(exp)
|
697
|
+
return exp.shift.dump
|
698
|
+
end
|
699
|
+
|
700
|
+
def process_super(exp)
|
701
|
+
args = exp.shift
|
702
|
+
args[0] = :arglist
|
703
|
+
"super(#{process(args)})"
|
704
|
+
end
|
705
|
+
|
706
|
+
def process_svalue(exp)
|
707
|
+
process(exp.shift)
|
708
|
+
end
|
709
|
+
|
710
|
+
def process_to_ary(exp)
|
711
|
+
process(exp.shift)
|
712
|
+
end
|
713
|
+
|
714
|
+
def process_true(exp)
|
715
|
+
"true"
|
716
|
+
end
|
717
|
+
|
718
|
+
def process_undef(exp)
|
719
|
+
"undef #{process(exp.shift)}"
|
720
|
+
end
|
721
|
+
|
722
|
+
def process_until(exp)
|
723
|
+
cond_loop(exp, 'until')
|
724
|
+
end
|
725
|
+
|
726
|
+
def process_valias(exp)
|
727
|
+
"alias #{exp.shift} #{exp.shift}"
|
728
|
+
end
|
729
|
+
|
730
|
+
def process_vcall(exp)
|
731
|
+
return exp.shift.to_s
|
732
|
+
end
|
733
|
+
|
734
|
+
def process_when(exp)
|
735
|
+
cond = process(exp.shift).to_s[1..-2]
|
736
|
+
code = indent(process(exp.shift))
|
737
|
+
code = indent "# do nothing" if code =~ /\A\s*\Z/
|
738
|
+
"when #{cond} then\n#{code.chomp}"
|
739
|
+
end
|
740
|
+
|
741
|
+
def process_while(exp)
|
742
|
+
cond_loop(exp, 'while')
|
743
|
+
end
|
744
|
+
|
745
|
+
def process_xstr(exp)
|
746
|
+
"`#{process_str(exp)[1..-2]}`"
|
747
|
+
end
|
748
|
+
|
749
|
+
def process_yield(exp)
|
750
|
+
args = exp.shift
|
751
|
+
if args then
|
752
|
+
args[0] = :arglist if args.first == :array
|
753
|
+
args = process(args)
|
754
|
+
end
|
755
|
+
|
756
|
+
"yield" + (args ? "(#{args})" : "")
|
757
|
+
end
|
758
|
+
|
759
|
+
def process_zarray(exp)
|
760
|
+
"[]"
|
761
|
+
end
|
762
|
+
|
763
|
+
def process_zsuper(exp)
|
764
|
+
"super"
|
765
|
+
end
|
766
|
+
|
767
|
+
def cond_loop(exp, name)
|
768
|
+
cond = process(exp.shift)
|
769
|
+
body = indent(process(exp.shift)).chomp
|
770
|
+
head_controlled = exp.empty? ? false : exp.shift
|
771
|
+
|
772
|
+
code = []
|
773
|
+
if head_controlled then
|
774
|
+
code << "#{name} #{cond} do"
|
775
|
+
code << body
|
776
|
+
code << "end"
|
777
|
+
else
|
778
|
+
code << "begin"
|
779
|
+
code << body
|
780
|
+
code << "end #{name} #{cond}"
|
781
|
+
end
|
782
|
+
code.join("\n")
|
783
|
+
end
|
784
|
+
|
785
|
+
############################################################
|
786
|
+
# Rewriters
|
787
|
+
|
788
|
+
##
|
789
|
+
# defn: [:defn, :name, [:args...], [:scope, [:block, ...]]]
|
790
|
+
|
791
|
+
def rewrite_defs(exp)
|
792
|
+
target = exp.delete_at 1
|
793
|
+
exp[1] = :"#{target}.#{exp[1]}"
|
794
|
+
rewrite_defn(exp)
|
795
|
+
end
|
796
|
+
|
797
|
+
def rewrite_defn(exp)
|
798
|
+
# REFACTOR this needs help now
|
799
|
+
exp.shift # :defn
|
800
|
+
name = exp.shift
|
801
|
+
args = s(:args)
|
802
|
+
body = Sexp.from_array exp.shift
|
803
|
+
|
804
|
+
case body.first
|
805
|
+
when :args then # already normalized
|
806
|
+
args = body
|
807
|
+
body = exp.shift
|
808
|
+
assert_type args, :args
|
809
|
+
assert_type body, :scope
|
810
|
+
assert_type body[1], :block
|
811
|
+
when :scope, :fbody then
|
812
|
+
body = body[1] if body.first == :fbody
|
813
|
+
args = body.last.delete_at 1
|
814
|
+
assert_type args, :args
|
815
|
+
assert_type body, :scope
|
816
|
+
assert_type body[1], :block
|
817
|
+
|
818
|
+
if body[1][1].first == :block_arg then
|
819
|
+
block_arg = body[1].delete_at 1
|
820
|
+
args << block_arg
|
821
|
+
end
|
822
|
+
when :bmethod then
|
823
|
+
body.shift # :bmethod
|
824
|
+
if body.first.first == :dasgn_curr then
|
825
|
+
# WARN: there are some implications here of having an empty
|
826
|
+
# :args below namely, "proc { || " does not allow extra args
|
827
|
+
# passed in.
|
828
|
+
dasgn = body.shift
|
829
|
+
assert_type dasgn, :dasgn_curr
|
830
|
+
dasgn.shift # type
|
831
|
+
args.push(*dasgn)
|
832
|
+
body.find_and_replace_all(:dvar, :lvar)
|
833
|
+
end
|
834
|
+
if body.first.first == :block then
|
835
|
+
body = s(:scope, body.shift)
|
836
|
+
else
|
837
|
+
body = s(:scope, s(:block, body.shift)) # single statement
|
838
|
+
end
|
839
|
+
when :dmethod
|
840
|
+
# BEFORE: [:defn, :dmethod_added, [:dmethod, :bmethod_maker, ...]]
|
841
|
+
# AFTER: [:defn, :dmethod_added, ...]
|
842
|
+
iter = body[2][1][2] # UGH! FIX
|
843
|
+
iter.delete_at 1 # fcall define_method
|
844
|
+
args = iter[1].find_and_replace_all(:dasgn_curr, :args)
|
845
|
+
iter.delete_at 1 # args
|
846
|
+
iter[0] = :block
|
847
|
+
body = s(:scope, iter.find_and_replace_all(:dvar, :lvar))
|
848
|
+
when :ivar, :attrset then
|
849
|
+
# do nothing
|
850
|
+
else
|
851
|
+
raise "Unknown :defn format: #{name.inspect} #{args.inspect} #{body.inspect}"
|
852
|
+
end
|
853
|
+
|
854
|
+
return s(:defn, name, args, body)
|
855
|
+
end
|
856
|
+
|
857
|
+
def rewrite_resbody(exp)
|
858
|
+
result = []
|
859
|
+
|
860
|
+
code = result
|
861
|
+
while exp.first == :resbody do
|
862
|
+
code << exp.shift
|
863
|
+
list = exp.shift
|
864
|
+
body = exp.shift
|
865
|
+
exp = exp.shift # either another resbody or nil
|
866
|
+
|
867
|
+
# code may be nil, :lasgn, or :block
|
868
|
+
case body.first
|
869
|
+
when nil then
|
870
|
+
# do nothing
|
871
|
+
when :lasgn then
|
872
|
+
# TODO: check that it is assigning $!
|
873
|
+
list << body
|
874
|
+
body = nil
|
875
|
+
when :block then
|
876
|
+
# TODO: check that it is assigning $!
|
877
|
+
list << body.delete_at(1) if body[1].first == :lasgn
|
878
|
+
else
|
879
|
+
raise "unknown: #{code.inspect}"
|
880
|
+
end
|
881
|
+
|
882
|
+
code << list << body
|
883
|
+
if exp then
|
884
|
+
code = []
|
885
|
+
result << code
|
886
|
+
end
|
887
|
+
end
|
888
|
+
|
889
|
+
result
|
890
|
+
end
|
891
|
+
|
892
|
+
############################################################
|
893
|
+
# Utility Methods:
|
894
|
+
|
895
|
+
def indent(s)
|
896
|
+
s.to_s.map{|line| @indent + line}.join
|
897
|
+
end
|
898
|
+
end
|
899
|
+
|
900
|
+
class Method
|
901
|
+
def with_class_and_method_name
|
902
|
+
if self.inspect =~ /<Method: (.*)\#(.*)>/ then
|
903
|
+
klass = eval $1
|
904
|
+
method = $2.intern
|
905
|
+
raise "Couldn't determine class from #{self.inspect}" if klass.nil?
|
906
|
+
return yield(klass, method)
|
907
|
+
else
|
908
|
+
raise "Can't parse signature: #{self.inspect}"
|
909
|
+
end
|
910
|
+
end
|
911
|
+
|
912
|
+
def to_sexp
|
913
|
+
with_class_and_method_name do |klass, method|
|
914
|
+
ParseTree.new(false).parse_tree_for_method(klass, method)
|
915
|
+
end
|
916
|
+
end
|
917
|
+
end
|
918
|
+
|
919
|
+
class ProcStoreTmp
|
920
|
+
@@n = 0
|
921
|
+
def self.name
|
922
|
+
@@n += 1
|
923
|
+
return :"myproc#{@@n}"
|
924
|
+
end
|
925
|
+
end
|
926
|
+
|
927
|
+
class UnboundMethod
|
928
|
+
def to_ruby
|
929
|
+
name = ProcStoreTmp.name
|
930
|
+
ProcStoreTmp.send(:define_method, name, self)
|
931
|
+
m = ProcStoreTmp.new.method(name)
|
932
|
+
result = m.to_ruby.sub(/def #{name}\(([^\)]*)\)/,
|
933
|
+
'proc { |\1|').sub(/end\Z/, '}')
|
934
|
+
return result
|
935
|
+
end
|
936
|
+
end
|
937
|
+
|
938
|
+
class Proc
|
939
|
+
def to_method
|
940
|
+
name = ProcStoreTmp.name
|
941
|
+
ProcStoreTmp.send(:define_method, name, self)
|
942
|
+
ProcStoreTmp.new.method(name)
|
943
|
+
end
|
944
|
+
|
945
|
+
def to_sexp
|
946
|
+
body = self.to_method.to_sexp[2][1..-1]
|
947
|
+
[:proc, *body]
|
948
|
+
end
|
949
|
+
|
950
|
+
def to_ruby
|
951
|
+
self.to_method.to_ruby.sub(/def #{name}\(([^\)]*)\)/,
|
952
|
+
'proc { |\1|').sub(/end\Z/, '}')
|
953
|
+
end
|
954
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
begin require 'rubygems'; rescue LoadError; end
|
5
|
+
require 'ruby2ruby'
|
6
|
+
require 'pt_testcase'
|
7
|
+
|
8
|
+
class TestRubyToRuby < Test::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
@processor = RubyToRuby.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_rewrite_resbody
|
14
|
+
inn = [:resbody,
|
15
|
+
[:array, [:const, :SyntaxError]],
|
16
|
+
[:block, [:lasgn, :e1, [:gvar, :$!]], [:lit, 2]],
|
17
|
+
[:resbody,
|
18
|
+
[:array, [:const, :Exception]],
|
19
|
+
[:block, [:lasgn, :e2, [:gvar, :$!]], [:lit, 3]]]]
|
20
|
+
|
21
|
+
out = [:resbody,
|
22
|
+
[:array, [:const, :SyntaxError], [:lasgn, :e1, [:gvar, :$!]]],
|
23
|
+
[:block, [:lit, 2]],
|
24
|
+
[:resbody,
|
25
|
+
[:array, [:const, :Exception], [:lasgn, :e2, [:gvar, :$!]]],
|
26
|
+
[:block, [:lit, 3]]]]
|
27
|
+
|
28
|
+
assert_equal out, @processor.rewrite_resbody(inn)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_rewrite_resbody_lasgn
|
32
|
+
inn = [:resbody,
|
33
|
+
[:array, [:const, :SyntaxError]],
|
34
|
+
[:lasgn, :e1, [:gvar, :$!]],
|
35
|
+
[:resbody,
|
36
|
+
[:array, [:const, :Exception]],
|
37
|
+
[:block, [:lasgn, :e2, [:gvar, :$!]], [:lit, 3]]]]
|
38
|
+
|
39
|
+
out = [:resbody,
|
40
|
+
[:array, [:const, :SyntaxError], [:lasgn, :e1, [:gvar, :$!]]],
|
41
|
+
nil,
|
42
|
+
[:resbody,
|
43
|
+
[:array, [:const, :Exception], [:lasgn, :e2, [:gvar, :$!]]],
|
44
|
+
[:block, [:lit, 3]]]]
|
45
|
+
|
46
|
+
assert_equal out, @processor.rewrite_resbody(inn)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
ParseTreeTestCase.testcases.each do |node, data|
|
51
|
+
define_method :"test_#{node}" do
|
52
|
+
pt = data['ParseTree']
|
53
|
+
rb = data['Ruby2Ruby'] || data['Ruby']
|
54
|
+
|
55
|
+
result = @processor.process(pt)
|
56
|
+
|
57
|
+
assert_not_nil pt, "ParseTree for #{node} undefined"
|
58
|
+
assert_not_nil rb, "Ruby for #{node} undefined"
|
59
|
+
assert_equal rb, result
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
class R2RTest < Test::Unit::TestCase
|
67
|
+
|
68
|
+
def xtest_self_translation
|
69
|
+
r2r2r = RubyToRuby.translate(RubyToRuby).sub("RubyToRuby","RubyToRubyToRuby")
|
70
|
+
|
71
|
+
Object.class_eval r2r2r
|
72
|
+
|
73
|
+
r2r2r2 = RubyToRubyToRuby.translate(RubyToRuby).sub("RubyToRuby","RubyToRubyToRuby")
|
74
|
+
r2r2r2r = RubyToRubyToRuby.translate(RubyToRubyToRuby)
|
75
|
+
assert_equal(r2r2r, r2r2r2, "first generation must equal second generation")
|
76
|
+
assert_equal(r2r2r, r2r2r2r, "first generation must equal third generation")
|
77
|
+
end
|
78
|
+
|
79
|
+
def hairy_method(z,x=10,y=20*z.abs,&blok)
|
80
|
+
n = 1 + 2 * 40.0 / (z - 2)
|
81
|
+
retried = false
|
82
|
+
begin
|
83
|
+
raise ArgumentError, n if retried
|
84
|
+
n -= yield x,y,z,[z,x,y].map(&blok)
|
85
|
+
n = n / 1.1 until n < 500 # TODO: translated isn't respecting post iter
|
86
|
+
n = "hop hop #{"%.4f" % n}"
|
87
|
+
raise n
|
88
|
+
rescue RuntimeError => e
|
89
|
+
raise if n != e.message
|
90
|
+
n = lambda do |i|
|
91
|
+
lambda do |j|
|
92
|
+
"#{i} #{z+2*2} #{j.message.reverse}"
|
93
|
+
end
|
94
|
+
end[n].call(e)
|
95
|
+
unless retried
|
96
|
+
retried = true
|
97
|
+
retry
|
98
|
+
end
|
99
|
+
rescue ArgumentError => e
|
100
|
+
e.message
|
101
|
+
rescue
|
102
|
+
end
|
103
|
+
ensure
|
104
|
+
x << "ensure a-working"
|
105
|
+
end
|
106
|
+
|
107
|
+
def foobar a, █ block.call(a) end
|
108
|
+
def k; foobar [1,2,3].each { |x| x*2 } do |x| x*2 end end
|
109
|
+
|
110
|
+
def test_block_precedence_escape
|
111
|
+
eval RubyToRuby.translate(self.class, :k).sub(" k"," l")
|
112
|
+
assert_equal(k, l)
|
113
|
+
end
|
114
|
+
|
115
|
+
def HACK_test_hairy_method
|
116
|
+
src = RubyToRuby.translate(self.class, :hairy_method).sub(" h", " f")
|
117
|
+
|
118
|
+
eval src
|
119
|
+
|
120
|
+
blk = lambda{|x,y,z,arr|
|
121
|
+
unless y
|
122
|
+
x.to_i*2
|
123
|
+
else
|
124
|
+
x.to_i*y*z*arr.inject(1){|s,i| s+i}
|
125
|
+
end
|
126
|
+
}
|
127
|
+
x1 = ""
|
128
|
+
x2 = ""
|
129
|
+
res = [hairy_method(-5,x1,&blk), fairy_method(-5,x2,&blk)]
|
130
|
+
assert_equal(res.first, res.last)
|
131
|
+
assert_equal(x1, x2)
|
132
|
+
assert_equal("ensure a-working", x1)
|
133
|
+
end
|
134
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: ruby2ruby
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.1.0
|
7
|
+
date: 2006-10-11 00:00:00 -07:00
|
8
|
+
summary: ruby2ruby provides a means of generating pure ruby code easily from ParseTree's Sexps.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
- test
|
12
|
+
email: ryand-ruby@zenspider.com
|
13
|
+
homepage: http://seattlerb.rubyforge.org/
|
14
|
+
rubyforge_project: seattlerb
|
15
|
+
description: ruby2ruby provides a means of generating pure ruby code easily from ParseTree's Sexps. This makes making dynamic language processors much easier in ruby than ever before.
|
16
|
+
autorequire:
|
17
|
+
default_executable:
|
18
|
+
bindir: bin
|
19
|
+
has_rdoc: true
|
20
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
post_install_message:
|
30
|
+
authors:
|
31
|
+
- Ryan Davis
|
32
|
+
files:
|
33
|
+
- History.txt
|
34
|
+
- Manifest.txt
|
35
|
+
- README.txt
|
36
|
+
- Rakefile
|
37
|
+
- lib/ruby2ruby.rb
|
38
|
+
- test/test_ruby2ruby.rb
|
39
|
+
test_files: []
|
40
|
+
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
executables: []
|
46
|
+
|
47
|
+
extensions: []
|
48
|
+
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
dependencies:
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: hoe
|
54
|
+
version_requirement:
|
55
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 1.1.1
|
60
|
+
version:
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: ParseTree
|
63
|
+
version_requirement:
|
64
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.0.0
|
69
|
+
version:
|