live_ast_ruby_parser 0.5.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.rdoc ADDED
@@ -0,0 +1,10 @@
1
+
2
+ = live_ast_ruby_parser ChangeLog
3
+
4
+ == Version 0.4.0
5
+
6
+ * new parser plugin design to work around obscure autoload failure
7
+
8
+ == Version 0.3.0
9
+
10
+ * initial release
data/MANIFEST ADDED
@@ -0,0 +1,8 @@
1
+ CHANGES.rdoc
2
+ MANIFEST
3
+ README.rdoc
4
+ Rakefile
5
+ devel/jumpstart.rb
6
+ lib/live_ast_ruby_parser.rb
7
+ lib/live_ast_ruby_parser/test_forms.rb
8
+ lib/live_ast_ruby_parser/unparser.rb
data/README.rdoc ADDED
@@ -0,0 +1,47 @@
1
+
2
+ = live_ast_ruby_parser
3
+
4
+ == Summary
5
+
6
+ This is the default RubyParser-based parser used by LiveAST.
7
+
8
+ == Description
9
+
10
+ The nested TestForms module enables testing with the LiveAST test
11
+ suite. The Unparser module is used by +to_ruby+.
12
+
13
+ == Links
14
+
15
+ * Home: http://quix.github.com/live_ast_ruby_parser
16
+ * Feature Requests, Bug Reports: http://github.com/quix/live_ast_ruby_parser/issues
17
+ * Manual Download: http://github.com/quix/live_ast_ruby_parser/archives/master
18
+ * Repository: http://github.com/quix/live_ast_ruby_parser
19
+
20
+ == Author
21
+
22
+ * James M. Lawrence < quixoticsycophant@gmail.com >
23
+
24
+ == License
25
+
26
+ Copyright (c) 2011 James M. Lawrence. All rights reserved.
27
+
28
+ Permission is hereby granted, free of charge, to any person
29
+ obtaining a copy of this software and associated documentation files
30
+ (the "Software"), to deal in the Software without restriction,
31
+ including without limitation the rights to use, copy, modify, merge,
32
+ publish, distribute, sublicense, and/or sell copies of the Software,
33
+ and to permit persons to whom the Software is furnished to do so,
34
+ subject to the following conditions:
35
+
36
+ The above copyright notice and this permission notice shall be
37
+ included in all copies or substantial portions of the Software.
38
+
39
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
40
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
41
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
42
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
43
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
44
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
45
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
46
+ SOFTWARE.
47
+
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require_relative 'devel/jumpstart'
2
+
3
+ Jumpstart.new "live_ast_ruby_parser" do |s|
4
+ s.developers << ["James M. Lawrence", "quixoticsycophant@gmail.com"]
5
+ s.github_user = "quix"
6
+ s.version = "0.5.0"
7
+
8
+ # my code compensates for a ruby_parser bug; make this equal for now
9
+ s.dependencies << ["ruby_parser", "= 2.0.6"]
10
+
11
+ s.dependencies << ["ruby2ruby"]
12
+ end
13
+
14
+ # testing done inside live_ast
15
+ task :test do
16
+ end
17
+
@@ -0,0 +1,901 @@
1
+
2
+ class Jumpstart
3
+ class Installer
4
+ def initialize
5
+ require 'fileutils'
6
+ require 'rbconfig'
7
+ require 'find'
8
+ dest_root = RbConfig::CONFIG["sitelibdir"]
9
+ sources = []
10
+ Find.find("./lib") { |source|
11
+ if install_file?(source)
12
+ sources << source
13
+ end
14
+ }
15
+ @spec = sources.inject(Array.new) { |acc, source|
16
+ if source == "./lib"
17
+ acc
18
+ else
19
+ dest = File.join(dest_root, source.sub(%r!\A\./lib!, ""))
20
+
21
+ install = lambda {
22
+ if File.directory?(source)
23
+ unless File.directory?(dest)
24
+ puts "mkdir #{dest}"
25
+ FileUtils.mkdir(dest)
26
+ end
27
+ else
28
+ puts "install #{source} --> #{dest}"
29
+ FileUtils.install(source, dest)
30
+ end
31
+ }
32
+
33
+ uninstall = lambda {
34
+ if File.directory?(source)
35
+ if File.directory?(dest)
36
+ puts "rmdir #{dest}"
37
+ FileUtils.rmdir(dest)
38
+ end
39
+ else
40
+ if File.file?(dest)
41
+ puts "rm #{dest}"
42
+ FileUtils.rm(dest)
43
+ end
44
+ end
45
+ }
46
+
47
+ acc << {
48
+ :source => source,
49
+ :dest => dest,
50
+ :install => install,
51
+ :uninstall => uninstall,
52
+ }
53
+ end
54
+ }
55
+ end
56
+
57
+ def install_file?(source)
58
+ File.directory?(source) or
59
+ (File.file?(source) and File.extname(source) == ".rb")
60
+ end
61
+
62
+ def install
63
+ @spec.each { |entry|
64
+ entry[:install].call
65
+ }
66
+ end
67
+
68
+ def uninstall
69
+ @spec.reverse.each { |entry|
70
+ entry[:uninstall].call
71
+ }
72
+ end
73
+
74
+ def run(args = ARGV)
75
+ if args.empty?
76
+ install
77
+ elsif args.size == 1 and args.first == "--uninstall"
78
+ uninstall
79
+ else
80
+ raise "unrecognized arguments: #{args.inspect}"
81
+ end
82
+ end
83
+ end
84
+
85
+ module AttrLazy
86
+ def attr_lazy(name, &block)
87
+ AttrLazy.define_reader(class << self ; self ; end, name, &block)
88
+ end
89
+
90
+ def attr_lazy_accessor(name, &block)
91
+ attr_lazy(name, &block)
92
+ AttrLazy.define_writer(class << self ; self ; end, name, &block)
93
+ end
94
+
95
+ class << self
96
+ def included(mod)
97
+ (class << mod ; self ; end).class_eval do
98
+ def attr_lazy(name, &block)
99
+ AttrLazy.define_reader(self, name, &block)
100
+ end
101
+
102
+ def attr_lazy_accessor(name, &block)
103
+ attr_lazy(name, &block)
104
+ AttrLazy.define_writer(self, name, &block)
105
+ end
106
+ end
107
+ end
108
+
109
+ def define_evaluated_reader(instance, name, value)
110
+ (class << instance ; self ; end).class_eval do
111
+ remove_method name rescue nil
112
+ define_method name do
113
+ value
114
+ end
115
+ end
116
+ end
117
+
118
+ def define_reader(klass, name, &block)
119
+ klass.class_eval do
120
+ remove_method name rescue nil
121
+ define_method name do
122
+ value = instance_eval(&block)
123
+ AttrLazy.define_evaluated_reader(self, name, value)
124
+ value
125
+ end
126
+ end
127
+ end
128
+
129
+ def define_writer(klass, name, &block)
130
+ klass.class_eval do
131
+ writer = "#{name}="
132
+ remove_method writer rescue nil
133
+ define_method writer do |value|
134
+ AttrLazy.define_evaluated_reader(self, name, value)
135
+ value
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ module Ruby
143
+ module_function
144
+
145
+ def executable
146
+ require 'rbconfig'
147
+
148
+ name = File.join(
149
+ RbConfig::CONFIG["bindir"],
150
+ RbConfig::CONFIG["RUBY_INSTALL_NAME"]
151
+ )
152
+
153
+ if RbConfig::CONFIG["host"] =~ %r!(mswin|cygwin|mingw)! and
154
+ File.basename(name) !~ %r!\.(exe|com|bat|cmd)\Z!i
155
+ name + RbConfig::CONFIG["EXEEXT"]
156
+ else
157
+ name
158
+ end
159
+ end
160
+
161
+ def run(*args)
162
+ cmd = [executable, *args]
163
+ unless system(*cmd)
164
+ cmd_str = cmd.map { |t| "'#{t}'" }.join(", ")
165
+ raise "system(#{cmd_str}) failed with status #{$?.exitstatus}"
166
+ end
167
+ end
168
+
169
+ def run_code_and_capture(code)
170
+ IO.popen(%{"#{executable}"}, "r+") { |pipe|
171
+ pipe.print(code)
172
+ pipe.flush
173
+ pipe.close_write
174
+ pipe.read
175
+ }
176
+ end
177
+
178
+ def run_file_and_capture(file)
179
+ unless File.file? file
180
+ raise "file does not exist: `#{file}'"
181
+ end
182
+ IO.popen(%{"#{executable}" "#{file}"}, "r") { |pipe|
183
+ pipe.read
184
+ }
185
+ end
186
+
187
+ def with_warnings(value = true)
188
+ previous = $VERBOSE
189
+ $VERBOSE = value
190
+ begin
191
+ yield
192
+ ensure
193
+ $VERBOSE = previous
194
+ end
195
+ end
196
+
197
+ def no_warnings(&block)
198
+ with_warnings(nil, &block)
199
+ end
200
+ end
201
+
202
+ module Util
203
+ module_function
204
+
205
+ def run_ruby_on_each(*files)
206
+ files.each { |file|
207
+ Ruby.run("-w", file)
208
+ }
209
+ end
210
+
211
+ def to_camel_case(str)
212
+ str.split('_').map { |t| t.capitalize }.join
213
+ end
214
+
215
+ def write_file(file)
216
+ contents = yield
217
+ File.open(file, "wb") { |out|
218
+ out.print(contents)
219
+ }
220
+ contents
221
+ end
222
+ end
223
+
224
+ module InstanceEvalWithArgs
225
+ module_function
226
+
227
+ def with_temp_method(instance, method_name, method_block)
228
+ (class << instance ; self ; end).class_eval do
229
+ define_method(method_name, &method_block)
230
+ begin
231
+ yield method_name
232
+ ensure
233
+ remove_method(method_name)
234
+ end
235
+ end
236
+ end
237
+
238
+ def call_temp_method(instance, method_name, *args, &method_block)
239
+ with_temp_method(instance, method_name, method_block) {
240
+ instance.send(method_name, *args)
241
+ }
242
+ end
243
+
244
+ def instance_eval_with_args(instance, *args, &block)
245
+ call_temp_method(instance, :__temp_method, *args, &block)
246
+ end
247
+ end
248
+
249
+ include AttrLazy
250
+ include Util
251
+
252
+ def initialize(project_name)
253
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
254
+
255
+ require 'rubygems/package_task'
256
+
257
+ @project_name = project_name
258
+
259
+ yield self
260
+
261
+ self.class.instance_methods(false).select { |t|
262
+ t.to_s =~ %r!\Adefine_!
263
+ }.sort.each { |method_name|
264
+ send(method_name)
265
+ }
266
+ end
267
+
268
+ class << self
269
+ alias_method :attribute, :attr_lazy_accessor
270
+ end
271
+
272
+ attribute :name do
273
+ @project_name
274
+ end
275
+
276
+ attribute :version_constant_name do
277
+ "VERSION"
278
+ end
279
+
280
+ attribute :camel_name do
281
+ to_camel_case(name)
282
+ end
283
+
284
+ attribute :version do
285
+ catch :bail do
286
+ if File.file?(version_file = "./lib/#{name}/version.rb")
287
+ require version_file
288
+ elsif File.file?("./lib/#{name}.rb")
289
+ require name
290
+ else
291
+ throw :bail
292
+ end
293
+ mod = Kernel.const_get(camel_name)
294
+ constants = mod.constants.map { |t| t.to_sym }
295
+ unless constants.include?(version_constant_name.to_sym)
296
+ throw :bail
297
+ end
298
+ mod.const_get(version_constant_name)
299
+ end or "0.0.0"
300
+ end
301
+
302
+ attribute :readme_file do
303
+ "README.rdoc"
304
+ end
305
+
306
+ attribute :history_file do
307
+ "CHANGES.rdoc"
308
+ end
309
+
310
+ attribute :doc_dir do
311
+ "doc"
312
+ end
313
+
314
+ attribute :spec_files do
315
+ Dir["./spec/*_{spec,example}.rb"]
316
+ end
317
+
318
+ attribute :test_files do
319
+ (Dir["./test/test_*.rb"] + Dir["./test/*_test.rb"]).uniq
320
+ end
321
+
322
+ attribute :cov_dir do
323
+ "coverage"
324
+ end
325
+
326
+ attribute :spec_output_dir do
327
+ "rspec_output"
328
+ end
329
+
330
+ attribute :spec_output_file do
331
+ "spec.html"
332
+ end
333
+
334
+ attr_lazy :spec_output do
335
+ "#{spec_output_dir}/#{spec_output_file}"
336
+ end
337
+
338
+ [:gem, :tgz].each { |ext|
339
+ attribute ext do
340
+ "pkg/#{name}-#{version}.#{ext}"
341
+ end
342
+ }
343
+
344
+ attribute :rcov_options do
345
+ # workaround for the default rspec task
346
+ Dir["*"].select { |f| File.directory? f }.inject(Array.new) { |acc, dir|
347
+ if dir == "lib"
348
+ acc
349
+ else
350
+ acc + ["--exclude", dir + "/"]
351
+ end
352
+ } + ["--text-report"]
353
+ end
354
+
355
+ attribute :readme_file do
356
+ "README.rdoc"
357
+ end
358
+
359
+ attribute :manifest_file do
360
+ "MANIFEST"
361
+ end
362
+
363
+ attribute :generated_files do
364
+ []
365
+ end
366
+
367
+ attribute :files do
368
+ if File.file? manifest_file
369
+ File.read(manifest_file).split("\n")
370
+ elsif source_control?
371
+ IO.popen("git ls-files") { |pipe| pipe.read.split "\n" }
372
+ end.to_a + [manifest_file] + generated_files
373
+ end
374
+
375
+ def files_in_require_paths
376
+ require_paths.inject([]) { |acc, dir|
377
+ acc + Dir.glob("#{dir}/**/*.rb")
378
+ }
379
+ end
380
+
381
+ attribute :rdoc_files do
382
+ files_in_require_paths
383
+ end
384
+
385
+ attribute :rdoc_title do
386
+ "#{name}: #{summary}"
387
+ end
388
+
389
+ attribute :require_paths do
390
+ ["lib"]
391
+ end
392
+
393
+ attribute :rdoc_options do
394
+ if File.file?(readme_file)
395
+ ["--main", readme_file]
396
+ else
397
+ []
398
+ end + [
399
+ "--title", rdoc_title,
400
+ ] + (files_in_require_paths - rdoc_files).inject(Array.new) {
401
+ |acc, file|
402
+ acc + ["--exclude", file]
403
+ }
404
+ end
405
+
406
+ attribute :extra_rdoc_files do
407
+ File.file?(readme_file) ? [readme_file] : []
408
+ end
409
+
410
+ attribute :browser do
411
+ require 'rbconfig'
412
+ if RbConfig::CONFIG["host"] =~ %r!darwin!
413
+ "open"
414
+ else
415
+ "firefox"
416
+ end
417
+ end
418
+
419
+ attribute :gemspec do
420
+ Gem::Specification.new do |g|
421
+ g.has_rdoc = true
422
+ %w[
423
+ name
424
+ authors
425
+ email
426
+ summary
427
+ version
428
+ description
429
+ files
430
+ rdoc_options
431
+ extra_rdoc_files
432
+ require_paths
433
+ ].each { |param|
434
+ value = send(param) and (
435
+ g.send("#{param}=", value)
436
+ )
437
+ }
438
+
439
+ g.homepage = url if url
440
+
441
+ dependencies.each { |dep|
442
+ g.add_dependency(*dep)
443
+ }
444
+
445
+ development_dependencies.each { |dep|
446
+ g.add_development_dependency(*dep)
447
+ }
448
+ end
449
+ end
450
+
451
+ attribute :readme_contents do
452
+ File.read(readme_file) rescue "FIXME: readme_file"
453
+ end
454
+
455
+ attribute :sections do
456
+ begin
457
+ data = readme_contents.split(%r!^==\s*(.*?)\s*$!)
458
+ pairs = data[1..-1].each_slice(2).map { |section, contents|
459
+ [section.downcase, contents.strip]
460
+ }
461
+ Hash[*pairs.flatten]
462
+ rescue
463
+ nil
464
+ end
465
+ end
466
+
467
+ attribute :description_section do
468
+ "description"
469
+ end
470
+
471
+ attribute :summary_section do
472
+ "summary"
473
+ end
474
+
475
+ attribute :description_sentences do
476
+ 1
477
+ end
478
+
479
+ attribute :summary_sentences do
480
+ 1
481
+ end
482
+
483
+ [:summary, :description].each { |section|
484
+ attribute section do
485
+ begin
486
+ sections[send("#{section}_section")].
487
+ gsub("\n", " ").
488
+ split(%r!\.\s*!m).
489
+ first(send("#{section}_sentences")).
490
+ join(". ") << "."
491
+ rescue
492
+ "FIXME: #{section}"
493
+ end
494
+ end
495
+ }
496
+
497
+ attribute :url do
498
+ "http://#{github_user}.github.com/#{name}"
499
+ end
500
+
501
+ attribute :github_user do
502
+ raise "github_user not set"
503
+ end
504
+
505
+ attribute :rubyforge_info do
506
+ nil
507
+ end
508
+
509
+ attribute :authors do
510
+ developers.map { |d| d[0] }
511
+ end
512
+
513
+ attribute :email do
514
+ developers.map { |d| d[1] }
515
+ end
516
+
517
+ attribute :dependencies do
518
+ []
519
+ end
520
+
521
+ attribute :development_dependencies do
522
+ []
523
+ end
524
+
525
+ attribute :developers do
526
+ []
527
+ end
528
+
529
+ def define_clean
530
+ require 'rake/clean'
531
+ task :clean do
532
+ Rake::Task[:clobber].invoke
533
+ end
534
+ end
535
+
536
+ def define_package
537
+ if source_control?
538
+ task manifest_file do
539
+ create_manifest
540
+ end
541
+ CLEAN.add manifest_file
542
+ task :package => :clean
543
+ Gem::PackageTask.new(gemspec).define
544
+ end
545
+ end
546
+
547
+ def define_spec
548
+ unless spec_files.empty?
549
+ Ruby.no_warnings {
550
+ require 'spec/rake/spectask'
551
+ }
552
+
553
+ desc "run specs"
554
+ Spec::Rake::SpecTask.new('spec') do |t|
555
+ t.spec_files = spec_files
556
+ end
557
+
558
+ desc "run specs with text output"
559
+ Spec::Rake::SpecTask.new('text_spec') do |t|
560
+ t.spec_files = spec_files
561
+ t.spec_opts = ['-fs']
562
+ end
563
+
564
+ desc "run specs with html output"
565
+ Spec::Rake::SpecTask.new('full_spec') do |t|
566
+ t.spec_files = spec_files
567
+ t.rcov = true
568
+ t.rcov_opts = rcov_options
569
+ t.spec_opts = ["-fh:#{spec_output}"]
570
+ end
571
+
572
+ suppress_task_warnings :spec, :full_spec, :text_spec
573
+
574
+ desc "run full_spec then open browser"
575
+ task :show_spec => :full_spec do
576
+ open_browser(spec_output, cov_dir + "/index.html")
577
+ end
578
+
579
+ desc "run specs individually"
580
+ task :spec_deps do
581
+ run_ruby_on_each(*spec_files)
582
+ end
583
+
584
+ task :prerelease => [:spec, :spec_deps]
585
+ task :default => :spec
586
+
587
+ CLEAN.add spec_output_dir
588
+ end
589
+ end
590
+
591
+ def define_test
592
+ unless test_files.empty?
593
+ desc "run tests"
594
+ task :test do
595
+ test_files.each { |file| require file }
596
+
597
+ # if we use at_exit hook instead, it won't run before :release
598
+ MiniTest::Unit.new.run ARGV
599
+ end
600
+
601
+ desc "run tests with coverage"
602
+ if ruby_18?
603
+ task :full_test do
604
+ verbose(false) {
605
+ sh("rcov", "-o", cov_dir, "--text-report",
606
+ *(test_files + rcov_options)
607
+ )
608
+ }
609
+ end
610
+ else
611
+ task :full_test do
612
+ rm_rf cov_dir
613
+ require 'simplecov'
614
+ SimpleCov.start do
615
+ add_filter "test/"
616
+ add_filter "devel/"
617
+ end
618
+ Rake::Task[:test].invoke
619
+ end
620
+ end
621
+
622
+ desc "run full_test then open browser"
623
+ task :show_test => :full_test do
624
+ show = lambda { open_browser(cov_dir + "/index.html") }
625
+ if ruby_18?
626
+ show.call
627
+ else
628
+ SimpleCov.at_exit do
629
+ SimpleCov.result.format!
630
+ show.call
631
+ end
632
+ end
633
+ end
634
+
635
+ desc "run tests individually"
636
+ task :test_deps do
637
+ run_ruby_on_each(*test_files)
638
+ end
639
+
640
+ task :prerelease => [:test, :test_deps]
641
+ task :default => :test
642
+
643
+ CLEAN.add cov_dir
644
+ end
645
+ end
646
+
647
+ def define_doc
648
+ desc "run rdoc"
649
+ task :doc => :clean_doc do
650
+ Kernel.send :gem, 'rdoc' rescue nil
651
+ require 'rdoc/rdoc'
652
+ args = (
653
+ gemspec.rdoc_options +
654
+ gemspec.require_paths.clone +
655
+ gemspec.extra_rdoc_files +
656
+ ["-o", doc_dir]
657
+ ).flatten.map { |t| t.to_s }
658
+ RDoc::RDoc.new.document args
659
+ end
660
+
661
+ task :clean_doc do
662
+ # normally rm_rf, but mimic rake/clean output
663
+ rm_r(doc_dir) rescue nil
664
+ end
665
+
666
+ desc "run rdoc then open browser"
667
+ task :show_doc => :doc do
668
+ open_browser(doc_dir + "/index.html")
669
+ end
670
+
671
+ task :rdoc => :doc
672
+ task :clean => :clean_doc
673
+ end
674
+
675
+ def define_publish
676
+ if source_control?
677
+ desc "publish docs"
678
+ task :publish => [:clean, :check_directory, :doc] do
679
+ if rubyforge_info
680
+ user, project = rubyforge_info
681
+ Dir.chdir(doc_dir) do
682
+ sh "scp", "-r",
683
+ ".",
684
+ "#{user}@rubyforge.org:/var/www/gforge-projects/#{project}"
685
+ end
686
+ end
687
+ git "branch", "-D", "gh-pages"
688
+ git "checkout", "--orphan", "gh-pages"
689
+ FileUtils.rm ".git/index"
690
+ git "clean", "-fdx", "-e", "doc"
691
+ Dir["doc/*"].each { |path|
692
+ FileUtils.mv path, "."
693
+ }
694
+ FileUtils.rmdir "doc"
695
+ git "add", "."
696
+ git "commit", "-m", "generated by rdoc"
697
+ git "push", "-f", "origin", "gh-pages"
698
+ end
699
+ end
700
+ end
701
+
702
+ def define_install
703
+ desc "direct install (no gem)"
704
+ task :install do
705
+ Installer.new.run([])
706
+ end
707
+
708
+ desc "direct uninstall (no gem)"
709
+ task :uninstall do
710
+ Installer.new.run(["--uninstall"])
711
+ end
712
+ end
713
+
714
+ def define_check_directory
715
+ task :check_directory do
716
+ unless `git status` =~ %r!nothing to commit \(working directory clean\)!
717
+ raise "directory not clean"
718
+ end
719
+ end
720
+ end
721
+
722
+ def define_ping
723
+ task :ping do
724
+ require 'rbconfig'
725
+ %w[github.com].each { |server|
726
+ cmd = "ping " + (
727
+ if RbConfig::CONFIG["host"] =~ %r!darwin!
728
+ "-c2 #{server}"
729
+ else
730
+ "#{server} 2 2"
731
+ end
732
+ )
733
+ unless `#{cmd}` =~ %r!0% packet loss!
734
+ raise "No ping for #{server}"
735
+ end
736
+ }
737
+ end
738
+ end
739
+
740
+ def git(*args)
741
+ sh "git", *args
742
+ end
743
+
744
+ def create_manifest
745
+ write_file(manifest_file) {
746
+ files.sort.join("\n")
747
+ }
748
+ end
749
+
750
+ def define_release
751
+ task :prerelease => [:clean, :check_directory, :ping, history_file]
752
+
753
+ task :finish_release do
754
+ git "tag", "#{name}-" + version.to_s
755
+ git "push", "--tags", "origin", "master"
756
+ sh "gem", "push", gem
757
+ end
758
+
759
+ task :release => [:prerelease, :package, :finish_release]
760
+ end
761
+
762
+ def define_debug_gem
763
+ task :debug_gem do
764
+ puts gemspec.to_ruby
765
+ end
766
+ end
767
+
768
+ def open_browser(*files)
769
+ sh(*([browser].flatten + files))
770
+ end
771
+
772
+ def suppress_task_warnings(*task_names)
773
+ task_names.each { |task_name|
774
+ Rake::Task[task_name].actions.map! { |action|
775
+ lambda { |*args|
776
+ Ruby.no_warnings {
777
+ action.call(*args)
778
+ }
779
+ }
780
+ }
781
+ }
782
+ end
783
+
784
+ def ruby_18?
785
+ RUBY_VERSION =~ %r!\A1\.8!
786
+ end
787
+
788
+ def source_control?
789
+ File.directory? ".git"
790
+ end
791
+
792
+ class << self
793
+ include Util
794
+ include InstanceEvalWithArgs
795
+
796
+ # From minitest, part of the Ruby source; by Ryan Davis.
797
+ def capture_io
798
+ require 'stringio'
799
+
800
+ orig_stdout, orig_stderr = $stdout, $stderr
801
+ captured_stdout, captured_stderr = StringIO.new, StringIO.new
802
+ $stdout, $stderr = captured_stdout, captured_stderr
803
+
804
+ yield
805
+
806
+ return captured_stdout.string, captured_stderr.string
807
+ ensure
808
+ $stdout = orig_stdout
809
+ $stderr = orig_stderr
810
+ end
811
+
812
+ def run_doc_code(code, expected, index, instance, &block)
813
+ lib = File.expand_path(File.dirname(__FILE__) + "/../lib")
814
+ header = %{
815
+ $LOAD_PATH.unshift "#{lib}"
816
+ begin
817
+ }
818
+ footer = %{
819
+ rescue Exception => __jumpstart_exception
820
+ puts "raises \#{__jumpstart_exception.class}"
821
+ end
822
+ }
823
+ final_code = header + code + footer
824
+
825
+ # Sometimes code is required to be inside a file.
826
+ actual = nil
827
+ require 'tempfile'
828
+ Tempfile.open("run-rdoc-code") { |temp_file|
829
+ temp_file.print(final_code)
830
+ temp_file.close
831
+ actual = Ruby.run_file_and_capture(temp_file.path).chomp
832
+ }
833
+
834
+ instance_eval_with_args(instance, expected, actual, index, &block)
835
+ end
836
+
837
+ def run_doc_section(file, section, instance, &block)
838
+ contents = File.read(file)
839
+ re = %r!^=+[ \t]#{Regexp.quote(section)}.*?\n(.*?)^=!m
840
+ if section_contents = contents[re, 1]
841
+ index = 0
842
+ section_contents.scan(%r!^( \S.*?)(?=(^\S|\Z))!m) { |indented, unused|
843
+ code_sections = indented.split(%r!^ \#\#\#\# output:\s*$!)
844
+ code, expected = (
845
+ case code_sections.size
846
+ when 1
847
+ [indented, indented.scan(%r!\# => (.*?)\n!).flatten.join("\n")]
848
+ when 2
849
+ code_sections
850
+ else
851
+ raise "parse error"
852
+ end
853
+ )
854
+ run_doc_code(code, expected, index, instance, &block)
855
+ index += 1
856
+ }
857
+ else
858
+ raise "couldn't find section `#{section}' of `#{file}'"
859
+ end
860
+ end
861
+
862
+ def doc_to_spec(file, *sections, &block)
863
+ jump = self
864
+ describe file do
865
+ sections.each { |section|
866
+ describe "section `#{section}'" do
867
+ it "should run as claimed" do
868
+ if block
869
+ jump.run_doc_section(file, section, self, &block)
870
+ else
871
+ jump.run_doc_section(file, section, self) {
872
+ |expected, actual, index|
873
+ actual.should == expected
874
+ }
875
+ end
876
+ end
877
+ end
878
+ }
879
+ end
880
+ end
881
+
882
+ def doc_to_test(file, *sections, &block)
883
+ jump = self
884
+ klass = Class.new MiniTest::Unit::TestCase do
885
+ sections.each { |section|
886
+ define_method "test_#{file}_#{section}" do
887
+ if block
888
+ jump.run_doc_section(file, section, self, &block)
889
+ else
890
+ jump.run_doc_section(file, section, self) {
891
+ |expected, actual, index|
892
+ assert_equal expected, actual
893
+ }
894
+ end
895
+ end
896
+ }
897
+ end
898
+ Object.const_set("Test#{file}".gsub(".", ""), klass)
899
+ end
900
+ end
901
+ end
@@ -0,0 +1,60 @@
1
+ require 'ruby_parser'
2
+ require 'sexp_processor'
3
+
4
+ class LiveASTRubyParser < SexpProcessor
5
+ #
6
+ # Whether this is Ryan Davis' unified sexp format.
7
+ #
8
+ def self.unified?
9
+ true
10
+ end
11
+
12
+ #
13
+ # Returns a line --> sexp hash where sexp corresponds to the
14
+ # method or block defined at the given line.
15
+ #
16
+ def parse(source)
17
+ @defs = {}
18
+ process RubyParser.new.parse(source)
19
+ @defs
20
+ end
21
+
22
+ def process_defn(sexp)
23
+ result = Sexp.new
24
+ result << sexp.shift
25
+ result << sexp.shift
26
+ result << process(sexp.shift)
27
+ result << process(sexp.shift)
28
+
29
+ store_sexp(result, sexp.line)
30
+ s()
31
+ end
32
+
33
+ def process_iter(sexp)
34
+ line = sexp[1].line
35
+
36
+ result = Sexp.new
37
+ result << sexp.shift
38
+ result << process(sexp.shift)
39
+ result << process(sexp.shift)
40
+ result << process(sexp.shift)
41
+
42
+ #
43
+ # ruby_parser bug: a method without args attached to a
44
+ # multi-line block reports the wrong line. workaround.
45
+ #
46
+ if result[1][3].size == 1
47
+ line = sexp.line
48
+ end
49
+
50
+ store_sexp(result, line)
51
+ s()
52
+ end
53
+
54
+ def store_sexp(sexp, line)
55
+ @defs[line] = @defs.has_key?(line) ? :multiple : sexp
56
+ end
57
+ end
58
+
59
+ LiveASTRubyParser.autoload :Unparser, 'live_ast_ruby_parser/unparser'
60
+ LiveASTRubyParser.autoload :TestForms, 'live_ast_ruby_parser/test_forms'
@@ -0,0 +1,118 @@
1
+
2
+ # For testing with LiveAST.
3
+ module LiveASTRubyParser::TestForms
4
+ #
5
+ # no_arg_def(:f, "A#f") returns the ast of
6
+ #
7
+ # def f
8
+ # "A#f"
9
+ # end
10
+ #
11
+ def no_arg_def(name, ret)
12
+ s(:defn, name, s(:args), s(:scope, s(:block, s(:str, ret))))
13
+ end
14
+
15
+ #
16
+ # no_arg_def_return(no_arg_def(:f, "A#f")) == "A#f"
17
+ #
18
+ def no_arg_def_return(ast)
19
+ ast[3][1][1][1]
20
+ end
21
+
22
+ #
23
+ # binop_def(:f, :+) returns the ast of
24
+ #
25
+ # def f(x, y)
26
+ # x + y
27
+ # end
28
+ #
29
+ def binop_def(name, op)
30
+ s(:defn,
31
+ name,
32
+ s(:args, :x, :y),
33
+ s(:scope,
34
+ s(:block, s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))))
35
+ end
36
+
37
+ #
38
+ # binop_define_method(:f, :*) returns the ast of
39
+ #
40
+ # define_method :f do |x, y|
41
+ # x * y
42
+ # end
43
+ #
44
+ # binop_define_method(:f, :-, :my_def) returns the ast of
45
+ #
46
+ # my_def :f do |x, y|
47
+ # x - y
48
+ # end
49
+ #
50
+ def binop_define_method(name, op, using = :define_method)
51
+ s(:iter,
52
+ s(:call, nil, using, s(:arglist, s(:lit, name))),
53
+ s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
54
+ s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
55
+ end
56
+
57
+ #
58
+ # binop_define_method_with_var(:method_name, :/) returns the ast of
59
+ #
60
+ # define_method method_name do |x, y|
61
+ # x / y
62
+ # end
63
+ #
64
+ def binop_define_method_with_var(var_name, op)
65
+ s(:iter,
66
+ s(:call, nil, :define_method, s(:arglist, s(:lvar, var_name))),
67
+ s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
68
+ s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
69
+ end
70
+
71
+ #
72
+ # binop_define_singleton_method(:f, :+, :a) returns the ast of
73
+ #
74
+ # a.define_singleton_method :f do |x, y|
75
+ # x + y
76
+ # end
77
+ #
78
+ def binop_define_singleton_method(name, op, receiver)
79
+ s(:iter,
80
+ s(:call, s(:lvar, receiver), :define_singleton_method,
81
+ s(:arglist, s(:lit, name))),
82
+ s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
83
+ s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
84
+ end
85
+
86
+ #
87
+ # no_arg_block(:foo, "bar") returns the ast of
88
+ #
89
+ # foo { "bar" }
90
+ #
91
+ def no_arg_block(name, ret)
92
+ s(:iter, s(:call, nil, name, s(:arglist)), nil, s(:str, ret))
93
+ end
94
+
95
+ #
96
+ # binop_block(:foo, :+) returns the ast of
97
+ #
98
+ # foo { |x, y| x + y }
99
+ #
100
+ def binop_block(name, op)
101
+ s(:iter,
102
+ s(:call, nil, name, s(:arglist)),
103
+ s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
104
+ s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
105
+ end
106
+
107
+ #
108
+ # binop_proc_new(:*) returns the ast of
109
+ #
110
+ # Proc.new { |x, y| x * y }
111
+ #
112
+ def binop_proc_new(op)
113
+ s(:iter,
114
+ s(:call, s(:const, :Proc), :new, s(:arglist)),
115
+ s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
116
+ s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
117
+ end
118
+ end
@@ -0,0 +1,15 @@
1
+ require 'ruby2ruby'
2
+
3
+ module LiveASTRubyParser::Unparser
4
+ class << self
5
+ # Whether the unparsed code matches ruby2ruby output.
6
+ def ruby2ruby?
7
+ true
8
+ end
9
+
10
+ # Return a ruby source string which reflects the given AST.
11
+ def unparse(sexp)
12
+ Ruby2Ruby.new.process(sexp)
13
+ end
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: live_ast_ruby_parser
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.5.0
6
+ platform: ruby
7
+ authors:
8
+ - James M. Lawrence
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-02-24 00:00:00 -05:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: ruby_parser
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - "="
23
+ - !ruby/object:Gem::Version
24
+ version: 2.0.6
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: ruby2ruby
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ description: The nested TestForms module enables testing with the LiveAST test suite.
39
+ email:
40
+ - quixoticsycophant@gmail.com
41
+ executables: []
42
+
43
+ extensions: []
44
+
45
+ extra_rdoc_files:
46
+ - README.rdoc
47
+ files:
48
+ - CHANGES.rdoc
49
+ - README.rdoc
50
+ - Rakefile
51
+ - devel/jumpstart.rb
52
+ - lib/live_ast_ruby_parser.rb
53
+ - lib/live_ast_ruby_parser/test_forms.rb
54
+ - lib/live_ast_ruby_parser/unparser.rb
55
+ - MANIFEST
56
+ has_rdoc: true
57
+ homepage: http://quix.github.com/live_ast_ruby_parser
58
+ licenses: []
59
+
60
+ post_install_message:
61
+ rdoc_options:
62
+ - --main
63
+ - README.rdoc
64
+ - --title
65
+ - "live_ast_ruby_parser: This is the default RubyParser-based parser used by LiveAST."
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.5.2
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: This is the default RubyParser-based parser used by LiveAST.
87
+ test_files: []
88
+