dokaz 0.0.3 → 0.0.5
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 +5 -13
- data/Changelog.md +5 -0
- data/bin/dokaz +8 -4
- data/dokaz.gemspec +5 -1
- data/examples/README.md +2 -1
- data/lib/dokaz/formatters.rb +23 -8
- data/lib/dokaz/parser.rb +72 -4
- data/lib/dokaz.rb +14 -7
- metadata +56 -15
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
NTkxNjdlMDk0Mjk5NDZiYmU0ODBlMDE2YjUzYTJjMzliM2YyN2UyZg==
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 523736088a32b27b2e16d362c0ebe5cb704eff2153cd6b07a98565b58fd7dc01
|
4
|
+
data.tar.gz: c86ec189e60c7eaa6f485ef6b5ee807e5bc245300cff3d759bfb1b9a270b37fd
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
YWEyNDk0OTZkOGVmYjg5ZDcwNWIxYTc5OGM2ODMzNzRmNTljZTY3Y2VkOGM1
|
11
|
-
ZmEzZWM5Zjg1NjQ2ZmU2MWZhZTQwYWZjMjE1MDFiNmYzOGY5OGU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
Y2JmMGY4ODljN2QxZjE0ODA4ZDYwN2Y4Mjg0MmM1M2EwYWNkYjM1YTBjYzIw
|
14
|
-
YTU2MTYwMjllOTc1NzgyMzUyODQxZmIyN2Y1NWQyMWNlM2E3ZWFmZmFlNThk
|
15
|
-
OTcyMjVjMjE5ZmI3ZWUwYTZhZGM5MjE4MTEwYTM0MTA0OGU1ZGY=
|
6
|
+
metadata.gz: 31c454210e0d3f8dc5ed652975fe24408c76c2004e743acea40b15b9914b102f759d7e569ce3f0b219e876a7ec07e7773e8ecc79f36abb18e69ca7c0aa925111
|
7
|
+
data.tar.gz: b798d663c0acf6c223a90f638c28dec10b52fb2b0b4112bf95a43371cb1bff2b81cf30ea50d2069d01b0665ddb70646660faa3c36466877ebeca08693aa48e15
|
data/Changelog.md
ADDED
data/bin/dokaz
CHANGED
@@ -5,13 +5,10 @@ require 'slop'
|
|
5
5
|
$:.unshift 'lib'
|
6
6
|
require 'dokaz'
|
7
7
|
|
8
|
-
if File.
|
8
|
+
if File.exist?('.dokaz')
|
9
9
|
ARGV.push(*File.read('.dokaz').split(/\s+/m))
|
10
10
|
end
|
11
11
|
|
12
|
-
patterns = []
|
13
|
-
patterns << ARGV.shift until ARGV.empty? || ARGV.first =~ /^-/
|
14
|
-
|
15
12
|
HELP = %Q{
|
16
13
|
Usage: dokaz [patterns] [options]
|
17
14
|
|
@@ -26,12 +23,19 @@ Options:
|
|
26
23
|
--help Shows this message
|
27
24
|
}
|
28
25
|
|
26
|
+
patterns = []
|
27
|
+
patterns << ARGV.shift until ARGV.empty? || ARGV.first =~ /^-/
|
28
|
+
|
29
29
|
options = Slop.parse do
|
30
30
|
on :r, :require=, "Additional files to require, comma-separated"
|
31
31
|
on :f, :format=, "Output format (spec or show[case])"
|
32
32
|
on :help
|
33
33
|
end
|
34
34
|
|
35
|
+
if patterns.empty?
|
36
|
+
patterns.concat(Dir['README.{md,markdown}'])
|
37
|
+
end
|
38
|
+
|
35
39
|
if patterns.empty? || options.help?
|
36
40
|
puts HELP
|
37
41
|
exit
|
data/dokaz.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'dokaz'
|
3
|
-
s.version = '0.0.
|
3
|
+
s.version = '0.0.5'
|
4
4
|
s.authors = ['Victor Shepelev']
|
5
5
|
s.email = 'zverok.offline@gmail.com'
|
6
6
|
s.homepage = 'https://github.com/zverok/dokaz'
|
@@ -24,7 +24,11 @@ Gem::Specification.new do |s|
|
|
24
24
|
|
25
25
|
s.add_dependency 'ansi'
|
26
26
|
s.add_dependency 'slop', '~> 3'
|
27
|
+
s.add_dependency 'rouge', '~> 4'
|
27
28
|
|
28
29
|
s.add_development_dependency 'rspec', '~> 3'
|
29
30
|
s.add_development_dependency 'rspec-its', '~> 1'
|
31
|
+
|
32
|
+
s.add_development_dependency 'rake'
|
33
|
+
s.add_development_dependency 'rubygems-tasks'
|
30
34
|
end
|
data/examples/README.md
CHANGED
@@ -51,13 +51,14 @@ puts a.sum(10)
|
|
51
51
|
This code throws an error:
|
52
52
|
|
53
53
|
```ruby
|
54
|
+
# It's a comment, but not seen while evaluating
|
54
55
|
100 / 0
|
55
56
|
```
|
56
57
|
|
57
58
|
This code requires additional require:
|
58
59
|
|
59
60
|
```ruby
|
60
|
-
BigDecimal.new(
|
61
|
+
BigDecimal.new('0')
|
61
62
|
```
|
62
63
|
|
63
64
|
Try to run it with option `--require cgi`.
|
data/lib/dokaz/formatters.rb
CHANGED
@@ -1,8 +1,14 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'ansi/code'
|
3
|
+
require 'rouge'
|
3
4
|
|
4
5
|
class Dokaz
|
5
6
|
class Formatter
|
7
|
+
def initialize
|
8
|
+
@rouge = Rouge::Formatters::Terminal256.new(Rouge::Themes::Molokai.new)
|
9
|
+
@lexer = Rouge::Lexers::Ruby.new
|
10
|
+
end
|
11
|
+
|
6
12
|
def start_block(block)
|
7
13
|
end
|
8
14
|
|
@@ -35,6 +41,14 @@ class Dokaz
|
|
35
41
|
color(:dark, str)
|
36
42
|
end
|
37
43
|
|
44
|
+
def code(str)
|
45
|
+
if STDOUT.tty?
|
46
|
+
@rouge.format(@lexer.lex(str))
|
47
|
+
else
|
48
|
+
code
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
38
52
|
def color(code, str)
|
39
53
|
if STDOUT.tty?
|
40
54
|
ANSI.send(code){str}
|
@@ -46,6 +60,7 @@ class Dokaz
|
|
46
60
|
|
47
61
|
class SpecFormatter < Formatter
|
48
62
|
def initialize
|
63
|
+
super
|
49
64
|
@ok = 0
|
50
65
|
@errors = []
|
51
66
|
end
|
@@ -65,14 +80,14 @@ class Dokaz
|
|
65
80
|
puts
|
66
81
|
puts
|
67
82
|
|
68
|
-
@errors.each do |
|
69
|
-
puts code
|
83
|
+
@errors.each do |src, e|
|
84
|
+
puts code(src)
|
70
85
|
puts( error("#{e.message} (#{e.class})\n " + filter_backtrace(e.backtrace).join("\n ") + "\n"))
|
71
86
|
end
|
72
87
|
|
73
88
|
puts
|
74
89
|
@errors.each do |code, e|
|
75
|
-
ln = e.backtrace.
|
90
|
+
ln = filter_backtrace(e.backtrace).last.to_s.sub(/:in .*$/, '')
|
76
91
|
puts error("dokaz #{ln}") + comment(" # #{e.message} (#{e.class})")
|
77
92
|
end
|
78
93
|
|
@@ -97,16 +112,16 @@ class Dokaz
|
|
97
112
|
puts "#{block.caption}\n#{'=' * block.caption.size}\n\n"
|
98
113
|
end
|
99
114
|
|
100
|
-
def output(
|
101
|
-
puts code
|
115
|
+
def output(src, res, out)
|
116
|
+
puts code(src)
|
102
117
|
unless out.empty?
|
103
|
-
puts comment("# Prints: \n# " + out.split("\n").join("\n#
|
118
|
+
puts comment("# Prints: \n# " + out.split("\n").join("\n# "))
|
104
119
|
end
|
105
120
|
puts comment("# => " + res.inspect.split("\n").join("\n# "))
|
106
121
|
end
|
107
122
|
|
108
|
-
def output_err(
|
109
|
-
puts code
|
123
|
+
def output_err(src, e)
|
124
|
+
puts code(src)
|
110
125
|
puts comment("# Throws: #{e.message} (#{e.class})")
|
111
126
|
end
|
112
127
|
|
data/lib/dokaz/parser.rb
CHANGED
@@ -1,11 +1,48 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'strscan'
|
3
|
+
require 'stringio'
|
3
4
|
|
4
5
|
class Dokaz
|
6
|
+
class Statement
|
7
|
+
attr_reader :code, :line, :block
|
8
|
+
attr_reader :pre_comment
|
9
|
+
attr_accessor :comment
|
10
|
+
|
11
|
+
def initialize(code, line, block)
|
12
|
+
@raw_code, @line, @block = code, line, block
|
13
|
+
@comment = ''
|
14
|
+
|
15
|
+
parse!
|
16
|
+
end
|
17
|
+
|
18
|
+
def empty?
|
19
|
+
code.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def parse!
|
25
|
+
pre_lines = []
|
26
|
+
lines = @raw_code.split("\n")
|
27
|
+
while !lines.empty? && (lines.first =~ /^\s*\#/ || lines.first.strip.empty?)
|
28
|
+
pre_lines << lines.shift
|
29
|
+
@line += 1
|
30
|
+
end
|
31
|
+
@code = lines.join("\n")
|
32
|
+
@pre_comment = pre_lines.reject{|ln| ln.strip.empty?}.join("\n")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
5
36
|
class Block
|
37
|
+
FakeIRBContext = Struct.new(:local_variables)
|
38
|
+
|
6
39
|
attr_reader :code, :line, :file
|
40
|
+
attr_reader :statements
|
41
|
+
|
7
42
|
def initialize(code, line, file)
|
8
43
|
@code, @line, @file = code, line, file
|
44
|
+
|
45
|
+
parse!
|
9
46
|
end
|
10
47
|
|
11
48
|
def end_line
|
@@ -19,6 +56,35 @@ class Dokaz
|
|
19
56
|
def inside?(ln)
|
20
57
|
(line..end_line).cover?(ln)
|
21
58
|
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def parse!
|
63
|
+
@statements = []
|
64
|
+
lex = RubyLex.new
|
65
|
+
|
66
|
+
# We do unholy things by reusing IRB's internal helper classes.
|
67
|
+
# In 3.2 (ver.1.6), IRB changed them to be more complicated. I only had
|
68
|
+
# time to quick-hack it around with fake copies of object IRB use.
|
69
|
+
# It might fail anytime, but works on test examples :shrug:
|
70
|
+
if IRB::VERSION >= '1.6'
|
71
|
+
ctx = FakeIRBContext.new(local_variables: [])
|
72
|
+
lex.set_input(SpecIO.new(code), context: ctx)
|
73
|
+
lex.each_top_level_statement(ctx) do |st, line_no|
|
74
|
+
@statements << Statement.new(st, line + line_no, self)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
lex.set_input(SpecIO.new(code))
|
78
|
+
lex.each_top_level_statement do |st, line_no|
|
79
|
+
@statements << Statement.new(st, line + line_no, self)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
@statements.each_cons(2){|s1, s2|
|
84
|
+
s1.comment = s2.pre_comment
|
85
|
+
}
|
86
|
+
@statements.reject!(&:empty?)
|
87
|
+
end
|
22
88
|
end
|
23
89
|
|
24
90
|
class Parser
|
@@ -27,9 +93,11 @@ class Dokaz
|
|
27
93
|
end
|
28
94
|
|
29
95
|
def parse
|
30
|
-
|
96
|
+
blocks = []
|
31
97
|
ln = 0
|
98
|
+
|
32
99
|
scanner = StringScanner.new(File.read(@path))
|
100
|
+
|
33
101
|
loop do
|
34
102
|
text = scanner.scan_until(/\n```ruby\n/)
|
35
103
|
break unless text
|
@@ -37,14 +105,14 @@ class Dokaz
|
|
37
105
|
ln += text.count("\n")
|
38
106
|
code = scanner.scan_until(/\n```\n/)
|
39
107
|
if !code
|
40
|
-
|
108
|
+
blocks << Block.new(scanner.rest, ln, @path)
|
41
109
|
break
|
42
110
|
end
|
43
|
-
|
111
|
+
blocks << Block.new(code.sub(/```\Z/, ''), ln, @path)
|
44
112
|
ln += code.count("\n")
|
45
113
|
end
|
46
114
|
|
47
|
-
|
115
|
+
blocks
|
48
116
|
end
|
49
117
|
end
|
50
118
|
end
|
data/lib/dokaz.rb
CHANGED
@@ -11,6 +11,13 @@ class Dokaz
|
|
11
11
|
'show' => ShowcaseFormatter,
|
12
12
|
'showcase' => ShowcaseFormatter
|
13
13
|
}
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def before(&block)
|
17
|
+
return @before || ->(){} unless block
|
18
|
+
@before = block
|
19
|
+
end
|
20
|
+
end
|
14
21
|
|
15
22
|
def initialize(patterns, options = {})
|
16
23
|
@blocks = select_blocks(patterns)
|
@@ -23,6 +30,8 @@ class Dokaz
|
|
23
30
|
end
|
24
31
|
|
25
32
|
def run
|
33
|
+
self.class.before.call
|
34
|
+
|
26
35
|
puts "Running #{@blocks.count} blocks from #{@blocks.map(&:file).uniq.count} files\n\n"
|
27
36
|
|
28
37
|
@blocks.each do |b|
|
@@ -36,17 +45,15 @@ class Dokaz
|
|
36
45
|
private
|
37
46
|
|
38
47
|
def process_block(block)
|
39
|
-
|
40
|
-
lex.set_input(SpecIO.new(block.code))
|
41
|
-
lex.each_top_level_statement do |line, line_no|
|
48
|
+
block.statements.each do |st|
|
42
49
|
begin
|
43
50
|
res = nil
|
44
51
|
out = capture_output{
|
45
|
-
res = eval(
|
52
|
+
res = eval(st.code, TOPLEVEL_BINDING, block.file, st.line)
|
46
53
|
}
|
47
|
-
@formatter.output(
|
48
|
-
rescue => e
|
49
|
-
@formatter.output_err(
|
54
|
+
@formatter.output(st.code, res, out)
|
55
|
+
rescue Exception => e
|
56
|
+
@formatter.output_err(st.code, e)
|
50
57
|
break
|
51
58
|
end
|
52
59
|
end
|
metadata
CHANGED
@@ -1,71 +1,113 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dokaz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Shepelev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ansi
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: slop
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '3'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rouge
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rspec
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- - ~>
|
59
|
+
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
61
|
version: '3'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
|
-
- - ~>
|
66
|
+
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '3'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rspec-its
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
|
-
- - ~>
|
73
|
+
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
75
|
version: '1'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
|
-
- - ~>
|
80
|
+
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubygems-tasks
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
69
111
|
description:
|
70
112
|
email: zverok.offline@gmail.com
|
71
113
|
executables:
|
@@ -73,6 +115,7 @@ executables:
|
|
73
115
|
extensions: []
|
74
116
|
extra_rdoc_files: []
|
75
117
|
files:
|
118
|
+
- Changelog.md
|
76
119
|
- LICENSE.txt
|
77
120
|
- README.md
|
78
121
|
- bin/dokaz
|
@@ -94,19 +137,17 @@ require_paths:
|
|
94
137
|
- lib
|
95
138
|
required_ruby_version: !ruby/object:Gem::Requirement
|
96
139
|
requirements:
|
97
|
-
- -
|
140
|
+
- - ">="
|
98
141
|
- !ruby/object:Gem::Version
|
99
142
|
version: '0'
|
100
143
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
144
|
requirements:
|
102
|
-
- -
|
145
|
+
- - ">="
|
103
146
|
- !ruby/object:Gem::Version
|
104
147
|
version: '0'
|
105
148
|
requirements: []
|
106
|
-
|
107
|
-
rubygems_version: 2.4.6
|
149
|
+
rubygems_version: 3.1.6
|
108
150
|
signing_key:
|
109
151
|
specification_version: 4
|
110
152
|
summary: Use your documentation as a specification
|
111
153
|
test_files: []
|
112
|
-
has_rdoc:
|