pdd 0.17.9 → 0.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +10 -0
- data/.rultor.yml +1 -0
- data/.simplecov +3 -8
- data/Gemfile +0 -2
- data/README.md +38 -3
- data/Rakefile +11 -4
- data/assets/puzzles.xsd +25 -23
- data/assets/puzzles.xsl +53 -32
- data/bin/pdd +68 -41
- data/features/catches_broken_puzzles.feature +2 -2
- data/features/cli.feature +1 -1
- data/features/html_output.feature +1 -1
- data/features/step_definitions/steps.rb +4 -5
- data/features/support/env.rb +0 -2
- data/features/unicode.feature +1 -1
- data/features/uses_config.feature +1 -1
- data/lib/pdd.rb +18 -13
- data/lib/pdd/puzzle.rb +0 -2
- data/lib/pdd/rule/duplicates.rb +0 -2
- data/lib/pdd/rule/estimates.rb +2 -4
- data/lib/pdd/rule/roles.rb +0 -2
- data/lib/pdd/rule/text.rb +1 -3
- data/lib/pdd/source.rb +42 -30
- data/lib/pdd/sources.rb +0 -3
- data/lib/pdd/version.rb +1 -3
- data/pdd.gemspec +9 -7
- data/test/test__helper.rb +0 -2
- data/test/test_duplicates.rb +0 -2
- data/test/test_estimates.rb +0 -2
- data/test/test_pdd.rb +7 -8
- data/test/test_roles.rb +0 -2
- data/test/test_source.rb +6 -5
- data/test/test_sources.rb +0 -2
- data/test/test_text.rb +0 -2
- metadata +39 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99bde0870af357f7eba5e562cf4e80367fd5022a
|
4
|
+
data.tar.gz: 0fc0b88a2e83a2eccb98ed6a5089b469a6d549b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69b16a076410aec375c78acb4bb01332718edc630541b50c64da84bb92151d9205dddbbce3fe97ef708122fed0d5b832ecf07e1fcef3eb7b6ae61be0f351e146
|
7
|
+
data.tar.gz: 1685a80e5bf84944218a5211b41f905a7bdccbd8112bf877515518dd79b6ef8f28275f2b6519e86ae52d04428b4a9199369f51b2e8f4d736dedb7ea5b9990982
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,16 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- 'bin/**/*'
|
4
|
+
- 'assets/**/*'
|
5
|
+
DisplayCopNames: true
|
6
|
+
|
1
7
|
MethodLength:
|
2
8
|
Max: 30
|
3
9
|
Style/ClassLength:
|
4
10
|
Max: 150
|
5
11
|
Metrics/AbcSize:
|
6
12
|
Max: 37
|
13
|
+
Style/MultilineBlockChain:
|
14
|
+
Enabled: false
|
15
|
+
Metrics/BlockLength:
|
16
|
+
Max: 50
|
data/.rultor.yml
CHANGED
data/.simplecov
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -20,8 +18,6 @@
|
|
20
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
19
|
# SOFTWARE.
|
22
20
|
|
23
|
-
require 'coveralls'
|
24
|
-
|
25
21
|
if Gem.win_platform? then
|
26
22
|
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
27
23
|
SimpleCov::Formatter::HTMLFormatter
|
@@ -31,10 +27,9 @@ if Gem.win_platform? then
|
|
31
27
|
add_filter "/features/"
|
32
28
|
end
|
33
29
|
else
|
34
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter
|
35
|
-
SimpleCov::Formatter::HTMLFormatter
|
36
|
-
|
37
|
-
]
|
30
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
31
|
+
SimpleCov::Formatter::HTMLFormatter
|
32
|
+
)
|
38
33
|
SimpleCov.start do
|
39
34
|
add_filter "/test/"
|
40
35
|
add_filter "/features/"
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
<img src="https://avatars2.githubusercontent.com/u/24456188" width="64px" height="64px"/>
|
2
2
|
|
3
|
-
[![
|
3
|
+
[![Managed by Zerocracy](http://www.zerocracy.com/badge.svg)](http://www.zerocracy.com)
|
4
4
|
[![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/pdd)](http://www.rultor.com/p/yegor256/pdd)
|
5
5
|
[![We recommend RubyMine](http://img.teamed.io/rubymine-recommend.svg)](https://www.jetbrains.com/ruby/)
|
6
6
|
|
@@ -99,9 +99,44 @@ Here is a list of rules available now:
|
|
99
99
|
|
100
100
|
* `min-words:5` blocks puzzles with descriptions shorter than five words.
|
101
101
|
|
102
|
-
* `max-duplicates:1` blocks more than one duplicate of any puzzle
|
103
|
-
|
102
|
+
* `max-duplicates:1` blocks more than one duplicate of any puzzle.
|
103
|
+
This rule is used by default and you can't configure it at the moment,
|
104
|
+
it must always be set to `1`.
|
104
105
|
|
105
106
|
You can put all command line options into `.pdd` file. The options from the
|
106
107
|
file will be used first. Command line options may be added on top of them.
|
107
108
|
See, how it is done in [yegor256/0pdd](https://github.com/yegor256/0pdd/blob/master/.pdd).
|
109
|
+
|
110
|
+
## How to contribute?
|
111
|
+
|
112
|
+
Just submit a pull request. Make sure `rake` passes.
|
113
|
+
|
114
|
+
This is how you run it locally to test how it works:
|
115
|
+
|
116
|
+
```bash
|
117
|
+
$ ./bin/pdd --help
|
118
|
+
```
|
119
|
+
|
120
|
+
## License
|
121
|
+
|
122
|
+
(The MIT License)
|
123
|
+
|
124
|
+
Copyright (c) 2016-2017 Yegor Bugayenko
|
125
|
+
|
126
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
127
|
+
of this software and associated documentation files (the 'Software'), to deal
|
128
|
+
in the Software without restriction, including without limitation the rights
|
129
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
130
|
+
copies of the Software, and to permit persons to whom the Software is
|
131
|
+
furnished to do so, subject to the following conditions:
|
132
|
+
|
133
|
+
The above copyright notice and this permission notice shall be included in all
|
134
|
+
copies or substantial portions of the Software.
|
135
|
+
|
136
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
137
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
138
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
139
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
140
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
141
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
142
|
+
SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -33,7 +31,7 @@ def version
|
|
33
31
|
Gem::Specification.load(Dir['*.gemspec'].first).version
|
34
32
|
end
|
35
33
|
|
36
|
-
task default: [
|
34
|
+
task default: %i[clean test features rubocop xcop copyright]
|
37
35
|
|
38
36
|
require 'rake/testtask'
|
39
37
|
desc 'Run all unit tests'
|
@@ -60,8 +58,17 @@ RuboCop::RakeTask.new(:rubocop) do |task|
|
|
60
58
|
task.requires << 'rubocop-rspec'
|
61
59
|
end
|
62
60
|
|
61
|
+
require 'xcop/rake_task'
|
62
|
+
desc 'Validate all XML/XSL/XSD/HTML files for formatting'
|
63
|
+
Xcop::RakeTask.new :xcop do |task|
|
64
|
+
task.license = 'LICENSE.txt'
|
65
|
+
task.includes = ['**/*.xml', '**/*.xsl', '**/*.xsd', '**/*.html']
|
66
|
+
task.excludes = ['target/**/*', 'coverage/**/*']
|
67
|
+
end
|
68
|
+
|
63
69
|
require 'cucumber/rake/task'
|
64
|
-
Cucumber::Rake::Task.new(:features) do
|
70
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
71
|
+
t.cucumber_opts = 'features --format progress'
|
65
72
|
Rake::Cleaner.cleanup_files(['coverage'])
|
66
73
|
end
|
67
74
|
Cucumber::Rake::Task.new(:'features:html') do |t|
|
data/assets/puzzles.xsd
CHANGED
@@ -1,25 +1,27 @@
|
|
1
1
|
<?xml version="1.0"?>
|
2
2
|
<!--
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
3
|
+
(The MIT License)
|
4
|
+
|
5
|
+
Copyright (c) 2014-2017 Yegor Bugayenko
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
of this software and associated documentation files (the 'Software'), to deal
|
9
|
+
in the Software without restriction, including without limitation the rights
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
12
|
+
furnished to do so, subject to the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
15
|
+
copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
23
|
+
SOFTWARE.
|
24
|
+
-->
|
23
25
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
24
26
|
<xs:complexType name="puzzle">
|
25
27
|
<xs:all>
|
@@ -92,14 +94,14 @@
|
|
92
94
|
<xs:element name="puzzles">
|
93
95
|
<xs:complexType>
|
94
96
|
<xs:sequence>
|
95
|
-
<xs:element name="puzzle" type="puzzle" minOccurs="0" maxOccurs="unbounded"
|
97
|
+
<xs:element name="puzzle" type="puzzle" minOccurs="0" maxOccurs="unbounded"/>
|
96
98
|
</xs:sequence>
|
97
99
|
<xs:attribute name="version" use="required" type="xs:string"/>
|
98
100
|
<xs:attribute name="date" use="required" type="xs:dateTime"/>
|
99
101
|
</xs:complexType>
|
100
102
|
<xs:unique name="puzzleBody">
|
101
|
-
<xs:selector xpath="./puzzle"
|
102
|
-
<xs:field xpath="body"
|
103
|
+
<xs:selector xpath="./puzzle"/>
|
104
|
+
<xs:field xpath="body"/>
|
103
105
|
</xs:unique>
|
104
106
|
</xs:element>
|
105
107
|
</xs:schema>
|
data/assets/puzzles.xsl
CHANGED
@@ -1,27 +1,28 @@
|
|
1
1
|
<?xml version="1.0"?>
|
2
2
|
<!--
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
3
|
+
(The MIT License)
|
4
|
+
|
5
|
+
Copyright (c) 2014-2017 Yegor Bugayenko
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
of this software and associated documentation files (the 'Software'), to deal
|
9
|
+
in the Software without restriction, including without limitation the rights
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
12
|
+
furnished to do so, subject to the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
15
|
+
copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
23
|
+
SOFTWARE.
|
24
|
+
-->
|
25
|
+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="1.0">
|
25
26
|
<xsl:template match="/">
|
26
27
|
<xsl:text disable-output-escaping="yes"><!DOCTYPE html></xsl:text>
|
27
28
|
<html lang="en">
|
@@ -30,7 +31,9 @@
|
|
30
31
|
<meta name="description" content="PDD puzzles"/>
|
31
32
|
<meta name="keywords" content="puzzle driven development"/>
|
32
33
|
<meta name="author" content="teamed.io"/>
|
33
|
-
<title
|
34
|
+
<title>
|
35
|
+
<xsl:text>PDD Summary Report</xsl:text>
|
36
|
+
</title>
|
34
37
|
<style type="text/css">
|
35
38
|
body {
|
36
39
|
background-color: #e6e1ce;
|
@@ -67,11 +70,21 @@
|
|
67
70
|
</colgroup>
|
68
71
|
<thead>
|
69
72
|
<tr>
|
70
|
-
<th
|
71
|
-
|
72
|
-
|
73
|
-
<th
|
74
|
-
|
73
|
+
<th>
|
74
|
+
<xsl:text>id</xsl:text>
|
75
|
+
</th>
|
76
|
+
<th>
|
77
|
+
<xsl:text>ticket</xsl:text>
|
78
|
+
</th>
|
79
|
+
<th>
|
80
|
+
<xsl:text>body</xsl:text>
|
81
|
+
</th>
|
82
|
+
<th>
|
83
|
+
<xsl:text>estimate</xsl:text>
|
84
|
+
</th>
|
85
|
+
<th>
|
86
|
+
<xsl:text>role</xsl:text>
|
87
|
+
</th>
|
75
88
|
</tr>
|
76
89
|
</thead>
|
77
90
|
<tbody>
|
@@ -84,8 +97,12 @@
|
|
84
97
|
</xsl:template>
|
85
98
|
<xsl:template match="puzzle">
|
86
99
|
<tr>
|
87
|
-
<td
|
88
|
-
|
100
|
+
<td>
|
101
|
+
<xsl:value-of select="id"/>
|
102
|
+
</td>
|
103
|
+
<td>
|
104
|
+
<xsl:value-of select="ticket"/>
|
105
|
+
</td>
|
89
106
|
<td>
|
90
107
|
<code>
|
91
108
|
<xsl:value-of select="file"/>
|
@@ -95,8 +112,12 @@
|
|
95
112
|
<br/>
|
96
113
|
<xsl:value-of select="body"/>
|
97
114
|
</td>
|
98
|
-
<td
|
99
|
-
|
115
|
+
<td>
|
116
|
+
<xsl:value-of select="estimate"/>
|
117
|
+
</td>
|
118
|
+
<td>
|
119
|
+
<xsl:value-of select="role"/>
|
120
|
+
</td>
|
100
121
|
</tr>
|
101
122
|
</xsl:template>
|
102
123
|
</xsl:stylesheet>
|
data/bin/pdd
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# encoding: utf-8
|
3
|
-
#
|
4
2
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
5
3
|
#
|
6
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -25,51 +23,80 @@ STDOUT.sync = true
|
|
25
23
|
|
26
24
|
require 'slop'
|
27
25
|
require 'nokogiri'
|
26
|
+
require 'rainbow'
|
28
27
|
require_relative '../lib/pdd'
|
29
28
|
require_relative '../lib/pdd/version'
|
30
29
|
|
31
|
-
|
32
|
-
args
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
o.string '-s', '--source', 'Source directory to parse'
|
42
|
-
o.string '-f', '--file', 'File to save XML into'
|
43
|
-
o.array '-e', '--exclude', 'Glob pattern to exclude'
|
44
|
-
o.string '-t', '--format', 'Format to use (xml|html)'
|
45
|
-
o.array '-r', '--rule', 'Rule to apply', delimiter: ';'
|
46
|
-
end
|
30
|
+
begin
|
31
|
+
args = []
|
32
|
+
if File.exist?('.pdd')
|
33
|
+
cfg = File.new('.pdd')
|
34
|
+
body = File.read(cfg)
|
35
|
+
extra = body.split(/\s+/).map(&:strip)
|
36
|
+
args += extra
|
37
|
+
puts "Found #{body.split(/\n/).length} lines in #{File.absolute_path(cfg)}"
|
38
|
+
end
|
39
|
+
args += ARGV
|
47
40
|
|
48
|
-
|
41
|
+
begin
|
42
|
+
opts = Slop.parse(args, strict: true, help: true) do |o|
|
43
|
+
o.banner = "Usage (#{PDD::VERSION}): pdd [options]"
|
44
|
+
o.bool '-h', '--help', 'Show these instructions'
|
45
|
+
o.bool '-v', '--verbose', 'Enable verbose mode (a lot of logging)'
|
46
|
+
o.bool '-q', '--quiet', 'Enable quiet mode (almost no logging)'
|
47
|
+
o.bool '-i', '--version', 'Show current version' do
|
48
|
+
puts PDD::VERSION
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
o.string '-s', '--source', 'Source directory to parse ("." by default)'
|
52
|
+
o.string '-f', '--file', 'File to save XML into'
|
53
|
+
o.array '-e', '--exclude', 'Glob pattern to exclude, e.g. "**/*.jpg"'
|
54
|
+
o.string '-t', '--format', 'Format of the report (xml|html)'
|
55
|
+
o.array(
|
56
|
+
'-r', '--rule', 'Rule to apply (can be used many times)',
|
57
|
+
delimiter: ';'
|
58
|
+
)
|
59
|
+
end
|
60
|
+
rescue Slop::Error => ex
|
61
|
+
raise StandardError, "#{ex.message}, try --help"
|
62
|
+
end
|
49
63
|
|
50
|
-
if opts.help?
|
51
|
-
|
52
|
-
|
53
|
-
|
64
|
+
if opts.help?
|
65
|
+
puts opts
|
66
|
+
puts "This is our README to learn more: \
|
67
|
+
https://github.com/yegor256/pdd/blob/master/README.md"
|
68
|
+
exit
|
69
|
+
end
|
54
70
|
|
55
|
-
if opts.
|
56
|
-
|
57
|
-
|
58
|
-
end
|
71
|
+
if opts.verbose? && !opts.file?
|
72
|
+
raise '-f is mandatory when using -v, try --help for more information'
|
73
|
+
end
|
59
74
|
|
60
|
-
Encoding.default_external = Encoding::UTF_8
|
61
|
-
Encoding.default_internal = Encoding::UTF_8
|
62
|
-
file = opts.file? ? File.new(opts[:file], 'w') : STDOUT
|
63
|
-
output = PDD::Base.new(opts).xml
|
64
|
-
if opts[:format]
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
75
|
+
Encoding.default_external = Encoding::UTF_8
|
76
|
+
Encoding.default_internal = Encoding::UTF_8
|
77
|
+
file = opts.file? ? File.new(opts[:file], 'w') : STDOUT
|
78
|
+
output = PDD::Base.new(opts).xml
|
79
|
+
if opts[:format]
|
80
|
+
if opts[:format] == 'html'
|
81
|
+
xslt = File.join(
|
82
|
+
File.dirname(File.dirname(__FILE__)),
|
83
|
+
'assets', 'puzzles.xsl'
|
84
|
+
)
|
85
|
+
output = Nokogiri::XSLT(File.read(xslt)).transform(Nokogiri::XML(output))
|
86
|
+
elsif opts[:format] != 'xml'
|
87
|
+
raise 'Invalid format, use html or xml'
|
88
|
+
end
|
73
89
|
end
|
90
|
+
file << output
|
91
|
+
rescue SystemExit => ex
|
92
|
+
puts ex.message unless ex.success?
|
93
|
+
exit(ex.status)
|
94
|
+
rescue StandardError => ex
|
95
|
+
puts "#{Rainbow('ERROR').red}: #{ex.message}"
|
96
|
+
puts "If you can't understand the cause of this issue or you don't know \
|
97
|
+
how to fix it, please submit a GitHub issue, we will try to help you: \
|
98
|
+
https://github.com/yegor256/pdd/issues. This tool is still in its beta \
|
99
|
+
version and we will appreciate your feedback. Here is where you can find \
|
100
|
+
more documentation: https://github.com/yegor256/pdd/blob/master/README.md."
|
101
|
+
exit(-1)
|
74
102
|
end
|
75
|
-
file << output
|
@@ -21,7 +21,7 @@ Feature: Catches Broken Puzzles
|
|
21
21
|
}
|
22
22
|
"""
|
23
23
|
When I run pdd it fails with "Space expected"
|
24
|
-
When I run pdd it fails with "
|
24
|
+
When I run pdd it fails with "puzzle at line #6"
|
25
25
|
|
26
26
|
Scenario: Throwing exception on another broken puzzle
|
27
27
|
Given I have a "Sample.java" file with content:
|
@@ -36,7 +36,7 @@ Feature: Catches Broken Puzzles
|
|
36
36
|
}
|
37
37
|
}
|
38
38
|
"""
|
39
|
-
When I run pdd it fails with "Too many spaces"
|
39
|
+
When I run pdd it fails with "Too many leading spaces"
|
40
40
|
|
41
41
|
Scenario: Throwing exception on yet another broken puzzle
|
42
42
|
Given I have a "Sample.java" file with content:
|
data/features/cli.feature
CHANGED
@@ -26,7 +26,7 @@ Feature: Command Line Processing
|
|
26
26
|
"""
|
27
27
|
When I run bin/pdd with "-v -s . -f out.xml"
|
28
28
|
Then Exit code is zero
|
29
|
-
And Stdout contains "
|
29
|
+
And Stdout contains "Reading ."
|
30
30
|
And XML file "out.xml" matches "/puzzles[count(puzzle)=1]"
|
31
31
|
|
32
32
|
Scenario: Using basic rules
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -31,8 +29,9 @@ Before do
|
|
31
29
|
@dir = Dir.mktmpdir('test')
|
32
30
|
FileUtils.mkdir_p(@dir) unless File.exist?(@dir)
|
33
31
|
Dir.chdir(@dir)
|
34
|
-
@opts = Slop.parse ['-
|
32
|
+
@opts = Slop.parse ['-q', '-s', @dir] do |o|
|
35
33
|
o.bool '-v', '--verbose'
|
34
|
+
o.bool '-q', '--quiet'
|
36
35
|
o.string '-s', '--source'
|
37
36
|
end
|
38
37
|
end
|
@@ -95,11 +94,11 @@ Then(/^XML file "([^"]+)" matches "([^"]+)"$/) do |file, xpath|
|
|
95
94
|
end
|
96
95
|
|
97
96
|
Then(/^Exit code is zero$/) do
|
98
|
-
raise "Non-zero exit code #{@exitstatus}" unless @exitstatus
|
97
|
+
raise "Non-zero exit code #{@exitstatus}" unless @exitstatus.zero?
|
99
98
|
end
|
100
99
|
|
101
100
|
Then(/^Exit code is not zero$/) do
|
102
|
-
raise 'Zero exit code' if @exitstatus
|
101
|
+
raise 'Zero exit code' if @exitstatus.zero?
|
103
102
|
end
|
104
103
|
|
105
104
|
When(/^I run bash with$/) do |text|
|
data/features/support/env.rb
CHANGED
data/features/unicode.feature
CHANGED
data/lib/pdd.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -23,6 +21,7 @@
|
|
23
21
|
require 'nokogiri'
|
24
22
|
require 'logger'
|
25
23
|
require 'time'
|
24
|
+
require 'rainbow'
|
26
25
|
require_relative 'pdd/sources'
|
27
26
|
require_relative 'pdd/version'
|
28
27
|
require_relative 'pdd/rule/estimates'
|
@@ -53,10 +52,14 @@ module PDD
|
|
53
52
|
|
54
53
|
# Get logger.
|
55
54
|
def self.log
|
56
|
-
unless @logger
|
55
|
+
unless defined?(@logger)
|
57
56
|
@logger = Logger.new(STDOUT)
|
58
57
|
@logger.formatter = proc { |severity, _, _, msg|
|
59
|
-
|
58
|
+
if severity == 'ERROR'
|
59
|
+
"#{Rainbow(severity).red}: #{msg}\n"
|
60
|
+
else
|
61
|
+
"#{msg}\n"
|
62
|
+
end
|
60
63
|
}
|
61
64
|
@logger.level = Logger::ERROR
|
62
65
|
end
|
@@ -75,19 +78,21 @@ module PDD
|
|
75
78
|
@opts = opts
|
76
79
|
PDD.log.level = Logger::INFO if @opts[:verbose]
|
77
80
|
PDD.log.level = Logger::ERROR if @opts[:quiet]
|
78
|
-
PDD.log.info "
|
81
|
+
PDD.log.info "My version is #{PDD::VERSION}"
|
79
82
|
PDD.log.info "Ruby version is #{RUBY_VERSION} at #{RUBY_PLATFORM}"
|
80
83
|
end
|
81
84
|
|
82
85
|
# Generate XML.
|
83
86
|
def xml
|
84
87
|
dir = @opts[:source] ? @opts[:source] : Dir.pwd
|
85
|
-
PDD.log.info "
|
88
|
+
PDD.log.info "Reading #{dir}"
|
86
89
|
sources = Sources.new(dir)
|
87
|
-
@opts[:exclude].
|
88
|
-
|
89
|
-
|
90
|
-
|
90
|
+
unless @opts[:exclude].nil?
|
91
|
+
@opts[:exclude].each do |p|
|
92
|
+
sources = sources.exclude(p)
|
93
|
+
PDD.log.info "Excluding #{p}"
|
94
|
+
end
|
95
|
+
end
|
91
96
|
sanitize(
|
92
97
|
rules(
|
93
98
|
Nokogiri::XML::Builder.new do |xml|
|
@@ -95,7 +100,7 @@ module PDD
|
|
95
100
|
xml.puzzles(attrs) do
|
96
101
|
sources.fetch.each do |source|
|
97
102
|
source.puzzles.each do |puzzle|
|
98
|
-
PDD.log.info "
|
103
|
+
PDD.log.info "Puzzle #{puzzle.props[:id]} " \
|
99
104
|
"#{puzzle.props[:estimate]}/#{puzzle.props[:role]}" \
|
100
105
|
" at #{puzzle.props[:file]}"
|
101
106
|
render puzzle, xml
|
@@ -145,13 +150,13 @@ module PDD
|
|
145
150
|
list.push('max-duplicates:1').map do |r|
|
146
151
|
name, value = r.split(':')
|
147
152
|
rule = RULES[name]
|
148
|
-
raise "
|
153
|
+
raise "Rule '#{name}' doesn't exist" if rule.nil?
|
149
154
|
rule.new(doc, value).errors.each do |e|
|
150
155
|
PDD.log.error e
|
151
156
|
total += 1
|
152
157
|
end
|
153
158
|
end
|
154
|
-
raise PDD::Error, "#{total} errors, see log above" unless total
|
159
|
+
raise PDD::Error, "#{total} errors, see log above" unless total.zero?
|
155
160
|
xml
|
156
161
|
end
|
157
162
|
|
data/lib/pdd/puzzle.rb
CHANGED
data/lib/pdd/rule/duplicates.rb
CHANGED
data/lib/pdd/rule/estimates.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -34,7 +32,7 @@ module PDD
|
|
34
32
|
|
35
33
|
def errors
|
36
34
|
@xml.xpath("//puzzle[number(estimate) < #{@min}]").map do |p|
|
37
|
-
"
|
35
|
+
"Puzzle #{p.xpath('file/text()')}:#{p.xpath('lines/text()')}"\
|
38
36
|
" has an estimate of #{p.xpath('estimate/text()')} minutes,"\
|
39
37
|
" which is lower than #{@min} minutes"
|
40
38
|
end
|
@@ -52,7 +50,7 @@ module PDD
|
|
52
50
|
|
53
51
|
def errors
|
54
52
|
@xml.xpath("//puzzle[number(estimate) > #{@min}]").map do |p|
|
55
|
-
"
|
53
|
+
"Puzzle #{p.xpath('file/text()')}:#{p.xpath('lines/text()')}"\
|
56
54
|
" has an estimate of #{p.xpath('estimate/text()')} minutes,"\
|
57
55
|
" which is bigger than #{@min} minutes"
|
58
56
|
end
|
data/lib/pdd/rule/roles.rb
CHANGED
data/lib/pdd/rule/text.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -36,7 +34,7 @@ module PDD
|
|
36
34
|
@xml.xpath('//puzzle').map do |p|
|
37
35
|
words = p.xpath('body/text()').to_s.split.size
|
38
36
|
next nil if words >= @min
|
39
|
-
"
|
37
|
+
"Puzzle #{p.xpath('file/text()')}:#{p.xpath('lines/text()')}"\
|
40
38
|
" has a very short description of just #{words} words while"\
|
41
39
|
" a minimum of #{@min} is required"
|
42
40
|
end.compact
|
data/lib/pdd/source.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -22,7 +20,6 @@
|
|
22
20
|
|
23
21
|
require 'digest/md5'
|
24
22
|
require 'shellwords'
|
25
|
-
require_relative '../pdd'
|
26
23
|
require_relative '../pdd/puzzle'
|
27
24
|
|
28
25
|
module PDD
|
@@ -38,7 +35,7 @@ module PDD
|
|
38
35
|
|
39
36
|
# Fetch all puzzles.
|
40
37
|
def puzzles
|
41
|
-
PDD.log.info "
|
38
|
+
PDD.log.info "Reading #{@path}..."
|
42
39
|
re = %r{(.*(?:^|\s))@todo\s+#([\w\-\.:/]+)\s+(.+)}
|
43
40
|
puzzles = []
|
44
41
|
lines = File.readlines(@file)
|
@@ -47,10 +44,8 @@ module PDD
|
|
47
44
|
re.match(line) do |match|
|
48
45
|
puzzles << puzzle(lines.drop(idx + 1), match, idx)
|
49
46
|
end
|
50
|
-
rescue Error => ex
|
51
|
-
raise Error,
|
52
|
-
rescue ArgumentError => ex
|
53
|
-
raise Error, ["in line ##{idx + 1}", ex]
|
47
|
+
rescue Error, ArgumentError => ex
|
48
|
+
raise Error, "puzzle at line ##{idx + 1}; #{ex.message}"
|
54
49
|
end
|
55
50
|
end
|
56
51
|
lines.each_with_index do |line, idx|
|
@@ -66,7 +61,7 @@ explains: https://github.com/yegor256/pdd#how-to-format"
|
|
66
61
|
|
67
62
|
# Fetch puzzle
|
68
63
|
def puzzle(lines, match, idx)
|
69
|
-
tail = tail(lines, match[1])
|
64
|
+
tail = tail(lines, match[1], idx)
|
70
65
|
body = (match[3] + ' ' + tail.join(' ')).gsub(/\s+/, ' ').strip
|
71
66
|
marker = marker(match[2])
|
72
67
|
Puzzle.new(
|
@@ -102,35 +97,52 @@ against the rules explained here: https://github.com/yegor256/pdd#how-to-format"
|
|
102
97
|
end
|
103
98
|
|
104
99
|
# Fetch puzzle tail (all lines after the first one)
|
105
|
-
def tail(lines, prefix)
|
100
|
+
def tail(lines, prefix, start)
|
106
101
|
lines
|
107
102
|
.take_while { |t| t.start_with?(prefix) }
|
108
103
|
.map { |t| t[prefix.length, t.length] }
|
109
104
|
.take_while { |t| t =~ /^[ a-zA-Z0-9]/ }
|
110
|
-
.
|
111
|
-
|
105
|
+
.each_with_index do |t, i|
|
106
|
+
next if t.start_with?(' ')
|
107
|
+
raise Error, "Space expected at #{start + i + 2}:#{prefix.length}; \
|
108
|
+
make sure all lines in the puzzle body have a single leading space."
|
109
|
+
end
|
110
|
+
.each_with_index do |t, i|
|
111
|
+
next if t !~ /^\s{2,}/
|
112
|
+
raise Error, "Too many leading spaces \
|
113
|
+
at #{start + i + 2}:#{prefix.length}; \
|
114
|
+
make sure all lines that include the puzzle body start \
|
115
|
+
at position ##{prefix.length + 1}."
|
116
|
+
end
|
112
117
|
.map { |t| t[1, t.length] }
|
113
118
|
end
|
114
119
|
|
115
120
|
# Git information at the line
|
116
121
|
def git(pos)
|
117
|
-
|
118
|
-
|
119
|
-
#{
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
122
|
+
dir = Shellwords.escape(File.dirname(@file))
|
123
|
+
name = Shellwords.escape(File.basename(@file))
|
124
|
+
git = "cd #{dir} && git"
|
125
|
+
if `#{git} rev-parse --is-inside-work-tree 2>/dev/null`.strip == 'true'
|
126
|
+
cmd = "#{git} blame -L #{pos},#{pos} --porcelain #{name}"
|
127
|
+
Hash[
|
128
|
+
`#{cmd}`.split("\n").map do |line|
|
129
|
+
if line =~ /^author /
|
130
|
+
[:author, line.sub(/^author /, '')]
|
131
|
+
elsif line =~ /^author-mail /
|
132
|
+
[:email, line.sub(/^author-mail <(.+)>$/, '\1')]
|
133
|
+
elsif line =~ /^author-time /
|
134
|
+
[
|
135
|
+
:time,
|
136
|
+
Time.at(
|
137
|
+
line.sub(/^author-time ([0-9]+)$/, '\1').to_i
|
138
|
+
).utc.iso8601
|
139
|
+
]
|
140
|
+
end
|
141
|
+
end.compact
|
142
|
+
]
|
143
|
+
else
|
144
|
+
{}
|
145
|
+
end
|
134
146
|
end
|
135
147
|
end
|
136
148
|
|
@@ -148,7 +160,7 @@ git blame -L #{pos},#{pos} --porcelain \
|
|
148
160
|
def puzzles
|
149
161
|
@source.puzzles
|
150
162
|
rescue Error => ex
|
151
|
-
raise Error,
|
163
|
+
raise Error, "#{@file}; #{ex.message}"
|
152
164
|
end
|
153
165
|
end
|
154
166
|
end
|
data/lib/pdd/sources.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -22,7 +20,6 @@
|
|
22
20
|
|
23
21
|
require 'shellwords'
|
24
22
|
require 'English'
|
25
|
-
require_relative '../pdd'
|
26
23
|
require_relative 'source'
|
27
24
|
|
28
25
|
module PDD
|
data/lib/pdd/version.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -25,5 +23,5 @@
|
|
25
23
|
# Copyright:: Copyright (c) 2014-2017 Yegor Bugayenko
|
26
24
|
# License:: MIT
|
27
25
|
module PDD
|
28
|
-
VERSION = '0.
|
26
|
+
VERSION = '0.18'.freeze
|
29
27
|
end
|
data/pdd.gemspec
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -20,6 +18,8 @@
|
|
20
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
19
|
# SOFTWARE.
|
22
20
|
|
21
|
+
require 'English'
|
22
|
+
|
23
23
|
lib = File.expand_path('../lib', __FILE__)
|
24
24
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
25
25
|
require_relative 'lib/pdd/version'
|
@@ -35,7 +35,7 @@ Gem::Specification.new do |s|
|
|
35
35
|
s.version = PDD::VERSION
|
36
36
|
s.license = 'MIT'
|
37
37
|
s.summary = 'Puzzle Driven Development collector'
|
38
|
-
s.description = 'Collects PDD puzzles from source code base'
|
38
|
+
s.description = 'Collects PDD puzzles from a source code base'
|
39
39
|
s.authors = ['Yegor Bugayenko']
|
40
40
|
s.email = 'yegor256@gmail.com'
|
41
41
|
s.homepage = 'http://github.com/yegor256/pdd'
|
@@ -44,14 +44,16 @@ Gem::Specification.new do |s|
|
|
44
44
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
45
45
|
s.rdoc_options = ['--charset=UTF-8']
|
46
46
|
s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
47
|
-
s.add_runtime_dependency 'nokogiri', '~>1.7
|
48
|
-
s.add_runtime_dependency 'slop', '~>4.4
|
47
|
+
s.add_runtime_dependency 'nokogiri', '~>1.7'
|
48
|
+
s.add_runtime_dependency 'slop', '~>4.4'
|
49
|
+
s.add_runtime_dependency 'rainbow', '~>2.2'
|
49
50
|
s.add_development_dependency 'rake', '12.0.0'
|
50
51
|
s.add_development_dependency 'codecov', '0.1.10'
|
51
52
|
s.add_development_dependency 'rdoc', '4.2.0'
|
52
53
|
s.add_development_dependency 'cucumber', '1.3.17'
|
53
54
|
s.add_development_dependency 'minitest', '5.5.0'
|
54
|
-
s.add_development_dependency 'rubocop', '0.
|
55
|
-
s.add_development_dependency 'rubocop-rspec', '1.
|
55
|
+
s.add_development_dependency 'rubocop', '0.48.1'
|
56
|
+
s.add_development_dependency 'rubocop-rspec', '1.15.1'
|
56
57
|
s.add_development_dependency 'rspec-rails', '3.1.0'
|
58
|
+
s.add_development_dependency 'xcop', '~>0.5'
|
57
59
|
end
|
data/test/test__helper.rb
CHANGED
data/test/test_duplicates.rb
CHANGED
data/test/test_estimates.rb
CHANGED
data/test/test_pdd.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -33,7 +31,7 @@ require_relative '../lib/pdd'
|
|
33
31
|
class TestPDD < Minitest::Test
|
34
32
|
def test_basic
|
35
33
|
Dir.mktmpdir 'test' do |dir|
|
36
|
-
opts = opts(['-
|
34
|
+
opts = opts(['-q', '-s', dir, '-e', '**/*.png', '-r', 'max-estimate:15'])
|
37
35
|
File.write(File.join(dir, 'a.txt'), '@todo #55 hello!')
|
38
36
|
matches(
|
39
37
|
Nokogiri::XML(PDD::Base.new(opts).xml),
|
@@ -50,7 +48,7 @@ class TestPDD < Minitest::Test
|
|
50
48
|
|
51
49
|
def test_rules_failure
|
52
50
|
Dir.mktmpdir 'test' do |dir|
|
53
|
-
opts = opts(['-
|
51
|
+
opts = opts(['-q', '-s', dir, '-e', '**/*.png', '-r', 'min-estimate:30'])
|
54
52
|
File.write(File.join(dir, 'a.txt'), '@todo #90 hello!')
|
55
53
|
assert_raises PDD::Error do
|
56
54
|
PDD::Base.new(opts).xml
|
@@ -61,21 +59,21 @@ class TestPDD < Minitest::Test
|
|
61
59
|
def test_git_repo
|
62
60
|
skip if Gem.win_platform?
|
63
61
|
Dir.mktmpdir 'test' do |dir|
|
64
|
-
opts = opts(['-
|
62
|
+
opts = opts(['-q', '-s', dir])
|
65
63
|
raise unless system("
|
66
64
|
set -e
|
67
65
|
cd '#{dir}'
|
68
|
-
git init .
|
66
|
+
git init --quiet .
|
69
67
|
git config user.email test@teamed.io
|
70
68
|
git config user.name 'Mr. Tester'
|
71
69
|
mkdir 'a long dir name'
|
72
70
|
cd 'a long dir name'
|
73
71
|
mkdir 'a kid'
|
74
72
|
cd 'a kid'
|
75
|
-
echo '@todo #1 this is
|
73
|
+
echo '@todo #1 this is some puzzle' > '.это файл.txt'
|
76
74
|
cd ../..
|
77
75
|
git add -f .
|
78
|
-
git commit -am 'first version'
|
76
|
+
git commit --quiet -am 'first version'
|
79
77
|
")
|
80
78
|
matches(
|
81
79
|
Nokogiri::XML(PDD::Base.new(opts).xml),
|
@@ -96,6 +94,7 @@ class TestPDD < Minitest::Test
|
|
96
94
|
def opts(args)
|
97
95
|
Slop.parse args do |o|
|
98
96
|
o.bool '-v', '--verbose'
|
97
|
+
o.bool '-q', '--quiet'
|
99
98
|
o.string '-s', '--source'
|
100
99
|
o.array '-e', '--exclude'
|
101
100
|
o.array '-r', '--rule'
|
data/test/test_roles.rb
CHANGED
data/test/test_source.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2014-2017 Yegor Bugayenko
|
4
2
|
#
|
5
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -22,6 +20,7 @@
|
|
22
20
|
|
23
21
|
require 'minitest/autorun'
|
24
22
|
require 'tmpdir'
|
23
|
+
require_relative '../lib/pdd'
|
25
24
|
require_relative '../lib/pdd/sources'
|
26
25
|
|
27
26
|
# Source test.
|
@@ -49,6 +48,9 @@ class TestSource < Minitest::Test
|
|
49
48
|
assert_equal '2-3', puzzle.props[:lines]
|
50
49
|
assert_equal 'hello, how are you doing?', puzzle.props[:body]
|
51
50
|
assert_equal '44', puzzle.props[:ticket]
|
51
|
+
assert puzzle.props[:author].nil?
|
52
|
+
assert puzzle.props[:email].nil?
|
53
|
+
assert puzzle.props[:time].nil?
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
@@ -119,13 +121,12 @@ class TestSource < Minitest::Test
|
|
119
121
|
raise unless system("
|
120
122
|
set -e
|
121
123
|
cd '#{dir}'
|
122
|
-
git init .
|
124
|
+
git init --quiet .
|
123
125
|
git config user.email test@teamed.io
|
124
126
|
git config user.name test
|
125
127
|
echo '@todo #1 this is the puzzle' > a.txt
|
126
128
|
git add a.txt
|
127
|
-
git commit -am 'first version'
|
128
|
-
git blame a.txt
|
129
|
+
git commit --quiet -am 'first version'
|
129
130
|
")
|
130
131
|
list = PDD::Source.new(File.join(dir, 'a.txt'), '').puzzles
|
131
132
|
assert_equal 1, list.size
|
data/test/test_sources.rb
CHANGED
data/test/test_text.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pdd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.18'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -16,28 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.7
|
19
|
+
version: '1.7'
|
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
|
-
version: 1.7
|
26
|
+
version: '1.7'
|
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
|
-
version: 4.4
|
33
|
+
version: '4.4'
|
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
|
-
version: 4.4
|
40
|
+
version: '4.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rainbow
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.2'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,28 +128,28 @@ dependencies:
|
|
114
128
|
requirements:
|
115
129
|
- - '='
|
116
130
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.
|
131
|
+
version: 0.48.1
|
118
132
|
type: :development
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
135
|
requirements:
|
122
136
|
- - '='
|
123
137
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.
|
138
|
+
version: 0.48.1
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: rubocop-rspec
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
128
142
|
requirements:
|
129
143
|
- - '='
|
130
144
|
- !ruby/object:Gem::Version
|
131
|
-
version: 1.
|
145
|
+
version: 1.15.1
|
132
146
|
type: :development
|
133
147
|
prerelease: false
|
134
148
|
version_requirements: !ruby/object:Gem::Requirement
|
135
149
|
requirements:
|
136
150
|
- - '='
|
137
151
|
- !ruby/object:Gem::Version
|
138
|
-
version: 1.
|
152
|
+
version: 1.15.1
|
139
153
|
- !ruby/object:Gem::Dependency
|
140
154
|
name: rspec-rails
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,7 +164,21 @@ dependencies:
|
|
150
164
|
- - '='
|
151
165
|
- !ruby/object:Gem::Version
|
152
166
|
version: 3.1.0
|
153
|
-
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: xcop
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0.5'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0.5'
|
181
|
+
description: Collects PDD puzzles from a source code base
|
154
182
|
email: yegor256@gmail.com
|
155
183
|
executables:
|
156
184
|
- pdd
|