remlint 0.1.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 +7 -0
- data/LICENSE +328 -0
- data/config/default.yml +374 -0
- data/docs/remlint-rules.md +390 -0
- data/docs/remlint.md +238 -0
- data/exe/remlint +8 -0
- data/lib/remlint/cli.rb +300 -0
- data/lib/remlint/command.rb +229 -0
- data/lib/remlint/config.rb +255 -0
- data/lib/remlint/date_literal.rb +283 -0
- data/lib/remlint/document.rb +161 -0
- data/lib/remlint/expr_lexer.rb +197 -0
- data/lib/remlint/extractors.rb +210 -0
- data/lib/remlint/formatter.rb +96 -0
- data/lib/remlint/invocation.rb +145 -0
- data/lib/remlint/logical_line.rb +194 -0
- data/lib/remlint/offense.rb +117 -0
- data/lib/remlint/rule.rb +216 -0
- data/lib/remlint/rules/addomit_without_scanfrom.rb +189 -0
- data/lib/remlint/rules/advance_warning_body.rb +176 -0
- data/lib/remlint/rules/banner_placement.rb +126 -0
- data/lib/remlint/rules/calendar_text_limited.rb +125 -0
- data/lib/remlint/rules/callback_signature.rb +221 -0
- data/lib/remlint/rules/clause_needs_full_date.rb +176 -0
- data/lib/remlint/rules/clause_requires_at.rb +178 -0
- data/lib/remlint/rules/clause_value_range.rb +257 -0
- data/lib/remlint/rules/color_component_range.rb +295 -0
- data/lib/remlint/rules/coordinate_not_string.rb +175 -0
- data/lib/remlint/rules/dangling_continuation.rb +134 -0
- data/lib/remlint/rules/date_out_of_range.rb +180 -0
- data/lib/remlint/rules/debug_command.rb +189 -0
- data/lib/remlint/rules/easterdate_from_today.rb +160 -0
- data/lib/remlint/rules/function_arity.rb +385 -0
- data/lib/remlint/rules/function_redefinition.rb +159 -0
- data/lib/remlint/rules/generated_file_edited.rb +125 -0
- data/lib/remlint/rules/hebrew_date.rb +245 -0
- data/lib/remlint/rules/iftrig_with_satisfy.rb +101 -0
- data/lib/remlint/rules/include_path.rb +155 -0
- data/lib/remlint/rules/info_clause.rb +186 -0
- data/lib/remlint/rules/info_substitution_without_header.rb +169 -0
- data/lib/remlint/rules/invocation_mismatch.rb +223 -0
- data/lib/remlint/rules/keyword_case.rb +172 -0
- data/lib/remlint/rules/license_header.rb +101 -0
- data/lib/remlint/rules/line_length.rb +101 -0
- data/lib/remlint/rules/literal_type_mismatch.rb +324 -0
- data/lib/remlint/rules/localization_pack.rb +144 -0
- data/lib/remlint/rules/moon_phase_argument.rb +162 -0
- data/lib/remlint/rules/omit_aware_delta.rb +168 -0
- data/lib/remlint/rules/push_vars_missing_name.rb +158 -0
- data/lib/remlint/rules/repeat_trigger.rb +188 -0
- data/lib/remlint/rules/satisfy_constraint.rb +230 -0
- data/lib/remlint/rules/shell_maxlen.rb +170 -0
- data/lib/remlint/rules/shell_use_while_run_disabled.rb +172 -0
- data/lib/remlint/rules/string_escape.rb +158 -0
- data/lib/remlint/rules/syntax.rb +229 -0
- data/lib/remlint/rules/system_variable_assignment.rb +197 -0
- data/lib/remlint/rules/tag_syntax.rb +145 -0
- data/lib/remlint/rules/text_after_eof_marker.rb +134 -0
- data/lib/remlint/rules/time_zone_name.rb +212 -0
- data/lib/remlint/rules/tk_tag_namespace.rb +121 -0
- data/lib/remlint/rules/todo_complete_through.rb +122 -0
- data/lib/remlint/rules/trailing_whitespace.rb +116 -0
- data/lib/remlint/rules/translate_command.rb +203 -0
- data/lib/remlint/rules/unbalanced_blocks.rb +305 -0
- data/lib/remlint/rules/unbalanced_delimiters.rb +251 -0
- data/lib/remlint/rules/unknown_special_type.rb +155 -0
- data/lib/remlint/rules/unknown_substitution_sequence.rb +255 -0
- data/lib/remlint/rules/unknown_system_variable.rb +145 -0
- data/lib/remlint/rules/unquoted_shell_substitution.rb +266 -0
- data/lib/remlint/rules/until_before_from.rb +204 -0
- data/lib/remlint/rules/world_writable_script.rb +128 -0
- data/lib/remlint/rules.rb +60 -0
- data/lib/remlint/runner.rb +274 -0
- data/lib/remlint/source.rb +36 -0
- data/lib/remlint/tables.rb +395 -0
- data/lib/remlint/trigger.rb +359 -0
- data/lib/remlint/version.rb +5 -0
- data/lib/remlint/vocabulary.rb +236 -0
- data/lib/remlint.rb +35 -0
- data/tasks/generate_tables.rb +175 -0
- metadata +170 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Regenerates lib/remlint/tables.rb from the Remind C sources.
|
|
5
|
+
#
|
|
6
|
+
# Every fact the linter asserts about Remind's vocabulary -- which keywords
|
|
7
|
+
# exist, how far each may be abbreviated, which functions take how many
|
|
8
|
+
# arguments, which system variables are writable and over what range -- is
|
|
9
|
+
# transcribed from the tables Remind itself dispatches on:
|
|
10
|
+
#
|
|
11
|
+
# src/token.c TokArray[] keyword, minimum abbreviation length, type
|
|
12
|
+
# src/funcs.c Func[] builtin name, min args, max args
|
|
13
|
+
# src/var.c SysVarArr[] $SysVar name, modifiable flag, type, min, max
|
|
14
|
+
#
|
|
15
|
+
# Hand-maintaining that vocabulary would guarantee drift the first time Remind
|
|
16
|
+
# gains a function. Run this against a Remind checkout instead:
|
|
17
|
+
#
|
|
18
|
+
# ruby tasks/generate_tables.rb /path/to/remind
|
|
19
|
+
#
|
|
20
|
+
# The generated file is committed, so the gem builds and tests without a
|
|
21
|
+
# Remind checkout present.
|
|
22
|
+
|
|
23
|
+
require "pathname"
|
|
24
|
+
|
|
25
|
+
SOURCE_ROOT = Pathname.new(ARGV.fetch(0, "..")).expand_path
|
|
26
|
+
OUTPUT = Pathname.new(__dir__).join("../lib/remlint/tables.rb").cleanpath
|
|
27
|
+
|
|
28
|
+
# `{ "banner", 3, T_Banner, 0 },` -- name, minimum abbreviation length, type.
|
|
29
|
+
TOKEN_ROW = /^\s*\{\s*"([a-z0-9-]+)"\s*,\s*(\d+)\s*,\s*(T_\w+)\s*,/
|
|
30
|
+
|
|
31
|
+
# `{ "ampm", 1, 4, 1, FAmpm, NULL },` -- name, min args, max args.
|
|
32
|
+
# NO_MAX_ARGS (127) is Remind's "variadic" sentinel.
|
|
33
|
+
FUNC_ROW = /^\s*\{\s*"([a-z0-9_]+)"\s*,\s*(\d+|NO_MAX_ARGS)\s*,\s*(\d+|NO_MAX_ARGS)\s*,/
|
|
34
|
+
|
|
35
|
+
# `{"FormWidth", 1, INT_TYPE, &FormWidth, 20, 500 },`
|
|
36
|
+
# -- name, modifiable, type, value, min, max. The min/max columns only bound
|
|
37
|
+
# anything for INT_TYPE; for the other types they are 0/0 filler.
|
|
38
|
+
SYSVAR_ROW = /^\s*\{\s*"(\w+)"\s*,\s*([01])\s*,\s*(\w+)\s*,\s*[^,]+,\s*([^,]+),\s*([^}]+)\}/
|
|
39
|
+
|
|
40
|
+
NO_MAX_ARGS = 127
|
|
41
|
+
|
|
42
|
+
def read_source(relative)
|
|
43
|
+
path = SOURCE_ROOT.join(relative)
|
|
44
|
+
|
|
45
|
+
unless path.exist?
|
|
46
|
+
abort "#{path} not found; pass the root of a Remind checkout as ARGV[0]"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
path.read
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def scan(relative, pattern)
|
|
53
|
+
read_source(relative).each_line.filter_map do |line|
|
|
54
|
+
match = line.match(pattern)
|
|
55
|
+
|
|
56
|
+
if match
|
|
57
|
+
yield match
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def parse_arg_count(text)
|
|
63
|
+
if text == "NO_MAX_ARGS"
|
|
64
|
+
NO_MAX_ARGS
|
|
65
|
+
else
|
|
66
|
+
Integer(text)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Only INT_TYPE variables carry a real range, and only when the two columns
|
|
71
|
+
# actually differ -- `0, 0` is Remind's filler, not a variable pinned to zero.
|
|
72
|
+
def parse_bounds(type, min, max)
|
|
73
|
+
if type == "INT_TYPE" && min.strip.match?(/\A-?\d+\z/) && max.strip.match?(/\A-?\d+\z/) && min.strip != max.strip
|
|
74
|
+
[Integer(min.strip), Integer(max.strip)]
|
|
75
|
+
else
|
|
76
|
+
[nil, nil]
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def literal(value)
|
|
81
|
+
case value
|
|
82
|
+
when nil then "nil"
|
|
83
|
+
when String then value.inspect
|
|
84
|
+
else value.to_s
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def render_rows(rows, columns)
|
|
89
|
+
widths = columns.to_h do |column|
|
|
90
|
+
[column, rows.map { |row| literal(row[column]).length }.max]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
rows.map do |row|
|
|
94
|
+
cells = columns.map do |column|
|
|
95
|
+
literal(row[column]).ljust(widths.fetch(column))
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
" [#{cells.join(', ')}],"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
keywords = scan("src/token.c", TOKEN_ROW) do |match|
|
|
103
|
+
{
|
|
104
|
+
name: match[1].upcase,
|
|
105
|
+
minlen: Integer(match[2]),
|
|
106
|
+
type: match[3],
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
functions = scan("src/funcs.c", FUNC_ROW) do |match|
|
|
111
|
+
{
|
|
112
|
+
name: match[1],
|
|
113
|
+
min: parse_arg_count(match[2]),
|
|
114
|
+
max: parse_arg_count(match[3]),
|
|
115
|
+
}
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
sysvars = scan("src/var.c", SYSVAR_ROW) do |match|
|
|
119
|
+
min, max = parse_bounds(match[3], match[4], match[5])
|
|
120
|
+
|
|
121
|
+
{
|
|
122
|
+
name: match[1],
|
|
123
|
+
modifiable: match[2] == "1",
|
|
124
|
+
type: match[3],
|
|
125
|
+
min: min,
|
|
126
|
+
max: max,
|
|
127
|
+
}
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# src/version.h.in holds an unsubstituted @VERSION@ placeholder in a source
|
|
131
|
+
# tree that has not been configured, so take the number from its origin.
|
|
132
|
+
version = read_source("configure.ac")[/AC_INIT\(\s*remind\s*,\s*([^,\s)]+)/, 1] || "unknown"
|
|
133
|
+
|
|
134
|
+
body = <<~GENERATED
|
|
135
|
+
# frozen_string_literal: true
|
|
136
|
+
|
|
137
|
+
# GENERATED FILE -- do not edit by hand.
|
|
138
|
+
#
|
|
139
|
+
# Transcribed from Remind #{version} by tasks/generate_tables.rb, which reads
|
|
140
|
+
# the same tables the interpreter dispatches on (src/token.c, src/funcs.c,
|
|
141
|
+
# src/var.c). Regenerate rather than patch:
|
|
142
|
+
#
|
|
143
|
+
# ruby tasks/generate_tables.rb /path/to/remind
|
|
144
|
+
module RemLint
|
|
145
|
+
# Remind's vocabulary, exactly as the interpreter knows it.
|
|
146
|
+
module Tables
|
|
147
|
+
# Remind's variadic sentinel: `char(...)` and friends take any number of
|
|
148
|
+
# arguments above their minimum.
|
|
149
|
+
NO_MAX_ARGS = #{NO_MAX_ARGS}
|
|
150
|
+
|
|
151
|
+
# [keyword, minimum abbreviation length, token type]. Remind accepts any
|
|
152
|
+
# prefix at least `minlen` characters long, which is why `INC` is
|
|
153
|
+
# `INCLUDE` and `SCAN` is `SCANFROM`.
|
|
154
|
+
KEYWORD_ROWS = [
|
|
155
|
+
#{render_rows(keywords, %i[name minlen type]).join("\n")}
|
|
156
|
+
].freeze
|
|
157
|
+
|
|
158
|
+
# [name, minimum arguments, maximum arguments].
|
|
159
|
+
FUNCTION_ROWS = [
|
|
160
|
+
#{render_rows(functions, %i[name min max]).join("\n")}
|
|
161
|
+
].freeze
|
|
162
|
+
|
|
163
|
+
# [name, modifiable, type, minimum, maximum]. Non-modifiable variables
|
|
164
|
+
# are readable but reject `SET`; the bounds are populated only for the
|
|
165
|
+
# integer-valued variables Remind range-checks.
|
|
166
|
+
SYSVAR_ROWS = [
|
|
167
|
+
#{render_rows(sysvars, %i[name modifiable type min max]).join("\n")}
|
|
168
|
+
].freeze
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
GENERATED
|
|
172
|
+
|
|
173
|
+
OUTPUT.write(body)
|
|
174
|
+
|
|
175
|
+
puts "#{OUTPUT}: #{keywords.size} keywords, #{functions.size} functions, #{sysvars.size} system variables"
|
metadata
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: remlint
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Nathan Kidd
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-01 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rake
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '13.0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '13.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rubocop
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.88'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.88'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: scampi
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '1.0'
|
|
54
|
+
description: |
|
|
55
|
+
RemLint checks Remind reminder files for style, consistency and structure:
|
|
56
|
+
unbalanced IF/ENDIF blocks, mistyped $SysVars, wrong argument counts,
|
|
57
|
+
continuations that do not continue, and trailing whitespace that breaks
|
|
58
|
+
rem2ps. Its vocabulary is transcribed from Remind's own dispatch tables, so
|
|
59
|
+
keyword abbreviations and function arities match the interpreter exactly.
|
|
60
|
+
|
|
61
|
+
It reads Remind out of shell heredocs as well as .rem files, and reports
|
|
62
|
+
line numbers in the enclosing file.
|
|
63
|
+
email: nathanblenheimkidd@gmail.com
|
|
64
|
+
executables:
|
|
65
|
+
- remlint
|
|
66
|
+
extensions: []
|
|
67
|
+
extra_rdoc_files:
|
|
68
|
+
- docs/remlint.md
|
|
69
|
+
files:
|
|
70
|
+
- LICENSE
|
|
71
|
+
- config/default.yml
|
|
72
|
+
- docs/remlint-rules.md
|
|
73
|
+
- docs/remlint.md
|
|
74
|
+
- exe/remlint
|
|
75
|
+
- lib/remlint.rb
|
|
76
|
+
- lib/remlint/cli.rb
|
|
77
|
+
- lib/remlint/command.rb
|
|
78
|
+
- lib/remlint/config.rb
|
|
79
|
+
- lib/remlint/date_literal.rb
|
|
80
|
+
- lib/remlint/document.rb
|
|
81
|
+
- lib/remlint/expr_lexer.rb
|
|
82
|
+
- lib/remlint/extractors.rb
|
|
83
|
+
- lib/remlint/formatter.rb
|
|
84
|
+
- lib/remlint/invocation.rb
|
|
85
|
+
- lib/remlint/logical_line.rb
|
|
86
|
+
- lib/remlint/offense.rb
|
|
87
|
+
- lib/remlint/rule.rb
|
|
88
|
+
- lib/remlint/rules.rb
|
|
89
|
+
- lib/remlint/rules/addomit_without_scanfrom.rb
|
|
90
|
+
- lib/remlint/rules/advance_warning_body.rb
|
|
91
|
+
- lib/remlint/rules/banner_placement.rb
|
|
92
|
+
- lib/remlint/rules/calendar_text_limited.rb
|
|
93
|
+
- lib/remlint/rules/callback_signature.rb
|
|
94
|
+
- lib/remlint/rules/clause_needs_full_date.rb
|
|
95
|
+
- lib/remlint/rules/clause_requires_at.rb
|
|
96
|
+
- lib/remlint/rules/clause_value_range.rb
|
|
97
|
+
- lib/remlint/rules/color_component_range.rb
|
|
98
|
+
- lib/remlint/rules/coordinate_not_string.rb
|
|
99
|
+
- lib/remlint/rules/dangling_continuation.rb
|
|
100
|
+
- lib/remlint/rules/date_out_of_range.rb
|
|
101
|
+
- lib/remlint/rules/debug_command.rb
|
|
102
|
+
- lib/remlint/rules/easterdate_from_today.rb
|
|
103
|
+
- lib/remlint/rules/function_arity.rb
|
|
104
|
+
- lib/remlint/rules/function_redefinition.rb
|
|
105
|
+
- lib/remlint/rules/generated_file_edited.rb
|
|
106
|
+
- lib/remlint/rules/hebrew_date.rb
|
|
107
|
+
- lib/remlint/rules/iftrig_with_satisfy.rb
|
|
108
|
+
- lib/remlint/rules/include_path.rb
|
|
109
|
+
- lib/remlint/rules/info_clause.rb
|
|
110
|
+
- lib/remlint/rules/info_substitution_without_header.rb
|
|
111
|
+
- lib/remlint/rules/invocation_mismatch.rb
|
|
112
|
+
- lib/remlint/rules/keyword_case.rb
|
|
113
|
+
- lib/remlint/rules/license_header.rb
|
|
114
|
+
- lib/remlint/rules/line_length.rb
|
|
115
|
+
- lib/remlint/rules/literal_type_mismatch.rb
|
|
116
|
+
- lib/remlint/rules/localization_pack.rb
|
|
117
|
+
- lib/remlint/rules/moon_phase_argument.rb
|
|
118
|
+
- lib/remlint/rules/omit_aware_delta.rb
|
|
119
|
+
- lib/remlint/rules/push_vars_missing_name.rb
|
|
120
|
+
- lib/remlint/rules/repeat_trigger.rb
|
|
121
|
+
- lib/remlint/rules/satisfy_constraint.rb
|
|
122
|
+
- lib/remlint/rules/shell_maxlen.rb
|
|
123
|
+
- lib/remlint/rules/shell_use_while_run_disabled.rb
|
|
124
|
+
- lib/remlint/rules/string_escape.rb
|
|
125
|
+
- lib/remlint/rules/syntax.rb
|
|
126
|
+
- lib/remlint/rules/system_variable_assignment.rb
|
|
127
|
+
- lib/remlint/rules/tag_syntax.rb
|
|
128
|
+
- lib/remlint/rules/text_after_eof_marker.rb
|
|
129
|
+
- lib/remlint/rules/time_zone_name.rb
|
|
130
|
+
- lib/remlint/rules/tk_tag_namespace.rb
|
|
131
|
+
- lib/remlint/rules/todo_complete_through.rb
|
|
132
|
+
- lib/remlint/rules/trailing_whitespace.rb
|
|
133
|
+
- lib/remlint/rules/translate_command.rb
|
|
134
|
+
- lib/remlint/rules/unbalanced_blocks.rb
|
|
135
|
+
- lib/remlint/rules/unbalanced_delimiters.rb
|
|
136
|
+
- lib/remlint/rules/unknown_special_type.rb
|
|
137
|
+
- lib/remlint/rules/unknown_substitution_sequence.rb
|
|
138
|
+
- lib/remlint/rules/unknown_system_variable.rb
|
|
139
|
+
- lib/remlint/rules/unquoted_shell_substitution.rb
|
|
140
|
+
- lib/remlint/rules/until_before_from.rb
|
|
141
|
+
- lib/remlint/rules/world_writable_script.rb
|
|
142
|
+
- lib/remlint/runner.rb
|
|
143
|
+
- lib/remlint/source.rb
|
|
144
|
+
- lib/remlint/tables.rb
|
|
145
|
+
- lib/remlint/trigger.rb
|
|
146
|
+
- lib/remlint/version.rb
|
|
147
|
+
- lib/remlint/vocabulary.rb
|
|
148
|
+
- tasks/generate_tables.rb
|
|
149
|
+
homepage: https://dianne.skoll.ca/projects/remind/
|
|
150
|
+
licenses:
|
|
151
|
+
- GPL-2.0-only
|
|
152
|
+
metadata: {}
|
|
153
|
+
rdoc_options: []
|
|
154
|
+
require_paths:
|
|
155
|
+
- lib
|
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
157
|
+
requirements:
|
|
158
|
+
- - ">="
|
|
159
|
+
- !ruby/object:Gem::Version
|
|
160
|
+
version: '3.3'
|
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
162
|
+
requirements:
|
|
163
|
+
- - ">="
|
|
164
|
+
- !ruby/object:Gem::Version
|
|
165
|
+
version: '0'
|
|
166
|
+
requirements: []
|
|
167
|
+
rubygems_version: 3.7.2
|
|
168
|
+
specification_version: 4
|
|
169
|
+
summary: A style and consistency linter for Remind reminder files
|
|
170
|
+
test_files: []
|