xmp2assert 1
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.
- 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
|