pdd 0.20.7 → 0.20.8
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/.gitignore +5 -5
- data/.overcommit.yml +96 -0
- data/.pdd +4 -0
- data/.rubocop.yml +0 -3
- data/.simplecov +5 -5
- data/README.md +27 -3
- data/Rakefile +6 -0
- data/bin/pdd +19 -20
- data/features/cli.feature +1 -1
- data/features/html_output.feature +1 -1
- data/features/rake.feature +14 -12
- data/features/step_definitions/steps.rb +4 -3
- data/features/uses_config.feature +1 -1
- data/lib/pdd/rake_task.rb +15 -6
- data/lib/pdd/rule/duplicates.rb +1 -0
- data/lib/pdd/rule/roles.rb +1 -0
- data/lib/pdd/rule/text.rb +1 -0
- data/lib/pdd/source.rb +27 -23
- data/lib/pdd/sources.rb +31 -23
- data/lib/pdd/version.rb +1 -1
- data/lib/pdd.rb +14 -14
- data/pdd.gemspec +5 -3
- data/test/test__helper.rb +1 -1
- data/test/test_pdd.rb +1 -0
- data/test/test_rake_task.rb +7 -4
- data/test/test_source.rb +24 -1
- data/test/test_source_todo.rb +12 -0
- data/test/test_sources.rb +5 -3
- data/utils/glob.rb +67 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3ff37e6f0ac2629e0b31888df2b56f7024512b04b07bd58c29a0525186a40f0
|
4
|
+
data.tar.gz: 61076844123f2eda0b32734b2c917ed6eb033956177197626219bda878add5b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9b46c3238588062c781b1b3705cf343d1ca0e70481b2546ffc407b9a5be6534d45b3c8d0d4ebaab0ac39630ebfc6652feb8c69a8dd8d787bf33eae1a9cb0935
|
7
|
+
data.tar.gz: 790b7d73f1b7ea5d2666864b238dfdde211572186d3d84c29a6d6448936b54ef87a567473b83fccfad83ec945ad6f9677a739b0730fde5199618dc79f6cc9ead
|
data/.gitignore
CHANGED
data/.overcommit.yml
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# Use this file to configure the Overcommit hooks you wish to use. This will
|
2
|
+
# extend the default configuration defined in:
|
3
|
+
# https://github.com/sds/overcommit/blob/master/config/default.yml
|
4
|
+
#
|
5
|
+
# At the topmost level of this YAML file is a key representing type of hook
|
6
|
+
# being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
|
7
|
+
# customize each hook, such as whether to only run it on certain files (via
|
8
|
+
# `include`), whether to only display output if it fails (via `quiet`), etc.
|
9
|
+
#
|
10
|
+
# For a complete list of hooks, see:
|
11
|
+
# https://github.com/sds/overcommit/tree/master/lib/overcommit/hook
|
12
|
+
#
|
13
|
+
# For a complete list of options that you can use to customize hooks, see:
|
14
|
+
# https://github.com/sds/overcommit#configuration
|
15
|
+
|
16
|
+
PreCommit:
|
17
|
+
ALL:
|
18
|
+
problem_on_unmodified_line: report
|
19
|
+
requires_files: true
|
20
|
+
required: false
|
21
|
+
quiet: false
|
22
|
+
|
23
|
+
AuthorEmail:
|
24
|
+
enabled: true
|
25
|
+
description: 'Check author email'
|
26
|
+
requires_files: false
|
27
|
+
required: true
|
28
|
+
quiet: true
|
29
|
+
pattern: '^[^@]+@.*$'
|
30
|
+
|
31
|
+
AuthorName:
|
32
|
+
enabled: true
|
33
|
+
description: 'Check for author name'
|
34
|
+
requires_files: false
|
35
|
+
required: true
|
36
|
+
quiet: true
|
37
|
+
|
38
|
+
BundleCheck:
|
39
|
+
enabled: true
|
40
|
+
description: 'Check Gemfile dependencies'
|
41
|
+
required_executable: 'bundle'
|
42
|
+
flags: ['check']
|
43
|
+
include:
|
44
|
+
- 'Gemfile'
|
45
|
+
- 'Gemfile.lock'
|
46
|
+
- '*.gemspec'
|
47
|
+
|
48
|
+
BundleOutdated:
|
49
|
+
enabled: true
|
50
|
+
description: 'List installed gems with newer versions available'
|
51
|
+
required_executable: 'bundle'
|
52
|
+
flags: ['outdated', '--strict', '--parseable']
|
53
|
+
|
54
|
+
RuboCop:
|
55
|
+
enabled: true
|
56
|
+
description: 'Analyze with RuboCop'
|
57
|
+
required_executable: 'bundle'
|
58
|
+
flags: ['exec', 'rubocop']
|
59
|
+
|
60
|
+
# Hooks that are run against every commit message after a user has written it.
|
61
|
+
# These hooks are useful for enforcing policies on commit messages written for a
|
62
|
+
# project.
|
63
|
+
CommitMsg:
|
64
|
+
ALL:
|
65
|
+
requires_files: false
|
66
|
+
quiet: false
|
67
|
+
|
68
|
+
EmptyMessage:
|
69
|
+
enabled: true
|
70
|
+
description: 'Check for empty commit message'
|
71
|
+
quiet: true
|
72
|
+
|
73
|
+
MessageFormat:
|
74
|
+
enabled: true
|
75
|
+
description: 'Check commit message matches expected pattern'
|
76
|
+
pattern: '(\[#)(.+)(\]\s)(.+)'
|
77
|
+
expected_pattern_message: '[#<Issue Id>] <Commit Message Description>'
|
78
|
+
sample_message: '[#167] Refactored onboarding flow'
|
79
|
+
|
80
|
+
PrePush:
|
81
|
+
ALL:
|
82
|
+
requires_files: false
|
83
|
+
required: false
|
84
|
+
quiet: false
|
85
|
+
|
86
|
+
RakeTarget:
|
87
|
+
enabled: true
|
88
|
+
quite: true
|
89
|
+
description: 'Run rake targets'
|
90
|
+
targets:
|
91
|
+
- 'rubocop'
|
92
|
+
- 'test'
|
93
|
+
- 'xcop'
|
94
|
+
required_executable: 'bundle'
|
95
|
+
flags: ['exec', 'rake']
|
96
|
+
|
data/.pdd
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
--source=.
|
2
2
|
--verbose
|
3
3
|
--skip-errors
|
4
|
+
--skip-gitignore
|
5
|
+
--include lib/pdd/sources.rb
|
4
6
|
--exclude .idea/**/*
|
7
|
+
--exclude .bundle/**/*
|
5
8
|
--exclude target/**/*
|
6
9
|
--exclude coverage/**/*
|
10
|
+
--exclude test_assets/**/*
|
7
11
|
--exclude README.md
|
8
12
|
--exclude features/cli.feature
|
9
13
|
--exclude features/parsing.feature
|
data/.rubocop.yml
CHANGED
@@ -16,8 +16,5 @@ Style/MultilineBlockChain:
|
|
16
16
|
Enabled: false
|
17
17
|
Metrics/BlockLength:
|
18
18
|
Max: 50
|
19
|
-
# @todo #123:30m Needs to enable this check and fix all issues.
|
20
|
-
# For now, this is out of the scope of this issue.
|
21
|
-
# This issue appeared after update TargetRubyVersion to 2.3
|
22
19
|
Style/FrozenStringLiteralComment:
|
23
20
|
Enabled: false
|
data/.simplecov
CHANGED
@@ -18,21 +18,21 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
19
|
# SOFTWARE.
|
20
20
|
|
21
|
-
if Gem.win_platform?
|
21
|
+
if Gem.win_platform?
|
22
22
|
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
23
23
|
SimpleCov::Formatter::HTMLFormatter
|
24
24
|
]
|
25
25
|
SimpleCov.start do
|
26
|
-
add_filter
|
27
|
-
add_filter
|
26
|
+
add_filter '/test/'
|
27
|
+
add_filter '/features/'
|
28
28
|
end
|
29
29
|
else
|
30
30
|
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
31
31
|
SimpleCov::Formatter::HTMLFormatter
|
32
32
|
)
|
33
33
|
SimpleCov.start do
|
34
|
-
add_filter
|
35
|
-
add_filter
|
34
|
+
add_filter '/test/'
|
35
|
+
add_filter '/features/'
|
36
36
|
minimum_coverage 90
|
37
37
|
end
|
38
38
|
end
|
data/README.md
CHANGED
@@ -41,7 +41,13 @@ Run it locally and read its output:
|
|
41
41
|
$ pdd --help
|
42
42
|
```
|
43
43
|
|
44
|
-
|
44
|
+
### File and Directory Selection
|
45
|
+
You can exclude & include certain number of files from the search via these options:
|
46
|
+
|
47
|
+
`` --exclude=glob ``
|
48
|
+
|
49
|
+
You can skip any file(s) with a name suffix that matches the pattern glob, using wildcard matching;
|
50
|
+
a name suffix is either the whole path and name, or reg expr, for example:
|
45
51
|
|
46
52
|
```bash
|
47
53
|
pdd --exclude=src/**/*.java --exclude=target/**/*
|
@@ -49,6 +55,17 @@ pdd --exclude=src/**/*.java # exclude .java files in src/
|
|
49
55
|
pdd --exclude=src/**/* # exclude all files in src/
|
50
56
|
```
|
51
57
|
|
58
|
+
`` --include=glob ``
|
59
|
+
|
60
|
+
Search only files whose name matches glob, using wildcard matching as described under ``--exclude``.
|
61
|
+
If contradictory ``--include`` and ``--exclude`` options are given, the last matching one wins.
|
62
|
+
If no ``--include`` or ``--exclude`` options are given, all files from working directory are included, example:
|
63
|
+
аомтрптм
|
64
|
+
```bash
|
65
|
+
pdd --include=src/**/*.py # include only .py files in src/
|
66
|
+
pdd --include=src/**/* # include all files in src/
|
67
|
+
```
|
68
|
+
|
52
69
|
## How to Format?
|
53
70
|
|
54
71
|
Every puzzle has to be formatted like this (pay attention
|
@@ -169,6 +186,7 @@ The XML produced will look approximately like this (here is a
|
|
169
186
|
</puzzle>
|
170
187
|
</puzzles>
|
171
188
|
```
|
189
|
+
NOTE: puzzles are saved with utf-8 encoding
|
172
190
|
|
173
191
|
[XSD Schema](http://pdd-xsd.teamed.io/0.19.4.xsd) is here.
|
174
192
|
The most interesting parts of each puzzle are:
|
@@ -189,15 +207,21 @@ The most interesting parts of each puzzle are:
|
|
189
207
|
## How to contribute
|
190
208
|
|
191
209
|
Read [these guidelines](https://www.yegor256.com/2014/04/15/github-guidelines.html).
|
192
|
-
Make sure
|
210
|
+
Make sure your build is green before you contribute
|
193
211
|
your pull request. You will need to have [Ruby](https://www.ruby-lang.org/en/) 2.3+ and
|
194
212
|
[Bundler](https://bundler.io/) installed. Then:
|
195
213
|
|
196
214
|
```
|
197
|
-
$ bundle
|
215
|
+
$ bundle install --path .bundle
|
198
216
|
$ bundle exec rake
|
199
217
|
```
|
200
218
|
|
219
|
+
Next, install and run overcommit to install hooks (required once)
|
220
|
+
```
|
221
|
+
$ gem install overcommit -v '=0.58.0'
|
222
|
+
$ overcommit --install
|
223
|
+
```
|
224
|
+
|
201
225
|
If it's clean and you don't see any error messages, submit your pull request.
|
202
226
|
|
203
227
|
This is how you run the tool locally to test how it works:
|
data/Rakefile
CHANGED
@@ -66,6 +66,12 @@ Xcop::RakeTask.new :xcop do |task|
|
|
66
66
|
task.excludes = ['target/**/*', 'coverage/**/*']
|
67
67
|
end
|
68
68
|
|
69
|
+
require 'pdd/rake_task'
|
70
|
+
desc 'Collecting and parsing all puzzles in project'
|
71
|
+
PDD::RakeTask.new :pdd do |task|
|
72
|
+
task.includes = ['**/*']
|
73
|
+
end
|
74
|
+
|
69
75
|
require 'cucumber/rake/task'
|
70
76
|
Cucumber::Rake::Task.new(:features) do |t|
|
71
77
|
t.cucumber_opts = 'features --format progress'
|
data/bin/pdd
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
20
|
# SOFTWARE.
|
21
21
|
|
22
|
-
|
22
|
+
$stdout.sync = true
|
23
23
|
|
24
24
|
require 'shellwords'
|
25
25
|
require 'English'
|
@@ -42,11 +42,6 @@ begin
|
|
42
42
|
end
|
43
43
|
args += ARGV
|
44
44
|
|
45
|
-
dir = Dir.pwd
|
46
|
-
@dir = File.absolute_path(dir)
|
47
|
-
files = Dir.glob(
|
48
|
-
File.join(@dir, '**/*'), File::FNM_DOTMATCH
|
49
|
-
).reject { |f| File.directory?(f) }
|
50
45
|
begin
|
51
46
|
opts = Slop.parse(args, strict: true, help: true) do |o|
|
52
47
|
o.banner = "Usage (#{PDD::VERSION}): pdd [options]"
|
@@ -65,15 +60,15 @@ begin
|
|
65
60
|
o.array '-e', '--exclude', 'Glob pattern to exclude, e.g. "**/*.jpg"',
|
66
61
|
default: []
|
67
62
|
o.array '-n', '--include', 'Glob pattern to include, e.g. "**/*.jpg"',
|
68
|
-
default: [
|
63
|
+
default: []
|
69
64
|
o.string '-t', '--format', 'Format of the report (xml|html)'
|
70
65
|
o.array(
|
71
66
|
'-r', '--rule', 'Rule to apply (can be used many times)',
|
72
67
|
delimiter: ';'
|
73
68
|
)
|
74
69
|
end
|
75
|
-
rescue Slop::Error =>
|
76
|
-
raise StandardError, "#{
|
70
|
+
rescue Slop::Error => e
|
71
|
+
raise StandardError, "#{e.message}, try --help"
|
77
72
|
end
|
78
73
|
|
79
74
|
if opts.help?
|
@@ -87,13 +82,17 @@ https://github.com/cqfn/pdd/blob/master/README.md"
|
|
87
82
|
raise '-f is mandatory when using -v, try --help for more information'
|
88
83
|
end
|
89
84
|
|
90
|
-
if opts['skip-gitignore']
|
91
|
-
|
85
|
+
if opts['skip-gitignore'] && File.exist?('.gitignore')
|
86
|
+
cfg = File.new('.gitignore')
|
87
|
+
body = File.read(cfg)
|
88
|
+
extra = body.split(/\s+/).map(&:strip)
|
89
|
+
opts['skip-gitignore'] = extra
|
90
|
+
puts "Found #{body.split(/\n/).length} lines in #{File.absolute_path(cfg)}"
|
92
91
|
end
|
93
92
|
|
94
93
|
Encoding.default_external = Encoding::UTF_8
|
95
94
|
Encoding.default_internal = Encoding::UTF_8
|
96
|
-
file = opts.file? ? File.new(opts[:file], 'w') :
|
95
|
+
file = opts.file? ? File.new(opts[:file], 'w') : $stdout
|
97
96
|
output = PDD::Base.new(opts).xml
|
98
97
|
if opts[:format]
|
99
98
|
if opts[:format] == 'html'
|
@@ -107,12 +106,12 @@ https://github.com/cqfn/pdd/blob/master/README.md"
|
|
107
106
|
end
|
108
107
|
end
|
109
108
|
file << output
|
110
|
-
rescue SystemExit =>
|
111
|
-
puts
|
112
|
-
PDD.log.info "Exit code is #{
|
113
|
-
exit(
|
114
|
-
rescue PDD::Error =>
|
115
|
-
puts "#{Rainbow('ERROR').red}: #{
|
109
|
+
rescue SystemExit => e
|
110
|
+
puts e.message unless e.success?
|
111
|
+
PDD.log.info "Exit code is #{e.status}"
|
112
|
+
exit(e.status)
|
113
|
+
rescue PDD::Error => e
|
114
|
+
puts "#{Rainbow('ERROR').red}: #{e.message}
|
116
115
|
If you can't understand the cause of this issue or you don't know \
|
117
116
|
how to fix it, please submit a GitHub issue, we will try to help you: \
|
118
117
|
https://github.com/cqfn/pdd/issues. This tool is still in its beta \
|
@@ -120,8 +119,8 @@ version and we will appreciate your feedback. Here is where you can find \
|
|
120
119
|
more documentation: https://github.com/cqfn/pdd/blob/master/README.md."
|
121
120
|
PDD.log.info 'Exit code is 1'
|
122
121
|
exit(1)
|
123
|
-
rescue StandardError =>
|
124
|
-
puts "#{Rainbow('ERROR').red} (#{
|
122
|
+
rescue StandardError => e
|
123
|
+
puts "#{Rainbow('ERROR').red} (#{e.class.name}): #{e.message}"
|
125
124
|
PDD.log.info 'Exit code is 255'
|
126
125
|
exit(255)
|
127
126
|
end
|
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 "Reading ."
|
29
|
+
And Stdout contains "Reading from root dir ."
|
30
30
|
And XML file "out.xml" matches "/puzzles[count(puzzle)=1]"
|
31
31
|
And XML file "out.xml" matches "//puzzle[starts-with(body,'Привет, Let')]"
|
32
32
|
|
data/features/rake.feature
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
Feature: Rake Task
|
2
|
-
|
2
|
+
As a source code writer I want to be able to
|
3
|
+
run PDD from Rakefile
|
4
|
+
Scenario: PDD can be used in Rakefile
|
3
5
|
Given It is Unix
|
4
|
-
And
|
6
|
+
And I have a "Rakefile" file with content:
|
5
7
|
"""
|
6
8
|
require 'pdd/rake_task'
|
7
|
-
PDD::RakeTask.new
|
9
|
+
PDD::RakeTask.new(:pdd) do |task|
|
10
|
+
task.includes = ['a.txt']
|
11
|
+
end
|
8
12
|
"""
|
9
|
-
|
10
|
-
"""bash
|
11
|
-
rake pdd
|
13
|
+
And I have a "a.txt" file with content:
|
12
14
|
"""
|
13
|
-
|
14
|
-
And the stderr should contain:
|
15
|
+
\x40todo #55 hello!
|
15
16
|
"""
|
16
|
-
|
17
|
-
""
|
18
|
-
|
19
|
-
|
17
|
+
|
18
|
+
When I run bash with "rake pdd"
|
19
|
+
Then Exit code is zero
|
20
|
+
|
21
|
+
|
@@ -64,9 +64,9 @@ When(/^I run pdd it fails with "([^"]*)"$/) do |txt|
|
|
64
64
|
begin
|
65
65
|
PDD::Base.new(@opts).xml
|
66
66
|
passed = true
|
67
|
-
rescue PDD::Error =>
|
68
|
-
unless
|
69
|
-
raise "PDD failed but exception doesn't contain \"#{txt}\": #{
|
67
|
+
rescue PDD::Error => e
|
68
|
+
unless e.message.include?(txt)
|
69
|
+
raise "PDD failed but exception doesn't contain \"#{txt}\": #{e.message}"
|
70
70
|
end
|
71
71
|
end
|
72
72
|
raise "PDD didn't fail" if passed
|
@@ -90,6 +90,7 @@ end
|
|
90
90
|
|
91
91
|
Then(/^XML file "([^"]+)" matches "([^"]+)"$/) do |file, xpath|
|
92
92
|
raise "File #{file} doesn't exit" unless File.exist?(file)
|
93
|
+
|
93
94
|
xml = Nokogiri::XML.parse(File.read(file))
|
94
95
|
xml.remove_namespaces!
|
95
96
|
if xml.xpath(xpath).empty?
|
data/lib/pdd/rake_task.rb
CHANGED
@@ -1,16 +1,23 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/tasklib'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'slop'
|
7
|
+
require 'pdd'
|
3
8
|
|
4
9
|
# PDD Rake task
|
5
10
|
module PDD
|
6
11
|
# Rake task
|
7
12
|
class RakeTask < Rake::TaskLib
|
8
|
-
attr_accessor :name
|
13
|
+
attr_accessor :name, :fail_on_error, :includes, :license, :quiet
|
14
|
+
|
9
15
|
def initialize(*args, &task_block)
|
10
|
-
# @todo #125:30m Needs to have more parameters to run this task.
|
11
|
-
# For now, we just have a single parameter - the name.
|
12
|
-
# Needs more parameters like the xcop rake task has.
|
13
16
|
@name = args.shift || :pdd
|
17
|
+
@includes = []
|
18
|
+
@excludes = []
|
19
|
+
@license = nil
|
20
|
+
@quiet = false
|
14
21
|
desc 'Run PDD' unless ::Rake.application.last_description
|
15
22
|
task(name, *args) do |_, task_args|
|
16
23
|
RakeFileUtils.send(:verbose, true) do
|
@@ -20,11 +27,13 @@ module PDD
|
|
20
27
|
end
|
21
28
|
end
|
22
29
|
|
30
|
+
private
|
31
|
+
|
23
32
|
def run
|
24
33
|
# @todo #125:30m need to implement this method.
|
25
34
|
# For now, it's just a task,
|
26
|
-
# that
|
27
|
-
|
35
|
+
# that prints a simple Running pdd... message to user
|
36
|
+
puts 'Running pdd...' unless @quiet
|
28
37
|
end
|
29
38
|
end
|
30
39
|
end
|
data/lib/pdd/rule/duplicates.rb
CHANGED
@@ -35,6 +35,7 @@ module PDD
|
|
35
35
|
.group_by { |p| p.xpath('body/text()').to_s }
|
36
36
|
.map do |_, puzzles|
|
37
37
|
next nil if puzzles.count <= @max
|
38
|
+
|
38
39
|
"there are #{puzzles.count} duplicate(s) of the same puzzle: " +
|
39
40
|
puzzles.map do |p|
|
40
41
|
"#{p.xpath('file/text()')}:#{p.xpath('lines/text()')}"
|
data/lib/pdd/rule/roles.rb
CHANGED
data/lib/pdd/rule/text.rb
CHANGED
@@ -34,6 +34,7 @@ module PDD
|
|
34
34
|
@xml.xpath('//puzzle').map do |p|
|
35
35
|
words = p.xpath('body/text()').to_s.split.size
|
36
36
|
next nil if words >= @min
|
37
|
+
|
37
38
|
"Puzzle #{p.xpath('file/text()')}:#{p.xpath('lines/text()')}"\
|
38
39
|
" has a very short description of just #{words} words while"\
|
39
40
|
" a minimum of #{@min} is required"
|
data/lib/pdd/source.rb
CHANGED
@@ -39,7 +39,7 @@ module PDD
|
|
39
39
|
|
40
40
|
def match_markers(line)
|
41
41
|
MARKERS.map do |mkr|
|
42
|
-
%r{(.*(?:^|\s))#{mkr}\s+#([\w
|
42
|
+
%r{(.*(?:^|\s))#{mkr}\s+#([\w\-.:/]+)\s+(.+)}.match(line)
|
43
43
|
end.compact
|
44
44
|
end
|
45
45
|
|
@@ -106,7 +106,7 @@ see https://github.com/cqfn/pdd#how-to-format"
|
|
106
106
|
# Fetch puzzle
|
107
107
|
def puzzle(lines, match, idx)
|
108
108
|
tail = tail(lines, match[1], idx)
|
109
|
-
body =
|
109
|
+
body = "#{match[3]} #{tail.join(' ')}".gsub(/\s+/, ' ').strip
|
110
110
|
body = body.chomp('*/-->').strip
|
111
111
|
marker = marker(match[2])
|
112
112
|
Puzzle.new(
|
@@ -121,7 +121,7 @@ see https://github.com/cqfn/pdd#how-to-format"
|
|
121
121
|
|
122
122
|
# Parse a marker.
|
123
123
|
def marker(text)
|
124
|
-
re = %r{([\w
|
124
|
+
re = %r{([\w\-.]+)(?::(\d+)(?:(m|h)[a-z]*)?)?(?:/([A-Z]+))?}
|
125
125
|
match = re.match(text)
|
126
126
|
if match.nil?
|
127
127
|
raise "Invalid puzzle marker \"#{text}\", most probably formatted \
|
@@ -148,10 +148,11 @@ against the rules explained here: https://github.com/cqfn/pdd#how-to-format"
|
|
148
148
|
.map { |t| t[prefix.length, t.length] }
|
149
149
|
.take_while { |t| t =~ /^[ a-zA-Z0-9]/ }
|
150
150
|
.each_with_index do |t, i|
|
151
|
-
|
152
|
-
|
151
|
+
next if t.start_with?(' ')
|
152
|
+
|
153
|
+
raise Error, "Space expected at #{start + i + 2}:#{prefix.length}; \
|
153
154
|
make sure all lines in the puzzle body have a single leading space."
|
154
|
-
|
155
|
+
end
|
155
156
|
.map { |t| t[1, t.length] }
|
156
157
|
end
|
157
158
|
|
@@ -167,21 +168,22 @@ make sure all lines in the puzzle body have a single leading space."
|
|
167
168
|
if `#{git} rev-parse --is-inside-work-tree 2>/dev/null`.strip == 'true'
|
168
169
|
cmd = "#{git} blame -L #{pos},#{pos} --porcelain #{name}"
|
169
170
|
add_github_login(Hash[
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
171
|
+
`#{cmd}`.split("\n").map do |line|
|
172
|
+
case line
|
173
|
+
when /^author /
|
174
|
+
[:author, line.sub(/^author /, '')]
|
175
|
+
when /^author-mail [^@]+@[^.]+\..+/
|
176
|
+
[:email, line.sub(/^author-mail <(.+)>$/, '\1')]
|
177
|
+
when /^author-time /
|
178
|
+
[
|
179
|
+
:time,
|
180
|
+
Time.at(
|
181
|
+
line.sub(/^author-time ([0-9]+)$/, '\1').to_i
|
182
|
+
).utc.iso8601
|
183
|
+
]
|
184
|
+
end
|
185
|
+
end.compact
|
186
|
+
])
|
185
187
|
else
|
186
188
|
{}
|
187
189
|
end
|
@@ -207,12 +209,14 @@ make sure all lines in the puzzle body have a single leading space."
|
|
207
209
|
email, author = info.values_at(:email, :author)
|
208
210
|
# if email is not defined, changes have not been committed
|
209
211
|
return if email.nil?
|
212
|
+
|
210
213
|
base_uri = 'https://api.github.com/search/users?per_page=1'
|
211
214
|
query = base_uri + "&q=#{email}+in:email"
|
212
215
|
json = get_json query
|
213
216
|
# find user by name instead since users can make github email private
|
214
217
|
unless json['total_count'].positive?
|
215
218
|
return if author.nil?
|
219
|
+
|
216
220
|
query = base_uri + "&q=#{author}+in:fullname"
|
217
221
|
json = get_json query
|
218
222
|
end
|
@@ -240,8 +244,8 @@ make sure all lines in the puzzle body have a single leading space."
|
|
240
244
|
# Fetch all puzzles.
|
241
245
|
def puzzles
|
242
246
|
@source.puzzles
|
243
|
-
rescue Error =>
|
244
|
-
raise Error, "#{@file}; #{
|
247
|
+
rescue Error => e
|
248
|
+
raise Error, "#{@file}; #{e.message}"
|
245
249
|
end
|
246
250
|
end
|
247
251
|
end
|
data/lib/pdd/sources.rb
CHANGED
@@ -18,54 +18,61 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
19
|
# SOFTWARE.
|
20
20
|
|
21
|
+
require 'rainbow'
|
21
22
|
require 'shellwords'
|
22
23
|
require 'English'
|
23
24
|
require_relative 'source'
|
25
|
+
require_relative '../../utils/glob'
|
24
26
|
|
25
27
|
module PDD
|
26
28
|
# Code base abstraction
|
27
29
|
class Sources
|
28
30
|
# Ctor.
|
29
31
|
# +dir+:: Directory with source code files
|
30
|
-
def initialize(dir
|
32
|
+
def initialize(dir)
|
31
33
|
@dir = File.absolute_path(dir)
|
32
|
-
@exclude =
|
33
|
-
@include =
|
34
|
+
@exclude = ['.git/**/*']
|
35
|
+
@include = []
|
34
36
|
end
|
35
37
|
|
36
38
|
# Fetch all sources.
|
37
39
|
def fetch
|
40
|
+
exclude_paths = @exclude.map do |ptn|
|
41
|
+
Glob.new(File.join(@dir, ptn)).to_regexp
|
42
|
+
end
|
38
43
|
files = Dir.glob(
|
39
44
|
File.join(@dir, '**/*'), File::FNM_DOTMATCH
|
40
|
-
).reject
|
41
|
-
|
42
|
-
@include.each do |ptn|
|
43
|
-
Dir.glob(File.join(@dir, ptn), File::FNM_DOTMATCH) do |f|
|
44
|
-
files.keep_if { |i| i != f }
|
45
|
-
included += 1
|
46
|
-
end
|
45
|
+
).reject do |f|
|
46
|
+
File.directory?(f) || exclude_paths.any? { |ptn| f.match(ptn) }
|
47
47
|
end
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
files.delete_if { |i| i == f }
|
53
|
-
excluded += 1
|
54
|
-
end
|
55
|
-
end
|
56
|
-
PDD.log.info "#{files.size} file(s) found, #{excluded} excluded"
|
48
|
+
files += Dir.glob(
|
49
|
+
@include.map { |ptn| File.join(@dir, ptn) }
|
50
|
+
).reject { |f| File.directory?(f) }
|
51
|
+
files = files.uniq # remove duplicates
|
57
52
|
files.reject { |f| binary?(f) }.map do |file|
|
58
53
|
path = file[@dir.length + 1, file.length]
|
59
54
|
VerboseSource.new(path, Source.new(file, path))
|
60
55
|
end
|
61
56
|
end
|
62
57
|
|
63
|
-
def exclude(
|
64
|
-
|
58
|
+
def exclude(paths)
|
59
|
+
paths = paths.nil? ? [] : paths
|
60
|
+
paths = paths.is_a?(Array) ? paths : [paths]
|
61
|
+
@exclude.push(*paths)
|
62
|
+
paths&.each do |path|
|
63
|
+
PDD.log.info "#{Rainbow('Excluding').orange} #{path}"
|
64
|
+
end
|
65
|
+
self
|
65
66
|
end
|
66
67
|
|
67
|
-
def include(
|
68
|
-
|
68
|
+
def include(paths)
|
69
|
+
paths = paths.nil? ? [] : paths
|
70
|
+
paths = paths.is_a?(Array) ? paths : [paths]
|
71
|
+
@include.push(*paths)
|
72
|
+
paths&.each do |path|
|
73
|
+
PDD.log.info "#{Rainbow('Including').blue} #{path}"
|
74
|
+
end
|
75
|
+
self
|
69
76
|
end
|
70
77
|
|
71
78
|
private
|
@@ -76,6 +83,7 @@ module PDD
|
|
76
83
|
# `test_ignores_binary_files` in `test_sources.rb`.
|
77
84
|
def binary?(file)
|
78
85
|
return false if Gem.win_platform?
|
86
|
+
|
79
87
|
`grep -qI '.' #{Shellwords.escape(file)}`
|
80
88
|
if $CHILD_STATUS.success?
|
81
89
|
false
|
data/lib/pdd/version.rb
CHANGED
data/lib/pdd.rb
CHANGED
@@ -52,11 +52,12 @@ module PDD
|
|
52
52
|
# Get logger.
|
53
53
|
def self.log
|
54
54
|
unless defined?(@logger)
|
55
|
-
@logger = Logger.new(
|
55
|
+
@logger = Logger.new($stdout)
|
56
56
|
@logger.formatter = proc { |severity, _, _, msg|
|
57
|
-
|
57
|
+
case severity
|
58
|
+
when 'ERROR'
|
58
59
|
"#{Rainbow(severity).red}: #{msg}\n"
|
59
|
-
|
60
|
+
when 'WARN'
|
60
61
|
"#{Rainbow(severity).orange}: #{msg}\n"
|
61
62
|
else
|
62
63
|
"#{msg}\n"
|
@@ -87,20 +88,15 @@ module PDD
|
|
87
88
|
|
88
89
|
# Generate XML.
|
89
90
|
def xml
|
90
|
-
dir = @opts[:source]
|
91
|
-
PDD.log.info "Reading #{dir}"
|
91
|
+
dir = @opts[:source] || Dir.pwd
|
92
|
+
PDD.log.info "Reading from root dir #{dir}"
|
92
93
|
require_relative 'pdd/sources'
|
93
|
-
sources = Sources.new(dir)
|
94
|
-
@opts[:
|
95
|
-
|
96
|
-
end
|
97
|
-
@opts[:exclude]&.each do |p|
|
98
|
-
sources = sources.exclude(p)
|
99
|
-
PDD.log.info "Excluding #{p}"
|
100
|
-
end
|
94
|
+
sources = Sources.new(File.expand_path(dir))
|
95
|
+
sources.exclude((@opts[:exclude] || []) + (@opts['skip-gitignore'] || []))
|
96
|
+
sources.include(@opts[:include])
|
101
97
|
sanitize(
|
102
98
|
rules(
|
103
|
-
Nokogiri::XML::Builder.new do |xml|
|
99
|
+
Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
104
100
|
xml << "<?xml-stylesheet type='text/xsl' href='#{xsl}'?>"
|
105
101
|
xml.puzzles(attrs) do
|
106
102
|
sources.fetch.each do |source|
|
@@ -152,16 +148,19 @@ module PDD
|
|
152
148
|
unless list.select { |r| r.start_with?('max-duplicates:') }.empty?
|
153
149
|
raise PDD::Error, 'You can\'t modify max-duplicates, it\'s always 1'
|
154
150
|
end
|
151
|
+
|
155
152
|
list.push('max-duplicates:1').map do |r|
|
156
153
|
name, value = r.split(':')
|
157
154
|
rule = RULES[name]
|
158
155
|
raise "Rule '#{name}' doesn't exist" if rule.nil?
|
156
|
+
|
159
157
|
rule.new(doc, value).errors.each do |e|
|
160
158
|
PDD.log.error e
|
161
159
|
total += 1
|
162
160
|
end
|
163
161
|
end
|
164
162
|
raise PDD::Error, "#{total} errors, see log above" unless total.zero?
|
163
|
+
|
165
164
|
xml
|
166
165
|
end
|
167
166
|
|
@@ -173,6 +172,7 @@ module PDD
|
|
173
172
|
errors.each { |e| PDD.log.error e }
|
174
173
|
PDD.log.error(xml) unless errors.empty?
|
175
174
|
raise SchemaError, errors.join('; ') unless errors.empty?
|
175
|
+
|
176
176
|
xml
|
177
177
|
end
|
178
178
|
end
|
data/pdd.gemspec
CHANGED
@@ -20,17 +20,18 @@
|
|
20
20
|
|
21
21
|
require 'English'
|
22
22
|
|
23
|
-
lib = File.expand_path('
|
23
|
+
lib = File.expand_path('lib', __dir__)
|
24
24
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
25
25
|
require_relative 'lib/pdd/version'
|
26
26
|
|
27
27
|
Gem::Specification.new do |s|
|
28
28
|
s.specification_version = 2 if s.respond_to? :specification_version=
|
29
29
|
if s.respond_to? :required_rubygems_version=
|
30
|
-
s.required_rubygems_version =
|
30
|
+
s.required_rubygems_version =
|
31
|
+
Gem::Requirement.new('>= 0')
|
31
32
|
end
|
32
33
|
s.rubygems_version = '2.3'
|
33
|
-
s.required_ruby_version = '
|
34
|
+
s.required_ruby_version = '~> 2.3'
|
34
35
|
s.name = 'pdd'
|
35
36
|
s.version = PDD::VERSION
|
36
37
|
s.license = 'MIT'
|
@@ -56,5 +57,6 @@ Gem::Specification.new do |s|
|
|
56
57
|
s.add_development_dependency 'rspec-rails', '3.1.0'
|
57
58
|
s.add_development_dependency 'rubocop', '0.52.1'
|
58
59
|
s.add_development_dependency 'rubocop-rspec', '1.15.1'
|
60
|
+
s.add_development_dependency 'slop', '4.9.1'
|
59
61
|
s.add_development_dependency 'xcop', '0.5.8'
|
60
62
|
end
|
data/test/test__helper.rb
CHANGED
data/test/test_pdd.rb
CHANGED
data/test/test_rake_task.rb
CHANGED
@@ -5,11 +5,14 @@ require_relative '../lib/pdd/rake_task'
|
|
5
5
|
|
6
6
|
# Test for RakeTask
|
7
7
|
class TestRakeTask < Minitest::Test
|
8
|
-
def
|
9
|
-
|
10
|
-
|
8
|
+
def test_basic
|
9
|
+
Dir.mktmpdir 'test' do |dir|
|
10
|
+
file = File.join(dir, 'a.txt')
|
11
|
+
File.write(file, "\x40todo #55 hello!")
|
12
|
+
PDD::RakeTask.new(:pdd1) do |task|
|
13
|
+
task.quiet = true
|
14
|
+
end
|
11
15
|
Rake::Task['pdd1'].invoke
|
12
16
|
end
|
13
|
-
assert_equal('NOT IMPLEMENTED', error.message)
|
14
17
|
end
|
15
18
|
end
|
data/test/test_source.rb
CHANGED
@@ -122,6 +122,25 @@ class TestSource < Minitest::Test
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
+
def test_succeed_utf8_encoded_body
|
126
|
+
Dir.mktmpdir 'test' do |dir|
|
127
|
+
file = File.join(dir, 'a.txt')
|
128
|
+
File.write(
|
129
|
+
file,
|
130
|
+
"
|
131
|
+
* \x40todo #44 Привет, мир, мне кофе
|
132
|
+
* вторая линия
|
133
|
+
"
|
134
|
+
)
|
135
|
+
list = PDD::VerboseSource.new(file, PDD::Source.new(file, 'hey')).puzzles
|
136
|
+
assert_equal 1, list.size
|
137
|
+
puzzle = list.first
|
138
|
+
assert_equal '2-3', puzzle.props[:lines]
|
139
|
+
assert_equal 'Привет, мир, мне кофе вторая линия', puzzle.props[:body]
|
140
|
+
assert_equal '44', puzzle.props[:ticket]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
125
144
|
def test_failing_on_incomplete_puzzle
|
126
145
|
Dir.mktmpdir 't5' do |dir|
|
127
146
|
file = File.join(dir, 'ff.txt')
|
@@ -141,7 +160,7 @@ class TestSource < Minitest::Test
|
|
141
160
|
def test_failing_on_broken_unicode
|
142
161
|
Dir.mktmpdir 'test' do |dir|
|
143
162
|
file = File.join(dir, 'xx.txt')
|
144
|
-
File.write(file,
|
163
|
+
File.write(file, " * \\x40todo #44 this is a broken unicode: #{0x92.chr}")
|
145
164
|
assert_raises PDD::Error do
|
146
165
|
stub_source_find_github_user(file, 'xx', &:puzzles)
|
147
166
|
end
|
@@ -209,6 +228,7 @@ class TestSource < Minitest::Test
|
|
209
228
|
git add a.txt
|
210
229
|
git commit --quiet -am 'first version'
|
211
230
|
")
|
231
|
+
|
212
232
|
stub_source_find_github_user(File.join(dir, 'a.txt')) do |source|
|
213
233
|
list = source.puzzles
|
214
234
|
assert_equal 1, list.size
|
@@ -237,6 +257,7 @@ class TestSource < Minitest::Test
|
|
237
257
|
git add a.txt
|
238
258
|
git commit --quiet -am 'first version'
|
239
259
|
")
|
260
|
+
|
240
261
|
stub_source_find_github_user(File.join(dir, 'a.txt')) do |source|
|
241
262
|
list = source.puzzles
|
242
263
|
assert_equal 1, list.size
|
@@ -264,6 +285,7 @@ class TestSource < Minitest::Test
|
|
264
285
|
git add a.txt
|
265
286
|
git commit --quiet -am 'first version'
|
266
287
|
")
|
288
|
+
|
267
289
|
stub_source_find_github_user(File.join(dir, 'a.txt')) do |source|
|
268
290
|
list = source.puzzles
|
269
291
|
assert_equal 1, list.size
|
@@ -286,6 +308,7 @@ class TestSource < Minitest::Test
|
|
286
308
|
git commit --quiet -am 'first version'
|
287
309
|
echo '\x40todo #1 this is a puzzle uncommitted' > a.txt
|
288
310
|
")
|
311
|
+
|
289
312
|
stub_source_find_github_user(File.join(dir, 'a.txt')) do |source|
|
290
313
|
list = source.puzzles
|
291
314
|
assert_equal 1, list.size
|
data/test/test_source_todo.rb
CHANGED
@@ -73,6 +73,18 @@ class TestSourceTodo < Minitest::Test
|
|
73
73
|
)
|
74
74
|
end
|
75
75
|
|
76
|
+
def test_todo_utf8_encoded_body
|
77
|
+
check_valid_puzzle(
|
78
|
+
"
|
79
|
+
// TODO #45 Привет, мир, мне кофе
|
80
|
+
// вторая линия
|
81
|
+
",
|
82
|
+
'2-3',
|
83
|
+
'Привет, мир, мне кофе вторая линия',
|
84
|
+
'45'
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
76
88
|
def test_todo_colon_parsing
|
77
89
|
check_valid_puzzle(
|
78
90
|
"
|
data/test/test_sources.rb
CHANGED
@@ -92,14 +92,16 @@ class TestSources < Minitest::Test
|
|
92
92
|
def test_includes_by_pattern
|
93
93
|
in_temp(['a/first.txt', 'b/c/d/second.txt']) do |dir|
|
94
94
|
list = PDD::Sources.new(dir).include('b/c/d/second.txt').fetch
|
95
|
-
assert_equal
|
95
|
+
assert_equal 2, list.size
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
99
|
def test_includes_recursively
|
100
100
|
in_temp(['a/first.txt', 'b/c/second.txt', 'b/c/d/third.txt']) do |dir|
|
101
|
-
|
102
|
-
|
101
|
+
sources = PDD::Sources.new(dir).exclude('b/c/**')
|
102
|
+
sources.include('b/c/d/third.txt')
|
103
|
+
list = sources.fetch
|
104
|
+
assert_equal 2, list.size
|
103
105
|
end
|
104
106
|
end
|
105
107
|
|
data/utils/glob.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Copyright (c) 2014-2021 Yegor Bugayenko
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
# Utility glob class
|
22
|
+
class Glob
|
23
|
+
NO_LEADING_DOT = '(?=[^\.])'.freeze
|
24
|
+
|
25
|
+
def initialize(glob_string)
|
26
|
+
@glob_string = glob_string
|
27
|
+
end
|
28
|
+
|
29
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
30
|
+
# rubocop:disable Metrics/MethodLength
|
31
|
+
def to_regexp
|
32
|
+
chars = @glob_string.gsub(%r{(\*\*\/\*)|(\*\*)}, '*').split('')
|
33
|
+
in_curlies = 0, escaping = false
|
34
|
+
chars.map do |char|
|
35
|
+
if escaping
|
36
|
+
escaping = false
|
37
|
+
return char
|
38
|
+
end
|
39
|
+
case char
|
40
|
+
when '*'
|
41
|
+
'.*'
|
42
|
+
when '?'
|
43
|
+
'.'
|
44
|
+
when '.'
|
45
|
+
'\\.'
|
46
|
+
when '{'
|
47
|
+
in_curlies += 1
|
48
|
+
'('
|
49
|
+
when '}'
|
50
|
+
if in_curlies.positive?
|
51
|
+
in_curlies -= 1
|
52
|
+
return ')'
|
53
|
+
end
|
54
|
+
return char
|
55
|
+
when ','
|
56
|
+
in_curlies.positive? ? '|' : char
|
57
|
+
when '\\'
|
58
|
+
escaping = true
|
59
|
+
'\\'
|
60
|
+
else
|
61
|
+
char
|
62
|
+
end
|
63
|
+
end.join
|
64
|
+
end
|
65
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
66
|
+
# rubocop:enable Metrics/MethodLength
|
67
|
+
end
|
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.20.
|
4
|
+
version: 0.20.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -178,6 +178,20 @@ dependencies:
|
|
178
178
|
- - '='
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: 1.15.1
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: slop
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - '='
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: 4.9.1
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - '='
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: 4.9.1
|
181
195
|
- !ruby/object:Gem::Dependency
|
182
196
|
name: xcop
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -206,6 +220,7 @@ files:
|
|
206
220
|
- ".github/ISSUE_TEMPLATE.md"
|
207
221
|
- ".github/PULL_REQUEST_TEMPLATE.md"
|
208
222
|
- ".gitignore"
|
223
|
+
- ".overcommit.yml"
|
209
224
|
- ".pdd"
|
210
225
|
- ".rubocop.yml"
|
211
226
|
- ".rultor.yml"
|
@@ -258,6 +273,7 @@ files:
|
|
258
273
|
- test_assets/cambria.woff
|
259
274
|
- test_assets/elegant-objects.png
|
260
275
|
- test_assets/favicon.ico
|
276
|
+
- utils/glob.rb
|
261
277
|
homepage: http://github.com/cqfn/pdd
|
262
278
|
licenses:
|
263
279
|
- MIT
|
@@ -269,7 +285,7 @@ require_paths:
|
|
269
285
|
- lib
|
270
286
|
required_ruby_version: !ruby/object:Gem::Requirement
|
271
287
|
requirements:
|
272
|
-
- - "
|
288
|
+
- - "~>"
|
273
289
|
- !ruby/object:Gem::Version
|
274
290
|
version: '2.3'
|
275
291
|
required_rubygems_version: !ruby/object:Gem::Requirement
|