boc 0.3.2-x86-mswin32

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/devel/levitate.rb ADDED
@@ -0,0 +1,958 @@
1
+
2
+ class Levitate
3
+ class Installer
4
+ def initialize
5
+ require 'fileutils'
6
+ require 'rbconfig'
7
+ require 'find'
8
+
9
+ rb_root = RbConfig::CONFIG["sitelibdir"]
10
+ @spec = []
11
+
12
+ Find.find "lib" do |source|
13
+ next if source == "lib"
14
+ next unless File.directory?(source) || File.extname(source) == ".rb"
15
+ dest = File.join(rb_root, source.sub(%r!\Alib/!, ""))
16
+ @spec << { :source => source, :dest => dest }
17
+ end
18
+ end
19
+
20
+ def install
21
+ @spec.each do |entry|
22
+ source, dest = entry.values_at(:source, :dest)
23
+ if File.directory?(source)
24
+ unless File.directory?(dest)
25
+ puts "mkdir #{dest}"
26
+ FileUtils.mkdir(dest)
27
+ end
28
+ else
29
+ puts "install #{source} --> #{dest}"
30
+ FileUtils.install(source, dest)
31
+ end
32
+ end
33
+ end
34
+
35
+ def uninstall
36
+ @spec.reverse.each do |entry|
37
+ source, dest = entry.values_at(:source, :dest)
38
+ if File.directory?(source)
39
+ if File.directory?(dest)
40
+ puts "rmdir #{dest}"
41
+ FileUtils.rmdir(dest)
42
+ end
43
+ else
44
+ if File.file?(dest)
45
+ puts "rm #{dest}"
46
+ FileUtils.rm(dest)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ module AttrLazy
54
+ def attr_lazy(name, &block)
55
+ AttrLazy.define_reader(class << self ; self ; end, name, &block)
56
+ end
57
+
58
+ def attr_lazy_accessor(name, &block)
59
+ attr_lazy(name, &block)
60
+ AttrLazy.define_writer(class << self ; self ; end, name, &block)
61
+ end
62
+
63
+ class << self
64
+ def included(mod)
65
+ (class << mod ; self ; end).class_eval do
66
+ def attr_lazy(name, &block)
67
+ AttrLazy.define_reader(self, name, &block)
68
+ end
69
+
70
+ def attr_lazy_accessor(name, &block)
71
+ attr_lazy(name, &block)
72
+ AttrLazy.define_writer(self, name, &block)
73
+ end
74
+ end
75
+ end
76
+
77
+ def define_evaluated_reader(instance, name, value)
78
+ (class << instance ; self ; end).class_eval do
79
+ remove_method name rescue nil
80
+ define_method name do
81
+ value
82
+ end
83
+ end
84
+ end
85
+
86
+ def define_reader(klass, name, &block)
87
+ klass.class_eval do
88
+ remove_method name rescue nil
89
+ define_method name do
90
+ value = instance_eval(&block)
91
+ AttrLazy.define_evaluated_reader(self, name, value)
92
+ value
93
+ end
94
+ end
95
+ end
96
+
97
+ def define_writer(klass, name, &block)
98
+ klass.class_eval do
99
+ writer = "#{name}="
100
+ remove_method writer rescue nil
101
+ define_method writer do |value|
102
+ AttrLazy.define_evaluated_reader(self, name, value)
103
+ value
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ module Ruby
111
+ module_function
112
+
113
+ def executable
114
+ require 'rbconfig'
115
+
116
+ name = File.join(
117
+ RbConfig::CONFIG["bindir"],
118
+ RbConfig::CONFIG["RUBY_INSTALL_NAME"]
119
+ )
120
+
121
+ if RbConfig::CONFIG["host"] =~ %r!(mswin|cygwin|mingw)! and
122
+ File.basename(name) !~ %r!\.(exe|com|bat|cmd)\Z!i
123
+ name + RbConfig::CONFIG["EXEEXT"]
124
+ else
125
+ name
126
+ end
127
+ end
128
+
129
+ def run(*args)
130
+ cmd = [executable, *args]
131
+ unless system(*cmd)
132
+ cmd_str = cmd.map { |t| "'#{t}'" }.join(", ")
133
+ raise "system(#{cmd_str}) failed with status #{$?.exitstatus}"
134
+ end
135
+ end
136
+
137
+ def run_code_and_capture(code)
138
+ IO.popen(%{"#{executable}"}, "r+") { |pipe|
139
+ pipe.print(code)
140
+ pipe.flush
141
+ pipe.close_write
142
+ pipe.read
143
+ }
144
+ end
145
+
146
+ def run_file_and_capture(file)
147
+ unless File.file? file
148
+ raise "file does not exist: `#{file}'"
149
+ end
150
+ IO.popen(%{"#{executable}" "#{file}"}, "r") { |pipe|
151
+ pipe.read
152
+ }
153
+ end
154
+
155
+ def with_warnings(value = true)
156
+ previous = $VERBOSE
157
+ $VERBOSE = value
158
+ begin
159
+ yield
160
+ ensure
161
+ $VERBOSE = previous
162
+ end
163
+ end
164
+
165
+ def no_warnings(&block)
166
+ with_warnings(nil, &block)
167
+ end
168
+ end
169
+
170
+ module Util
171
+ module_function
172
+
173
+ def run_ruby_on_each(*files)
174
+ files.each { |file|
175
+ Ruby.run("-w", file)
176
+ }
177
+ end
178
+
179
+ def to_camel_case(str)
180
+ str.split('_').map { |t| t.capitalize }.join
181
+ end
182
+
183
+ def write_file(file)
184
+ contents = yield
185
+ File.open(file, "wb") { |out|
186
+ out.print(contents)
187
+ }
188
+ contents
189
+ end
190
+
191
+ def instance_exec2(obj, *args, &block)
192
+ method_name = ["_", obj.object_id, "_", Thread.current.object_id].join
193
+ (class << obj ; self ; end).class_eval do
194
+ define_method method_name, &block
195
+ begin
196
+ obj.send(method_name, *args)
197
+ ensure
198
+ remove_method method_name
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+ include AttrLazy
205
+ include Util
206
+
207
+ def initialize(gem_name)
208
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
209
+
210
+ require 'rubygems/package_task'
211
+
212
+ @gem_name = gem_name
213
+
214
+ yield self
215
+
216
+ self.class.instance_methods(false).select { |t|
217
+ t.to_s =~ %r!\Adefine_!
218
+ }.sort.each { |method_name|
219
+ send(method_name)
220
+ }
221
+ end
222
+
223
+ class << self
224
+ alias_method :attribute, :attr_lazy_accessor
225
+ end
226
+
227
+ attr_reader :gem_name
228
+
229
+ attribute :version_constant_name do
230
+ "VERSION"
231
+ end
232
+
233
+ attribute :camel_name do
234
+ to_camel_case(gem_name)
235
+ end
236
+
237
+ attribute :version do
238
+ catch :bail do
239
+ if File.file?(version_file = "./lib/#{gem_name}/version.rb")
240
+ require version_file
241
+ elsif File.file?("./lib/#{gem_name}.rb")
242
+ require gem_name
243
+ else
244
+ throw :bail
245
+ end
246
+ mod = Kernel.const_get(camel_name)
247
+ constants = mod.constants.map { |t| t.to_sym }
248
+ unless constants.include?(version_constant_name.to_sym)
249
+ throw :bail
250
+ end
251
+ mod.const_get(version_constant_name)
252
+ end or "0.0.0"
253
+ end
254
+
255
+ attribute :required_ruby_version do
256
+ ">= 0"
257
+ end
258
+
259
+ attribute :readme_file do
260
+ "README.rdoc"
261
+ end
262
+
263
+ attribute :history_file do
264
+ "CHANGES.rdoc"
265
+ end
266
+
267
+ attribute :doc_dir do
268
+ "doc"
269
+ end
270
+
271
+ attribute :spec_files do
272
+ Dir["./spec/*_{spec,example}.rb"]
273
+ end
274
+
275
+ attribute :test_files do
276
+ (Dir["./test/test_*.rb"] + Dir["./test/*_test.rb"]).uniq
277
+ end
278
+
279
+ attribute :cov_dir do
280
+ "coverage"
281
+ end
282
+
283
+ attribute :spec_output_dir do
284
+ "rspec_output"
285
+ end
286
+
287
+ attribute :spec_output_file do
288
+ "spec.html"
289
+ end
290
+
291
+ attr_lazy :spec_output do
292
+ "#{spec_output_dir}/#{spec_output_file}"
293
+ end
294
+
295
+ [:gem, :tgz].each { |ext|
296
+ attribute ext do
297
+ "pkg/#{gem_name}-#{version}.#{ext}"
298
+ end
299
+ }
300
+
301
+ attribute :rcov_options do
302
+ # workaround for the default rspec task
303
+ Dir["*"].select { |f| File.directory? f }.inject(Array.new) { |acc, dir|
304
+ if dir == "lib"
305
+ acc
306
+ else
307
+ acc + ["--exclude", dir + "/"]
308
+ end
309
+ } + ["--text-report"]
310
+ end
311
+
312
+ attribute :readme_file do
313
+ "README.rdoc"
314
+ end
315
+
316
+ attribute :manifest_file do
317
+ "MANIFEST"
318
+ end
319
+
320
+ attribute :generated_files do
321
+ []
322
+ end
323
+
324
+ attribute :extra_gemspec do
325
+ lambda { |spec| }
326
+ end
327
+
328
+ attribute :files do
329
+ if File.file? manifest_file
330
+ File.read(manifest_file).split("\n")
331
+ elsif source_control?
332
+ IO.popen("git ls-files") { |pipe| pipe.read.split "\n" }
333
+ end.to_a + [manifest_file] + generated_files
334
+ end
335
+
336
+ def files_in_require_paths
337
+ require_paths.inject([]) { |acc, dir|
338
+ acc + Dir.glob("#{dir}/**/*.rb")
339
+ }
340
+ end
341
+
342
+ attribute :rdoc_files do
343
+ files_in_require_paths
344
+ end
345
+
346
+ attribute :rdoc_title do
347
+ "#{gem_name}: #{summary}".sub(/\.\Z/, "")
348
+ end
349
+
350
+ attribute :require_paths do
351
+ ["lib"]
352
+ end
353
+
354
+ attribute :rdoc_options do
355
+ if File.file?(readme_file)
356
+ ["--main", readme_file]
357
+ else
358
+ []
359
+ end + [
360
+ "--title", rdoc_title,
361
+ ] + (files_in_require_paths - rdoc_files).inject(Array.new) {
362
+ |acc, file|
363
+ acc + ["--exclude", file]
364
+ }
365
+ end
366
+
367
+ attribute :extra_rdoc_files do
368
+ [readme_file, history_file].select { |file| File.file?(file) }
369
+ end
370
+
371
+ attribute :browser do
372
+ require 'rbconfig'
373
+ if RbConfig::CONFIG["host"] =~ %r!darwin!
374
+ "open"
375
+ else
376
+ "firefox"
377
+ end
378
+ end
379
+
380
+ attribute :gemspec do
381
+ Gem::Specification.new do |g|
382
+ %w[
383
+ authors
384
+ email
385
+ summary
386
+ version
387
+ description
388
+ files
389
+ rdoc_options
390
+ extra_rdoc_files
391
+ require_paths
392
+ required_ruby_version
393
+ extensions
394
+ ].each do |param|
395
+ t = send(param) and g.send("#{param}=", t)
396
+ end
397
+ g.name = gem_name
398
+ g.has_rdoc = true
399
+ g.homepage = url if url
400
+ dependencies.each { |dep|
401
+ g.add_dependency(*dep)
402
+ }
403
+ development_dependencies.each { |dep|
404
+ g.add_development_dependency(*dep)
405
+ }
406
+ extra_gemspec.call(g)
407
+ end
408
+ end
409
+
410
+ attribute :readme_contents do
411
+ File.read(readme_file) rescue "FIXME: readme_file"
412
+ end
413
+
414
+ attribute :sections do
415
+ begin
416
+ data = readme_contents.split(%r!^==\s*(.*?)\s*$!)
417
+ pairs = data[1..-1].each_slice(2).map { |section, contents|
418
+ [section.downcase, contents.strip]
419
+ }
420
+ Hash[*pairs.flatten]
421
+ rescue
422
+ nil
423
+ end
424
+ end
425
+
426
+ attribute :description_section do
427
+ "description"
428
+ end
429
+
430
+ attribute :summary_section do
431
+ "summary"
432
+ end
433
+
434
+ attribute :description_sentences do
435
+ 1
436
+ end
437
+
438
+ attribute :summary_sentences do
439
+ 1
440
+ end
441
+
442
+ [:summary, :description].each { |section|
443
+ attribute section do
444
+ begin
445
+ sections[send("#{section}_section")].
446
+ gsub("\n", " ").
447
+ split(%r!\.\s+!m).
448
+ first(send("#{section}_sentences")).
449
+ join(". ").
450
+ concat(".").
451
+ sub(%r!\.+\Z!, ".")
452
+ rescue
453
+ "FIXME: #{section}"
454
+ end
455
+ end
456
+ }
457
+
458
+ attribute :url do
459
+ "http://#{username}.github.com/#{gem_name}"
460
+ end
461
+
462
+ attribute :username do
463
+ raise "username not set"
464
+ end
465
+
466
+ attribute :rubyforge_info do
467
+ nil
468
+ end
469
+
470
+ def authors
471
+ developers.map { |d| d[0] }
472
+ end
473
+
474
+ def email
475
+ developers.map { |d| d[1] }
476
+ end
477
+
478
+ attribute :dependencies do
479
+ []
480
+ end
481
+
482
+ attribute :development_dependencies do
483
+ []
484
+ end
485
+
486
+ attribute :developers do
487
+ []
488
+ end
489
+
490
+ attribute :extensions do
491
+ ["ext/#{gem_name}/extconf.rb"].select { |f| File.file? f }
492
+ end
493
+
494
+ attribute :so_file do
495
+ unless extensions.empty?
496
+ require 'rbconfig'
497
+ "lib/" + gem_name + "." + RbConfig::CONFIG["DLEXT"]
498
+ end
499
+ end
500
+
501
+ def define_clean
502
+ require 'rake/clean'
503
+ task :clean do
504
+ Rake::Task[:clobber].invoke
505
+ end
506
+ end
507
+
508
+ def define_package
509
+ if source_control?
510
+ task manifest_file do
511
+ create_manifest
512
+ end
513
+ CLEAN.add manifest_file
514
+ task :package => :clean
515
+ Gem::PackageTask.new(gemspec).define
516
+ end
517
+ end
518
+
519
+ def define_spec
520
+ unless spec_files.empty?
521
+ Ruby.no_warnings {
522
+ require 'spec/rake/spectask'
523
+ }
524
+
525
+ desc "run specs"
526
+ Spec::Rake::SpecTask.new('spec') do |t|
527
+ t.spec_files = spec_files
528
+ end
529
+
530
+ desc "run specs with text output"
531
+ Spec::Rake::SpecTask.new('text_spec') do |t|
532
+ t.spec_files = spec_files
533
+ t.spec_opts = ['-fs']
534
+ end
535
+
536
+ desc "run specs with html output"
537
+ Spec::Rake::SpecTask.new('full_spec') do |t|
538
+ t.spec_files = spec_files
539
+ t.rcov = true
540
+ t.rcov_opts = rcov_options
541
+ t.spec_opts = ["-fh:#{spec_output}"]
542
+ end
543
+
544
+ suppress_task_warnings :spec, :full_spec, :text_spec
545
+
546
+ desc "run full_spec then open browser"
547
+ task :show_spec => :full_spec do
548
+ open_browser(spec_output, cov_dir + "/index.html")
549
+ end
550
+
551
+ desc "run specs individually"
552
+ task :spec_deps do
553
+ run_ruby_on_each(*spec_files)
554
+ end
555
+
556
+ task :prerelease => [:spec, :spec_deps]
557
+ task :default => :spec
558
+
559
+ CLEAN.add spec_output_dir
560
+ end
561
+ end
562
+
563
+ def define_test
564
+ unless test_files.empty?
565
+ desc "run tests"
566
+ task :test do
567
+ test_files.each { |file| require file }
568
+
569
+ # if we use at_exit hook instead, it won't run before :release
570
+ MiniTest::Unit.new.run ARGV
571
+ end
572
+
573
+ desc "run tests with coverage"
574
+ if ruby_18?
575
+ task :full_test do
576
+ verbose(false) {
577
+ sh("rcov", "-o", cov_dir, "--text-report",
578
+ *(test_files + rcov_options)
579
+ )
580
+ }
581
+ end
582
+ else
583
+ task :full_test do
584
+ rm_rf cov_dir
585
+ require 'simplecov'
586
+ SimpleCov.start do
587
+ add_filter "test/"
588
+ add_filter "devel/"
589
+ end
590
+ Rake::Task[:test].invoke
591
+ end
592
+ end
593
+
594
+ desc "run full_test then open browser"
595
+ task :show_test => :full_test do
596
+ show = lambda { open_browser(cov_dir + "/index.html") }
597
+ if ruby_18?
598
+ show.call
599
+ else
600
+ SimpleCov.at_exit do
601
+ SimpleCov.result.format!
602
+ show.call
603
+ end
604
+ end
605
+ end
606
+
607
+ desc "run tests individually"
608
+ task :test_deps do
609
+ run_ruby_on_each(*test_files)
610
+ end
611
+
612
+ task :prerelease => [:test, :test_deps]
613
+ task :default => :test
614
+
615
+ CLEAN.add cov_dir
616
+ end
617
+ end
618
+
619
+ def define_doc
620
+ desc "run rdoc"
621
+ task :doc => :clean_doc do
622
+ Kernel.send :gem, 'rdoc' rescue nil
623
+ require 'rdoc/rdoc'
624
+ args = (
625
+ gemspec.rdoc_options +
626
+ gemspec.require_paths.clone +
627
+ gemspec.extra_rdoc_files +
628
+ ["-o", doc_dir]
629
+ ).flatten.map { |t| t.to_s }
630
+ RDoc::RDoc.new.document args
631
+ end
632
+
633
+ task :clean_doc do
634
+ # normally rm_rf, but mimic rake/clean output
635
+ rm_r(doc_dir) rescue nil
636
+ end
637
+
638
+ desc "run rdoc then open browser"
639
+ task :show_doc => :doc do
640
+ open_browser(doc_dir + "/index.html")
641
+ end
642
+
643
+ task :rdoc => :doc
644
+ task :clean => :clean_doc
645
+ end
646
+
647
+ def define_publish
648
+ if source_control?
649
+ desc "publish docs"
650
+ task :publish => [:clean, :check_directory, :doc] do
651
+ if rubyforge_info
652
+ user, project = rubyforge_info
653
+ Dir.chdir(doc_dir) do
654
+ sh "scp", "-r",
655
+ ".",
656
+ "#{user}@rubyforge.org:/var/www/gforge-projects/#{project}"
657
+ end
658
+ end
659
+ git "branch", "-D", "gh-pages"
660
+ git "checkout", "--orphan", "gh-pages"
661
+ FileUtils.rm ".git/index"
662
+ git "clean", "-fdx", "-e", "doc"
663
+ Dir["doc/*"].each { |path|
664
+ FileUtils.mv path, "."
665
+ }
666
+ FileUtils.rmdir "doc"
667
+ git "add", "."
668
+ git "commit", "-m", "generated by rdoc"
669
+ git "push", "-f", "origin", "gh-pages"
670
+ end
671
+ end
672
+ end
673
+
674
+ def define_install
675
+ desc "direct install (no gem)"
676
+ task :install do
677
+ Installer.new.install
678
+ end
679
+
680
+ desc "direct uninstall (no gem)"
681
+ task :uninstall do
682
+ Installer.new.uninstall
683
+ end
684
+
685
+ if so_file
686
+ dest = File.join(RbConfig::CONFIG["sitearchdir"], File.basename(so_file))
687
+
688
+ task :install => so_file do
689
+ puts "install #{so_file} --> #{dest}"
690
+ FileUtils.install(so_file, dest)
691
+ end
692
+
693
+ task :uninstall do
694
+ if File.file?(dest)
695
+ puts "rm #{dest}"
696
+ FileUtils.rm(dest)
697
+ end
698
+ end
699
+ end
700
+ end
701
+
702
+ def define_check_directory
703
+ task :check_directory do
704
+ unless `git status` =~ %r!nothing to commit \(working directory clean\)!
705
+ raise "directory not clean"
706
+ end
707
+ end
708
+ end
709
+
710
+ def define_ping
711
+ task :ping do
712
+ require 'rbconfig'
713
+ %w[github.com].each { |server|
714
+ cmd = "ping " + (
715
+ if RbConfig::CONFIG["host"] =~ %r!darwin!
716
+ "-c2 #{server}"
717
+ else
718
+ "#{server} 2 2"
719
+ end
720
+ )
721
+ unless `#{cmd}` =~ %r!0% packet loss!
722
+ raise "No ping for #{server}"
723
+ end
724
+ }
725
+ end
726
+ end
727
+
728
+ def define_update_levitate
729
+ url = ENV["LEVITATE"] ||
730
+ "https://github.com/quix/levitate/raw/master/levitate.rb"
731
+ task :update_levitate do
732
+ if system "curl", "-s", "-o", __FILE__, url
733
+ if `git diff #{__FILE__}` == ""
734
+ puts "Already up-to-date."
735
+ else
736
+ git "commit", __FILE__, "-m", "updated levitate"
737
+ puts "Updated levitate."
738
+ end
739
+ else
740
+ raise "levitate download failed"
741
+ end
742
+ end
743
+ end
744
+
745
+ def define_changes
746
+ task :changes do
747
+ if File.read(history_file).index version
748
+ raise "version not updated"
749
+ end
750
+
751
+ header = "\n\n== Version #{version}\n\n"
752
+
753
+ bullets = `git log --format=%s #{last_release}..HEAD`.lines.map { |line|
754
+ "* #{line}"
755
+ }.join.chomp
756
+
757
+ write_file(history_file) do
758
+ File.read(history_file).sub(/(?<=#{gem_name} Changes)/) {
759
+ header + bullets
760
+ }
761
+ end
762
+ end
763
+ end
764
+
765
+ def last_release
766
+ `git tag`.lines.select { |t| t.index(gem_name) == 0 }.last.chomp
767
+ end
768
+
769
+ def git(*args)
770
+ sh "git", *args
771
+ end
772
+
773
+ def create_manifest
774
+ write_file(manifest_file) {
775
+ files.sort.join("\n")
776
+ }
777
+ end
778
+
779
+ def define_release
780
+ task :prerelease => [:clean, :check_directory, :ping, history_file]
781
+
782
+ task :finish_release do
783
+ git "tag", "#{gem_name}-" + version.to_s
784
+ git "push", "--tags", "origin", "master"
785
+ sh "gem", "push", gem
786
+ end
787
+
788
+ task :release => [:prerelease, :package, :finish_release]
789
+ end
790
+
791
+ def define_debug_gem
792
+ task :debug_gem do
793
+ puts gemspec.to_ruby
794
+ end
795
+ end
796
+
797
+ def define_extension
798
+ if source_control? or (so_file and !File.file?(so_file))
799
+ require 'rbconfig'
800
+ require 'rake/extensiontask'
801
+
802
+ Rake::ExtensionTask.new gem_name, gemspec do |ext|
803
+ ext.cross_compile = true
804
+ ext.cross_platform = 'i386-mswin32'
805
+ ext.cross_compiling do |gemspec|
806
+ gemspec.post_install_message =
807
+ "U got dat binary versionation of this gemination!"
808
+ end
809
+ end
810
+
811
+ so = "lib/#{gem_name}.#{RbConfig::CONFIG["DLEXT"]}"
812
+ if Rake::Task[so].needed?
813
+ task :test => so
814
+ end
815
+
816
+ task :cross_native_gem do
817
+ Rake::Task[:gem].reenable
818
+ Rake.application.top_level_tasks.replace %w[cross native gem]
819
+ Rake.application.top_level
820
+ end
821
+
822
+ task :gem => :cross_native_gem
823
+ end
824
+ end
825
+
826
+ def open_browser(*files)
827
+ sh(*([browser].flatten + files))
828
+ end
829
+
830
+ def suppress_task_warnings(*task_names)
831
+ task_names.each { |task_name|
832
+ Rake::Task[task_name].actions.map! { |action|
833
+ lambda { |*args|
834
+ Ruby.no_warnings {
835
+ action.call(*args)
836
+ }
837
+ }
838
+ }
839
+ }
840
+ end
841
+
842
+ def ruby_18?
843
+ RUBY_VERSION =~ %r!\A1\.8!
844
+ end
845
+
846
+ def source_control?
847
+ File.directory? ".git"
848
+ end
849
+
850
+ class << self
851
+ include Util
852
+
853
+ # From minitest, part of the Ruby source; by Ryan Davis.
854
+ def capture_io
855
+ require 'stringio'
856
+
857
+ orig_stdout, orig_stderr = $stdout, $stderr
858
+ captured_stdout, captured_stderr = StringIO.new, StringIO.new
859
+ $stdout, $stderr = captured_stdout, captured_stderr
860
+
861
+ yield
862
+
863
+ return captured_stdout.string, captured_stderr.string
864
+ ensure
865
+ $stdout = orig_stdout
866
+ $stderr = orig_stderr
867
+ end
868
+
869
+ def run_doc_code(code, expected, index, instance, &block)
870
+ lib = File.expand_path(File.dirname(__FILE__) + "/../lib")
871
+ header = %{
872
+ $LOAD_PATH.unshift "#{lib}"
873
+ begin
874
+ }
875
+ footer = %{
876
+ rescue Exception => __levitate_exception
877
+ puts "raises \#{__levitate_exception.class}"
878
+ end
879
+ }
880
+ final_code = header + code + footer
881
+
882
+ # Sometimes code is required to be inside a file.
883
+ actual = nil
884
+ require 'tempfile'
885
+ Tempfile.open("run-rdoc-code") { |temp_file|
886
+ temp_file.print(final_code)
887
+ temp_file.close
888
+ actual = Ruby.run_file_and_capture(temp_file.path).chomp
889
+ }
890
+
891
+ instance_exec2(instance, expected, actual, index, &block)
892
+ end
893
+
894
+ def run_doc_section(file, section, instance, &block)
895
+ contents = File.read(file)
896
+ re = %r!^=+[ \t]#{Regexp.quote(section)}.*?\n(.*?)^=!m
897
+ if section_contents = contents[re, 1]
898
+ index = 0
899
+ section_contents.scan(%r!^( \S.*?)(?=(^\S|\Z))!m) { |indented, unused|
900
+ code_sections = indented.split(%r!^ \#\#\#\# output:\s*$!)
901
+ code, expected = (
902
+ case code_sections.size
903
+ when 1
904
+ [indented, indented.scan(%r!\# => (.*?)\n!).flatten.join("\n")]
905
+ when 2
906
+ code_sections
907
+ else
908
+ raise "parse error"
909
+ end
910
+ )
911
+ run_doc_code(code, expected, index, instance, &block)
912
+ index += 1
913
+ }
914
+ else
915
+ raise "couldn't find section `#{section}' of `#{file}'"
916
+ end
917
+ end
918
+
919
+ def doc_to_spec(file, *sections, &block)
920
+ levitate = self
921
+ describe file do
922
+ sections.each { |section|
923
+ describe "section `#{section}'" do
924
+ it "should run as claimed" do
925
+ if block
926
+ levitate.run_doc_section(file, section, self, &block)
927
+ else
928
+ levitate.run_doc_section(file, section, self) {
929
+ |expected, actual, index|
930
+ actual.should == expected
931
+ }
932
+ end
933
+ end
934
+ end
935
+ }
936
+ end
937
+ end
938
+
939
+ def doc_to_test(file, *sections, &block)
940
+ levitate = self
941
+ klass = Class.new MiniTest::Unit::TestCase do
942
+ sections.each { |section|
943
+ define_method "test_#{file}_#{section}" do
944
+ if block
945
+ levitate.run_doc_section(file, section, self, &block)
946
+ else
947
+ levitate.run_doc_section(file, section, self) {
948
+ |expected, actual, index|
949
+ assert_equal expected, actual
950
+ }
951
+ end
952
+ end
953
+ }
954
+ end
955
+ Object.const_set("Test#{file}".gsub(".", ""), klass)
956
+ end
957
+ end
958
+ end