rubocop-rspec-extra 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +14 -2
- data/README.md +1 -1
- data/config/default.yml +3 -3
- data/docs/antora.yml +1 -1
- data/docs/modules/ROOT/pages/cops_rspec_extra.adoc +10 -4
- data/lib/rubocop/cop/rspec/extra/restrict_block_tag.rb +3 -2
- data/lib/rubocop/cop/rspec/extra/restrict_block_tag_value.rb +4 -2
- data/lib/rubocop/rspec/extra/version.rb +1 -1
- data/tasks/cut_release.rake +1 -1
- metadata +5 -8
- data/tasks/changelog.rake +0 -35
- data/tasks/changelog.rb +0 -193
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 15b0c1d5b0b7c30874b0c8f567006e6ae733d4ad096eaa885b9397feed61de69
|
|
4
|
+
data.tar.gz: 47e774fa8976ee7a0d8f3b348224d2ccb95bc529334880aa1bd6a71f02e941a2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 53973d3db669c54dcdcee88596381906a407d33d63eec4c1536c361f118b59de9a3f8bc90a4984462cd6507af0c9bb080cfd59de20724341c6e3fff7969a2609
|
|
7
|
+
data.tar.gz: ed2a3474c9676133f943bab5170cc0f0b20a1f5b5f06e8d6f6ba60e8aea78b721838e8df9ff2e8a4d85bc06902489e543e50d2a46d886421727d347fff2bb04a
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Master (Unreleased)
|
|
4
|
+
|
|
5
|
+
## 0.2.0 (2024-03-01)
|
|
6
|
+
|
|
7
|
+
- Fix an error for `RSpec/Extra/RestrictBlockTag`. ([@ydah])
|
|
8
|
+
- Fix an error for `RSpec/Extra/RestrictBlockTagValue`. ([@ydah])
|
|
9
|
+
- Drop Ruby 2.6 support. ([@ydah])
|
|
10
|
+
|
|
11
|
+
## 0.1.0 (2023-04-18)
|
|
4
12
|
|
|
5
13
|
- Initial release
|
|
14
|
+
|
|
15
|
+
<!-- Contributors (alphabetically) -->
|
|
16
|
+
|
|
17
|
+
[@ydah]: https://github.com/ydah
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Rubocop::Rspec::Extra
|
|
2
2
|
|
|
3
|
-
   [](https://github.com/ydah/rubocop-rspec-extra/actions/workflows/ci.yml) [](https://codeclimate.com/github/ydah/rubocop-rspec-extra/maintainability)
|
|
3
|
+
  [](https://badge.fury.io/rb/rubocop-rspec-extra)  [](https://github.com/ydah/rubocop-rspec-extra/actions/workflows/ci.yml) [](https://codeclimate.com/github/ydah/rubocop-rspec-extra/maintainability)
|
|
4
4
|
|
|
5
5
|
A [RuboCop](https://github.com/rubocop/rubocop) extension focused on enforcing RSpec. A place where no one is officially employed, but where useful cops can gather.
|
|
6
6
|
|
data/config/default.yml
CHANGED
|
@@ -5,17 +5,17 @@ RSpec/Extra:
|
|
|
5
5
|
RSpec/Extra/BeEmpty:
|
|
6
6
|
Description: Prefer using `be_empty` when checking for an empty array.
|
|
7
7
|
Enabled: pending
|
|
8
|
-
VersionAdded: '
|
|
8
|
+
VersionAdded: '0.1'
|
|
9
9
|
Reference: https://www.rubydoc.info/gems/rubocop-rspec-extra/RuboCop/Cop/RSpec/Extra/BeEmpty
|
|
10
10
|
|
|
11
11
|
RSpec/Extra/RestrictBlockTag:
|
|
12
12
|
Description: 'Restrict to only allowed block tags.'
|
|
13
13
|
Enabled: false
|
|
14
|
-
VersionAdded: '
|
|
14
|
+
VersionAdded: '0.1'
|
|
15
15
|
AllowTags: []
|
|
16
16
|
|
|
17
17
|
RSpec/Extra/RestrictBlockTagValue:
|
|
18
18
|
Description: 'Restrict to only allowed block tag value.'
|
|
19
19
|
Enabled: pending
|
|
20
|
-
VersionAdded: '
|
|
20
|
+
VersionAdded: '0.1'
|
|
21
21
|
AllowTagValues: {}
|
data/docs/antora.yml
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
////
|
|
2
|
+
Do NOT edit this file by hand directly, as it is automatically generated.
|
|
3
|
+
|
|
4
|
+
Please make any necessary changes to the cop documentation within the source files themselves.
|
|
5
|
+
////
|
|
6
|
+
|
|
1
7
|
= RSpec/Extra
|
|
2
8
|
|
|
3
9
|
== RSpec/Extra/BeEmpty
|
|
@@ -7,8 +13,8 @@
|
|
|
7
13
|
|
|
8
14
|
| Pending
|
|
9
15
|
| Yes
|
|
10
|
-
|
|
|
11
|
-
|
|
|
16
|
+
| Always
|
|
17
|
+
| 0.2
|
|
12
18
|
| -
|
|
13
19
|
|===
|
|
14
20
|
|
|
@@ -44,7 +50,7 @@ expect(array).to be_empty
|
|
|
44
50
|
| Disabled
|
|
45
51
|
| Yes
|
|
46
52
|
| No
|
|
47
|
-
|
|
|
53
|
+
| 0.2
|
|
48
54
|
| -
|
|
49
55
|
|===
|
|
50
56
|
|
|
@@ -95,7 +101,7 @@ end
|
|
|
95
101
|
| Pending
|
|
96
102
|
| Yes
|
|
97
103
|
| No
|
|
98
|
-
|
|
|
104
|
+
| 0.2
|
|
99
105
|
| -
|
|
100
106
|
|===
|
|
101
107
|
|
|
@@ -30,8 +30,9 @@ module RuboCop
|
|
|
30
30
|
class RestrictBlockTag < Base
|
|
31
31
|
include Metadata
|
|
32
32
|
|
|
33
|
-
def on_metadata(symbols,
|
|
34
|
-
|
|
33
|
+
def on_metadata(symbols, hash)
|
|
34
|
+
symbols += hash.pairs.map(&:key) unless hash.nil?
|
|
35
|
+
offenses = symbols.filter do |symbol|
|
|
35
36
|
!allow_tags.include?(symbol.value.to_s)
|
|
36
37
|
end
|
|
37
38
|
|
|
@@ -19,8 +19,10 @@ module RuboCop
|
|
|
19
19
|
include Metadata
|
|
20
20
|
MSG = "This value is not allowed in this tag. Allowed tag value: %<allow_tag_value>s."
|
|
21
21
|
|
|
22
|
-
def on_metadata(_symbols,
|
|
23
|
-
|
|
22
|
+
def on_metadata(_symbols, hash)
|
|
23
|
+
return if hash.nil?
|
|
24
|
+
|
|
25
|
+
offenses = hash.pairs.filter do |pair|
|
|
24
26
|
allow_tag_values.any? do |k, v|
|
|
25
27
|
pair.key.value.to_s == k &&
|
|
26
28
|
pair.value.value.to_s != v
|
data/tasks/cut_release.rake
CHANGED
|
@@ -5,7 +5,7 @@ require "bump"
|
|
|
5
5
|
namespace :cut_release do
|
|
6
6
|
%w[major minor patch pre].each do |release_type|
|
|
7
7
|
desc "Cut a new #{release_type} release and create release notes."
|
|
8
|
-
task release_type
|
|
8
|
+
task release_type do
|
|
9
9
|
run(release_type)
|
|
10
10
|
end
|
|
11
11
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubocop-rspec-extra
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ydah
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-02-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rubocop
|
|
@@ -25,7 +25,6 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0'
|
|
27
27
|
description: |
|
|
28
|
-
Automatic committee code style checking tool.
|
|
29
28
|
A RuboCop extension focused on enforcing RSpec.
|
|
30
29
|
A place where no one is officially employed, but where useful cops can gather.
|
|
31
30
|
email:
|
|
@@ -60,8 +59,6 @@ files:
|
|
|
60
59
|
- lib/rubocop/cop/rspec/extra/restrict_block_tag_value.rb
|
|
61
60
|
- lib/rubocop/rspec/extra/inject.rb
|
|
62
61
|
- lib/rubocop/rspec/extra/version.rb
|
|
63
|
-
- tasks/changelog.rake
|
|
64
|
-
- tasks/changelog.rb
|
|
65
62
|
- tasks/cops_documentation.rake
|
|
66
63
|
- tasks/cut_release.rake
|
|
67
64
|
- tasks/new_cop.rake
|
|
@@ -81,15 +78,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
81
78
|
requirements:
|
|
82
79
|
- - ">="
|
|
83
80
|
- !ruby/object:Gem::Version
|
|
84
|
-
version: 2.
|
|
81
|
+
version: 2.7.0
|
|
85
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
83
|
requirements:
|
|
87
84
|
- - ">="
|
|
88
85
|
- !ruby/object:Gem::Version
|
|
89
86
|
version: '0'
|
|
90
87
|
requirements: []
|
|
91
|
-
rubygems_version: 3.
|
|
88
|
+
rubygems_version: 3.5.3
|
|
92
89
|
signing_key:
|
|
93
90
|
specification_version: 4
|
|
94
|
-
summary:
|
|
91
|
+
summary: A RuboCop extension focused on enforcing RSpec.
|
|
95
92
|
test_files: []
|
data/tasks/changelog.rake
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
autoload :Changelog, "#{__dir__}/changelog"
|
|
4
|
-
|
|
5
|
-
namespace :changelog do
|
|
6
|
-
%i[new fix change].each do |type|
|
|
7
|
-
desc "Create a Changelog entry (#{type})"
|
|
8
|
-
task type, [:id] do |_task, args|
|
|
9
|
-
ref_type = :pull if args[:id]
|
|
10
|
-
path = Changelog::Entry.new(type: type, ref_id: args[:id], ref_type: ref_type).write
|
|
11
|
-
cmd = "git add #{path}"
|
|
12
|
-
system cmd
|
|
13
|
-
puts "Entry '#{path}' created and added to git index"
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
desc "Merge entries and delete them"
|
|
18
|
-
task :merge do
|
|
19
|
-
raise "No entries!" unless Changelog.pending?
|
|
20
|
-
|
|
21
|
-
Changelog.new.merge!.and_delete!
|
|
22
|
-
cmd = "git commit -a -m 'Update Changelog'"
|
|
23
|
-
puts cmd
|
|
24
|
-
system cmd
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
desc "Check to see if there are any entries left"
|
|
28
|
-
task :check_clean do
|
|
29
|
-
next unless Changelog.pending?
|
|
30
|
-
|
|
31
|
-
puts "*** Pending changelog entries!"
|
|
32
|
-
puts "Do `bundle exec rake changelog:merge`"
|
|
33
|
-
exit(1)
|
|
34
|
-
end
|
|
35
|
-
end
|
data/tasks/changelog.rb
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
if RUBY_VERSION < "2.6"
|
|
4
|
-
puts "Changelog utilities available only for Ruby 2.6+"
|
|
5
|
-
exit(1)
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
# Changelog utility
|
|
9
|
-
class Changelog
|
|
10
|
-
ENTRIES_PATH = "changelog/"
|
|
11
|
-
FIRST_HEADER = /#{Regexp.escape("## Master (Unreleased)\n")}/m.freeze
|
|
12
|
-
CONTRIBUTORS_HEADER = /#{Regexp.escape("<!-- Contributors (alphabetically) -->\n\n")}/m.freeze
|
|
13
|
-
ENTRIES_PATH_TEMPLATE = "#{ENTRIES_PATH}%<type>s_%<name>s.md"
|
|
14
|
-
TYPE_REGEXP = /#{Regexp.escape(ENTRIES_PATH)}([a-z]+)_/.freeze
|
|
15
|
-
TYPE_TO_HEADER = { new: "New features", fix: "Bug fixes", change: "Changes" }.freeze
|
|
16
|
-
HEADER = /### (.*)/.freeze
|
|
17
|
-
PATH = "CHANGELOG.md"
|
|
18
|
-
REF_URL = "https://github.com/rubocop/rubocop-rspec-extra"
|
|
19
|
-
MAX_LENGTH = 40
|
|
20
|
-
CONTRIBUTOR = "[@%<link>s]: https://github.com/%<user>s"
|
|
21
|
-
SIGNATURE = Regexp.new(format(Regexp.escape("[@%<user>s]"), user: '([\w-]+)'))
|
|
22
|
-
EOF = "\n"
|
|
23
|
-
|
|
24
|
-
# New entry
|
|
25
|
-
Entry = Struct.new(:type, :body, :ref_type, :ref_id, :user, keyword_init: true) do
|
|
26
|
-
def initialize(type:, body: last_commit_title, ref_type: nil, ref_id: nil, user: github_user)
|
|
27
|
-
id, body = extract_id(body)
|
|
28
|
-
ref_id ||= id || "x"
|
|
29
|
-
ref_type ||= id ? :issues : :pull
|
|
30
|
-
super
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def write
|
|
34
|
-
FileUtils.mkdir_p(ENTRIES_PATH)
|
|
35
|
-
File.write(path, content)
|
|
36
|
-
path
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def path
|
|
40
|
-
format(ENTRIES_PATH_TEMPLATE, type: type, name: str_to_filename(body))
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def content
|
|
44
|
-
period = "." unless body.end_with? "."
|
|
45
|
-
"- #{ref}: #{body}#{period} ([@#{user}])\n"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def ref
|
|
49
|
-
"[##{ref_id}](#{REF_URL}/#{ref_type}/#{ref_id})"
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def last_commit_title
|
|
53
|
-
`git log -1 --pretty=%B`.lines.first.chomp
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def extract_id(body)
|
|
57
|
-
/^\[Fix(?:es)? #(\d+)\] (.*)/.match(body)&.captures || [nil, body]
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def str_to_filename(str)
|
|
61
|
-
str
|
|
62
|
-
.split
|
|
63
|
-
.reject(&:empty?)
|
|
64
|
-
.map { |s| prettify(s) }
|
|
65
|
-
.inject do |result, word|
|
|
66
|
-
s = "#{result}_#{word}"
|
|
67
|
-
return result if s.length > MAX_LENGTH
|
|
68
|
-
|
|
69
|
-
s
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def github_user
|
|
74
|
-
user = `git config --global credential.username`.chomp
|
|
75
|
-
warn 'Set your username with `git config --global credential.username "myusernamehere"`' if user.empty?
|
|
76
|
-
|
|
77
|
-
user
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
private
|
|
81
|
-
|
|
82
|
-
def prettify(str)
|
|
83
|
-
str.gsub!(/\W/, "_")
|
|
84
|
-
|
|
85
|
-
# Separate word boundaries by `_`.
|
|
86
|
-
str.gsub!(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) do
|
|
87
|
-
(Regexp.last_match(1) || Regexp.last_match(2)) << "_"
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
str.gsub!(/\A_+|_+\z/, "")
|
|
91
|
-
str.downcase!
|
|
92
|
-
str
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def self.pending?
|
|
97
|
-
entry_paths.any?
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def self.entry_paths
|
|
101
|
-
Dir["#{ENTRIES_PATH}*"]
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def self.read_entries
|
|
105
|
-
entry_paths.to_h { |path| [path, File.read(path)] }
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
attr_reader :header, :rest
|
|
109
|
-
|
|
110
|
-
def initialize(content: File.read(PATH), entries: Changelog.read_entries)
|
|
111
|
-
require "strscan"
|
|
112
|
-
|
|
113
|
-
parse(content)
|
|
114
|
-
@entries = entries
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def and_delete!
|
|
118
|
-
@entries.each_key { |path| File.delete(path) }
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def merge!
|
|
122
|
-
File.write(PATH, merge_content)
|
|
123
|
-
self
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def unreleased_content
|
|
127
|
-
entry_map = parse_entries(@entries)
|
|
128
|
-
merged_map = merge_entries(entry_map)
|
|
129
|
-
merged_map.flat_map do |header, things|
|
|
130
|
-
["### #{header}\n", *things, ""]
|
|
131
|
-
end.join("\n")
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def merge_content
|
|
135
|
-
merged_content = [@header, unreleased_content, @changes.chomp, *all_contributors].join("\n")
|
|
136
|
-
|
|
137
|
-
merged_content << EOF
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def all_contributors
|
|
141
|
-
(@contributors.split(/\R/) + new_contributors).uniq.sort
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def new_contributors
|
|
145
|
-
contributors
|
|
146
|
-
.map { |user| format(CONTRIBUTOR, link: user.downcase, user: user) }
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def contributors
|
|
150
|
-
contributors = @entries.values.flat_map do |entry|
|
|
151
|
-
entry.match(/\. \((?<contributors>.+)\)\n/)[:contributors].split(",")
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
contributors.join.scan(SIGNATURE).flatten
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
private
|
|
158
|
-
|
|
159
|
-
def merge_entries(entry_map)
|
|
160
|
-
all = @unreleased.merge(entry_map) { |_k, v1, v2| v1.concat(v2) }
|
|
161
|
-
canonical = TYPE_TO_HEADER.values.to_h { |v| [v, nil] }
|
|
162
|
-
canonical.merge(all).compact
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def parse(content)
|
|
166
|
-
ss = StringScanner.new(content)
|
|
167
|
-
@header = ss.scan_until(FIRST_HEADER)
|
|
168
|
-
@unreleased = parse_release(ss.scan_until(/\n(?=## )/m))
|
|
169
|
-
@changes = ss.scan_until(CONTRIBUTORS_HEADER)
|
|
170
|
-
@contributors = ss.rest
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
# @return [Hash<type, Array<String>]]
|
|
174
|
-
def parse_release(unreleased)
|
|
175
|
-
unreleased
|
|
176
|
-
.lines
|
|
177
|
-
.map(&:chomp)
|
|
178
|
-
.reject(&:empty?)
|
|
179
|
-
.slice_before(HEADER)
|
|
180
|
-
.to_h do |header, *entries|
|
|
181
|
-
[HEADER.match(header)[1], entries]
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def parse_entries(path_content_map)
|
|
186
|
-
changes = Hash.new { |h, k| h[k] = [] }
|
|
187
|
-
path_content_map.each do |path, content|
|
|
188
|
-
header = TYPE_TO_HEADER.fetch(TYPE_REGEXP.match(path)[1].to_sym)
|
|
189
|
-
changes[header].concat(content.lines.map(&:chomp))
|
|
190
|
-
end
|
|
191
|
-
changes
|
|
192
|
-
end
|
|
193
|
-
end
|