docspec 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +96 -0
- data/bin/docspec +28 -0
- data/lib/docspec.rb +6 -0
- data/lib/docspec/document.rb +28 -0
- data/lib/docspec/example.rb +52 -0
- data/lib/docspec/output_capturer.rb +16 -0
- data/lib/docspec/tester.rb +39 -0
- data/lib/docspec/version.rb +3 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 285211d9493c575fb886a6e587e6163440017936c9171a015f323ee5b5e75f12
|
4
|
+
data.tar.gz: 8481fd32a94801a88e995c82acee35cbf82f703f59212194e5b8da07d88c1607
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: acee792d5459ed127e6508feb898c3dc37f7cd0a705c3076ac0adbe457470de40b13282a465527a58275cdc7c21785a4e74cd8fd9d692bb3c24d1e026c6e0def
|
7
|
+
data.tar.gz: c5e0e51cef54cf5080914695a1f6292bdd50bfbf113deb10d439e5b093d5265715d02f0172df6f4d551161ea002e5a9416ea00f8b51d30c607ee4f1f1b1a817d
|
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
Docspec
|
2
|
+
==================================================
|
3
|
+
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/docspec.svg)](https://badge.fury.io/rb/docspec)
|
5
|
+
|
6
|
+
Inline tests in Markdown documents.
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
|
11
|
+
Installation
|
12
|
+
--------------------------------------------------
|
13
|
+
|
14
|
+
$ gem install docspec
|
15
|
+
|
16
|
+
|
17
|
+
Usage
|
18
|
+
--------------------------------------------------
|
19
|
+
|
20
|
+
Add ruby or shell code blocks to your `README.md` document, then run
|
21
|
+
`docspec` to evaluate them.
|
22
|
+
|
23
|
+
|
24
|
+
Rules
|
25
|
+
--------------------------------------------------
|
26
|
+
|
27
|
+
- Anything outside of a code fence is ignored.
|
28
|
+
- Both `ruby` and `shell` code blocks are supported.
|
29
|
+
- Inside a code block, any piece of code that we care about should print
|
30
|
+
something.
|
31
|
+
- Inside a code block, anything starting with `#=>` should define the
|
32
|
+
expected output.
|
33
|
+
- If a piece of code raises an error, the captured output will be the
|
34
|
+
`#inspect` string of that exception.
|
35
|
+
|
36
|
+
To test the `README.md` in the current folder, just run:
|
37
|
+
|
38
|
+
$ docspec
|
39
|
+
|
40
|
+
To test a different file, provide it as the first argument:
|
41
|
+
|
42
|
+
$ docspec TESTS.md
|
43
|
+
|
44
|
+
|
45
|
+
Examples
|
46
|
+
--------------------------------------------------
|
47
|
+
|
48
|
+
These will be tested with `docspec`:
|
49
|
+
|
50
|
+
### Ruby
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
# The first line is an optional label
|
54
|
+
puts 'hello world'.upcase
|
55
|
+
#=> HELLO WORLD
|
56
|
+
```
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
# Exceptions are captured
|
60
|
+
raise ArgumentError, "Testing error raising"
|
61
|
+
#=> #<ArgumentError: Testing error raising>
|
62
|
+
```
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
# Multiple lines of code
|
66
|
+
string = "hello"
|
67
|
+
3.times do
|
68
|
+
puts string
|
69
|
+
end
|
70
|
+
#=> hello
|
71
|
+
#=> hello
|
72
|
+
#=> hello
|
73
|
+
```
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
# Interleaving code and output
|
77
|
+
puts 2 + 3
|
78
|
+
#=> 5
|
79
|
+
|
80
|
+
puts 2 - 3
|
81
|
+
#=> -1
|
82
|
+
```
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
# This example should fail
|
86
|
+
puts 'hello world'.upcase
|
87
|
+
#=> hello world
|
88
|
+
```
|
89
|
+
|
90
|
+
### Shell
|
91
|
+
|
92
|
+
```shell
|
93
|
+
# Shell commands
|
94
|
+
echo hello world
|
95
|
+
#=> hello world
|
96
|
+
```
|
data/bin/docspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'simplecov'
|
3
|
+
SimpleCov.start
|
4
|
+
|
5
|
+
require 'docspec'
|
6
|
+
require 'colsole'
|
7
|
+
include Colsole
|
8
|
+
|
9
|
+
document = ARGV[0] || 'README.md'
|
10
|
+
abort "File not found #{document}" unless File.exist? document
|
11
|
+
tester = Docspec::Tester.new document
|
12
|
+
success = tester.execute
|
13
|
+
|
14
|
+
say ''
|
15
|
+
|
16
|
+
if tester.expected_failures != 0
|
17
|
+
say "!txtblu!Expected failures: #{tester.expected_failures}"
|
18
|
+
end
|
19
|
+
|
20
|
+
if success
|
21
|
+
say "!txtgrn!#{tester.total} tests, #{tester.errors} failed\n"
|
22
|
+
exit 0
|
23
|
+
else
|
24
|
+
say "!txtred!#{tester.total} tests, #{tester.errors} failed\n"
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
|
28
|
+
|
data/lib/docspec.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Docspec
|
2
|
+
class Document
|
3
|
+
attr_reader :filename
|
4
|
+
|
5
|
+
def initialize(filename)
|
6
|
+
@filename = filename
|
7
|
+
end
|
8
|
+
|
9
|
+
def markdown
|
10
|
+
@markdown ||= File.read filename
|
11
|
+
end
|
12
|
+
|
13
|
+
def examples
|
14
|
+
@examples ||= examples!
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def examples!
|
20
|
+
result = []
|
21
|
+
markdown.scan(/```(ruby|shell)\n(.*?)```/m) do |type, code|
|
22
|
+
result << Example.new(code, type)
|
23
|
+
end
|
24
|
+
result
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'diffy'
|
2
|
+
|
3
|
+
module Docspec
|
4
|
+
class Example
|
5
|
+
include OutputCapturer
|
6
|
+
|
7
|
+
attr_reader :code, :type
|
8
|
+
|
9
|
+
def initialize(code, type)
|
10
|
+
@code, @type = code, type
|
11
|
+
end
|
12
|
+
|
13
|
+
def label
|
14
|
+
@label ||= label!
|
15
|
+
end
|
16
|
+
|
17
|
+
def expected
|
18
|
+
@expected ||= code.scan(/#=>\s*(.*)/).map { |match| match.first.strip }.join "\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
def actual
|
22
|
+
@actual ||= actual!
|
23
|
+
end
|
24
|
+
|
25
|
+
def passing?
|
26
|
+
actual == expected
|
27
|
+
end
|
28
|
+
|
29
|
+
def diff
|
30
|
+
Diffy::Diff.new(expected, actual, context: 2).to_s :color
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def label!
|
36
|
+
first_line = code.split("\n").first
|
37
|
+
first_line.gsub(/^#\s*/, '').strip
|
38
|
+
end
|
39
|
+
|
40
|
+
def actual!
|
41
|
+
capture_output do
|
42
|
+
case type
|
43
|
+
when 'ruby'
|
44
|
+
instance_eval(code)
|
45
|
+
when 'shell'
|
46
|
+
puts `#{code}`
|
47
|
+
end
|
48
|
+
end.strip
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Docspec
|
2
|
+
module OutputCapturer
|
3
|
+
def capture_output
|
4
|
+
original_stdout = $stdout
|
5
|
+
$stdout = StringIO.new
|
6
|
+
begin
|
7
|
+
yield
|
8
|
+
$stdout.string
|
9
|
+
rescue => e
|
10
|
+
"#{$stdout.string}#{e.inspect}"
|
11
|
+
ensure
|
12
|
+
$stdout = original_stdout
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'colsole'
|
2
|
+
|
3
|
+
module Docspec
|
4
|
+
class Tester
|
5
|
+
include Colsole
|
6
|
+
attr_reader :document, :errors
|
7
|
+
|
8
|
+
def initialize(document)
|
9
|
+
document = Document.new document unless document.is_a? Document
|
10
|
+
@document = document
|
11
|
+
@errors = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def total
|
15
|
+
@total ||= document.examples.count
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute
|
19
|
+
document.examples.each do |example|
|
20
|
+
if example.passing?
|
21
|
+
say "!txtgrn!PASS: #{example.label}"
|
22
|
+
else
|
23
|
+
@errors += 1
|
24
|
+
say "!txtred!FAIL: #{example.label}"
|
25
|
+
say "---"
|
26
|
+
puts example.diff
|
27
|
+
say "---"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
errors == expected_failures
|
32
|
+
end
|
33
|
+
|
34
|
+
def expected_failures
|
35
|
+
ENV['DOCSPEC_EXPECTED_FAILURES']&.to_i || 0
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: docspec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Danny Ben Shitrit
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-10-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: colsole
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: diffy
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.3'
|
41
|
+
description: Make your READMEs testable
|
42
|
+
email: db@dannyben.com
|
43
|
+
executables:
|
44
|
+
- docspec
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- README.md
|
49
|
+
- bin/docspec
|
50
|
+
- lib/docspec.rb
|
51
|
+
- lib/docspec/document.rb
|
52
|
+
- lib/docspec/example.rb
|
53
|
+
- lib/docspec/output_capturer.rb
|
54
|
+
- lib/docspec/tester.rb
|
55
|
+
- lib/docspec/version.rb
|
56
|
+
homepage: https://github.com/dannyben/docspec
|
57
|
+
licenses:
|
58
|
+
- MIT
|
59
|
+
metadata: {}
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.5.0
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubygems_version: 3.0.4
|
76
|
+
signing_key:
|
77
|
+
specification_version: 4
|
78
|
+
summary: Embedded tests in Markdown documents
|
79
|
+
test_files: []
|