pdd 0.23.2 → 0.24.1

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.0pdd.yml +3 -0
  3. data/.github/workflows/actionlint.yml +25 -0
  4. data/.github/workflows/codecov.yml +18 -9
  5. data/.github/workflows/copyrights.yml +19 -0
  6. data/.github/workflows/markdown-lint.yml +19 -0
  7. data/.github/workflows/pdd.yml +8 -4
  8. data/.github/workflows/rake.yml +13 -8
  9. data/.github/workflows/reuse.yml +19 -0
  10. data/.github/workflows/typos.yml +19 -0
  11. data/.github/workflows/xcop.yml +6 -2
  12. data/.github/workflows/yamllint.yml +19 -0
  13. data/.gitignore +12 -5
  14. data/.markdownlint.yml +6 -0
  15. data/.pdd +1 -1
  16. data/.rubocop.yml +12 -2
  17. data/.rultor.yml +7 -2
  18. data/.simplecov +16 -36
  19. data/Gemfile +16 -30
  20. data/Gemfile.lock +173 -0
  21. data/LICENSE.txt +1 -1
  22. data/LICENSES/MIT.txt +21 -0
  23. data/README.md +152 -57
  24. data/REUSE.toml +43 -0
  25. data/Rakefile +7 -31
  26. data/assets/puzzles.xsd +3 -22
  27. data/assets/puzzles.xsl +3 -22
  28. data/assets/puzzles_json.xsl +60 -0
  29. data/bin/pdd +17 -24
  30. data/cucumber.yml +4 -0
  31. data/features/applies_rules.feature +2 -0
  32. data/features/avoiding_duplicates.feature +2 -0
  33. data/features/catches_broken_puzzles.feature +2 -0
  34. data/features/cli.feature +48 -5
  35. data/features/gem_package.feature +2 -0
  36. data/features/html_output.feature +2 -0
  37. data/features/json_output.feature +24 -0
  38. data/features/parsing.feature +2 -0
  39. data/features/rake.feature +2 -2
  40. data/features/remove.feature +2 -0
  41. data/features/step_definitions/steps.rb +11 -20
  42. data/features/support/env.rb +2 -19
  43. data/features/unicode.feature +2 -0
  44. data/features/uses_config.feature +2 -1
  45. data/lib/pdd/puzzle.rb +2 -19
  46. data/lib/pdd/rake_task.rb +3 -0
  47. data/lib/pdd/rule/duplicates.rb +2 -19
  48. data/lib/pdd/rule/estimates.rb +2 -19
  49. data/lib/pdd/rule/roles.rb +2 -19
  50. data/lib/pdd/rule/text.rb +2 -19
  51. data/lib/pdd/source.rb +34 -35
  52. data/lib/pdd/sources.rb +2 -19
  53. data/lib/pdd/version.rb +4 -21
  54. data/lib/pdd.rb +3 -20
  55. data/pdd.gemspec +8 -24
  56. data/test/test__helper.rb +24 -20
  57. data/test/test_duplicates.rb +5 -22
  58. data/test/test_estimates.rb +5 -22
  59. data/test/test_many.rb +3 -20
  60. data/test/test_pdd.rb +4 -21
  61. data/test/test_rake_task.rb +3 -0
  62. data/test/test_roles.rb +6 -23
  63. data/test/test_source.rb +17 -34
  64. data/test/test_source_todo.rb +121 -20
  65. data/test/test_sources.rb +4 -21
  66. data/test/test_text.rb +4 -21
  67. data/test_assets/aladdin.jpg +0 -0
  68. data/test_assets/elegant-objects.png +0 -0
  69. data/test_assets/puzzles/1-04e35eb3 +1 -1
  70. data/test_assets/puzzles/132-bc1dfafe +1 -1
  71. data/test_assets/puzzles/1425-59819ae3 +5 -5
  72. data/test_assets/puzzles/42-0d933cc0 +1 -1
  73. data/test_assets/puzzles/44-660e9d6f +2 -2
  74. data/test_assets/puzzles/91-ecb9aa47 +1 -1
  75. data/test_assets/puzzles/93-641fe341 +1 -1
  76. data/utils/glob.rb +2 -19
  77. metadata +33 -11
  78. data/.overcommit.yml +0 -96
data/README.md CHANGED
@@ -1,74 +1,107 @@
1
- <img alt="pdd logo" src="https://avatars2.githubusercontent.com/u/24456188" width="92px" height="92px"/>
1
+ # Collector of TODO Puzzles in Source Code
2
2
 
3
3
  [![EO principles respected here](https://www.elegantobjects.org/badge.svg)](https://www.elegantobjects.org)
4
- [![DevOps By Rultor.com](http://www.rultor.com/b/cqfn/pdd)](http://www.rultor.com/p/cqfn/pdd)
4
+ [![DevOps By Rultor.com](https://www.rultor.com/b/cqfn/pdd)](https://www.rultor.com/p/cqfn/pdd)
5
5
  [![We recommend RubyMine](https://www.elegantobjects.org/rubymine.svg)](https://www.jetbrains.com/ruby/)
6
6
 
7
7
  [![rake](https://github.com/cqfn/pdd/actions/workflows/rake.yml/badge.svg)](https://github.com/cqfn/pdd/actions/workflows/rake.yml)
8
- [![PDD status](http://www.0pdd.com/svg?name=cqfn/pdd)](http://www.0pdd.com/p?name=cqfn/pdd)
9
- [![codecov](https://codecov.io/gh/cqfn/pdd/branch/master/graph/badge.svg)](https://codecov.io/gh/cqfn/pdd)
10
- ![Lines of code](https://img.shields.io/tokei/lines/github/cqfn/pdd)
8
+ [![PDD status](https://www.0pdd.com/svg?name=cqfn/pdd)](https://www.0pdd.com/p?name=cqfn/pdd)
9
+ [![codecov](https://codecov.io/gh/yegor256/pdd/branch/master/graph/badge.svg)](https://codecov.io/gh/yegor/pdd)
11
10
  [![Hits-of-Code](https://hitsofcode.com/github/cqfn/pdd)](https://hitsofcode.com/view/github/cqfn/pdd)
12
11
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/cqfn/pdd/blob/master/LICENSE.txt)
13
- [![Gem Version](https://badge.fury.io/rb/pdd.svg)](http://badge.fury.io/rb/pdd)
12
+ [![Gem Version](https://badge.fury.io/rb/pdd.svg)](https://badge.fury.io/rb/pdd)
14
13
  [![Maintainability](https://api.codeclimate.com/v1/badges/c8e46256fdd8ddc817e5/maintainability)](https://codeclimate.com/github/cqfn/pdd/maintainability)
15
- [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/cqfn/pdd/master/frames)
14
+ [![Yard Docs](https://img.shields.io/badge/yard-docs-blue.svg)](https://rubydoc.info/github/cqfn/pdd/master/frames)
16
15
  [![Codacy Badge](https://app.codacy.com/project/badge/Grade/1792d42f96fb45448e8d495ebc4348aa)](https://www.codacy.com/gh/cqfn/pdd/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=cqfn/pdd&amp;utm_campaign=Badge_Grade)
17
16
 
18
17
  Read this article about
19
18
  [_Puzzle Driven Development_](http://www.yegor256.com/2009/03/04/pdd.html).
20
- Check also patent application [US 12/840,306](http://www.google.com/patents/US20120023476)
19
+ Check also patent application
20
+ [US 12/840,306](http://www.google.com/patents/US20120023476)
21
21
 
22
- Also, check [0pdd.com](http://www.0pdd.com): a hosted service,
22
+ Also, check [0pdd.com](https://www.0pdd.com): a hosted service,
23
23
  where this command line tool works for you.
24
24
 
25
25
  Read
26
26
  [_PDD in Action_](http://www.yegor256.com/2017/04/05/pdd-in-action.html)
27
27
  and watch [this webinar](https://www.youtube.com/watch?v=nsYGC2aUwfQ).
28
28
 
29
- You should have [Ruby installed](https://www.ruby-lang.org/en/documentation/installation/).
30
- Then, install our gem:
29
+ First, make sure Ruby 2.6+ and [`libmagic`](#how-to-install-libmagic)
30
+ are installed. Then, install our gem:
31
31
 
32
32
  ```bash
33
- $ gem install pdd
33
+ gem install pdd
34
34
  ```
35
35
 
36
36
  Run it locally and read its output:
37
37
 
38
38
  ```bash
39
- $ pdd --help
39
+ pdd --help
40
40
  ```
41
41
 
42
- You can exclude & include certain number of files from the search via these options:
42
+ ## Usage
43
43
 
44
- ```
45
- $ pdd --exclude=glob
44
+ You can exclude & include certain number of files from the search
45
+ via these options:
46
+
47
+ ```bash
48
+ pdd --exclude glob
46
49
  ```
47
50
 
48
- You can skip any file(s) with a name suffix that matches the pattern glob, using wildcard matching;
49
- a name suffix is either the whole path and name, or reg expr, for example:
51
+ You can skip any file(s) with a name suffix that matches the pattern glob,
52
+ using wildcard matching; a name suffix is either the whole
53
+ path and name, or reg expr, for example:
50
54
 
51
55
  ```bash
52
- $ pdd --exclude=src/**/*.java --exclude=target/**/*
53
- $ pdd --exclude=src/**/*.java # exclude .java files in src/
54
- $ pdd --exclude=src/**/* # exclude all files in src/
56
+ pdd --exclude src/**/*.java --exclude target/**/*
57
+ pdd --exclude src/**/*.java # exclude .java files in src/
58
+ pdd --exclude src/**/* # exclude all files in src/
55
59
  ```
56
60
 
57
61
  You can include too:
58
62
 
63
+ ```bash
64
+ pdd --include glob
59
65
  ```
60
- $ pdd --include=glob
66
+
67
+ Search only files whose name matches glob, using wildcard matching
68
+ as described under ``--exclude``.
69
+ If contradictory ``--include`` and ``--exclude`` options are given,
70
+ the last matching one wins.
71
+ If no ``--include`` or ``--exclude`` options are given, all files
72
+ from the working directory are included, example:
73
+
74
+ ```bash
75
+ pdd --include src/**/*.py # include only .py files in src/
76
+ pdd --include src/**/* # include all files in src/
61
77
  ```
62
78
 
63
- Search only files whose name matches glob, using wildcard matching as described under ``--exclude``.
64
- If contradictory ``--include`` and ``--exclude`` options are given, the last matching one wins.
65
- If no ``--include`` or ``--exclude`` options are given, all files from working directory are included, example:
79
+ Full command format is (all parameters are optional):
66
80
 
67
81
  ```bash
68
- $ pdd --include=src/**/*.py # include only .py files in src/
69
- $ pdd --include=src/**/* # include all files in src/
82
+ pdd [--verbose] [--quiet] [--remove] [--skip-gitignore] [--skip-errors] \
83
+ [--source <project_dir_path>] [--file puzzles_file.xml] \
84
+ [--include src/**/*.py] \
85
+ [--format xml|html] [--rule min-words:5] [--exclude src/**/*.java]
70
86
  ```
71
87
 
88
+ | Parameter | Description |
89
+ |-------------------------|---------------------------------------------------------------------------------------|
90
+ | --verbose | Enable verbose (debug) mode. --file must be used in case of using this option |
91
+ | --quiet | Disable logs |
92
+ | --remove | Remove all found puzzles from the source code |
93
+ | --skip-gitignore | Don't look into .gitignore for excludes |
94
+ | --skip-errors | Suppress error as warning and skip badly formatted puzzles (do not skip broken rules) |
95
+ | --source project-path | Source directory to parse ("." by default) |
96
+ | --file puzzles.xml | File to save report into (xml or html) (displayed in console by default) |
97
+ | --include *.py | Glob pattern to include (can be used several times) |
98
+ | --exclude *.java | Glob pattern to exclude (can be used several times) |
99
+ | --format xml | Format of the report xml or html (xml is default) |
100
+ | --rule min-words:5 | Rule to apply (can be used several times), described later |
101
+
102
+ :bulb: There is an option to create a .pdd file in your project and save all required parameters in it.
103
+ You can see a file example in this project.
104
+
72
105
  ## How to Format?
73
106
 
74
107
  Every puzzle has to be formatted like this (pay attention
@@ -81,9 +114,9 @@ to the leading space in every consecutive line):
81
114
  [related code]
82
115
  ```
83
116
 
84
- `[]` - Replace with apropriate data (see text enclosed in brackets)
117
+ `[]` - Replace with appropriate data (see text enclosed in brackets)
85
118
 
86
- `<>` - Omitable (enclosed data can be left out)
119
+ `<>` - Optional (enclosed data can be left out)
87
120
 
88
121
  Example:
89
122
 
@@ -92,13 +125,17 @@ Example:
92
125
  * @todo #234:15m/DEV This is something to do later
93
126
  * in one of the next releases. I can't figure out
94
127
  * how to implement it now, that's why the puzzle.
128
+ * The text can be so long, as needed, just use
129
+ * the same amount of spaces, as the second line.
130
+ * This text will not be a part of the puzzle, as
131
+ * it has less spaces.
95
132
  */
96
133
  void sendEmail() {
97
134
  throw new UnsupportedOperationException();
98
135
  }
99
136
  ```
100
137
 
101
- If you use it in combination with [0pdd](http://www.0pdd.com),
138
+ If you use it in combination with [0pdd](https://www.0pdd.com),
102
139
  after processing this text, the issue titled
103
140
  "File.java:10-13: This is something to do later in one of ..." will be created.
104
141
  The specified markers will be included in the issues body
@@ -112,39 +149,75 @@ There are 3 supported keywords, one of which must precede the mandatory
112
149
  puzzle marker. They are `@todo`, `TODO` and `TODO:`.
113
150
 
114
151
  As an example, it starts with `@todo`, followed by a space and a mandatory
115
- puzzle **marker**. Possible formats of puzzle markers (it doesn't matter what the
116
- line starts with and where it is located,
152
+ puzzle **marker**. Possible formats of puzzle markers
153
+ (it doesn't matter what the line starts with and where it is located,
117
154
  as long as you have one of the 3 supported keywords right in front
118
155
  of the mandatory marker):
119
156
 
120
- ```
121
- // @todo #224
122
- /* @todo #TEST-13 */
123
- # @todo #55:45min
124
- @todo #67/DES
125
- ;; @todo #678:40m/DEV
126
- // TODO: #1:30min
127
- (* TODO #42 *)
157
+ ```text
158
+ // @todo #224 Puzzle description
159
+ # @todo #55:45min Puzzle description
160
+ @todo #67/DES Puzzle description
161
+ ;; @todo #678:40m/DEV Puzzle description
162
+ // TODO #TEST-21:30min Puzzle description
128
163
  ```
129
164
 
130
- Here `DES` and `DEV` are the roles of people who must fix that puzzles;
165
+ Here `DES` and `DEV` are the roles of people who must fix these puzzles;
131
166
  `45min` and `40m` is the amount of time the puzzle should take;
132
- `224`, `TEST-13`, `55`, `67`, `678`, `1`, and `42` are the IDs of the tickets
167
+ `224`, `55`, `67`, `678` and `TEST-21` are the IDs of the tickets
133
168
  these puzzles are coming from.
134
169
 
135
170
  Markers are absolutely necessary for all puzzles, because they allow
136
171
  us to build a hierarchical dependency tree of all puzzles, like
137
- [this one](http://www.0pdd.com/p?name=yegor256/takes),
172
+ [this one](https://www.0pdd.com/p?name=yegor256/takes),
138
173
  for example. Technically, of course, you can abuse the system
139
174
  and put a dummy `#1` marker everywhere.
140
175
 
176
+ ### Multiline examples
177
+
178
+ For multiline puzzles there are two important things:
179
+
180
+ - **prefix** - any optional text followed by space before puzzle keyword (todo).
181
+ It should be the same for all lines of puzzle description.
182
+ - \ symbol can be used to logically divide puzzle description.
183
+ prefix should be presented with it.
184
+
185
+ Examples:
186
+
187
+ ```xml
188
+ <!--
189
+ ~ if comments should be started and closed by special symbols, then place them in
190
+ ~ a separate lines
191
+ ~ Any symbol can be used as a prefix, it will be excluded from the text.
192
+ ~ But do not forget about the space before puzzle keyword.
193
+ ~
194
+ ~ @todo #34 Description can be as long as needed.
195
+ ~ Just use at least the same amount of the spaces, as on the first line.
196
+ ~ It will be added to description.
197
+ -->
198
+ ```
199
+
200
+ ```java
201
+ /**
202
+ * @todo #36 Multiline text can use the same prefix in all lines or the same
203
+ * amount of spaces.
204
+ * So this will be added to the puzzle description. If you want to divide the
205
+ * puzzle logically by empty line, just add a backspace to that line
206
+ * \
207
+ * and continue the text after.
208
+ *
209
+ * This line is not part of the puzzle, because the line before does not contain
210
+ * prefix.
211
+ */
212
+ ```
213
+
141
214
  ## How to Configure Rules?
142
215
 
143
216
  You can specify post-parsing rules for your puzzles, in command line,
144
217
  for example:
145
218
 
146
- ```
147
- $ pdd --rule=min-estimate:60 --rule=max-estimate:120
219
+ ```bash
220
+ pdd --rule min-estimate:60 --rule max-estimate:120
148
221
  ```
149
222
 
150
223
  These two parameters will add two post-parsing rules `min-estimate`
@@ -168,14 +241,15 @@ Here is a list of rules available now:
168
241
  This rule is used by default and you can't configure it at the moment,
169
242
  it must always be set to `1`.
170
243
 
171
- You can put all command line options into `.pdd` file. The options from the
244
+ :bulb: You can put all command line options into `.pdd` file. The options from the
172
245
  file will be used first. Command line options may be added on top of them.
173
- See, how it is done in [yegor256/0pdd](https://github.com/yegor256/0pdd/blob/master/.pdd).
246
+ See, how it is done in
247
+ [yegor256/0pdd](https://github.com/yegor256/0pdd/blob/master/.pdd).
174
248
 
175
249
  ## How to read XML
176
250
 
177
251
  The XML produced will look approximately like this (here is a
178
- [real example](http://www.0pdd.com/snapshot?name=yegor256/takes)):
252
+ [real example](https://www.0pdd.com/snapshot?name=yegor256/takes)):
179
253
 
180
254
  ```xml
181
255
  <puzzles>
@@ -193,6 +267,7 @@ The XML produced will look approximately like this (here is a
193
267
  </puzzle>
194
268
  </puzzles>
195
269
  ```
270
+
196
271
  NOTE: puzzles are saved with utf-8 encoding
197
272
 
198
273
  [XSD Schema](http://pdd-xsd.teamed.io/0.19.4.xsd) is here.
@@ -211,22 +286,42 @@ The most interesting parts of each puzzle are:
211
286
 
212
287
  - `lines` is where the puzzle is found, inside the file.
213
288
 
289
+ ## How to install libmagic
290
+
291
+ For Debian/Ubuntu:
292
+
293
+ ```bash
294
+ apt install libmagic-dev
295
+ ```
296
+
297
+ For macOS:
298
+
299
+ ```bash
300
+ brew install libmagic
301
+ ```
302
+
303
+ Unfortunately, there is no easy way to install on Windows, try to use
304
+ [WSL](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux) or
305
+ [Docker](https://www.docker.com/).
306
+
214
307
  ## How to contribute
215
308
 
216
309
  Read [these guidelines](https://www.yegor256.com/2014/04/15/github-guidelines.html).
217
310
  Make sure your build is green before you contribute
218
- your pull request. You will need to have [Ruby](https://www.ruby-lang.org/en/) 2.3+ and
311
+ your pull request. You will need to have
312
+ [Ruby](https://www.ruby-lang.org/en/) 2.7+ and
219
313
  [Bundler](https://bundler.io/) installed. Then:
220
314
 
221
- ```
222
- $ bundle install
223
- $ bundle exec rake
315
+ ```bash
316
+ bundle install
317
+ bundle exec rake
224
318
  ```
225
319
 
226
320
  Next, install and run overcommit to install hooks (required once)
227
- ```
228
- $ gem install overcommit -v '=0.58.0'
229
- $ overcommit --install
321
+
322
+ ```bash
323
+ gem install overcommit -v '=0.58.0'
324
+ overcommit --install
230
325
  ```
231
326
 
232
327
  If it's clean and you don't see any error messages, submit your pull request.
@@ -234,11 +329,11 @@ If it's clean and you don't see any error messages, submit your pull request.
234
329
  This is how you run the tool locally to test how it works:
235
330
 
236
331
  ```bash
237
- $ ./bin/pdd --help
332
+ ./bin/pdd --help
238
333
  ```
239
334
 
240
335
  To run a single unit test:
241
336
 
242
337
  ```bash
243
- $ bundle exec ruby test/test_many.rb
338
+ bundle exec ruby test/test_many.rb
244
339
  ```
data/REUSE.toml ADDED
@@ -0,0 +1,43 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ version = 1
5
+ [[annotations]]
6
+ path = [
7
+ ".DS_Store",
8
+ ".gitattributes",
9
+ ".gitignore",
10
+ ".overcommit.yml",
11
+ ".pdd",
12
+ "**.ico",
13
+ "**.jpg",
14
+ "**.json",
15
+ "**.md",
16
+ "**.pdf",
17
+ "**.png",
18
+ "**.txt",
19
+ "**.woff",
20
+ "**/.DS_Store",
21
+ "**/.gitignore",
22
+ "**/.pdd",
23
+ "**/*.csv",
24
+ "**/*.jpg",
25
+ "**/*.json",
26
+ "**/*.md",
27
+ "**/*.pdf",
28
+ "**/*.png",
29
+ "**/*.svg",
30
+ "**/*.txt",
31
+ "**/*.vm",
32
+ "**/CITATION.cff",
33
+ "**/CNAME",
34
+ "**/Gemfile.lock",
35
+ "CITATION.cff",
36
+ "Gemfile.lock",
37
+ "README.md",
38
+ "renovate.json",
39
+ "test_assets/puzzles/**",
40
+ ]
41
+ precedence = "override"
42
+ SPDX-FileCopyrightText = "Copyright (c) 2025 Yegor Bugayenko"
43
+ SPDX-License-Identifier = "MIT"
data/Rakefile CHANGED
@@ -1,22 +1,5 @@
1
- # Copyright (c) 2014-2023 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 NONINFRINGEMENT. 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.
1
+ # SPDX-FileCopyrightText: Copyright (c) 2014-2025 Yegor Bugayenko
2
+ # SPDX-License-Identifier: MIT
20
3
 
21
4
  require 'rubygems'
22
5
  require 'rake'
@@ -31,7 +14,7 @@ def version
31
14
  Gem::Specification.load(Dir['*.gemspec'].first).version
32
15
  end
33
16
 
34
- task default: %i[clean test features rubocop xcop copyright]
17
+ task default: %i[clean test features rubocop xcop]
35
18
 
36
19
  require 'rake/testtask'
37
20
  desc 'Run all unit tests'
@@ -55,15 +38,13 @@ require 'rubocop/rake_task'
55
38
  desc 'Run RuboCop on all directories'
56
39
  RuboCop::RakeTask.new(:rubocop) do |task|
57
40
  task.fail_on_error = true
58
- task.requires << 'rubocop-rspec'
59
41
  end
60
42
 
61
43
  require 'xcop/rake_task'
62
44
  desc 'Validate all XML/XSL/XSD/HTML files for formatting'
63
45
  Xcop::RakeTask.new :xcop do |task|
64
- task.license = 'LICENSE.txt'
65
46
  task.includes = ['**/*.xml', '**/*.xsl', '**/*.xsd', '**/*.html']
66
- task.excludes = ['target/**/*', 'coverage/**/*']
47
+ task.excludes = ['target/**/*', 'coverage/**/*', 'vendor/**/*']
67
48
  end
68
49
 
69
50
  require 'pdd/rake_task'
@@ -74,17 +55,12 @@ end
74
55
 
75
56
  require 'cucumber/rake/task'
76
57
  Cucumber::Rake::Task.new(:features) do |t|
77
- t.cucumber_opts = 'features'
58
+ t.cucumber_opts = %w[features --strict-undefined]
78
59
  Rake::Cleaner.cleanup_files(['coverage'])
79
60
  end
80
61
  Cucumber::Rake::Task.new(:'features:html') do |t|
81
62
  t.profile = 'html_report'
82
63
  end
83
-
84
- task :copyright do
85
- sh "grep -q -r '2014-#{Date.today.strftime('%Y')}' \
86
- --include '*.rb' \
87
- --include '*.txt' \
88
- --include 'Rakefile' \
89
- ."
64
+ Cucumber::Rake::Task.new(:'features:json') do |t|
65
+ t.profile = 'json_report'
90
66
  end
data/assets/puzzles.xsd CHANGED
@@ -1,26 +1,7 @@
1
- <?xml version="1.0"?>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
2
  <!--
3
- (The MIT License)
4
-
5
- Copyright (c) 2014-2023 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.
3
+ * SPDX-FileCopyrightText: Copyright (c) 2014-2025 Yegor Bugayenko
4
+ * SPDX-License-Identifier: MIT
24
5
  -->
25
6
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
26
7
  <xs:complexType name="puzzle">
data/assets/puzzles.xsl CHANGED
@@ -1,26 +1,7 @@
1
- <?xml version="1.0"?>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
2
  <!--
3
- (The MIT License)
4
-
5
- Copyright (c) 2014-2023 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.
3
+ * SPDX-FileCopyrightText: Copyright (c) 2014-2025 Yegor Bugayenko
4
+ * SPDX-License-Identifier: MIT
24
5
  -->
25
6
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="1.0">
26
7
  <xsl:template match="/">
@@ -0,0 +1,60 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ * SPDX-FileCopyrightText: Copyright (c) 2014-2025 Yegor Bugayenko
4
+ * SPDX-License-Identifier: MIT
5
+ -->
6
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
7
+ <xsl:output method="text" omit-xml-declaration="yes"/>
8
+ <xsl:template match="/"><xsl:text disable-output-escaping="yes">{</xsl:text><xsl:apply-templates select="puzzles"/>
9
+ "puzzles": [
10
+ <xsl:apply-templates select="puzzles/puzzle"/>
11
+ <xsl:text disable-output-escaping="yes">
12
+ ]
13
+ }</xsl:text>
14
+ </xsl:template>
15
+ <xsl:template match="puzzles">
16
+ <xsl:text>
17
+ "version": "</xsl:text>
18
+ <xsl:value-of select="@version"/>
19
+ <xsl:text>",</xsl:text>
20
+ <xsl:text>
21
+ "date": "</xsl:text>
22
+ <xsl:value-of select="@date"/>
23
+ <xsl:text>", </xsl:text>
24
+ </xsl:template>
25
+ <xsl:template match="puzzle">
26
+ <xsl:text disable-output-escaping="no">{</xsl:text>
27
+ <xsl:text>
28
+ "id": "</xsl:text>
29
+ <xsl:value-of select="id"/>
30
+ <xsl:text>", </xsl:text>
31
+ <xsl:text>
32
+ "ticket": "</xsl:text>
33
+ <xsl:value-of select="ticket"/>
34
+ <xsl:text>", </xsl:text>
35
+ <xsl:text>
36
+ "file": "</xsl:text>
37
+ <xsl:value-of select="file"/>
38
+ <xsl:text>", </xsl:text>
39
+ <xsl:text>
40
+ "lines": "</xsl:text>
41
+ <xsl:value-of select="lines"/>
42
+ <xsl:text>", </xsl:text>
43
+ <xsl:text>
44
+ "body": "</xsl:text>
45
+ <xsl:value-of select="translate(body, '&quot;', '“')"/>
46
+ <xsl:text>", </xsl:text>
47
+ <xsl:text>
48
+ "estimate": "</xsl:text>
49
+ <xsl:value-of select="estimate"/>
50
+ <xsl:text>", </xsl:text>
51
+ <xsl:text>
52
+ "role": "</xsl:text>
53
+ <xsl:value-of select="role"/>
54
+ <xsl:text>"</xsl:text>
55
+ <xsl:text disable-output-escaping="yes">
56
+ }</xsl:text>
57
+ <xsl:if test="position() != last()">,
58
+ </xsl:if>
59
+ </xsl:template>
60
+ </xsl:stylesheet>
data/bin/pdd CHANGED
@@ -1,26 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
- # Copyright (c) 2014-2023 Yegor Bugayenko
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy
5
- # of this software and associated documentation files (the 'Software'), to deal
6
- # in the Software without restriction, including without limitation the rights
7
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- # copies of the Software, and to permit persons to whom the Software is
9
- # furnished to do so, subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in all
12
- # copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
17
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
- # SOFTWARE.
2
+ # SPDX-FileCopyrightText: Copyright (c) 2014-2025 Yegor Bugayenko
3
+ # SPDX-License-Identifier: MIT
21
4
 
22
5
  $stdout.sync = true
23
6
 
7
+ require 'backtrace'
24
8
  require 'shellwords'
25
9
  require 'English'
26
10
  require 'find'
@@ -59,12 +43,12 @@ begin
59
43
  exit
60
44
  end
61
45
  o.string '-s', '--source', 'Source directory to parse ("." by default)'
62
- o.string '-f', '--file', 'File to save XML into'
46
+ o.string '-f', '--file', 'File to save report into'
63
47
  o.array '-e', '--exclude', 'Glob pattern to exclude, e.g. "**/*.jpg"',
64
48
  default: []
65
49
  o.array '-n', '--include', 'Glob pattern to include, e.g. "**/*.jpg"',
66
50
  default: []
67
- o.string '-t', '--format', 'Format of the report (xml|html)'
51
+ o.string '-t', '--format', 'Format of the report (xml|html|json)'
68
52
  o.array(
69
53
  '-r', '--rule', 'Rule to apply (can be used many times)',
70
54
  delimiter: ';'
@@ -87,7 +71,8 @@ https://github.com/cqfn/pdd/blob/master/README.md"
87
71
 
88
72
  if opts['skip-gitignore'] && File.exist?('.gitignore')
89
73
  cfg = File.new('.gitignore')
90
- body = File.read(cfg)
74
+ body = ''
75
+ File.foreach(cfg) { |line| body << line unless line.start_with?('#') }
91
76
  extra = body.split(/\s+/).map(&:strip)
92
77
  opts['skip-gitignore'] = extra
93
78
  PDD.log.info "Found #{body.split("\n").length} lines in #{File.absolute_path(cfg)}"
@@ -105,8 +90,15 @@ https://github.com/cqfn/pdd/blob/master/README.md"
105
90
  'assets', 'puzzles.xsl'
106
91
  )
107
92
  output = Nokogiri::XSLT(File.read(xslt)).transform(Nokogiri::XML(xml))
93
+ elsif opts[:format] == 'json'
94
+ xslt = File.join(
95
+ File.dirname(File.dirname(__FILE__)),
96
+ 'assets', 'puzzles_json.xsl'
97
+ )
98
+ # result is not xml, so use apply
99
+ output = Nokogiri::XSLT(File.read(xslt)).apply_to(Nokogiri::XML(xml))
108
100
  elsif opts[:format] != 'xml'
109
- raise 'Invalid format, use html or xml'
101
+ raise 'Invalid format, use html or xml or json'
110
102
  end
111
103
  end
112
104
  file << output
@@ -124,7 +116,7 @@ https://github.com/cqfn/pdd/blob/master/README.md"
124
116
  File.write(
125
117
  f,
126
118
  File.readlines(f).reject.each_with_index do |_t, i|
127
- all.any? { |pair| i + 1 >= pair[0] && i + 1 <= pair[1] }
119
+ all.any? { |pair| i + (1.between?(pair[0], pair[1]) ? 1 : 0) }
128
120
  end.join
129
121
  )
130
122
  PDD.log.info "#{all.count} puzzles removed from #{src}"
@@ -145,6 +137,7 @@ more documentation: https://github.com/cqfn/pdd/blob/master/README.md."
145
137
  exit(1)
146
138
  rescue StandardError => e
147
139
  PDD.log.error "#{Rainbow('ERROR').red} (#{e.class.name}): #{e.message}"
140
+ PDD.log.error Backtrace.new(e).to_s
148
141
  PDD.log.info 'Exit code is 255'
149
142
  exit(255)
150
143
  end