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