pdd 0.17.9 → 0.18
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 +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
|
-
[](http://www.zerocracy.com)
|
4
4
|
[](http://www.rultor.com/p/yegor256/pdd)
|
5
5
|
[](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
|