sorcerer 0.0.7 → 0.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.
@@ -44,3 +44,58 @@ Ripper may be used to produce the s-expressions used by Sorcerer. The following
44
44
  puts Sorcerer.source(sexp)
45
45
  </pre>
46
46
 
47
+ h2. Options
48
+
49
+ h3. Multi-Line Output
50
+
51
+ If you want multi-line output of source, add the multiline option to
52
+ the source command.
53
+
54
+ For example, given:
55
+
56
+ <pre style="background: LightGrey">
57
+ sexp = Ripper::SexpBuilder.new("def foo; end").parse
58
+ </pre>
59
+
60
+ Then the following
61
+
62
+ <pre style="background: LightGrey">
63
+ puts Sorcerer.source(sexp)
64
+ </pre>
65
+
66
+ generates single line output (the default):
67
+
68
+ <pre style="background: LightBlue">
69
+ def foo; end
70
+ </pre>
71
+
72
+ And the following
73
+
74
+ <pre style="background: LightGrey">
75
+ puts Sorcerer.source(sexp, multiline: true)
76
+ </pre>
77
+
78
+ generates multi-line output
79
+
80
+ <pre style="background: LightBlue">
81
+ def foo
82
+ end
83
+ </pre>
84
+
85
+ h3. Debugging Output
86
+
87
+ If you wish to see the S-Expressions processed by Sorcerer and the
88
+ output emitted, then use the debug option:
89
+
90
+ <pre style="background: LightGrey">
91
+ puts Sorcerer.source(sexp, debug: true)
92
+ </pre>
93
+
94
+ h2. History
95
+
96
+ * 0.0.7 - Basic single line version
97
+ * 0.1.0 - Added support for multi-line output. Improved rendering of a
98
+ number of constructs
99
+
100
+
101
+
data/Rakefile CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  require 'rake/clean'
4
4
  require 'rake/testtask'
5
- require 'rake/rdoctask'
5
+ #require 'rdoc/task'
6
6
 
7
7
  require './lib/sorcerer/version'
8
8
 
9
9
  begin
10
10
  require 'rubygems'
11
- require 'rake/gempackagetask'
11
+ require 'rubygems/package_task'
12
12
  rescue Exception
13
13
  nil
14
14
  end
@@ -25,7 +25,7 @@ PKG_FILES = FileList[
25
25
  'lib/**/*.rb',
26
26
  'test/**/*.rb',
27
27
  ]
28
-
28
+
29
29
  BASE_RDOC_OPTIONS = [
30
30
  '--line-numbers', '--inline-source',
31
31
  '--main' , 'README.textile',
@@ -34,16 +34,17 @@ BASE_RDOC_OPTIONS = [
34
34
 
35
35
  task :default => :test
36
36
 
37
- rd = Rake::RDocTask.new("rdoc") do |rdoc|
38
- rdoc.rdoc_dir = 'html'
39
- rdoc.template = 'doc/jamis.rb'
40
- rdoc.title = "Sorcerer -- Its Like Magic"
41
- rdoc.options = BASE_RDOC_OPTIONS.dup
42
- rdoc.options << '-SHN' << '-f' << 'darkfish' if defined?(DARKFISH_ENABLED) && DARKFISH_ENABLED
43
-
44
- rdoc.rdoc_files.include('README.textile')
45
- rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc')
46
- rdoc.rdoc_files.exclude(/\bcontrib\b/)
37
+ RDOC_FILES = FileList['lib/**/*.rb', 'doc/**/*.rdoc'].exclude(/\bcontrib\b/)
38
+
39
+ if defined?(Rake::RDocTesk)
40
+ rd = Rake::RDocTask.new("rdoc") do |rdoc|
41
+ rdoc.rdoc_dir = 'html'
42
+ rdoc.template = 'doc/jamis.rb'
43
+ rdoc.title = "Sorcerer -- Its Like Magic"
44
+ rdoc.options = BASE_RDOC_OPTIONS.dup
45
+ rdoc.options << '-SHN' << '-f' << 'darkfish' if defined?(DARKFISH_ENABLED) && DARKFISH_ENABLED
46
+ rdoc.rdoc_files = RDOC_FILES
47
+ end
47
48
  end
48
49
 
49
50
  if ! defined?(Gem)
@@ -53,13 +54,11 @@ else
53
54
  s.name = 'sorcerer'
54
55
  s.version = PKG_VERSION
55
56
  s.summary = "Generate Source from Ripper ASTs"
56
- s.description = <<-EOF
57
- Generate the original Ruby source from a Ripper-style abstract syntax tree.
58
- EOF
59
- s.files = PKG_FILES.to_a
57
+ s.description = "Generate the original Ruby source from a Ripper-style abstract syntax tree."
58
+ s.files = PKG_FILES
60
59
  s.require_path = 'lib' # Use these for libraries.
61
60
  s.has_rdoc = true
62
- s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
61
+ s.extra_rdoc_files = RDOC_FILES.reject { |fn| fn =~ /\.rb$/ }.to_a
63
62
  s.rdoc_options = BASE_RDOC_OPTIONS
64
63
  s.author = "Jim Weirich"
65
64
  s.email = "jim.weirich@gmail.com"
@@ -67,7 +66,7 @@ else
67
66
  s.homepage = "http://github.com/jimweirich/sorcerer"
68
67
  end
69
68
 
70
- package_task = Rake::GemPackageTask.new(SPEC) do |pkg|
69
+ package_task = Gem::PackageTask.new(SPEC) do |pkg|
71
70
  pkg.need_zip = true
72
71
  pkg.need_tar = true
73
72
  end
@@ -1,7 +1,7 @@
1
1
  module Sorcerer
2
2
  # Generate the source code for teh given Ripper S-Expression.
3
- def self.source(sexp, debug=false)
4
- Sorcerer::Resource.new(sexp, debug).source
3
+ def self.source(sexp, options={})
4
+ Sorcerer::Resource.new(sexp, options).source
5
5
  end
6
6
 
7
7
  # Generate a list of interesting subexpressions for sexp.
@@ -2,62 +2,104 @@
2
2
 
3
3
  require 'ripper'
4
4
 
5
- module Sorcerer
5
+ module Sorcerer
6
6
  class Resource
7
- class NoHandlerError < StandardError
7
+ class SorcererError < StandardError
8
8
  end
9
-
10
- def initialize(sexp, debug=false)
9
+
10
+ class NoHandlerError < SorcererError
11
+ end
12
+
13
+ class NotSexpError < SorcererError
14
+ end
15
+
16
+ class UnexpectedSexpError < SorcererError
17
+ end
18
+
19
+ def initialize(sexp, options={})
11
20
  @sexp = sexp
12
21
  @source = ''
13
- @debug = debug
22
+ @debug = options[:debug]
23
+ @multiline = options[:multiline]
14
24
  @word_level = 0
25
+ @stack = []
15
26
  end
16
-
27
+
17
28
  def source
29
+ @stack.clear
18
30
  resource(@sexp)
19
31
  @source
20
32
  end
21
-
33
+
34
+ def sexp?(obj)
35
+ obj && obj.respond_to?(:each) && obj.first.is_a?(Symbol)
36
+ end
37
+
38
+ def nested_sexp?(obj)
39
+ obj && obj.respond_to?(:first) && sexp?(obj.first)
40
+ end
41
+
22
42
  def resource(sexp)
23
- return unless sexp
43
+ sexp = sexp.first if nested_sexp?(sexp)
44
+ fail NotSexpError, "Not an S-EXPER: #{sexp.inspect}" unless sexp?(sexp)
24
45
  handler = HANDLERS[sexp.first]
25
46
  raise NoHandlerError.new(sexp.first) unless handler
26
47
  if @debug
27
48
  puts "----------------------------------------------------------"
28
49
  pp sexp
29
50
  end
51
+ @stack.push(sexp.first)
30
52
  handler.call(self, sexp)
53
+ @stack.pop
31
54
  end
32
-
33
- def handle_block(sexp)
34
- resource(sexp[1]) # Arguments
55
+
56
+ def emit_block(sexp, do_word, end_word)
57
+ emit(" ")
58
+ emit(do_word)
59
+ resource(sexp[1]) if sexp[1] # Arguments
35
60
  if ! void?(sexp[2])
61
+ soft_newline
62
+ resource(sexp[2]) # Statements
63
+ end
64
+ if !void?(sexp[2])
65
+ soft_newline
66
+ else
36
67
  emit(" ")
37
- resource(sexp[2]) # Statements
38
68
  end
39
- emit(" ")
69
+ emit(end_word)
70
+ end
71
+
72
+ def params_have_parens?(sexp)
73
+ sexp.first == :arg_paren || sexp.first == :paren
40
74
  end
41
-
75
+
76
+ def params_are_empty?(sexp)
77
+ params = sexp
78
+ params = sexp[1] if sexp.first == :paren || sexp.first == :arg_paren
79
+ params[1].nil? || params[1].empty?
80
+ end
81
+
42
82
  def opt_parens(sexp)
43
- emit(" ") unless sexp.first == :arg_paren || sexp.first == :paren
83
+ if !params_have_parens?(sexp) && ! params_are_empty?(sexp)
84
+ emit(" ")
85
+ end
44
86
  resource(sexp)
45
87
  end
46
-
88
+
47
89
  def emit(string)
48
- puts "EMITTING '#{string}'" if @debug
90
+ puts "EMITTING '#{string}' (#{last_handler})" if @debug
49
91
  @source << string.to_s
50
92
  end
51
-
93
+
52
94
  def nyi(sexp)
53
95
  raise "Handler for #{sexp.first} not implemented (#{sexp.inspect})"
54
96
  end
55
-
97
+
56
98
  def emit_separator(sep, first)
57
99
  emit(sep) unless first
58
100
  false
59
101
  end
60
-
102
+
61
103
  def params(normal_args, default_args, rest_args, unknown, block_arg)
62
104
  first = true
63
105
  if normal_args
@@ -83,7 +125,7 @@ module Sorcerer
83
125
  resource(block_arg)
84
126
  end
85
127
  end
86
-
128
+
87
129
  def words(marker, sexp)
88
130
  emit("%#{marker}{") if @word_level == 0
89
131
  @word_level += 1
@@ -95,18 +137,62 @@ module Sorcerer
95
137
  @word_level -= 1
96
138
  emit("}") if @word_level == 0
97
139
  end
98
-
140
+
99
141
  VOID_STATEMENT = [:stmts_add, [:stmts_new], [:void_stmt]]
142
+ VOID_STATEMENT2 = [:stmts_add, [:stmts_new]]
100
143
  VOID_BODY = [:body_stmt, VOID_STATEMENT, nil, nil, nil]
101
144
  VOID_BODY2 = [:bodystmt, VOID_STATEMENT, nil, nil, nil]
102
-
145
+
103
146
  def void?(sexp)
104
147
  sexp.nil? ||
105
148
  sexp == VOID_STATEMENT ||
149
+ sexp == VOID_STATEMENT2 ||
106
150
  sexp == VOID_BODY ||
107
151
  sexp == VOID_BODY2
108
152
  end
109
-
153
+
154
+ def multiline?
155
+ @multiline
156
+ end
157
+
158
+ def last_handler
159
+ @stack.last
160
+ end
161
+
162
+ def newline
163
+ if multiline?
164
+ emit("\n")
165
+ else
166
+ emit("; ")
167
+ end
168
+ end
169
+
170
+ def soft_newline
171
+ if multiline?
172
+ emit("\n")
173
+ else
174
+ emit(" ")
175
+ end
176
+ end
177
+
178
+ BALANCED_DELIMS = {
179
+ '}' => '{',
180
+ ')' => '(',
181
+ '>' => '<',
182
+ ']' => '[',
183
+ }
184
+
185
+ def self.determine_regexp_delimiters(sexp)
186
+ sym, end_delim, other = sexp
187
+ fail UnexpectedSexpError, "Expected :@regexp_end, got #{sym.inspect}" unless sym == :@regexp_end
188
+ end_delim_char = end_delim[0]
189
+ first_delim = BALANCED_DELIMS[end_delim_char] || end_delim_char
190
+ if first_delim != '/'
191
+ first_delim = "%r#{first_delim}"
192
+ end
193
+ [first_delim, end_delim]
194
+ end
195
+
110
196
  NYI = lambda { |src, sexp| src.nyi(sexp) }
111
197
  DBG = lambda { |src, sexp| pp(sexp) }
112
198
  NOOP = lambda { |src, sexp| }
@@ -114,25 +200,31 @@ module Sorcerer
114
200
  PASS1 = lambda { |src, sexp| src.resource(sexp[1]) }
115
201
  PASS2 = lambda { |src, sexp| src.resource(sexp[2]) }
116
202
  EMIT1 = lambda { |src, sexp| src.emit(sexp[1]) }
117
-
203
+
118
204
  HANDLERS = {
119
205
  # parser keywords
120
-
206
+
121
207
  :BEGIN => lambda { |src, sexp|
122
208
  src.emit("BEGIN {")
123
- unless src.void?(sexp[1])
124
- src.emit(" ")
209
+ if src.void?(sexp[1])
210
+ src.emit " }"
211
+ else
212
+ src.soft_newline
125
213
  src.resource(sexp[1])
214
+ src.soft_newline
215
+ src.emit("}")
126
216
  end
127
- src.emit(" }")
128
217
  },
129
218
  :END => lambda { |src, sexp|
130
219
  src.emit("END {")
131
- unless src.void?(sexp[1])
132
- src.emit(" ")
220
+ if src.void?(sexp[1])
221
+ src.emit(" }")
222
+ else
223
+ src.soft_newline
133
224
  src.resource(sexp[1])
225
+ src.soft_newline
226
+ src.emit("}")
134
227
  end
135
- src.emit(" }")
136
228
  },
137
229
  :alias => lambda { |src, sexp|
138
230
  src.emit("alias ")
@@ -190,7 +282,7 @@ module Sorcerer
190
282
  :args_prepend => NYI,
191
283
  :array => lambda { |src, sexp|
192
284
  src.emit("[")
193
- src.resource(sexp[1])
285
+ src.resource(sexp[1]) if sexp[1]
194
286
  src.emit("]")
195
287
  },
196
288
  :assign => lambda { |src, sexp|
@@ -214,7 +306,7 @@ module Sorcerer
214
306
  },
215
307
  :bare_assoc_hash => lambda { |src, sexp|
216
308
  first = true
217
- sexp[1].each do |sx|
309
+ sexp[1].each do |sx|
218
310
  src.emit(", ") unless first
219
311
  first = false
220
312
  src.resource(sx)
@@ -222,7 +314,12 @@ module Sorcerer
222
314
  },
223
315
  :begin => lambda { |src, sexp|
224
316
  src.emit("begin")
225
- src.resource(sexp[1])
317
+ if src.void?(sexp[1])
318
+ src.emit(" ")
319
+ else
320
+ src.soft_newline
321
+ src.resource(sexp[1])
322
+ end
226
323
  src.emit("end")
227
324
  },
228
325
  :binary => lambda { |src, sexp|
@@ -243,14 +340,12 @@ module Sorcerer
243
340
  },
244
341
  :body_stmt => lambda { |src, sexp|
245
342
  src.resource(sexp[1]) # Main Body
246
- src.emit("; ")
247
- src.resource(sexp[2]) # Rescue
248
- src.resource(sexp[4]) # Ensure
343
+ src.newline unless src.void?(sexp[1])
344
+ src.resource(sexp[2]) if sexp[2] # Rescue
345
+ src.resource(sexp[4]) if sexp[4] # Ensure
249
346
  },
250
347
  :brace_block => lambda { |src, sexp|
251
- src.emit(" {")
252
- src.handle_block(sexp)
253
- src.emit("}")
348
+ src.emit_block(sexp, "{", "}")
254
349
  },
255
350
  :break => lambda { |src, sexp|
256
351
  src.emit("break")
@@ -265,9 +360,10 @@ module Sorcerer
265
360
  :case => lambda { |src, sexp|
266
361
  src.emit("case ")
267
362
  src.resource(sexp[1])
268
- src.emit(" ")
363
+ src.soft_newline
269
364
  src.resource(sexp[2])
270
- src.emit(" end")
365
+ src.newline
366
+ src.emit("end")
271
367
  },
272
368
  :class => lambda { |src, sexp|
273
369
  src.emit("class ")
@@ -276,7 +372,7 @@ module Sorcerer
276
372
  src.emit " < "
277
373
  src.resource(sexp[2])
278
374
  end
279
- src.emit("; ")
375
+ src.newline
280
376
  src.resource(sexp[3]) unless src.void?(sexp[3])
281
377
  src.emit("end")
282
378
  },
@@ -302,6 +398,7 @@ module Sorcerer
302
398
  src.emit("def ")
303
399
  src.resource(sexp[1])
304
400
  src.opt_parens(sexp[2])
401
+ src.newline
305
402
  src.resource(sexp[3])
306
403
  src.emit("end")
307
404
  },
@@ -312,9 +409,7 @@ module Sorcerer
312
409
  },
313
410
  :defs => NYI,
314
411
  :do_block => lambda { |src, sexp|
315
- src.emit(" do")
316
- src.handle_block(sexp)
317
- src.emit("end")
412
+ src.emit_block(sexp, "do", "end")
318
413
  },
319
414
  :dot2 => lambda { |src, sexp|
320
415
  src.resource(sexp[1])
@@ -332,21 +427,31 @@ module Sorcerer
332
427
  src.emit('"')
333
428
  },
334
429
  :else => lambda { |src, sexp|
335
- src.emit(" else ")
430
+ src.soft_newline
431
+ src.emit("else")
432
+ src.soft_newline
336
433
  src.resource(sexp[1])
337
434
  },
338
435
  :elsif => lambda { |src, sexp|
339
- src.emit(" elsif ")
436
+ src.soft_newline
437
+ src.emit("elsif ")
340
438
  src.resource(sexp[1])
341
- src.emit(" then ")
439
+ if src.multiline?
440
+ src.soft_newline
441
+ else
442
+ src.emit(" then ")
443
+ end
342
444
  src.resource(sexp[2])
343
- src.resource(sexp[3])
445
+ src.resource(sexp[3]) if sexp[3]
344
446
  },
345
447
  :ensure => lambda { |src, sexp|
346
- src.emit("ensure ")
347
- if sexp[1]
448
+ src.emit("ensure")
449
+ if src.void?(sexp[1])
450
+ src.soft_newline
451
+ else
452
+ src.soft_newline
348
453
  src.resource(sexp[1])
349
- src.emit("; ") unless src.void?(sexp[1])
454
+ src.newline unless src.void?(sexp[1])
350
455
  end
351
456
  },
352
457
  :excessed_comma => NYI,
@@ -370,16 +475,21 @@ module Sorcerer
370
475
  },
371
476
  :hash => lambda { |src, sexp|
372
477
  src.emit("{")
373
- src.resource(sexp[1])
478
+ src.resource(sexp[1]) if sexp[1]
374
479
  src.emit("}")
375
480
  },
376
481
  :if => lambda { |src, sexp|
377
482
  src.emit("if ")
378
483
  src.resource(sexp[1])
379
- src.emit(" then ")
484
+ if src.multiline?
485
+ src.newline
486
+ else
487
+ src.emit(" then ")
488
+ end
380
489
  src.resource(sexp[2])
381
- src.resource(sexp[3])
382
- src.emit(" end")
490
+ src.resource(sexp[3]) if sexp[3]
491
+ src.soft_newline
492
+ src.emit("end")
383
493
  },
384
494
  :if_mod => lambda { |src, sexp|
385
495
  src.resource(sexp[2])
@@ -438,8 +548,8 @@ module Sorcerer
438
548
  :module => lambda { |src, sexp|
439
549
  src.emit("module ")
440
550
  src.resource(sexp[1])
551
+ src.newline
441
552
  if src.void?(sexp[2])
442
- src.emit("; ")
443
553
  else
444
554
  src.resource(sexp[2])
445
555
  end
@@ -486,10 +596,12 @@ module Sorcerer
486
596
  :redo => lambda { |src, sexp|
487
597
  src.emit("redo")
488
598
  },
599
+ :regexp_add => PASS2,
489
600
  :regexp_literal => lambda { |src, sexp|
490
- src.emit("/")
601
+ delims = determine_regexp_delimiters(sexp[2])
602
+ src.emit(delims[0])
491
603
  src.resource(sexp[1])
492
- src.emit("/")
604
+ src.emit(delims[1])
493
605
  },
494
606
  :rescue => lambda { |src, sexp|
495
607
  src.emit("rescue")
@@ -501,17 +613,12 @@ module Sorcerer
501
613
  src.resource(sexp[1].first)
502
614
  end
503
615
  src.emit(" => ")
504
- src.resource(sexp[2])
616
+ src.resource(sexp[2])
505
617
  end
506
- src.emit(";")
507
- if sexp[3] # Rescue Code
508
- if src.void?(sexp[3])
509
- src.emit(" ")
510
- else
511
- src.emit(" ")
512
- src.resource(sexp[3])
513
- src.emit("; ")
514
- end
618
+ src.newline
619
+ if sexp[3] && ! src.void?(sexp[3])
620
+ src.resource(sexp[3])
621
+ src.newline
515
622
  end
516
623
  },
517
624
  :rescue_mod => lambda { |src, sexp|
@@ -528,18 +635,18 @@ module Sorcerer
528
635
  },
529
636
  :return => lambda { |src, sexp|
530
637
  src.emit("return")
531
- src.opt_parens(sexp[1])
638
+ src.opt_parens(sexp[1])
532
639
  },
533
640
  :return0 => lambda { |src, sexp|
534
641
  src.emit("return")
535
642
  },
536
643
  :sclass => NYI,
537
644
  :stmts_add => lambda { |src, sexp|
538
- if sexp[1] != [:stmts_new]
645
+ if sexp[1] != [:stmts_new] && ! src.void?(sexp[1])
539
646
  src.resource(sexp[1])
540
- src.emit("; ")
647
+ src.newline
541
648
  end
542
- src.resource(sexp[2])
649
+ src.resource(sexp[2]) if sexp[2]
543
650
  },
544
651
  :stmts_new => NOOP,
545
652
  :string_add => lambda { |src, sexp|
@@ -585,10 +692,15 @@ module Sorcerer
585
692
  :unless => lambda { |src, sexp|
586
693
  src.emit("unless ")
587
694
  src.resource(sexp[1])
588
- src.emit(" then ")
695
+ if src.multiline?
696
+ src.newline
697
+ else
698
+ src.emit(" then ")
699
+ end
589
700
  src.resource(sexp[2])
590
- src.resource(sexp[3])
591
- src.emit(" end")
701
+ src.resource(sexp[3]) if sexp[3]
702
+ src.soft_newline
703
+ src.emit("end")
592
704
  },
593
705
  :unless_mod => lambda { |src, sexp|
594
706
  src.resource(sexp[2])
@@ -614,19 +726,22 @@ module Sorcerer
614
726
  :when => lambda { |src, sexp|
615
727
  src.emit("when ")
616
728
  src.resource(sexp[1])
617
- src.emit("; ")
729
+ src.newline
618
730
  src.resource(sexp[2])
619
731
  if sexp[3] && sexp[3].first == :when
620
732
  src.emit(" ")
621
733
  end
622
- src.resource(sexp[3])
734
+ src.resource(sexp[3]) if sexp[3]
623
735
  },
624
736
  :while => lambda { |src, sexp|
625
737
  src.emit("while ")
626
738
  src.resource(sexp[1])
627
- src.emit(" do ")
628
- src.resource(sexp[2])
629
- src.emit(" end")
739
+ src.newline
740
+ unless src.void?(sexp[2])
741
+ src.resource(sexp[2])
742
+ src.newline
743
+ end
744
+ src.emit("end")
630
745
  },
631
746
  :while_mod => lambda { |src, sexp|
632
747
  src.resource(sexp[2])
@@ -659,9 +774,9 @@ module Sorcerer
659
774
  :zsuper => lambda { |src, sexp|
660
775
  src.emit("super")
661
776
  },
662
-
777
+
663
778
  # Scanner keywords
664
-
779
+
665
780
  :@CHAR => NYI,
666
781
  :@__end__ => NYI,
667
782
  :@backref => NYI,
@@ -711,5 +826,5 @@ module Sorcerer
711
826
  }
712
827
  HANDLERS[:bodystmt] = HANDLERS[:body_stmt]
713
828
  end
714
-
829
+
715
830
  end
@@ -1,7 +1,7 @@
1
1
  module Sorcerer
2
2
  VERSION_MAJOR = 0
3
- VERSION_MINOR = 0
4
- VERSION_BUILD = 7
3
+ VERSION_MINOR = 1
4
+ VERSION_BUILD = 0
5
5
  VERSION_BETA = 0
6
6
 
7
7
  VERSION_NUMBERS = [VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD] +
@@ -5,13 +5,13 @@ require 'ripper'
5
5
  require 'sorcerer'
6
6
 
7
7
  class SourcerTest < Test::Unit::TestCase
8
- def source(string, debug=false)
9
- if debug
8
+ def source(string, options={})
9
+ if options[:debug]
10
10
  puts
11
- puts "************************************************************"
11
+ puts "***************************** options: #{options.inspect}"
12
12
  end
13
13
  sexp = Ripper::SexpBuilder.new(string).parse
14
- Sorcerer.source(sexp, debug)
14
+ Sorcerer.source(sexp, options)
15
15
  end
16
16
 
17
17
  def test_can_source_variables
@@ -48,7 +48,7 @@ class SourcerTest < Test::Unit::TestCase
48
48
  assert_resource "obj.meth()"
49
49
  end
50
50
 
51
- def test_can_source_method_call_with_args
51
+ def test_can_source_method_call_with_args
52
52
  assert_resource "obj.meth(a)"
53
53
  assert_resource "obj.meth(a, b)"
54
54
  assert_resource "obj.meth(a, b, c)"
@@ -85,7 +85,7 @@ class SourcerTest < Test::Unit::TestCase
85
85
  assert_resource "meth &code"
86
86
  assert_resource "meth a, &code"
87
87
  assert_resource "meth a, *args, &code"
88
- assert_resource "meth a, *args do |x| x.y end"
88
+ assert_resource "meth a, *args do |x| x.y end",
89
89
  end
90
90
 
91
91
  def test_can_source_method_with_bare_assoc
@@ -96,14 +96,14 @@ class SourcerTest < Test::Unit::TestCase
96
96
  end
97
97
 
98
98
  def test_can_source_method_with_do_block
99
- assert_resource "meth do end"
100
- assert_resource "meth do |a| end"
101
- assert_resource "meth(x, y, *rest, &code) do |a, b=1, c=x, *args, &block| one; two; three end"
99
+ assert_resource_ml "meth do end"
100
+ assert_resource_ml "meth do |a| end"
101
+ assert_resource_ml "meth(x, y, *rest, &code) do |a, b=1, c=x, *args, &block|~one; two; three~end"
102
102
  end
103
103
 
104
104
  def test_can_source_method_with_block
105
105
  assert_resource "meth { }"
106
- assert_resource "meth { |a| }"
106
+ assert_resource "meth { |a| }"
107
107
  assert_resource "meth { |a, b| }"
108
108
  assert_resource "meth { |*args| }"
109
109
  assert_resource "meth { |a, *args| }"
@@ -138,7 +138,7 @@ class SourcerTest < Test::Unit::TestCase
138
138
  assert_resource "p.(a)"
139
139
  end
140
140
  end
141
-
141
+
142
142
  def test_can_source_numbers
143
143
  assert_resource "1"
144
144
  assert_resource "3.14"
@@ -178,12 +178,12 @@ class SourcerTest < Test::Unit::TestCase
178
178
  assert_resource '%W{a b c}'
179
179
  assert_resource '%W{Now is the time for all good men}'
180
180
  end
181
-
181
+
182
182
  def test_can_source_many_words
183
183
  assert_resource '[%w{a b}, %w{c d}]'
184
184
  assert_resource '[%W{a b}, %W{c d}]'
185
185
  end
186
-
186
+
187
187
  def test_can_source_symbols
188
188
  assert_resource ":sym"
189
189
  end
@@ -203,6 +203,19 @@ class SourcerTest < Test::Unit::TestCase
203
203
  assert_resource '/#{name}/'
204
204
  end
205
205
 
206
+ def test_can_source_regular_expressions_with_alternate_delimiters
207
+ assert_resource "%r{a}"
208
+ assert_resource "%r<a>"
209
+ assert_resource "%r[a]"
210
+ assert_resource "%r(a)"
211
+ assert_resource "%r|a|"
212
+ end
213
+
214
+ def test_can_source_regular_expressions_with_flags
215
+ assert_resource "%r{a}im"
216
+ assert_resource "/a/i"
217
+ end
218
+
206
219
  def test_can_source_range
207
220
  assert_resource "1..10"
208
221
  assert_resource "1...10"
@@ -252,7 +265,7 @@ class SourcerTest < Test::Unit::TestCase
252
265
  def test_can_source_trinary_expressions
253
266
  assert_resource "a ? b : c"
254
267
  end
255
-
268
+
256
269
  def test_can_source_complex_expressions
257
270
  assert_resource "a + 1 * 3"
258
271
  assert_resource "a + b"
@@ -308,41 +321,41 @@ class SourcerTest < Test::Unit::TestCase
308
321
  end
309
322
 
310
323
  def test_can_source_statement_sequences
311
- assert_resource "a"
312
- assert_resource "a; b"
313
- assert_resource "a; b; c"
324
+ assert_resource_ml "a"
325
+ assert_resource_ml "a; b"
326
+ assert_resource_ml "a; b; c"
314
327
  end
315
328
 
316
329
  def test_can_source_begin_end
317
- assert_resource "begin; end"
318
- assert_resource "begin; a; end"
319
- assert_resource "begin; a(); end"
320
- assert_resource "begin; a; b; c; end"
330
+ assert_resource_ml "begin end"
331
+ assert_resource_ml "begin~a; end"
332
+ assert_resource_ml "begin~a(); end"
333
+ assert_resource_ml "begin~a; b; c; end"
321
334
  end
322
335
 
323
336
  def test_can_source_begin_rescue_end
324
- assert_resource "begin; rescue; end"
325
- assert_resource "begin; rescue E => ex; b; end"
326
- assert_resource "begin; a; rescue E => ex; b; end"
327
- assert_resource "begin; a; rescue E, F => ex; b; end"
328
- assert_resource "begin; a; rescue E, F => ex; b; c; end"
329
- assert_resource "begin; rescue E, F => ex; b; c; end"
337
+ assert_resource_ml "begin~rescue; end"
338
+ assert_resource_ml "begin~rescue E => ex; b; end"
339
+ assert_resource_ml "begin~a; rescue E => ex; b; end"
340
+ assert_resource_ml "begin~a; rescue E, F => ex; b; end"
341
+ assert_resource_ml "begin~a; rescue E, F => ex; b; c; end"
342
+ assert_resource_ml "begin~rescue E, F => ex; b; c; end"
330
343
  end
331
344
 
332
345
  def test_can_source_begin_ensure_end
333
- assert_resource "begin; ensure end"
334
- assert_resource "begin; ensure b; end"
335
- assert_resource "begin; a; ensure b; end"
336
- assert_resource "begin; a; ensure ; b; end"
346
+ assert_resource_ml "begin~ensure~end"
347
+ assert_resource_ml "begin~ensure~b; end"
348
+ assert_resource_ml "begin~a; ensure~b; end"
349
+ assert_resource_ml "begin~a; ensure~b; end"
337
350
  end
338
351
 
339
352
  def test_can_source_begin_rescue_ensure_end
340
- assert_resource "begin; rescue; end"
341
- assert_resource "begin; rescue E => ex; b; ensure c; end"
342
- assert_resource "begin; a; rescue E => ex; b; ensure c; end"
343
- assert_resource "begin; a; rescue E, F => ex; b; ensure c; end"
344
- assert_resource "begin; a; rescue E, F => ex; b; c; ensure d; end"
345
- assert_resource "begin; rescue E, F => ex; b; c; ensure d; end"
353
+ assert_resource_ml "begin~rescue; end"
354
+ assert_resource_ml "begin~rescue E => ex; b; ensure~c; end"
355
+ assert_resource_ml "begin~a; rescue E => ex; b; ensure~c; end"
356
+ assert_resource_ml "begin~a; rescue E, F => ex; b; ensure~c; end"
357
+ assert_resource_ml "begin~a; rescue E, F => ex; b; c; ensure~d; end"
358
+ assert_resource_ml "begin~rescue E, F => ex; b; c; ensure~d; end"
346
359
  end
347
360
 
348
361
  def test_can_source_rescue_modifier
@@ -351,30 +364,37 @@ class SourcerTest < Test::Unit::TestCase
351
364
 
352
365
  def test_can_source_if
353
366
  assert_resource "if a then b end"
367
+ assert_resource "if a\nb\nend", multiline: true
354
368
  end
355
369
 
356
370
  def test_can_source_if_else
357
371
  assert_resource "if a then b else c end"
358
- end
359
-
360
- def test_can_source_if_elsif_else
361
- assert_resource "if a then b elsif c then d else e end"
372
+ assert_resource "if a\nb\nelse\nc\nend", multiline: true
362
373
  end
363
374
 
364
375
  def test_can_source_if_elsif
365
376
  assert_resource "if a then b elsif c then d end"
377
+ assert_resource "if a\nb\nelsif c\nd\nend", multiline: true
378
+ end
379
+
380
+ def test_can_source_if_elsif_else
381
+ assert_resource "if a then b elsif c then d else e end"
382
+ assert_resource "if a\nb\nelsif c\nd\nelse\ne\nend", multiline: true
366
383
  end
367
384
 
368
385
  def test_can_source_unless
369
386
  assert_resource "unless a then b end"
387
+ assert_resource "unless a\nb\nend", multiline: true
370
388
  end
371
389
 
372
390
  def test_can_source_unless_else
373
391
  assert_resource "unless a then b else c end"
392
+ assert_resource "unless a\nb\nelse\nc\nend", multiline: true
374
393
  end
375
394
 
376
395
  def test_can_source_while
377
- assert_resource "while c do body end"
396
+ assert_resource_ml "while c; end"
397
+ assert_resource_ml "while c; body; end"
378
398
  end
379
399
 
380
400
  def test_can_source_until
@@ -387,18 +407,19 @@ class SourcerTest < Test::Unit::TestCase
387
407
  end
388
408
 
389
409
  def test_can_source_break
390
- assert_resource "while c do a; break if b; c end"
391
- assert_resource "while c do a; break value if b; c end"
410
+ assert_resource_ml "while c; a; break if b; c; end"
411
+ assert_resource_ml "while c; a; break value if b; c; end"
392
412
  end
393
413
 
394
414
  def test_can_source_next
395
- assert_resource "while c do a; next if b; c end"
415
+ assert_resource_ml "while c; a; next if b; c; end"
416
+ assert_resource_ml "while c; a; next if b; c; end"
396
417
  end
397
418
 
398
419
  def test_can_source_case
399
- assert_resource "case a when b; c end"
400
- assert_resource "case a when b; c when d; e end"
401
- assert_resource "case a when b; c when d; e else f end"
420
+ assert_resource_ml "case a~when b; c; end"
421
+ assert_resource_ml "case a~when b; c when d; e; end"
422
+ assert_resource_ml "case a~when b; c when d; e~else~f; end"
402
423
  end
403
424
 
404
425
  def test_can_source_if_modifier
@@ -429,16 +450,16 @@ class SourcerTest < Test::Unit::TestCase
429
450
  def test_can_source_retry
430
451
  assert_resource "retry"
431
452
  end
432
-
453
+
433
454
  def test_can_source_redo
434
455
  assert_resource "redo"
435
456
  end
436
-
457
+
437
458
  def test_can_source_return
438
459
  assert_resource "return"
439
460
  assert_resource "return value"
440
461
  end
441
-
462
+
442
463
  def test_can_source_super
443
464
  assert_resource "super"
444
465
  assert_resource "super a"
@@ -457,72 +478,93 @@ class SourcerTest < Test::Unit::TestCase
457
478
  assert_resource "yield a"
458
479
  assert_resource "yield(a)"
459
480
  end
460
-
481
+
461
482
  def test_can_source_self
462
483
  assert_resource "self"
463
484
  end
464
485
 
465
486
  def test_can_source_def
466
- assert_resource "def f a; end"
467
- assert_resource "def f(); end"
468
- assert_resource "def f(a); end"
469
- assert_resource "def f(a, b); end"
470
- assert_resource "def f(a, *args); end"
471
- assert_resource "def f(a, *args, &block); end"
472
- assert_resource "def f(a); x; end"
473
- assert_resource "def f(a); x; y; end"
487
+ assert_resource_ml "def f; end"
488
+ assert_resource_ml "def f; x; end"
489
+ assert_resource_ml "def f a; end"
490
+ assert_resource_ml "def f(); end"
491
+ assert_resource_ml "def f(a); end"
492
+ assert_resource_ml "def f(a, b); end"
493
+ assert_resource_ml "def f(a, *args); end"
494
+ assert_resource_ml "def f(a, *args, &block); end"
495
+ assert_resource_ml "def f(a); x; end"
496
+ assert_resource_ml "def f(a); x; y; end"
474
497
  end
475
498
 
476
499
  def test_can_source_class_without_parent
477
- assert_resource "class X; end"
478
- assert_resource "class X; x; end"
479
- assert_resource "class X; def f(); end; end"
500
+ assert_resource_ml "class X; end"
501
+ assert_resource_ml "class X; x; end"
502
+ assert_resource_ml "class X; def f(); end; end"
480
503
  end
481
504
 
482
505
  def test_can_source_class_with_parent
483
- assert_resource "class X < Y; end"
484
- assert_resource "class X < Y; x; end"
506
+ assert_resource_ml "class X < Y; end"
507
+ assert_resource_ml "class X < Y; x; end"
485
508
  end
486
509
 
487
510
  def test_can_source_class_with_self_parent
488
- assert_resource "class X < self; end"
511
+ assert_resource_ml "class X < self; end"
489
512
  end
490
513
 
491
514
  def test_can_source_private_etc_in_class
492
- assert_resource "class X; public; def f(); end; end"
493
- assert_resource "class X; protected; def f(); end; end"
494
- assert_resource "class X; private; def f(); end; end"
495
- assert_resource "class X; def f(); end; public :f; end"
496
- assert_resource "class X; def f(); end; protected :f; end"
497
- assert_resource "class X; def f(); end; private :f; end"
515
+ assert_resource_ml "class X; public; def f(); end; end"
516
+ assert_resource_ml "class X; protected; def f(); end; end"
517
+ assert_resource_ml "class X; private; def f(); end; end"
518
+ assert_resource_ml "class X; def f(); end; public :f; end"
519
+ assert_resource_ml "class X; def f(); end; protected :f; end"
520
+ assert_resource_ml "class X; def f(); end; private :f; end"
498
521
  end
499
522
 
500
523
  def test_can_source_module
501
- assert_resource "module X; end"
502
- assert_resource "module X; x; end"
503
- assert_resource "module X; def f(); end; end"
524
+ assert_resource_ml "module X; end"
525
+ assert_resource_ml "module X; x; end"
526
+ assert_resource_ml "module X; def f(); end; end"
504
527
  end
505
528
 
506
529
  def test_can_source_BEGIN
507
- assert_resource "BEGIN { }"
508
- assert_resource "BEGIN { x }"
509
- assert_resource "BEGIN { x; y }"
530
+ assert_resource_ml "BEGIN { }"
531
+ assert_resource_ml "BEGIN {~x~}"
532
+ assert_resource_ml "BEGIN {~x; y~}"
510
533
  end
511
534
 
512
535
  def test_can_source_END
513
- assert_resource "END { }"
514
- assert_resource "END { x }"
515
- assert_resource "END { x; y }"
536
+ assert_resource_ml "END { }"
537
+ assert_resource_ml "END {~x~}"
538
+ assert_resource_ml "END {~x; y~}"
516
539
  end
517
540
 
518
541
  def test_can_source_then
519
- assert_resource "Then { a == b }"
542
+ assert_resource_ml "Then {~a == b~}"
543
+ assert_resource_ml "Then {~a == b; x~}"
544
+ end
545
+
546
+ def test_can_use_ripper_sexp_output
547
+ sexp = Ripper.sexp("a = 1")
548
+ assert_equal "a = 1", Sorcerer.source(sexp)
549
+ end
550
+
551
+ def test_can_handle_missing_statements
552
+ sexp = [:bodystmt, [:stmts_add, [:stmts_new]], nil, nil, nil]
553
+ assert_equal "", Sorcerer.source(sexp)
520
554
  end
521
555
 
522
556
  private
523
557
 
524
- def assert_resource(string, debug=nil)
525
- assert_equal string, source(string, debug)
558
+ def assert_resource(string, options={})
559
+ assert_equal string, source(string, options)
526
560
  end
527
-
561
+
562
+ def assert_resource_ml(string, options={})
563
+ expected = string.gsub(/~/, " ")
564
+ assert_equal expected, source(expected, options)
565
+
566
+ expected_ml = string.gsub(/~/, "\n").gsub(/; /, "\n")
567
+ assert_equal expected_ml, source(expected_ml, {multiline: true}.merge(options))
568
+ end
569
+
528
570
  end
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sorcerer
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 7
9
- version: 0.0.7
4
+ prerelease:
5
+ version: 0.1.0
10
6
  platform: ruby
11
7
  authors:
12
8
  - Jim Weirich
@@ -14,18 +10,17 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2010-04-23 00:00:00 -04:00
18
- default_executable:
13
+ date: 2012-07-01 00:00:00 Z
19
14
  dependencies: []
20
15
 
21
- description: " Generate the original Ruby source from a Ripper-style abstract syntax tree.\n"
16
+ description: Generate the original Ruby source from a Ripper-style abstract syntax tree.
22
17
  email: jim.weirich@gmail.com
23
18
  executables: []
24
19
 
25
20
  extensions: []
26
21
 
27
- extra_rdoc_files:
28
- - README.textile
22
+ extra_rdoc_files: []
23
+
29
24
  files:
30
25
  - README.textile
31
26
  - Rakefile
@@ -39,7 +34,6 @@ files:
39
34
  - lib/sorcerer.rb
40
35
  - test/sorcerer/resource_test.rb
41
36
  - test/sorcerer/subexpression_test.rb
42
- has_rdoc: true
43
37
  homepage: http://github.com/jimweirich/sorcerer
44
38
  licenses: []
45
39
 
@@ -54,23 +48,21 @@ rdoc_options:
54
48
  require_paths:
55
49
  - lib
56
50
  required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
57
52
  requirements:
58
53
  - - ">="
59
54
  - !ruby/object:Gem::Version
60
- segments:
61
- - 0
62
55
  version: "0"
63
56
  required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
64
58
  requirements:
65
59
  - - ">="
66
60
  - !ruby/object:Gem::Version
67
- segments:
68
- - 0
69
61
  version: "0"
70
62
  requirements: []
71
63
 
72
64
  rubyforge_project: sorcerer
73
- rubygems_version: 1.3.6
65
+ rubygems_version: 1.8.15
74
66
  signing_key:
75
67
  specification_version: 3
76
68
  summary: Generate Source from Ripper ASTs