syntax_tree 2.3.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5855cfed255d36a243d697083688e553ae02aa5373ec08af6bc730eea66ab995
4
- data.tar.gz: 15da5f28c3cff6953eb1204abbd42ac22b2c5ea78546242f543034360b39fb62
3
+ metadata.gz: '0804ba6e87e03ec83616511679283c17dc5c6250c5718c9e25aa218117abc2a1'
4
+ data.tar.gz: 485b0e850086f9b3cc949af3308edbd9f6a75b9ae0c13dda56a1eaf9847d2a28
5
5
  SHA512:
6
- metadata.gz: 49bd5ad54611d46c9379e98f53c0ae789949d5104b225af51a54e7d4780e274a9a9bbcff1322c5af641dadd4c5d8d633b94b1271436ef1767bd9eb869dcb6be5
7
- data.tar.gz: 12cd7e5be2218aeaf9a0833dd95ce40be9d2ee248933962e3f24e854ab5335dd25b2a86b9f6ecb2c6a7e24759dcf316a9db0e8aca8841a5365e6c8030882ac76
6
+ metadata.gz: f85fd10aec38d5d66f77359620ee37ad8b3494546763d96effc5ff0395a2bfdaacb3ade3698238d09201955a6e452a6b8ee52b575c9d17b00ca6fda17dfdbc79
7
+ data.tar.gz: 61faf8fc45245d9795717aa9a54c7bb4ccd2bc197facf0f8c9eeb9e55ce5dd04ddea63697d4e1c1cd7cf2663361ba8a078bf664f9407349860840958ce7d3c17
@@ -24,9 +24,28 @@ jobs:
24
24
  ruby-version: ${{ matrix.ruby }}
25
25
  - name: Test
26
26
  run: bundle exec rake test
27
+
28
+ check:
29
+ name: Check
30
+ runs-on: ubuntu-latest
31
+ env:
32
+ CI: true
33
+ steps:
34
+ - uses: actions/checkout@master
35
+ - uses: ruby/setup-ruby@v1
36
+ with:
37
+ bundler-cache: true
38
+ ruby-version: '3.1'
39
+ - name: Check
40
+ run: |
41
+ bundle exec rake check
42
+ bundle exec rubocop
43
+
27
44
  automerge:
28
45
  name: AutoMerge
29
- needs: ci
46
+ needs:
47
+ - ci
48
+ - check
30
49
  runs-on: ubuntu-latest
31
50
  if: github.event_name == 'pull_request_target' && github.actor == 'dependabot[bot]'
32
51
  steps:
data/.rubocop.yml ADDED
@@ -0,0 +1,80 @@
1
+ inherit_from: config/rubocop.yml
2
+
3
+ AllCops:
4
+ DisplayCopNames: true
5
+ DisplayStyleGuide: true
6
+ NewCops: enable
7
+ SuggestExtensions: false
8
+ TargetRubyVersion: 2.7
9
+ Exclude:
10
+ - '{bin,coverage,pkg,test/fixtures,vendor,tmp}/**/*'
11
+ - test.rb
12
+
13
+ Layout/LineLength:
14
+ Max: 80
15
+
16
+ Lint/DuplicateBranch:
17
+ Enabled: false
18
+
19
+ Lint/EmptyBlock:
20
+ Enabled: false
21
+
22
+ Lint/InterpolationCheck:
23
+ Enabled: false
24
+
25
+ Lint/MissingSuper:
26
+ Enabled: false
27
+
28
+ Lint/UnusedMethodArgument:
29
+ AllowUnusedKeywordArguments: true
30
+
31
+ Metrics:
32
+ Enabled: false
33
+
34
+ Naming/MethodName:
35
+ Enabled: false
36
+
37
+ Naming/MethodParameterName:
38
+ Enabled: false
39
+
40
+ Naming/RescuedExceptionsVariableName:
41
+ PreferredName: error
42
+
43
+ Style/ExplicitBlockArgument:
44
+ Enabled: false
45
+
46
+ Style/FormatString:
47
+ EnforcedStyle: percent
48
+
49
+ Style/GuardClause:
50
+ Enabled: false
51
+
52
+ Style/IdenticalConditionalBranches:
53
+ Enabled: false
54
+
55
+ Style/IfInsideElse:
56
+ Enabled: false
57
+
58
+ Style/KeywordParametersOrder:
59
+ Enabled: false
60
+
61
+ Style/MissingRespondToMissing:
62
+ Enabled: false
63
+
64
+ Style/MutableConstant:
65
+ Enabled: false
66
+
67
+ Style/NegatedIfElseCondition:
68
+ Enabled: false
69
+
70
+ Style/NumericPredicate:
71
+ Enabled: false
72
+
73
+ Style/ParallelAssignment:
74
+ Enabled: false
75
+
76
+ Style/PerlBackrefs:
77
+ Enabled: false
78
+
79
+ Style/SpecialGlobalVars:
80
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.4.0] - 2022-05-07
10
+
11
+ ### Added
12
+
13
+ - [#65](https://github.com/ruby-syntax-tree/syntax_tree/pull/65) - Add a rubocop config at `config/rubocop.yml` that we can ship with the gem so folks can inherit from it to get their styling correct.
14
+ - [#65](https://github.com/ruby-syntax-tree/syntax_tree/pull/65) - Improve hash pattern formatting by a lot - multiple lines are now not so ugly.
15
+ - [#62](https://github.com/ruby-syntax-tree/syntax_tree/issues/62) - Add `options` as a method on `SyntaxTree::RegexpLiteral`, add it to pattern matching, and describe it using the `SyntaxTree::Visitor::FieldVisitor` class.
16
+ - [#69](https://github.com/ruby-syntax-tree/syntax_tree/pull/69) - The `construct_keys` option has been added to every `SyntaxTree::Node` descendant. This allows building a pattern match expression that can be used later. It is meant as a reflection API, not necessarily something that should be eval'd.
17
+ - [#69](https://github.com/ruby-syntax-tree/syntax_tree/pull/69) - You can now call `stree json` to get a JSON representation of your syntax tree.
18
+ - [#69](https://github.com/ruby-syntax-tree/syntax_tree/pull/69) - You can now call `stree match` to get a Ruby pattern matching expression to match against the given input.
19
+
20
+ ### Changed
21
+
22
+ - [#69](https://github.com/ruby-syntax-tree/syntax_tree/pull/69) - Fixed a long-standing bug with pretty-print where if certain things were required in different orders you could end up with a bug in `PP` when calling pretty-print with a confusing error referring to inspect keys.
23
+ - [#69](https://github.com/ruby-syntax-tree/syntax_tree/pull/69) - `SyntaxTree.read` can now handle an empty file.
24
+
9
25
  ## [2.3.1] - 2022-04-22
10
26
 
11
27
  ### Changed
@@ -193,7 +209,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
193
209
 
194
210
  - 🎉 Initial release! 🎉
195
211
 
196
- [unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.3.0...HEAD
212
+ [unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.4.0...HEAD
213
+ [2.4.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.3.1...v2.4.0
214
+ [2.3.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.3.0...v2.3.1
197
215
  [2.3.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.2.0...v2.3.0
198
216
  [2.2.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.1.1...v2.2.0
199
217
  [2.1.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.1.0...v2.1.1
data/Gemfile CHANGED
@@ -3,3 +3,5 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
+
7
+ gem "rubocop"
data/Gemfile.lock CHANGED
@@ -1,20 +1,40 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- syntax_tree (2.3.1)
4
+ syntax_tree (2.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ ast (2.4.2)
9
10
  docile (1.4.0)
10
11
  minitest (5.15.0)
12
+ parallel (1.22.1)
13
+ parser (3.1.2.0)
14
+ ast (~> 2.4.1)
15
+ rainbow (3.1.1)
11
16
  rake (13.0.6)
17
+ regexp_parser (2.3.1)
18
+ rexml (3.2.5)
19
+ rubocop (1.29.0)
20
+ parallel (~> 1.10)
21
+ parser (>= 3.1.0.0)
22
+ rainbow (>= 2.2.2, < 4.0)
23
+ regexp_parser (>= 1.8, < 3.0)
24
+ rexml (>= 3.2.5, < 4.0)
25
+ rubocop-ast (>= 1.17.0, < 2.0)
26
+ ruby-progressbar (~> 1.7)
27
+ unicode-display_width (>= 1.4.0, < 3.0)
28
+ rubocop-ast (1.17.0)
29
+ parser (>= 3.1.1.0)
30
+ ruby-progressbar (1.11.0)
12
31
  simplecov (0.21.2)
13
32
  docile (~> 1.1)
14
33
  simplecov-html (~> 0.11)
15
34
  simplecov_json_formatter (~> 0.1)
16
35
  simplecov-html (0.12.3)
17
36
  simplecov_json_formatter (0.1.4)
37
+ unicode-display_width (2.1.0)
18
38
 
19
39
  PLATFORMS
20
40
  arm64-darwin-21
@@ -27,6 +47,7 @@ DEPENDENCIES
27
47
  bundler
28
48
  minitest
29
49
  rake
50
+ rubocop
30
51
  simplecov
31
52
  syntax_tree!
32
53
 
data/README.md CHANGED
@@ -16,6 +16,8 @@ It is built with only standard library dependencies. It additionally ships with
16
16
  - [ast](#ast)
17
17
  - [check](#check)
18
18
  - [format](#format)
19
+ - [json](#json)
20
+ - [match](#match)
19
21
  - [write](#write)
20
22
  - [Library](#library)
21
23
  - [SyntaxTree.read(filepath)](#syntaxtreereadfilepath)
@@ -27,6 +29,7 @@ It is built with only standard library dependencies. It additionally ships with
27
29
  - [pretty_print(q)](#pretty_printq)
28
30
  - [to_json(*opts)](#to_jsonopts)
29
31
  - [format(q)](#formatq)
32
+ - [construct_keys](#construct_keys)
30
33
  - [Visitor](#visitor)
31
34
  - [visit_method](#visit_method)
32
35
  - [Language server](#language-server)
@@ -34,6 +37,9 @@ It is built with only standard library dependencies. It additionally ships with
34
37
  - [textDocument/inlayHints](#textdocumentinlayhints)
35
38
  - [syntaxTree/visualizing](#syntaxtreevisualizing)
36
39
  - [Plugins](#plugins)
40
+ - [Integration](#integration)
41
+ - [RuboCop](#rubocop)
42
+ - [VSCode](#vscode)
37
43
  - [Contributing](#contributing)
38
44
  - [License](#license)
39
45
 
@@ -122,6 +128,73 @@ For a file that contains `1 + 1`, you will receive:
122
128
  1 + 1
123
129
  ```
124
130
 
131
+ ### json
132
+
133
+ This command will output a JSON representation of the syntax tree that is functionally equivalent to the input. This is mostly used in contexts where you need to access the tree from JavaScript or serialize it over a network.
134
+
135
+ ```sh
136
+ stree json path/to/file.rb
137
+ ```
138
+
139
+ For a file that contains `1 + 1`, you will receive:
140
+
141
+ ```json
142
+ {
143
+ "type": "program",
144
+ "location": [1, 0, 1, 6],
145
+ "statements": {
146
+ "type": "statements",
147
+ "location": [1, 0, 1, 6],
148
+ "body": [
149
+ {
150
+ "type": "binary",
151
+ "location": [1, 0, 1, 5],
152
+ "left": {
153
+ "type": "int",
154
+ "location": [1, 0, 1, 1],
155
+ "value": "1",
156
+ "comments": []
157
+ },
158
+ "operator": "+",
159
+ "right": {
160
+ "type": "int",
161
+ "location": [1, 4, 1, 5],
162
+ "value": "1",
163
+ "comments": []
164
+ },
165
+ "comments": []
166
+ }
167
+ ],
168
+ "comments": []
169
+ },
170
+ "comments": []
171
+ }
172
+ ```
173
+
174
+ ### match
175
+
176
+ This command will output a Ruby case-match expression that would match correctly against the input.
177
+
178
+ ```sh
179
+ stree match path/to/file.rb
180
+ ```
181
+
182
+ For a file that contains `1 + 1`, you will receive:
183
+
184
+ ```ruby
185
+ SyntaxTree::Program[
186
+ statements: SyntaxTree::Statements[
187
+ body: [
188
+ SyntaxTree::Binary[
189
+ left: SyntaxTree::Int[value: "1"],
190
+ operator: :+,
191
+ right: SyntaxTree::Int[value: "1"]
192
+ ]
193
+ ]
194
+ ]
195
+ ]
196
+ ```
197
+
125
198
  ### write
126
199
 
127
200
  This command will format the listed files and write that formatted version back to the source files. Note that this overwrites the original content, to be sure to be using a version control system.
@@ -223,6 +296,27 @@ formatter.output.join
223
296
  # => "1 + 1"
224
297
  ```
225
298
 
299
+ ### construct_keys
300
+
301
+ Every node responds to `construct_keys`, which will return a string that contains a Ruby pattern-matching expression that could be used to match against the current node. It's meant to be used in tooling and through the CLI mostly.
302
+
303
+ ```ruby
304
+ program = SyntaxTree.parse("1 + 1")
305
+ puts program.construct_keys
306
+
307
+ # SyntaxTree::Program[
308
+ # statements: SyntaxTree::Statements[
309
+ # body: [
310
+ # SyntaxTree::Binary[
311
+ # left: SyntaxTree::Int[value: "1"],
312
+ # operator: :+,
313
+ # right: SyntaxTree::Int[value: "1"]
314
+ # ]
315
+ # ]
316
+ # ]
317
+ # ]
318
+ ```
319
+
226
320
  ## Visitor
227
321
 
228
322
  If you want to operate over a set of nodes in the tree but don't want to walk the tree manually, the `Visitor` class makes it easy. `SyntaxTree::Visitor` is an implementation of the double dispatch visitor pattern. It works by the user defining visit methods that process nodes in the tree, which then call back to other visit methods to continue the descent. This is easier shown in code.
@@ -328,6 +422,25 @@ Below are listed all of the "official" plugins hosted under the same GitHub orga
328
422
  * [SyntaxTree::JSON](https://github.com/ruby-syntax-tree/syntax_tree-json) for JSON.
329
423
  * [SyntaxTree::RBS](https://github.com/ruby-syntax-tree/syntax_tree-rbs) for the [RBS type language](https://github.com/ruby/rbs).
330
424
 
425
+ When invoking the CLI, you pass through the list of plugins with the `--plugins` options to the commands that accept them. They should be a comma-delimited list. When the CLI first starts, it will require the files corresponding to those names.
426
+
427
+ ## Integration
428
+
429
+ Syntax Tree's goal is to seemlessly integrate into your workflow. To this end, it provides a couple of additional tools beyond the CLI and the Ruby library.
430
+
431
+ ### RuboCop
432
+
433
+ RuboCop and Syntax Tree serve different purposes, but there is overlap with some of RuboCop's functionality. Syntax Tree provides a RuboCop configuration file to disable rules that are redundant with Syntax Tree. To use this configuration file, add the following snippet to the top of your project's `.rubocop.yml`:
434
+
435
+ ```yaml
436
+ inherit_gem:
437
+ syntax_tree: config/rubocop.yml
438
+ ```
439
+
440
+ ### VSCode
441
+
442
+ To integrate Syntax Tree into VSCode, you should use the official VSCode extension [ruby-syntax-tree/vscode-syntax-tree](https://github.com/ruby-syntax-tree/vscode-syntax-tree).
443
+
331
444
  ## Contributing
332
445
 
333
446
  Bug reports and pull requests are welcome on GitHub at https://github.com/ruby-syntax-tree/syntax_tree.
data/Rakefile CHANGED
@@ -1,12 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/gem_tasks'
4
- require 'rake/testtask'
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
5
 
6
6
  Rake::TestTask.new(:test) do |t|
7
- t.libs << 'test'
8
- t.libs << 'lib'
9
- t.test_files = FileList['test/**/*_test.rb']
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
10
  end
11
11
 
12
12
  task default: :test
13
+
14
+ FILEPATHS = %w[
15
+ Gemfile
16
+ Rakefile
17
+ syntax_tree.gemspec
18
+ lib/**/*.rb
19
+ test/*.rb
20
+ ].freeze
21
+
22
+ task :syntax_tree do
23
+ $:.unshift File.expand_path("lib", __dir__)
24
+ require "syntax_tree"
25
+ require "syntax_tree/cli"
26
+ end
27
+
28
+ task check: :syntax_tree do
29
+ exit SyntaxTree::CLI.run(["check"] + FILEPATHS)
30
+ end
31
+
32
+ task format: :syntax_tree do
33
+ exit SyntaxTree::CLI.run(["write"] + FILEPATHS)
34
+ end
@@ -0,0 +1,64 @@
1
+ # Disabling all Layout/* rules, as they're unnecessary when the user is using
2
+ # Syntax Tree to handle all of the formatting.
3
+ Layout:
4
+ Enabled: false
5
+
6
+ # Re-enable Layout/LineLength because certain cops that most projects use
7
+ # (e.g. Style/IfUnlessModifier) require Layout/LineLength to be enabled.
8
+ # By leaving it disabled, those rules will mis-fire.
9
+ #
10
+ # Users can always override these defaults in their own rubocop.yml files.
11
+ # https://github.com/prettier/plugin-ruby/issues/825
12
+ Layout/LineLength:
13
+ Enabled: true
14
+
15
+ Style/MultilineIfModifier:
16
+ Enabled: false
17
+
18
+ # Syntax Tree will expand empty methods to put the end keyword on the subsequent
19
+ # line to reduce git diff noise.
20
+ Style/EmptyMethod:
21
+ EnforcedStyle: expanded
22
+
23
+ # lambdas that are constructed with the lambda method call cannot be safely
24
+ # turned into lambda literals without removing a method call.
25
+ Style/Lambda:
26
+ Enabled: false
27
+
28
+ # When method chains with multiple blocks are chained together, rubocop will let
29
+ # them pass if they're using braces but not if they're using do and end
30
+ # keywords. Because we will break individual blocks down to using keywords if
31
+ # they are multiline, this conflicts with rubocop.
32
+ Style/MultilineBlockChain:
33
+ Enabled: false
34
+
35
+ # Syntax Tree by default uses double quotes, so changing the configuration here
36
+ # to match that.
37
+ Style/StringLiterals:
38
+ EnforcedStyle: double_quotes
39
+
40
+ Style/StringLiteralsInInterpolation:
41
+ EnforcedStyle: double_quotes
42
+
43
+ Style/QuotedSymbols:
44
+ EnforcedStyle: double_quotes
45
+
46
+ # We let users have a little more freedom with symbol and words arrays. If the
47
+ # user only has an individual item like ["value"] then we don't bother
48
+ # converting it because it ends up being just noise.
49
+ Style/SymbolArray:
50
+ Enabled: false
51
+
52
+ Style/WordArray:
53
+ Enabled: false
54
+
55
+ # We don't support trailing commas in Syntax Tree by default, so just turning
56
+ # these off for now.
57
+ Style/TrailingCommaInArguments:
58
+ Enabled: false
59
+
60
+ Style/TrailingCommaInArrayLiteral:
61
+ Enabled: false
62
+
63
+ Style/TrailingCommaInHashLiteral:
64
+ Enabled: false
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SyntaxTree
4
+ # Syntax Tree ships with the `stree` CLI, which can be used to inspect and
5
+ # manipulate Ruby code. This module is responsible for powering that CLI.
4
6
  module CLI
5
7
  # A utility wrapper around colored strings in the output.
6
8
  class Color
@@ -46,7 +48,7 @@ module SyntaxTree
46
48
 
47
49
  # An action of the CLI that prints out the AST for the given source.
48
50
  class AST < Action
49
- def run(handler, filepath, source)
51
+ def run(handler, _filepath, source)
50
52
  pp handler.parse(source)
51
53
  end
52
54
  end
@@ -83,9 +85,7 @@ module SyntaxTree
83
85
  warning = "[#{Color.yellow("warn")}] #{filepath}"
84
86
  formatted = handler.format(source)
85
87
 
86
- if formatted != handler.format(formatted)
87
- raise NonIdempotentFormatError
88
- end
88
+ raise NonIdempotentFormatError if formatted != handler.format(formatted)
89
89
  rescue StandardError
90
90
  warn(warning)
91
91
  raise
@@ -102,8 +102,8 @@ module SyntaxTree
102
102
 
103
103
  # An action of the CLI that prints out the doc tree IR for the given source.
104
104
  class Doc < Action
105
- def run(handler, filepath, source)
106
- formatter = Formatter.new([])
105
+ def run(handler, _filepath, source)
106
+ formatter = Formatter.new(source, [])
107
107
  handler.parse(source).format(formatter)
108
108
  pp formatter.groups.first
109
109
  end
@@ -111,11 +111,28 @@ module SyntaxTree
111
111
 
112
112
  # An action of the CLI that formats the input source and prints it out.
113
113
  class Format < Action
114
- def run(handler, filepath, source)
114
+ def run(handler, _filepath, source)
115
115
  puts handler.format(source)
116
116
  end
117
117
  end
118
118
 
119
+ # An action of the CLI that converts the source into its equivalent JSON
120
+ # representation.
121
+ class Json < Action
122
+ def run(handler, _filepath, source)
123
+ object = Visitor::JSONVisitor.new.visit(handler.parse(source))
124
+ puts JSON.pretty_generate(object)
125
+ end
126
+ end
127
+
128
+ # An action of the CLI that outputs a pattern-matching Ruby expression that
129
+ # would match the input given.
130
+ class Match < Action
131
+ def run(handler, _filepath, source)
132
+ puts handler.parse(source).construct_keys
133
+ end
134
+ end
135
+
119
136
  # An action of the CLI that formats the input source and writes the
120
137
  # formatted output back to the file.
121
138
  class Write < Action
@@ -154,6 +171,12 @@ module SyntaxTree
154
171
  #{Color.bold("stree format [OPTIONS] [FILE]")}
155
172
  Print out the formatted version of the given files
156
173
 
174
+ #{Color.bold("stree json [OPTIONS] [FILE]")}
175
+ Print out the JSON representation of the given files
176
+
177
+ #{Color.bold("stree match [OPTIONS] [FILE]")}
178
+ Print out a pattern-matching Ruby expression that would match the given files
179
+
157
180
  #{Color.bold("stree help")}
158
181
  Display this help message
159
182
 
@@ -201,6 +224,10 @@ module SyntaxTree
201
224
  Debug.new
202
225
  when "doc"
203
226
  Doc.new
227
+ when "j", "json"
228
+ Json.new
229
+ when "m", "match"
230
+ Match.new
204
231
  when "f", "format"
205
232
  Format.new
206
233
  when "w", "write"
@@ -212,7 +239,7 @@ module SyntaxTree
212
239
 
213
240
  # If we're not reading from stdin and the user didn't supply and
214
241
  # filepaths to be read, then we exit with the usage message.
215
- if STDIN.tty? && arguments.empty?
242
+ if $stdin.tty? && arguments.empty?
216
243
  warn(HELP)
217
244
  return 1
218
245
  end
@@ -239,18 +266,11 @@ module SyntaxTree
239
266
  action.run(handler, filepath, source)
240
267
  rescue Parser::ParseError => error
241
268
  warn("Error: #{error.message}")
242
-
243
- if error.lineno
244
- highlight_error(error, source)
245
- else
246
- warn(error.message)
247
- warn(error.backtrace)
248
- end
249
-
269
+ highlight_error(error, source)
250
270
  errored = true
251
271
  rescue Check::UnformattedError, Debug::NonIdempotentFormatError
252
272
  errored = true
253
- rescue => error
273
+ rescue StandardError => error
254
274
  warn(error.message)
255
275
  warn(error.backtrace)
256
276
  errored = true
@@ -268,18 +288,20 @@ module SyntaxTree
268
288
  private
269
289
 
270
290
  def each_file(arguments)
271
- if STDIN.tty?
291
+ if $stdin.tty? || arguments.any?
272
292
  arguments.each do |pattern|
273
- Dir.glob(pattern).each do |filepath|
274
- next unless File.file?(filepath)
275
-
276
- handler = HANDLERS[File.extname(filepath)]
277
- source = handler.read(filepath)
278
- yield handler, filepath, source
279
- end
293
+ Dir
294
+ .glob(pattern)
295
+ .each do |filepath|
296
+ next unless File.file?(filepath)
297
+
298
+ handler = HANDLERS[File.extname(filepath)]
299
+ source = handler.read(filepath)
300
+ yield handler, filepath, source
301
+ end
280
302
  end
281
303
  else
282
- yield HANDLERS[".rb"], :stdin, STDIN.read
304
+ yield HANDLERS[".rb"], :stdin, $stdin.read
283
305
  end
284
306
  end
285
307
 
@@ -310,7 +332,21 @@ module SyntaxTree
310
332
  # Take a line of Ruby source and colorize the output.
311
333
  def colorize_line(line)
312
334
  require "irb"
313
- IRB::Color.colorize_code(line, complete: false, ignore_error: true)
335
+ IRB::Color.colorize_code(line, **colorize_options)
336
+ end
337
+
338
+ # These are the options we're going to pass into IRB::Color.colorize_code.
339
+ # Since we support multiple versions of IRB, we're going to need to do
340
+ # some reflection to make sure we always pass valid options.
341
+ def colorize_options
342
+ options = { complete: false }
343
+
344
+ parameters = IRB::Color.method(:colorize_code).parameters
345
+ if parameters.any? { |(_type, name)| name == :ignore_error }
346
+ options[:ignore_error] = true
347
+ end
348
+
349
+ options
314
350
  end
315
351
  end
316
352
  end
@@ -41,11 +41,12 @@ module SyntaxTree
41
41
 
42
42
  # If the node has a stree-ignore comment right before it, then we're
43
43
  # going to just print out the node as it was seen in the source.
44
- if leading.last&.ignore?
45
- doc = text(source[node.location.start_char...node.location.end_char])
46
- else
47
- doc = node.format(self)
48
- end
44
+ doc =
45
+ if leading.last&.ignore?
46
+ text(source[node.location.start_char...node.location.end_char])
47
+ else
48
+ node.format(self)
49
+ end
49
50
 
50
51
  # Print all comments that were found after the node.
51
52
  trailing.each do |comment|