guard-slimlint 1.4.0 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14b281a7110ec5e1176f8e57dc91b18c1569b3eec1a14c19d17f7cf99ab814e2
4
- data.tar.gz: a2ec22b0621349fadca501979d70687eceb86b4232a25241d5e78ba9987d0611
3
+ metadata.gz: dfb29b85e6e86adbf353fd8a8f7ebb7d4ddffc72f79d7015ccdc12927ae91ece
4
+ data.tar.gz: 6d50a482ee6fad85b3d5474ab4a59a398e62e0fb8c42fbe0ffb997d1d9e056d3
5
5
  SHA512:
6
- metadata.gz: 6096c002fa6518d50a22fcf29e9c98b9fc38f6b500f9cf043074feedd896c6e394bf96e3b949831044dd0517e6323de4a145ba90066c934443c3b68f67c01dde
7
- data.tar.gz: 2864c784c00d06c76fdae85d2c1ea2c4b9ea5a689853ad5d376cc391e74482fb75a1c2bbaef7155052b2b9f86e0cf974f9efac618a378ffaf7bc3ad9a7dfd4e1
6
+ metadata.gz: 9e294839c1b05bf9bee7527b13d7847c99adf6b876ac21ca442ad63f74cde6badb216098af6604257e7d4d568f543b0fb0d8170e9ab2c456ce939ac3dcda2a93
7
+ data.tar.gz: 4e40c7f1451eb500cafde4ad53798db37f6f8f114bde89cf1724215aaf698693fcc6b163acc16d2fe924e31522af38b8d5c5ecd3dfb697e68bcd10d6bfda37f3
data/CHANGELOG.md CHANGED
@@ -6,6 +6,48 @@ follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.0.0] - 2026-09-07
10
+
11
+ A behaviour release. The plugin still runs slim-lint as a subprocess, which
12
+ was a deliberate decision: Guard is a long-running process, and loading the
13
+ linter into it would freeze `.slim-lint.yml` at startup and let RuboCop's
14
+ caches grow all day. Four of the five comparable Guard plugins shell out for
15
+ the same reason.
16
+
17
+ ### Changed
18
+
19
+ - **`notify_on` now defaults to `:change`.** Notifications fire only when the
20
+ outcome flips, green to red or red to green. Saving a broken template twenty
21
+ times while fixing it produces one notification instead of twenty. Pass
22
+ `notify_on: :failure` for the old behaviour.
23
+ - **Ruby 3.3 or newer is required.** 3.2 reached end of life in March 2026.
24
+ - **`run_all` lints the directories Guard watches** rather than always
25
+ sweeping `.`. A `directories` line in your Guardfile now narrows it. Without
26
+ one, behaviour is unchanged.
27
+ - The Guardfile template watches `app/views` rather than every `.html.slim`
28
+ file anywhere in the project, and re-lints when `.slim-lint.yml` changes.
29
+ - Option readers are no longer writable. `notify_on` and `all_on_start` are
30
+ read once at construction, so the writers only ever looked useful.
31
+
32
+ ### Added
33
+
34
+ - `cli:` option, forwarding arbitrary arguments to slim-lint as a String or an
35
+ Array. This covers `-c`, linter selection and anything slim-lint adds later
36
+ without a new option here for each.
37
+ - `halt_on_fail:` option, default `true`, to opt out of failing Guard's task.
38
+ - An unrecognised `notify_on` now raises at startup instead of silently
39
+ disabling notifications for the whole session.
40
+ - Exit statuses that do not come from slim-lint itself now explain themselves.
41
+ Status 1 is Bundler failing to load the command, and 127 is a missing binary;
42
+ neither mentions Slim, so the bare number used to send people hunting for
43
+ lint errors in templates that were fine.
44
+
45
+ ### Removed
46
+
47
+ - The `colorize` runtime dependency. It monkeypatched `String` in every host
48
+ application to colour two log lines. Guard's own `Compat::UI.color` does the
49
+ same job, so the plugin now adds nothing to your object space.
50
+
9
51
  ## [1.4.0] - 2026-09-04
10
52
 
11
53
  The gem had not been touched since 2019 and could no longer be developed on any
@@ -75,7 +117,8 @@ without changing the plugin's interface.
75
117
  - `all_on_start` is honoured, so the plugin no longer lints everything on
76
118
  startup when the option is disabled.
77
119
 
78
- [Unreleased]: https://github.com/mike927/guard-slimlint/compare/v1.4.0...HEAD
120
+ [Unreleased]: https://github.com/mike927/guard-slimlint/compare/v2.0.0...HEAD
121
+ [2.0.0]: https://github.com/mike927/guard-slimlint/compare/v1.4.0...v2.0.0
79
122
  [1.4.0]: https://github.com/mike927/guard-slimlint/compare/v1.3.2...v1.4.0
80
123
  [1.3.2]: https://github.com/mike927/guard-slimlint/compare/v1.3.1...v1.3.2
81
124
  [1.3.1]: https://github.com/mike927/guard-slimlint/compare/v1.3.0...v1.3.1
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  Guard::SlimLint runs [slim-lint](https://github.com/sds/slim-lint) automatically
7
7
  every time a Slim template is added or changed.
8
8
 
9
- Requires Ruby 3.1 or newer.
9
+ Requires Ruby 3.3 or newer.
10
10
 
11
11
  ## Installation
12
12
 
@@ -24,12 +24,6 @@ Then run:
24
24
  bundle install
25
25
  ```
26
26
 
27
- Or install it yourself:
28
-
29
- ```
30
- gem install guard-slimlint
31
- ```
32
-
33
27
  ## Usage
34
28
 
35
29
  Add the plugin to your Guardfile:
@@ -50,27 +44,41 @@ Linting itself is configured by slim-lint, not by this plugin. Put a
50
44
  ## Options
51
45
 
52
46
  ```ruby
53
- guard :slimlint, notify_on: :failure, all_on_start: true do
47
+ guard :slimlint, notify_on: :change, cli: '-c config/.slim-lint.yml' do
54
48
  watch(%r{^app/views/.+\.slim$})
49
+ watch(%r{(?:.+/)?\.slim-lint\.yml$}) { |m| File.dirname(m[0]) }
55
50
  end
56
51
  ```
57
52
 
58
53
  | Option | Default | Meaning |
59
54
  |--------|---------|---------|
60
- | `notify_on` | `:failure` | When to send a desktop notification. One of `:failure`, `:success`, `:both`, `:none`. |
55
+ | `notify_on` | `:change` | When to send a desktop notification. One of `:change`, `:failure`, `:success`, `:both`, `:none`. |
61
56
  | `all_on_start` | `true` | Lint everything once when Guard starts. |
57
+ | `halt_on_fail` | `true` | Tell Guard the task failed, so a group's `halt_on_fail` can stop the rest of it. |
58
+ | `cli` | none | Extra arguments passed straight to slim-lint. String or Array. |
59
+
60
+ An unrecognised `notify_on` raises at startup rather than silently going quiet.
61
+
62
+ ### Notifications
63
+
64
+ `:change` notifies only when the outcome flips, green to red or red to green.
65
+ Saving a broken file twenty times while you fix it produces one notification,
66
+ not twenty. `:failure` notifies on every failing run, which is the older
67
+ behaviour if you prefer it.
68
+
69
+ Notifications come from Guard itself. On macOS, add `terminal-notifier-guard`
70
+ to your Gemfile, or you will only see the terminal window title change.
62
71
 
63
- Desktop notifications come from Guard itself. On macOS, add
64
- `terminal-notifier-guard` to your Gemfile to get them.
72
+ ### Running everything
65
73
 
66
- Guard's `halt_on_fail` group option is respected. Put the plugin in a group with
67
- `halt_on_fail: true` to stop the rest of the group when linting fails.
74
+ `run_all` lints the directories Guard is watching, so a `directories` line in
75
+ your Guardfile narrows it. Without one it falls back to the whole project.
68
76
 
69
77
  ## Exit status handling
70
78
 
71
79
  slim-lint reports its outcome with sysexits codes. This plugin treats status 65
72
80
  as "offences were found" and every other non-zero status as slim-lint itself
73
- failing, which is reported through `Guard::UI.error` with the status. A
81
+ failing, which is reported through `Guard::Compat::UI.error` with the status. A
74
82
  misconfigured `.slim-lint.yml` or a crash is therefore not mistaken for a lint
75
83
  failure.
76
84
 
@@ -1,6 +1,13 @@
1
1
  # available options:
2
- # notify_on:
3
- # failure, success, both, none
4
- guard :slimlint, notify_on: :failure do
5
- watch(/^.+(\.html\.slim)$/)
2
+ # notify_on: change (default), failure, success, both, none
3
+ # all_on_start: true (default), false
4
+ # halt_on_fail: true (default), false
5
+ # cli: extra arguments for slim-lint, e.g. '-c config/.slim-lint.yml'
6
+ guard :slimlint, notify_on: :change do
7
+ # Rails views. For a non-Rails project, watch wherever your templates live,
8
+ # for example watch(%r{^templates/.+\.slim$})
9
+ watch(%r{^app/views/.+\.slim$})
10
+
11
+ # Re-lint when the slim-lint configuration itself changes.
12
+ watch(%r{(?:.+/)?\.slim-lint\.yml$}) { |m| File.dirname(m[0]) }
6
13
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Guard
4
4
  class SlimLintVersion
5
- VERSION = '1.4.0'
5
+ VERSION = '2.0.0'
6
6
  end
7
7
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'English'
4
+ require 'shellwords'
4
5
  require 'guard/compat/plugin'
5
- require 'colorize'
6
6
 
7
7
  module Guard
8
8
  class SlimLint < Plugin
@@ -12,11 +12,33 @@ module Guard
12
12
  EXIT_SUCCESS = 0
13
13
  EXIT_LINT_FAILURE = 65
14
14
 
15
- attr_accessor :notify_on, :all_on_start
15
+ # Recognised :notify_on values. :change notifies only when the outcome
16
+ # flips, which is what stops a long editing session from producing one
17
+ # notification per save.
18
+ NOTIFY_MODES = %i[change failure success both none].freeze
19
+
20
+ # Statuses that are not slim-lint's own sysexits codes, paired with what a
21
+ # user is most likely looking at. Bundler exits 1 when it cannot load the
22
+ # command, and a shell exits 127 when the binary is missing; neither says
23
+ # anything about Slim, so the bare number sends people hunting for lint
24
+ # errors that do not exist.
25
+ STATUS_HINTS = {
26
+ 1 => 'the bundle is probably out of sync, try bundle install',
27
+ 127 => 'slim-lint is not on PATH, check that the gem is installed'
28
+ }.freeze
29
+
30
+ attr_reader :notify_on, :all_on_start, :halt_on_fail, :cli
16
31
 
17
32
  def initialize(options = {})
18
- @notify_on = options.fetch(:notify_on, :failure)
33
+ @notify_on = options.fetch(:notify_on, :change)
19
34
  @all_on_start = options.fetch(:all_on_start, true)
35
+ @halt_on_fail = options.fetch(:halt_on_fail, true)
36
+ @cli = options[:cli]
37
+ # Assume the project starts green, so a clean first run stays quiet
38
+ # under :change instead of announcing that nothing is wrong.
39
+ @last_success = true
40
+
41
+ validate_notify_on!
20
42
  super
21
43
  end
22
44
 
@@ -25,7 +47,7 @@ module Guard
25
47
  end
26
48
 
27
49
  def run_all
28
- run
50
+ run(lint_targets)
29
51
  end
30
52
 
31
53
  def run_on_modifications(paths)
@@ -38,7 +60,28 @@ module Guard
38
60
 
39
61
  private
40
62
 
41
- def run(paths = ['.'])
63
+ def validate_notify_on!
64
+ return if NOTIFY_MODES.include?(notify_on)
65
+
66
+ raise ArgumentError,
67
+ "unknown :notify_on #{notify_on.inspect}, expected one of " \
68
+ "#{NOTIFY_MODES.map(&:inspect).join(', ')}"
69
+ end
70
+
71
+ # The directories Guard was told to watch, so run_all honours a
72
+ # `directories` line in the Guardfile instead of always sweeping the
73
+ # whole project.
74
+ def lint_targets
75
+ dirs = Compat.watched_directories.map(&:to_s)
76
+ dirs.empty? ? ['.'] : dirs
77
+ rescue NotImplementedError
78
+ # guard-compat raises this when Guard's CLI is not loaded, which
79
+ # happens when the plugin is driven programmatically rather than by
80
+ # `guard`. Linting the whole project is what run_all did before 2.0.0.
81
+ ['.']
82
+ end
83
+
84
+ def run(paths)
42
85
  status = lint(paths)
43
86
 
44
87
  case status
@@ -54,57 +97,62 @@ module Guard
54
97
  # @param paths [Array<String>]
55
98
  # @return [Integer, nil] the exit status, or nil if slim-lint never ran
56
99
  def lint(paths)
57
- system('slim-lint', *paths)
100
+ system('slim-lint', *cli_args, *paths)
58
101
  $CHILD_STATUS&.exitstatus
59
102
  end
60
103
 
104
+ def cli_args
105
+ case cli
106
+ when Array then cli.map(&:to_s)
107
+ when String then cli.shellsplit
108
+ else []
109
+ end
110
+ end
111
+
61
112
  def report_success
62
- UI.info 'No Slim offences detected'.green
63
- check_and_notify(true)
113
+ Compat::UI.info(Compat::UI.color('No Slim offences detected', :green))
114
+ finish(true, 'No slim offences')
64
115
  end
65
116
 
66
117
  def report_offences
67
- UI.info 'Slim offences have been detected'.red
68
- check_and_notify(false)
69
- throw :task_has_failed
118
+ Compat::UI.info(Compat::UI.color('Slim offences have been detected', :red))
119
+ finish(false, 'Slim offences detected')
70
120
  end
71
121
 
72
122
  def report_error(status)
73
123
  message = error_message(status)
74
- UI.error message
75
- check_and_notify(false, message)
76
- throw :task_has_failed
124
+ Compat::UI.error(message)
125
+ finish(false, message)
77
126
  end
78
127
 
79
128
  def error_message(status)
80
129
  return 'slim-lint could not be run' if status.nil?
81
130
 
82
- "slim-lint exited with status #{status}"
131
+ message = "slim-lint exited with status #{status}"
132
+ hint = STATUS_HINTS[status]
133
+ hint ? "#{message}: #{hint}" : message
134
+ end
135
+
136
+ # Notifies if the configured mode calls for it, records the outcome so
137
+ # :change can compare against it next time, then hands back to Guard.
138
+ def finish(success, message)
139
+ notify(success, message) if notification_allowed?(success)
140
+ @last_success = success
141
+ throw :task_has_failed if halt_on_fail && !success
83
142
  end
84
143
 
85
- def notification_allowed?(result)
144
+ def notification_allowed?(success)
86
145
  case notify_on
87
- when :failure then !result
88
- when :success then result
146
+ when :change then success != @last_success
147
+ when :failure then !success
148
+ when :success then success
89
149
  when :both then true
90
150
  else false
91
151
  end
92
152
  end
93
153
 
94
- def check_and_notify(result, message = default_message(result))
95
- notify(result, message) if notification_allowed?(result)
96
- end
97
-
98
- def image(result)
99
- result ? :success : :failed
100
- end
101
-
102
- def default_message(result)
103
- result ? 'No slim offences' : 'Slim offences detected'
104
- end
105
-
106
- def notify(result, message = default_message(result))
107
- Notifier.notify(message, title: 'Slim-lint results', image: image(result))
154
+ def notify(success, message)
155
+ Compat::UI.notify(message, title: 'Slim-lint results', image: success ? :success : :failed)
108
156
  end
109
157
  end
110
158
  end
metadata CHANGED
@@ -1,35 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: guard-slimlint
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Gajowiak
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-09-04 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: colorize
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0.8'
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '2.0'
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: '0.8'
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '2.0'
33
12
  - !ruby/object:Gem::Dependency
34
13
  name: guard
35
14
  requirement: !ruby/object:Gem::Requirement
@@ -171,7 +150,6 @@ metadata:
171
150
  changelog_uri: https://github.com/mike927/guard-slimlint/blob/master/CHANGELOG.md
172
151
  bug_tracker_uri: https://github.com/mike927/guard-slimlint/issues
173
152
  rubygems_mfa_required: 'true'
174
- post_install_message:
175
153
  rdoc_options: []
176
154
  require_paths:
177
155
  - lib
@@ -179,15 +157,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
179
157
  requirements:
180
158
  - - ">="
181
159
  - !ruby/object:Gem::Version
182
- version: '3.1'
160
+ version: '3.3'
183
161
  required_rubygems_version: !ruby/object:Gem::Requirement
184
162
  requirements:
185
163
  - - ">="
186
164
  - !ruby/object:Gem::Version
187
165
  version: '0'
188
166
  requirements: []
189
- rubygems_version: 3.4.10
190
- signing_key:
167
+ rubygems_version: 3.6.9
191
168
  specification_version: 4
192
169
  summary: Guard plugin that runs slim-lint automatically
193
170
  test_files: []