xmp2assert 1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rubocop.yml +172 -0
- data/.yardopts +5 -0
- data/Gemfile +27 -0
- data/LICENSE.txt +19 -0
- data/README.md +40 -0
- data/Rakefile +61 -0
- data/Stylegiude.md +284 -0
- data/exe/xmpcheck.rb +75 -0
- data/lib/xmp2assert/assertions.rb +157 -0
- data/lib/xmp2assert/classifier.rb +71 -0
- data/lib/xmp2assert/converter.rb +113 -0
- data/lib/xmp2assert/prettier_inspect.rb +50 -0
- data/lib/xmp2assert/quasifile.rb +144 -0
- data/lib/xmp2assert/template.erb +37 -0
- data/lib/xmp2assert/version.rb +27 -0
- data/lib/xmp2assert/xmp2rexp.rb +56 -0
- data/lib/xmp2assert.rb +41 -0
- data/xmp2assert.gemspec +71 -0
- metadata +249 -0
data/exe/xmpcheck.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
#! /your/favourite/path/to/ruby
|
2
|
+
# -*- mode: ruby; coding: utf-8; indent-tabs-mode: nil; ruby-indent-level 2 -*-
|
3
|
+
# -*- frozen_string_literal: true -*-
|
4
|
+
# -*- warn_indent: true -*-
|
5
|
+
|
6
|
+
# Copyright (c) 2017 Urabe, Shyouhei
|
7
|
+
#
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
# of this software and associated documentation files (the "Software"), to deal
|
10
|
+
# in the Software without restriction, including without limitation the rights
|
11
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
# copies of the Software, and to permit persons to whom the Software is
|
13
|
+
# furnished to do so, subject to the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24
|
+
# SOFTWARE.
|
25
|
+
|
26
|
+
abort "usage: #$0 FILES..." if ARGV.empty?
|
27
|
+
|
28
|
+
require 'test/unit/autorunner'
|
29
|
+
require 'pathname'
|
30
|
+
require 'xmp2assert'
|
31
|
+
|
32
|
+
class TC_Main < Test::Unit::TestCase
|
33
|
+
include XMP2Assert::Assertions
|
34
|
+
|
35
|
+
def self.expandfs argv
|
36
|
+
files = []
|
37
|
+
argv.each do |i|
|
38
|
+
p = Pathname.new i
|
39
|
+
if p.directory? then
|
40
|
+
files += expandfs p.children # recur
|
41
|
+
else
|
42
|
+
files << p
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
files.map! do |i|
|
47
|
+
XMP2Assert::Quasifile.new i
|
48
|
+
end
|
49
|
+
|
50
|
+
return files
|
51
|
+
end
|
52
|
+
private_class_method :expandfs
|
53
|
+
|
54
|
+
a = expandfs ARGV
|
55
|
+
p a
|
56
|
+
a.each do |f|
|
57
|
+
klass = XMP2Assert::Classifier.classify f
|
58
|
+
|
59
|
+
if klass.empty? then
|
60
|
+
test f.__FILE__ do
|
61
|
+
pend "no tests for #{f.__FILE__}"
|
62
|
+
end
|
63
|
+
else
|
64
|
+
test f.__FILE__ do
|
65
|
+
t, o = XMP2Assert::Converter.convert f
|
66
|
+
if klass.include? :'=>' then
|
67
|
+
t.eval binding
|
68
|
+
end
|
69
|
+
if klass.include? :'>>' then
|
70
|
+
assert_capture2e o, f
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
#! /your/favourite/path/to/ruby
|
2
|
+
# -*- mode: ruby; coding: utf-8; indent-tabs-mode: nil; ruby-indent-level 2 -*-
|
3
|
+
# -*- frozen_string_literal: true -*-
|
4
|
+
# -*- warn_indent: true -*-
|
5
|
+
|
6
|
+
# Copyright (c) 2017 Urabe, Shyouhei
|
7
|
+
#
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
# of this software and associated documentation files (the "Software"), to deal
|
10
|
+
# in the Software without restriction, including without limitation the rights
|
11
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
# copies of the Software, and to permit persons to whom the Software is
|
13
|
+
# furnished to do so, subject to the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24
|
+
# SOFTWARE.
|
25
|
+
|
26
|
+
require 'rbconfig'
|
27
|
+
require 'open3'
|
28
|
+
require 'tempfile'
|
29
|
+
require 'erb'
|
30
|
+
require 'test/unit'
|
31
|
+
require 'test/unit/assertions'
|
32
|
+
require 'test/unit/assertion-failed-error'
|
33
|
+
require_relative 'xmp2rexp'
|
34
|
+
|
35
|
+
# Helper module that implements assertions.
|
36
|
+
module XMP2Assert::Assertions
|
37
|
+
include Test::Unit::Assertions
|
38
|
+
include XMP2Assert::XMP2Rexp
|
39
|
+
|
40
|
+
# Run a ruby script and assert for its output.
|
41
|
+
#
|
42
|
+
# ```ruby
|
43
|
+
# assert_capture2e "foo\n", Quasifile.new("puts 'foo'")
|
44
|
+
# ```
|
45
|
+
#
|
46
|
+
# @param expected [String] expected output.
|
47
|
+
# @param script [Quasifile] a ruby script.
|
48
|
+
# @param message [String] extra failure message.
|
49
|
+
# @param rubyopts [Array<String>] extra opts to pass to ruby process.
|
50
|
+
# @param opts [Hash{Symbol=>Object}] extra opts to pass to spawn.
|
51
|
+
# @note
|
52
|
+
# As the method name implies the assertion is against both stdin and stderr
|
53
|
+
# at once. This is for convenience.
|
54
|
+
def assert_capture2e expected, script, message = nil, rubyopts: nil, **opts
|
55
|
+
actual, _ = ruby script, rubyopts: rubyopts, **opts
|
56
|
+
actual.force_encoding expected.encoding
|
57
|
+
return assert_xmp_raw expected, actual, message
|
58
|
+
end
|
59
|
+
|
60
|
+
# Assert if the given expression is in the same form of xmp.
|
61
|
+
#
|
62
|
+
# ```ruby
|
63
|
+
# assert_xmp '#<Object:0x007f896c9b49c8>', Object.new
|
64
|
+
# ```
|
65
|
+
#
|
66
|
+
# @param xmp [String] expected pattern of inspect.
|
67
|
+
# @param expr [Object] object to check.
|
68
|
+
# @param message [String] extra failure message.
|
69
|
+
def assert_xmp xmp, expr, message = nil
|
70
|
+
assert_xmp_raw xmp, expr.inspect, message
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# :TODO: is it private?
|
76
|
+
def assert_xmp_raw xmp, actual, message = nil
|
77
|
+
msg = genmsg xmp, actual, message
|
78
|
+
expected = xmp2rexp xmp
|
79
|
+
|
80
|
+
raise unless expected.match actual
|
81
|
+
rescue
|
82
|
+
# Regexp#match can raise. That should also be a failure.
|
83
|
+
ix = Test::Unit::Assertions::AssertionMessage.convert xmp
|
84
|
+
ia = Test::Unit::Assertions::AssertionMessage.convert actual
|
85
|
+
ex = Test::Unit::AssertionFailedError.new(msg,
|
86
|
+
expected: xmp,
|
87
|
+
actual: actual,
|
88
|
+
inspected_expected: ix,
|
89
|
+
inspected_actual: ia,
|
90
|
+
user_message: message)
|
91
|
+
raise ex
|
92
|
+
else
|
93
|
+
return self # or...?
|
94
|
+
end
|
95
|
+
|
96
|
+
# We support pre-&. versions
|
97
|
+
def try obj, msg
|
98
|
+
return obj.send msg
|
99
|
+
rescue NoMethodError
|
100
|
+
return nil
|
101
|
+
end
|
102
|
+
|
103
|
+
def genmsg x, y, z = nil
|
104
|
+
diff = Test::Unit::Assertions::AssertionMessage.delayed_diff x, y
|
105
|
+
if try(x, :encoding) != try(y, :encoding) then
|
106
|
+
fmt = "<?>(?) expected but was\n<?>(?).?"
|
107
|
+
argv = [x, x.encoding.name, y, y.encoding.name, diff]
|
108
|
+
else
|
109
|
+
fmt = "<?> expected but was\n<?>.?"
|
110
|
+
argv = [x, y, diff]
|
111
|
+
end
|
112
|
+
return Test::Unit::Assertions::AssertionMessage.new z, fmt, argv
|
113
|
+
end
|
114
|
+
|
115
|
+
def erb
|
116
|
+
unless defined? @@erb
|
117
|
+
myself = Pathname.new __FILE__
|
118
|
+
path = myself + '../template.erb'
|
119
|
+
src = path.read mode: 'rb:binary:binary'
|
120
|
+
@@erb = ERB.new src, nil, '%-'
|
121
|
+
@@erb.filename = path.realpath.to_path if defined? $DEBUG
|
122
|
+
end
|
123
|
+
return @@erb
|
124
|
+
end
|
125
|
+
|
126
|
+
def empty_binding
|
127
|
+
# This `eval 'binding'` does not return the current binding but creates one
|
128
|
+
# on top of it. To make it really empty, this method has to have zero
|
129
|
+
# arity, and zero local variables.
|
130
|
+
return eval 'binding'
|
131
|
+
end
|
132
|
+
|
133
|
+
def empty_binding_with hash
|
134
|
+
return empty_binding.tap do |b|
|
135
|
+
hash.each_pair do |k, v|
|
136
|
+
b.local_variable_set k, v
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def ruby script, rubyopts: nil, **opts
|
142
|
+
Tempfile.create '' do |f|
|
143
|
+
b = empty_binding_with script: script
|
144
|
+
s = erb.result b
|
145
|
+
f.write s
|
146
|
+
argv = [RbConfig.ruby, rubyopts, f.path]
|
147
|
+
if defined? ENV['BUNDLE_BIN_PATH']
|
148
|
+
argv = [ENV['BUNDLE_BIN_PATH'], 'exec'] + argv
|
149
|
+
end
|
150
|
+
argv.flatten!
|
151
|
+
argv.compact!
|
152
|
+
f.flush
|
153
|
+
# STDERR.puts(f.path) ; sleep # for debug
|
154
|
+
return Open3.capture2e(*argv, binmode: true, **opts)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#! /your/favourite/path/to/ruby
|
2
|
+
# -*- mode: ruby; coding: utf-8; indent-tabs-mode: nil; ruby-indent-level 2 -*-
|
3
|
+
# -*- frozen_string_literal: true -*-
|
4
|
+
# -*- warn_indent: true -*-
|
5
|
+
|
6
|
+
# Copyright (c) 2017 Urabe, Shyouhei
|
7
|
+
#
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
# of this software and associated documentation files (the "Software"), to deal
|
10
|
+
# in the Software without restriction, including without limitation the rights
|
11
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
# copies of the Software, and to permit persons to whom the Software is
|
13
|
+
# furnished to do so, subject to the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24
|
+
# SOFTWARE.
|
25
|
+
|
26
|
+
require 'ripper'
|
27
|
+
|
28
|
+
# Usually, you want to check LOTS of files that may or may not contain xmp
|
29
|
+
# comments at once, maybe from inside of a CI process. That's OK but we want
|
30
|
+
# to speed things up, so here we filter out files that are not necessary to
|
31
|
+
# convert.
|
32
|
+
#
|
33
|
+
# Typical usage:
|
34
|
+
#
|
35
|
+
# ```ruby
|
36
|
+
# Pathname.glob('**/*.rb').select do |f|
|
37
|
+
# XMP2Assert::Classifier.classify(f)
|
38
|
+
# end
|
39
|
+
# ```
|
40
|
+
class XMP2Assert::Classifier < Ripper
|
41
|
+
private_class_method :new
|
42
|
+
|
43
|
+
# @param qfile [Quasifile] file-ish
|
44
|
+
# @return [<Symbol>] either empty, :=>, :>>, or both.
|
45
|
+
# @note syntax error results in empty return value.
|
46
|
+
def self.classify qfile
|
47
|
+
case qfile when XMP2Assert::Quasifile then
|
48
|
+
this = new qfile.read, qfile.__FILE__, qfile.__LINE__
|
49
|
+
return this.send :parse
|
50
|
+
else
|
51
|
+
q = XMP2Assert::Quasifile.new qfile
|
52
|
+
return classify q
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def parse
|
59
|
+
@ret = []
|
60
|
+
super
|
61
|
+
return @ret
|
62
|
+
end
|
63
|
+
|
64
|
+
def on_comment tok
|
65
|
+
case tok
|
66
|
+
when /^# =>/ then @ret |= [:'=>']
|
67
|
+
when /^# >>/ then @ret |= [:'>>']
|
68
|
+
when /^# ~>/ then @ret |= [:'>>']
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
#! /your/favourite/path/to/ruby
|
2
|
+
# -*- mode: ruby; coding: utf-8; indent-tabs-mode: nil; ruby-indent-level 2 -*-
|
3
|
+
# -*- frozen_string_literal: true -*-
|
4
|
+
# -*- warn_indent: true -*-
|
5
|
+
|
6
|
+
# Copyright (c) 2017 Urabe, Shyouhei
|
7
|
+
#
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
# of this software and associated documentation files (the "Software"), to deal
|
10
|
+
# in the Software without restriction, including without limitation the rights
|
11
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
# copies of the Software, and to permit persons to whom the Software is
|
13
|
+
# furnished to do so, subject to the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24
|
+
# SOFTWARE.
|
25
|
+
|
26
|
+
require 'ripper'
|
27
|
+
require 'uuid'
|
28
|
+
|
29
|
+
class XMP2Assert::Converter < Ripper
|
30
|
+
private_class_method :new
|
31
|
+
|
32
|
+
def self.convert qfile
|
33
|
+
case qfile when XMP2Assert::Quasifile then
|
34
|
+
this = new qfile.read, qfile.__FILE__, qfile.__LINE__
|
35
|
+
s, o = this.send :convert
|
36
|
+
r = XMP2Assert::Quasifile.new s, qfile.__FILE__, qfile.__LINE__
|
37
|
+
return r, o
|
38
|
+
else
|
39
|
+
q = XMP2Assert::Quasifile.new qfile
|
40
|
+
return convert q
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def pos
|
47
|
+
return [filename, lineno, column]
|
48
|
+
end
|
49
|
+
|
50
|
+
def convert
|
51
|
+
@ret = []
|
52
|
+
@xmps = []
|
53
|
+
@last_seen_xmp = nil
|
54
|
+
@outputs = String.new
|
55
|
+
parse
|
56
|
+
postprocess
|
57
|
+
return @ret.join, @outputs
|
58
|
+
end
|
59
|
+
|
60
|
+
def postprocess
|
61
|
+
@ret.sort!
|
62
|
+
@ret.map! do |(_, xmp, tok)|
|
63
|
+
if xmp
|
64
|
+
n = UUID.create_sha1 tok, Namespace
|
65
|
+
n = n.to_uri
|
66
|
+
n.gsub! %r/[:-]/, '_'
|
67
|
+
sprintf ".tap {|%s| assert_xmp(%s, %s) }\n", n, tok.chomp.dump, n
|
68
|
+
else
|
69
|
+
tok
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Namespace = UUID.create_random
|
75
|
+
private_constant :Namespace
|
76
|
+
|
77
|
+
def on_comment tok
|
78
|
+
xmp = false
|
79
|
+
case tok
|
80
|
+
when /^\# [~>]> (.+\n)/ then
|
81
|
+
@outputs << $1
|
82
|
+
when /^\# => (.+\n)/ then
|
83
|
+
if @last_seen_xmp
|
84
|
+
@last_seen_xmp << $1
|
85
|
+
tok = "#\n"
|
86
|
+
else
|
87
|
+
tok = @last_seen_xmp = $1
|
88
|
+
xmp = true
|
89
|
+
end
|
90
|
+
else
|
91
|
+
@last_seen_xmp = nil
|
92
|
+
end
|
93
|
+
@ret << [pos, xmp, tok]
|
94
|
+
end
|
95
|
+
|
96
|
+
def on_sp tok
|
97
|
+
# no reset @last_seen_xmp
|
98
|
+
@ret << [pos, false, tok]
|
99
|
+
end
|
100
|
+
|
101
|
+
def on_scanner_event tok
|
102
|
+
@last_seen_xmp = nil
|
103
|
+
@ret << [pos, false, tok]
|
104
|
+
end
|
105
|
+
|
106
|
+
pim = private_instance_methods false
|
107
|
+
SCANNER_EVENTS.each do |e|
|
108
|
+
m = :"on_#{e}"
|
109
|
+
unless pim.include? m then
|
110
|
+
alias_method m, :on_scanner_event
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#! /your/favourite/path/to/ruby
|
2
|
+
# -*- mode: ruby; coding: utf-8; indent-tabs-mode: nil; ruby-indent-level 2 -*-
|
3
|
+
# -*- frozen_string_literal: false -*-
|
4
|
+
# -*- warn_indent: true -*-
|
5
|
+
|
6
|
+
# Copyright (c) 2017 Urabe, Shyouhei
|
7
|
+
#
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
# of this software and associated documentation files (the "Software"), to deal
|
10
|
+
# in the Software without restriction, including without limitation the rights
|
11
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
# copies of the Software, and to permit persons to whom the Software is
|
13
|
+
# furnished to do so, subject to the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24
|
+
# SOFTWARE.
|
25
|
+
|
26
|
+
require 'pp'
|
27
|
+
|
28
|
+
# By including this module your class gets a {#inspect} method which uses
|
29
|
+
# {::PP} methods to control outputs. You don't have to worry about redefining
|
30
|
+
# both. Just define your {#pretty_print} and that should also work for
|
31
|
+
# inspection.
|
32
|
+
module XMP2Assert::PrettierInspect
|
33
|
+
|
34
|
+
# (see Object#inspect)
|
35
|
+
#
|
36
|
+
# Prettier inspection.
|
37
|
+
def inspect
|
38
|
+
str = PP.pp self, '', Float::INFINITY
|
39
|
+
str.chomp!
|
40
|
+
return str
|
41
|
+
end
|
42
|
+
|
43
|
+
# System-provided pretty print honors {#inspect} when present but we don't
|
44
|
+
# like that. Force it behave as if inspect wasn't there.
|
45
|
+
#
|
46
|
+
# @param pp [PP] pp.
|
47
|
+
def pretty_print pp
|
48
|
+
pp.pp_object self
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
#! /your/favourite/path/to/ruby
|
2
|
+
# -*- mode: ruby; coding: utf-8; indent-tabs-mode: nil; ruby-indent-level 2 -*-
|
3
|
+
# -*- frozen_string_literal: true -*-
|
4
|
+
# -*- warn_indent: true -*-
|
5
|
+
|
6
|
+
# Copyright (c) 2017 Urabe, Shyouhei
|
7
|
+
#
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
# of this software and associated documentation files (the "Software"), to deal
|
10
|
+
# in the Software without restriction, including without limitation the rights
|
11
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
# copies of the Software, and to permit persons to whom the Software is
|
13
|
+
# furnished to do so, subject to the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24
|
+
# SOFTWARE.
|
25
|
+
|
26
|
+
require 'open-uri'
|
27
|
+
require 'pathname'
|
28
|
+
|
29
|
+
# XMP2Assert converts a ruby script into a test file but we want to hold
|
30
|
+
# original path name / line number for diagnostic purposes. So this class.
|
31
|
+
class XMP2Assert::Quasifile
|
32
|
+
include XMP2Assert::PrettierInspect
|
33
|
+
|
34
|
+
# @return [Quasifile] a new quasifile.
|
35
|
+
#
|
36
|
+
# @overload new(qfile)
|
37
|
+
# Just return the given object (for possible recursive calls).
|
38
|
+
#
|
39
|
+
# @param qfile [Quasifile] an instance of this class.
|
40
|
+
# @return [Quasifile] identical to the argunemt.
|
41
|
+
#
|
42
|
+
# @overload new(uri, file = uri.to_s, line = 1)
|
43
|
+
# Obtains the resource pointed by the URI, parses the resource as a ruby
|
44
|
+
# script, and constructs a quasifile according to that.
|
45
|
+
#
|
46
|
+
# @param uri [URI] a URI of a ruby script.
|
47
|
+
# @param file [String] file path.
|
48
|
+
# @param line [Integer] line offset.
|
49
|
+
# @return [Quasifile] generated quasifile.
|
50
|
+
# @raise [OpenURI::HTTPError] 404 and such.
|
51
|
+
#
|
52
|
+
# @overload new(path, file = path.to_path, line = 1)
|
53
|
+
# Same as uri version, but accepts a pathname instead.
|
54
|
+
#
|
55
|
+
# @param path [#to_path] a pathname that points to a ruby script.
|
56
|
+
# @param file [String] file path.
|
57
|
+
# @param line [Integer] line offset.
|
58
|
+
# @return [Quasifile] generated qiasifile.
|
59
|
+
# @raise [Errno::ENOENT] not found.
|
60
|
+
# @raise [Errno::EISDIR] path is directory.
|
61
|
+
# @raise [Errno::EACCESS] permission denied.
|
62
|
+
# @raise [Errno::ELOOP] infinite symlink.
|
63
|
+
#
|
64
|
+
# @overload new(io, file = '(eval)', line = io.lineno + 1)
|
65
|
+
# Same as pathname version, but it also directly accepts arbitrary IO
|
66
|
+
# instances to read ruby scripts from. It migth be handy for you to pass a
|
67
|
+
# pipe here. The script filename may or may not be inferred depending on
|
68
|
+
# the IO (Files might be able to, Sockets hardly likely). Failures in
|
69
|
+
# filename resolution do not render exceptions. Rather the info lacks
|
70
|
+
# silently.
|
71
|
+
#
|
72
|
+
# @param io [#to_io] an IO that can be read.
|
73
|
+
# @param file [String] file path.
|
74
|
+
# @param line [Integer] line offset.
|
75
|
+
# @return [Quasifile] generated qiasifile.
|
76
|
+
# @raise [IOError] io not open for read, already closed, etc.
|
77
|
+
#
|
78
|
+
# @overload new(str, file = '(eval)', line = 1)
|
79
|
+
# Same as io version, but it also directly accepts a ruby script as a
|
80
|
+
# string. Obviously in this case, you cannot infer its filename.
|
81
|
+
#
|
82
|
+
# @param str [#to_io] a content of a ruby script.
|
83
|
+
# @param file [String] file path.
|
84
|
+
# @param line [Integer] line offset.
|
85
|
+
# @return [Quasifile] generated qiasifile.
|
86
|
+
#
|
87
|
+
def self.new(obj, file = nil, line = nil)
|
88
|
+
case
|
89
|
+
when src = switch { obj.to_str } then # LIKELY
|
90
|
+
return allocate.tap do |ret|
|
91
|
+
ret.send(:initialize, src, file||'(eval)', line||1)
|
92
|
+
end
|
93
|
+
when self === obj then return obj
|
94
|
+
when OpenURI::OpenRead === obj then src, path = obj.read, obj.to_s
|
95
|
+
when path = switch { obj.to_path } then src = obj.read
|
96
|
+
when io = switch { obj.to_io } then off, src = io.lineno+1, io.read
|
97
|
+
when src = switch { obj.read } then # unknown class but works
|
98
|
+
else
|
99
|
+
raise TypeError, "something readable expected but given: #{obj.class}"
|
100
|
+
end
|
101
|
+
|
102
|
+
return new(src, file || path, line || off) # recur
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.switch
|
106
|
+
return yield
|
107
|
+
rescue NoMethodError
|
108
|
+
return nil
|
109
|
+
end
|
110
|
+
private_class_method :switch
|
111
|
+
|
112
|
+
attr_reader :__FILE__ # @return [String] file name of this script.
|
113
|
+
attr_reader :__LINE__ # @return [Integer] line offset.
|
114
|
+
attr_reader :__ENCODING__ # @return [Encoding] script encoding.
|
115
|
+
attr_reader :read # @return [String] content of the ruby script.
|
116
|
+
|
117
|
+
# @param content [String] a content of a ruby script.
|
118
|
+
# @param file [String] file path.
|
119
|
+
# @param line [Integer] line offset.
|
120
|
+
def initialize(content, file, line)
|
121
|
+
@__FILE__ = file
|
122
|
+
@__LINE__ = line
|
123
|
+
@__ENCODING__ = content.encoding
|
124
|
+
@read = content
|
125
|
+
end
|
126
|
+
|
127
|
+
# Eavluate the content script
|
128
|
+
# @param b [Binding] target binding (default toplevel).
|
129
|
+
# @return anything that the content evaluates.
|
130
|
+
def eval b = TOPLEVEL_BINDING
|
131
|
+
Kernel.eval @read, b, @__FILE__, @__LINE__
|
132
|
+
end
|
133
|
+
|
134
|
+
unless $DEBUG
|
135
|
+
# @!group Inspection
|
136
|
+
|
137
|
+
# For pretty print
|
138
|
+
def pretty_print_instance_variables
|
139
|
+
return %w'@__FILE__ @__LINE__'
|
140
|
+
end
|
141
|
+
|
142
|
+
# @!endgroup
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#! /your/favourite/path/to/ruby
|
2
|
+
# -*- mode: ruby; <%=
|
3
|
+
"coding: #{script.__ENCODING__}"
|
4
|
+
%>; indent-tabs-mode: nil; ruby-indent-level: 2 -*-
|
5
|
+
%#> # <- :HACK: emacs font-lock
|
6
|
+
# -*- frozen_string_literal: true -*-
|
7
|
+
# -*- warn_indent: true -*-
|
8
|
+
|
9
|
+
# Copyright (c) 2017 Urabe, Shyouhei
|
10
|
+
#
|
11
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
12
|
+
# of this software and associated documentation files (the "Software"), to deal
|
13
|
+
# in the Software without restriction, including without limitation the rights
|
14
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
15
|
+
# copies of the Software, and to permit persons to whom the Software is
|
16
|
+
# furnished to do so, subject to the following conditions:
|
17
|
+
#
|
18
|
+
# The above copyright notice and this permission notice shall be
|
19
|
+
# included in all copies or substantial portions of the Software.
|
20
|
+
#
|
21
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
22
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
23
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
24
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
25
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
26
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
27
|
+
# SOFTWARE.
|
28
|
+
|
29
|
+
file = "<%= script.__FILE__ %>" #=
|
30
|
+
line = <%= script.__LINE__ %> #=
|
31
|
+
src = ::DATA.read
|
32
|
+
eval src, binding, file, line
|
33
|
+
|
34
|
+
# Below is a generated software, sourced from <%= script.__FILE__ %>.
|
35
|
+
# Above copyright notice does not apply any further. Consult the original.
|
36
|
+
__END__
|
37
|
+
<%= script.read.dup.force_encoding('binary') -%>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#! /your/favourite/path/to/ruby
|
2
|
+
# -*- mode: ruby; coding: utf-8; indent-tabs-mode: nil; ruby-indent-level 2 -*-
|
3
|
+
# -*- frozen_string_literal: true -*-
|
4
|
+
# -*- warn_indent: true -*-
|
5
|
+
|
6
|
+
# Copyright (c) 2017 Urabe, Shyouhei
|
7
|
+
#
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
# of this software and associated documentation files (the "Software"), to deal
|
10
|
+
# in the Software without restriction, including without limitation the rights
|
11
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
# copies of the Software, and to permit persons to whom the Software is
|
13
|
+
# furnished to do so, subject to the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24
|
+
# SOFTWARE.
|
25
|
+
;
|
26
|
+
|
27
|
+
XMP2Assert::VERSION = 1
|