live_ast_ripper 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.rdoc ADDED
@@ -0,0 +1,10 @@
1
+
2
+ = live_ast_ripper 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,7 @@
1
+ CHANGES.rdoc
2
+ MANIFEST
3
+ README.rdoc
4
+ Rakefile
5
+ devel/jumpstart.rb
6
+ lib/live_ast_ripper.rb
7
+ lib/live_ast_ripper/test_forms.rb
data/README.rdoc ADDED
@@ -0,0 +1,47 @@
1
+
2
+ = live_ast_ripper
3
+
4
+ == Summary
5
+
6
+ A Ripper-based parser plug-in for LiveAST.
7
+
8
+ == Description
9
+
10
+ The nested TestForms module enables testing with the LiveAST test
11
+ suite.
12
+
13
+ == Links
14
+
15
+ * Home: http://quix.github.com/live_ast_ripper
16
+ * Feature Requests, Bug Reports: http://github.com/quix/live_ast_ripper/issues
17
+ * Manual Download: http://github.com/quix/live_ast_ripper/archives/master
18
+ * Repository: http://github.com/quix/live_ast_ripper
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,11 @@
1
+ require_relative 'devel/jumpstart'
2
+
3
+ Jumpstart.new "live_ast_ripper" do |s|
4
+ s.developers << ["James M. Lawrence", "quixoticsycophant@gmail.com"]
5
+ s.github_user = "quix"
6
+ s.version = "0.5.0"
7
+ end
8
+
9
+ # testing done inside live_ast
10
+ task :test do
11
+ end
@@ -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,217 @@
1
+
2
+ # For testing with LiveAST.
3
+ module LiveASTRipper::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
+ [:def,
13
+ [:@ident, name.to_s],
14
+ [:params, nil, nil, nil, nil, nil],
15
+ [:bodystmt,
16
+ [[:string_literal,
17
+ [:string_content, [:@tstring_content, ret]]]],
18
+ nil,
19
+ nil,
20
+ nil]]
21
+ end
22
+
23
+ #
24
+ # no_arg_def_return(no_arg_def(:f, "A#f")) == "A#f"
25
+ #
26
+ def no_arg_def_return(ast)
27
+ ast[3][1][0][1][1][1]
28
+ end
29
+
30
+ #
31
+ # binop_def(:f, :+) returns the ast of
32
+ #
33
+ # def f(x, y)
34
+ # x + y
35
+ # end
36
+ #
37
+ def binop_def(name, op)
38
+ [:def,
39
+ [:@ident, name.to_s],
40
+ [:paren,
41
+ [:params,
42
+ [[:@ident, "x"], [:@ident, "y"]],
43
+ nil,
44
+ nil,
45
+ nil,
46
+ nil]],
47
+ [:bodystmt,
48
+ [[:binary,
49
+ [:var_ref, [:@ident, "x"]],
50
+ op,
51
+ [:var_ref, [:@ident, "y"]]]],
52
+ nil,
53
+ nil,
54
+ nil]]
55
+ end
56
+
57
+ #
58
+ # binop_define_method(:f, :*) returns the ast of
59
+ #
60
+ # define_method :f do |x, y|
61
+ # x * y
62
+ # end
63
+ #
64
+ # binop_define_method(:f, :-, :my_def) returns the ast of
65
+ #
66
+ # my_def :f do |x, y|
67
+ # x - y
68
+ # end
69
+ #
70
+ def binop_define_method(name, op, using = :define_method)
71
+ [:method_add_block,
72
+ [:command,
73
+ [:@ident, using.to_s],
74
+ [:args_add_block,
75
+ [[:symbol_literal, [:symbol, [:@ident, name.to_s]]]],
76
+ false]],
77
+ [:block,
78
+ [:block_var,
79
+ [:params,
80
+ [[:@ident, "x"], [:@ident, "y"]],
81
+ nil,
82
+ nil,
83
+ nil,
84
+ nil],
85
+ nil],
86
+ [[:binary,
87
+ [:var_ref, [:@ident, "x"]],
88
+ op,
89
+ [:var_ref, [:@ident, "y"]]]]]]
90
+ end
91
+
92
+ #
93
+ # binop_define_method_with_var(:method_name, :/) returns the ast of
94
+ #
95
+ # define_method method_name do |x, y|
96
+ # x / y
97
+ # end
98
+ #
99
+ def binop_define_method_with_var(name, op)
100
+ [:method_add_block,
101
+ [:command,
102
+ [:@ident, "define_method"],
103
+ [:args_add_block,
104
+ [[:var_ref, [:@ident, name.to_s]]],
105
+ false]],
106
+ [:block,
107
+ [:block_var,
108
+ [:params,
109
+ [[:@ident, "x"], [:@ident, "y"]],
110
+ nil,
111
+ nil,
112
+ nil,
113
+ nil],
114
+ nil],
115
+ [[:binary,
116
+ [:var_ref, [:@ident, "x"]],
117
+ op,
118
+ [:var_ref, [:@ident, "y"]]]]]]
119
+ end
120
+
121
+ #
122
+ # binop_define_singleton_method(:f, :+, :a) returns the ast of
123
+ #
124
+ # a.define_singleton_method :f do |x, y|
125
+ # x + y
126
+ # end
127
+ #
128
+ def binop_define_singleton_method(name, op, receiver)
129
+ [:method_add_block,
130
+ [:command_call,
131
+ [:var_ref, [:@ident, receiver.to_s]],
132
+ :".",
133
+ [:@ident, "define_singleton_method"],
134
+ [:args_add_block,
135
+ [[:symbol_literal, [:symbol, [:@ident, name.to_s]]]],
136
+ false]],
137
+ [:block,
138
+ [:block_var,
139
+ [:params,
140
+ [[:@ident, "x"], [:@ident, "y"]],
141
+ nil,
142
+ nil,
143
+ nil,
144
+ nil],
145
+ nil],
146
+ [[:binary,
147
+ [:var_ref, [:@ident, "x"]],
148
+ op,
149
+ [:var_ref, [:@ident, "y"]]]]]]
150
+ end
151
+
152
+ #
153
+ # no_arg_block(:foo, "bar") returns the ast of
154
+ #
155
+ # foo { "bar" }
156
+ #
157
+ def no_arg_block(name, ret)
158
+ [:method_add_block,
159
+ [:method_add_arg, [:fcall, [:@ident, name.to_s]], []],
160
+ [:block,
161
+ nil,
162
+ [[:string_literal,
163
+ [:string_content, [:@tstring_content, ret.to_s]]]]]]
164
+ end
165
+
166
+ #
167
+ # binop_block(:foo, :+) returns the ast of
168
+ #
169
+ # foo { |x, y| x + y }
170
+ #
171
+ def binop_block(name, op)
172
+ [:method_add_block,
173
+ [:method_add_arg, [:fcall, [:@ident, name.to_s]], []],
174
+ [:block,
175
+ [:block_var,
176
+ [:params,
177
+ [[:@ident, "x"], [:@ident, "y"]],
178
+ nil,
179
+ nil,
180
+ nil,
181
+ nil],
182
+ nil],
183
+ [[:binary,
184
+ [:var_ref, [:@ident, "x"]],
185
+ op,
186
+ [:var_ref, [:@ident, "y"]]]]]]
187
+ end
188
+
189
+ #
190
+ # binop_proc_new(:*) returns the ast of
191
+ #
192
+ # Proc.new { |x, y| x * y }
193
+ #
194
+ def binop_proc_new(op)
195
+ [:method_add_block,
196
+ [:call,
197
+ [:var_ref, [:@const, "Proc"]],
198
+ :".",
199
+ [:@ident, "new"]],
200
+ [:block,
201
+ [:block_var,
202
+ [:params,
203
+ [[:@ident, "x"], [:@ident, "y"]],
204
+ nil,
205
+ nil,
206
+ nil,
207
+ nil],
208
+ nil],
209
+ [[:binary,
210
+ [:var_ref, [:@ident, "x"]],
211
+ op,
212
+ [:var_ref, [:@ident, "y"]]]]]]
213
+ end
214
+ end
215
+
216
+ # testing assumes sexps are steamrolled
217
+ LiveASTRipper.steamroll = true
@@ -0,0 +1,99 @@
1
+ require 'live_ast/base'
2
+ require 'ripper'
3
+
4
+ class LiveASTRipper
5
+ class << self
6
+ #
7
+ # Whether to strip line/column and other personality traits.
8
+ #
9
+ # This is Ripper-specific -- not part of the live_ast API.
10
+ #
11
+ attr_accessor :steamroll
12
+ end
13
+
14
+ #
15
+ # Returns a line --> sexp hash where sexp corresponds to the
16
+ # method or block defined at the given line.
17
+ #
18
+ def parse(code)
19
+ @defs = {}
20
+ process(Ripper.sexp(code))
21
+ @defs
22
+ end
23
+
24
+ def process(sexp)
25
+ case sexp[0]
26
+ when :def
27
+ process_def(sexp)
28
+ when :method_add_block
29
+ process_method_add_block(sexp)
30
+ else
31
+ sexp.map { |elem|
32
+ elem.is_a?(Array) ? process(elem) : elem
33
+ }
34
+ end
35
+ end
36
+
37
+ def process_def(sexp)
38
+ line = sexp[1][2][0]
39
+
40
+ result = []
41
+ result << sexp.shift
42
+ result << sexp.shift
43
+ result << process(sexp.shift)
44
+ result << process(sexp.shift)
45
+
46
+ result = steamroll(result) if LiveASTRipper.steamroll
47
+ store_sexp(result, line)
48
+
49
+ []
50
+ end
51
+
52
+ def process_method_add_block(sexp)
53
+ line =
54
+ case sexp[1][0]
55
+ when :method_add_arg
56
+ sexp[1][1][1].last[0]
57
+ when :call, :command_call
58
+ sexp[1][3][2][0]
59
+ when :command
60
+ sexp[1][1][2][0]
61
+ end
62
+
63
+ result = []
64
+ result << sexp.shift
65
+ result << process(sexp.shift)
66
+ result << process(sexp.shift)
67
+
68
+ result = steamroll(result) if LiveASTRipper.steamroll
69
+ store_sexp(result, line)
70
+
71
+ []
72
+ end
73
+
74
+ def store_sexp(sexp, line)
75
+ @defs[line] = @defs.has_key?(line) ? :multiple : sexp
76
+ end
77
+
78
+ def steamroll(sexp)
79
+ sexp.map { |elem|
80
+ if elem.is_a? Array
81
+ sub_elem =
82
+ if elem[0].is_a?(Symbol) and elem[0][0] == "@"
83
+ elem[0..-2]
84
+ else
85
+ elem
86
+ end
87
+ steamroll(sub_elem)
88
+ elsif elem == :brace_block or elem == :do_block
89
+ :block
90
+ else
91
+ elem
92
+ end
93
+ }
94
+ end
95
+ end
96
+
97
+ LiveASTRipper.autoload :TestForms, "live_ast_ripper/test_forms"
98
+
99
+ LiveAST.parser = LiveASTRipper
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: live_ast_ripper
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
+
17
+ description: The nested TestForms module enables testing with the LiveAST test suite.
18
+ email:
19
+ - quixoticsycophant@gmail.com
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files:
25
+ - README.rdoc
26
+ files:
27
+ - CHANGES.rdoc
28
+ - README.rdoc
29
+ - Rakefile
30
+ - devel/jumpstart.rb
31
+ - lib/live_ast_ripper.rb
32
+ - lib/live_ast_ripper/test_forms.rb
33
+ - MANIFEST
34
+ has_rdoc: true
35
+ homepage: http://quix.github.com/live_ast_ripper
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options:
40
+ - --main
41
+ - README.rdoc
42
+ - --title
43
+ - "live_ast_ripper: A Ripper-based parser plug-in for LiveAST."
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.5.2
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: A Ripper-based parser plug-in for LiveAST.
65
+ test_files: []
66
+