dokaz 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ M2I3NzJkY2RlNjVjNjVmYzI1YmRiNmU0MmU0MjZiZmJlZDI3YzdkYw==
5
+ data.tar.gz: !binary |-
6
+ ODljNjkzMjE2MjI1NTlkZmQ2Yzk5ZGJmMzJmYzE3NDU1MTBkMDljYw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NzFkMWI0NDMxZDlhYjYwYzg4MjZmOWFmYjEzNTNiNGI0OTQyMzM4ZTYxMzg2
10
+ ZmQzZTFiZGU2YTZjNzhmYjIzOTQyYjllNjQyNDYxYTdhYmMyNzAzMWNiODUw
11
+ N2Q3NmNhZDgxZGM3YjQ3MDkzMTM0MTNjY2VkZmQ4YmMzNmQzODM=
12
+ data.tar.gz: !binary |-
13
+ ZTU4ZjRmMzAyNjA2MTlkNzI3NTYyMGY5MWJkYTdjMjMwZWMzYjJhNDk5OTRk
14
+ ZWY3MDI0NTQxYmY3NzZjMTA2N2MyNjFlODU4MTAyMDhmYjQwZmQxZjhkMjJj
15
+ YmQ2OTYyNmJhY2VmYmEyYjVlMzY3OTRkMGVkMzVhMGE5NWUwYjk=
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014-15 Victor 'Zverok' Shepelev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # Dokaz
2
+
3
+ Dokaz (До́каз) means "proof" in Ukrainian.
4
+
5
+ **Dokaz** gem allows you to check all code inside your documentation, and
6
+ see what it outputs.
7
+
8
+ It just finds all pieces of <pre>```ruby</pre>-marked code in your .md
9
+ files, tries to run it and shows you the consequences.
10
+
11
+ ## Install
12
+
13
+ Just as usual -- by adding `gem 'dokaz'` to your Gemfile then running
14
+ `bundle install`.
15
+
16
+ Or `[sudo] gem install dokaz`
17
+
18
+ ## Usage
19
+
20
+ ```
21
+ dokaz --help
22
+
23
+ Usage: dokaz [patterns] [options]
24
+
25
+ Patterns:
26
+ File.md one file
27
+ File.md:15 only block around line 15
28
+ folder/*.md all files in folder
29
+
30
+ Options:
31
+ -r, --require Additional files to require, comma-separated
32
+ -f, --format Output format ("spec" or "show[case]")
33
+ --help Shows this message
34
+ ```
35
+
36
+ Dokaz respects `.dokaz` file in local folder, which should be just its
37
+ options, each on newline.
38
+
39
+ ## Output formats
40
+
41
+ * "spec" -- simple "does it work?" check:
42
+
43
+ <img src="https://raw.github.com/zverok/dokaz/master/screenshots/spec.png" alt="--format spec"/>
44
+
45
+ * "showcase" or just "show" -- pretty copy-pasteable output of what
46
+ sample code returns and prints:
47
+
48
+ <img src="https://raw.github.com/zverok/dokaz/master/screenshots/showcase.png" alt="--format showcase"/>
49
+
50
+ You can just insert it back into your docs.
51
+
52
+ ## Using it for your project's README
53
+
54
+ * Add to project's Gemfile (preferably to `:dev` group) `gem 'dokaz'`
55
+ * Create file for example `spec/dokaz_helpers.rb`, containing all
56
+ initialization code to include your project files
57
+ * Create file `.dokaz`, containing:
58
+ ```
59
+ README.md
60
+ --require ./spec/dokaz_helpers.rb
61
+ ```
62
+ * Run `bundle exec dokaz`
63
+
64
+ ## Using it for your project's GitHub wiki
65
+
66
+ * Do the same as above
67
+ * Clone your project's wiki to some directory (outside your project's directory!):
68
+ `git clone git:github.com/myusername/myproject.wiki.git`
69
+ * At your project's directory, run `bundle exec dokaz /path/to/cloned/wiki/*.md`
70
+
71
+ ## Known issues
72
+
73
+ * ridiculously simple, naïve and not tested; though, works for me;
74
+ * all code from all blocks is evaluated in same context (so, if block
75
+ from one documentation file defines some class or variable, it is
76
+ visible to all other blocks). Typically, it is reasonable behaviour,
77
+ yet can produce unwanted effects when your docs demonstrate some
78
+ metaprogramming or do some serious side-effects.
79
+
80
+ ## License
81
+
82
+ MIT
data/bin/dokaz ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ require 'slop'
4
+
5
+ $:.unshift 'lib'
6
+ require 'dokaz'
7
+
8
+ if File.exists?('.dokaz')
9
+ ARGV.push(*File.read('.dokaz').split("\n"))
10
+ end
11
+
12
+ patterns = []
13
+ patterns << ARGV.shift until ARGV.empty? || ARGV.first =~ /^-/
14
+
15
+ HELP = %Q{
16
+ Usage: dokaz [patterns] [options]
17
+
18
+ Patterns:
19
+ File.md one file
20
+ File.md:15 only block around line 15
21
+ folder/*.md all files in folder
22
+
23
+ Options:
24
+ -r, --require Additional files to require, comma-separated
25
+ -f, --format Output format ("spec" or "show[case]")
26
+ --help Shows this message
27
+ }
28
+
29
+ options = Slop.parse do
30
+ on :r, :require=, "Additional files to require, comma-separated"
31
+ on :f, :format=, "Output format (spec or show[case])"
32
+ on :help
33
+ end
34
+
35
+ if patterns.empty? || options.help?
36
+ puts HELP
37
+ exit
38
+ end
39
+
40
+ Dokaz.new(patterns, options.to_hash).run
data/dokaz.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'dokaz'
3
+ s.version = '0.0.1'
4
+ s.authors = ['Victor Shepelev']
5
+ s.email = 'zverok.offline@gmail.com'
6
+ s.homepage = 'https://github.com/zverok/dokaz'
7
+
8
+ s.summary = 'Use your documentation as a specification'
9
+ s.licenses = ['MIT']
10
+
11
+ s.files = `git ls-files`.split($RS).reject do |file|
12
+ file =~ /^(?:
13
+ spec\/.*
14
+ |Gemfile
15
+ |Rakefile
16
+ |\.rspec
17
+ |\.gitignore
18
+ |\.rubocop.yml
19
+ |\.travis.yml
20
+ )$/x
21
+ end
22
+ s.require_paths = ["lib"]
23
+ s.executables << 'dokaz'
24
+
25
+ s.add_dependency 'ansi'
26
+ s.add_dependency 'slop', '~> 3'
27
+
28
+ s.add_development_dependency 'rspec', '~> 3'
29
+ s.add_development_dependency 'rspec-its', '~> 1'
30
+ end
@@ -0,0 +1,63 @@
1
+ This file shows you how DocSpec work.
2
+
3
+ Try this
4
+ * `docspec examples/example.md`
5
+ * `docspec examples/example.md --format showcase`
6
+
7
+ ## Example 1
8
+
9
+ So, lets begin with simple ruby code:
10
+
11
+ ```ruby
12
+ 1 + 18
13
+ ```
14
+
15
+ In default (check) mode, this first gives just green dot (it works!).
16
+ In showcase mode you'll see what this code outputs; which allows you to
17
+ paste it into your docs.
18
+
19
+ ## Example 2
20
+
21
+ This is more complex code, try it:
22
+
23
+ ```ruby
24
+ class A
25
+ def initialize(i)
26
+ @i = i
27
+ end
28
+
29
+ def sum(other)
30
+ @i + other
31
+ end
32
+ end
33
+
34
+ a = A.new(5)
35
+ a.sum(3)
36
+ ```
37
+
38
+ The code is evaluated in continuous manner, so, the `A` class and `a`
39
+ variable are already defined:
40
+
41
+ ```ruby
42
+ a.sum(8)
43
+ ```
44
+
45
+ This code not only returns values, but also outputs something to STDOUT:
46
+
47
+ ```ruby
48
+ puts a.sum(10)
49
+ ```
50
+
51
+ This code throws an error:
52
+
53
+ ```ruby
54
+ 100 / 0
55
+ ```
56
+
57
+ This code requires additional require:
58
+
59
+ ```ruby
60
+ BigDecimal.new("0")
61
+ ```
62
+
63
+ Try to run it with option `--require cgi`.
data/lib/dokaz.rb ADDED
@@ -0,0 +1,70 @@
1
+ # encoding: utf-8
2
+ require 'irb'
3
+
4
+ require_relative 'dokaz/parser'
5
+ require_relative 'dokaz/io_helpers'
6
+ require_relative 'dokaz/formatters'
7
+
8
+ class Dokaz
9
+ FORMATTERS = {
10
+ 'spec' => SpecFormatter,
11
+ 'show' => ShowcaseFormatter,
12
+ 'showcase' => ShowcaseFormatter
13
+ }
14
+
15
+ def initialize(patterns, options = {})
16
+ @blocks = select_blocks(patterns)
17
+
18
+ if options[:require]
19
+ options[:require].split(',').each{|f| require f}
20
+ end
21
+
22
+ @formatter = FORMATTERS[options[:format] || 'spec'].new
23
+ end
24
+
25
+ def run
26
+ puts "Running #{@blocks.count} blocks from #{@blocks.map(&:file).uniq.count} files\n\n"
27
+
28
+ @blocks.each do |b|
29
+ @formatter.start_block(b)
30
+ process_block(b)
31
+ @formatter.finish_block(b)
32
+ end
33
+ @formatter.finalize
34
+ end
35
+
36
+ private
37
+
38
+ def process_block(block)
39
+ lex = RubyLex.new
40
+ lex.set_input(SpecIO.new(block.code))
41
+ lex.each_top_level_statement do |line, line_no|
42
+ begin
43
+ res = nil
44
+ out = capture_output{
45
+ res = eval(line, TOPLEVEL_BINDING, block.file, block.line + line_no)
46
+ }
47
+ @formatter.output(line, res, out)
48
+ rescue => e
49
+ @formatter.output_err(line, e)
50
+ break
51
+ end
52
+ end
53
+ end
54
+
55
+ def capture_output(&block)
56
+ Out.new.capture(&block)
57
+ end
58
+
59
+ def select_blocks(patterns)
60
+ patterns.map{|pat|
61
+ path, ln = pat.split(':', 2)
62
+ files = Dir[path]
63
+ blocks = files.map{|f|
64
+ Parser.new(f).parse
65
+ }.flatten.select{|b|
66
+ ln ? b.inside?(ln.to_i) : true
67
+ }
68
+ }.flatten
69
+ end
70
+ end
@@ -0,0 +1,102 @@
1
+ # encoding: utf-8
2
+ require 'ansi/code'
3
+
4
+ class Dokaz
5
+ class Formatter
6
+ def start_block(block)
7
+ end
8
+
9
+ def finish_block(block)
10
+ end
11
+
12
+ def finalize
13
+ end
14
+
15
+ def output(code, res, out)
16
+ end
17
+
18
+ def output_err(code, e)
19
+ end
20
+
21
+ protected
22
+ def filter_backtrace(trace)
23
+ trace.take_while{|ln| ln !~ /lib\/dokaz/}
24
+ end
25
+ end
26
+
27
+ class SpecFormatter < Formatter
28
+ def initialize
29
+ @ok = 0
30
+ @errors = []
31
+ end
32
+
33
+ def start_block(block)
34
+ @err = false
35
+ end
36
+
37
+ def finish_block(block)
38
+ unless @err
39
+ @ok += 1
40
+ print ANSI.green{'.'}
41
+ end
42
+ end
43
+
44
+ def finalize
45
+ puts
46
+ puts
47
+
48
+ @errors.each do |code, e|
49
+ puts code
50
+ puts( ANSI.red{"#{e.message} (#{e.class})\n " + filter_backtrace(e.backtrace).join("\n ") + "\n"})
51
+ end
52
+
53
+ puts
54
+ @errors.each do |code, e|
55
+ ln = e.backtrace.first.sub(/:in .*$/, '')
56
+ puts ANSI.red{"dokaz #{ln}"} + ANSI.cyan{" # #{e.message} (#{e.class})"}
57
+ end
58
+
59
+ puts
60
+ puts [
61
+ "#{@ok + @errors.count} total",
62
+ !@ok.zero? && ANSI.green{"#{@ok} ok"},
63
+ !@errors.empty? && ANSI.red{"#{@errors.count} errors"}
64
+ ].select{|l| l}.join(', ')
65
+
66
+ end
67
+
68
+ def output_err(code, e)
69
+ @errors << [code, e]
70
+ print ANSI.red{'F'}
71
+ @err = true
72
+ end
73
+ end
74
+
75
+ class ShowcaseFormatter < Formatter
76
+ def start_block(block)
77
+ puts "#{block.caption}\n#{'=' * block.caption.size}\n\n"
78
+ end
79
+
80
+ def output(code, res, out)
81
+ puts code
82
+ unless out.empty?
83
+ puts comment("# Prints: \n# " + out.split("\n").join("\n# "))
84
+ end
85
+ puts comment("# => " + res.inspect.split("\n").join("\n# "))
86
+ end
87
+
88
+ def output_err(code, e)
89
+ puts code
90
+ puts comment("# Throws: #{e.message} (#{e.class})")
91
+ end
92
+
93
+ def finish_block(block)
94
+ puts "\n\n"
95
+ end
96
+
97
+ private
98
+ def comment(str)
99
+ ANSI.dark{str}
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ class Dokaz
3
+ class SpecIO < StringIO
4
+ def encoding
5
+ string.encoding
6
+ end
7
+ end
8
+
9
+ class Out < StringIO
10
+ def capture(&block)
11
+ orig = $stdout
12
+ $stdout = self
13
+ yield
14
+ string.to_s
15
+ ensure
16
+ $stdout = orig
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+ require 'strscan'
3
+
4
+ class Dokaz
5
+ class Block
6
+ attr_reader :code, :line, :file
7
+ def initialize(code, line, file)
8
+ @code, @line, @file = code, line, file
9
+ end
10
+
11
+ def end_line
12
+ line + code.count("\n")
13
+ end
14
+
15
+ def caption
16
+ "#{file}:#{line}"
17
+ end
18
+
19
+ def inside?(ln)
20
+ (line..end_line).cover?(ln)
21
+ end
22
+ end
23
+
24
+ class Parser
25
+ def initialize(path)
26
+ @path = path
27
+ end
28
+
29
+ def parse
30
+ res = []
31
+ ln = 0
32
+ scanner = StringScanner.new(File.read(@path))
33
+ loop do
34
+ text = scanner.scan_until(/\n```ruby\n/)
35
+ break unless text
36
+
37
+ ln += text.count("\n")
38
+ code = scanner.scan_until(/\n```\n/)
39
+ if !code
40
+ res << Block.new(scanner.rest, ln, @path)
41
+ break
42
+ end
43
+ res << Block.new(code.sub(/```\Z/, ''), ln, @path)
44
+ ln += code.count("\n")
45
+ end
46
+
47
+ res
48
+ end
49
+ end
50
+ end
Binary file
Binary file
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dokaz
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Victor Shepelev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ansi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: slop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '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'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-its
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1'
69
+ description:
70
+ email: zverok.offline@gmail.com
71
+ executables:
72
+ - dokaz
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - LICENSE.txt
77
+ - README.md
78
+ - bin/dokaz
79
+ - dokaz.gemspec
80
+ - examples/README.md
81
+ - lib/dokaz.rb
82
+ - lib/dokaz/formatters.rb
83
+ - lib/dokaz/io_helpers.rb
84
+ - lib/dokaz/parser.rb
85
+ - screenshots/showcase.png
86
+ - screenshots/spec.png
87
+ homepage: https://github.com/zverok/dokaz
88
+ licenses:
89
+ - MIT
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.4.6
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: Use your documentation as a specification
111
+ test_files: []
112
+ has_rdoc: