docspec 0.0.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.
@@ -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
@@ -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
+ ```
@@ -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
+
@@ -0,0 +1,6 @@
1
+ require 'byebug' if ENV['BYEBUG']
2
+
3
+ require 'docspec/output_capturer'
4
+ require 'docspec/example'
5
+ require 'docspec/tester'
6
+ require 'docspec/document'
@@ -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
+
@@ -0,0 +1,3 @@
1
+ module Docspec
2
+ VERSION = "0.0.1"
3
+ end
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: []