pdd 0.20.7 → 0.20.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|