syntax_tree 3.4.0 → 3.5.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: 52707e3169fedfce017259222e4740b2e1032d210dfb628d454134eef578a7b6
4
- data.tar.gz: aed3d5b3e6de7ed1e156c5b104007db6a01dab65e0ee80913afa2c1b5c63a5c0
3
+ metadata.gz: f4410889ecf31d320edb7e45b5491c97ec1af42f782e486cf946cad4672ee5cd
4
+ data.tar.gz: c81d09784f746b0b115af55409196a640d17d972a91e7d116a45b9b69bcb7c14
5
5
  SHA512:
6
- metadata.gz: b81b4753a5e765712bd31081dedca6e50c67d04a7935a717fc56d278424154e6ed95b648ac1cbdd59b500ee44c2d8d89f57f52e3851f9615e378d8c9c2c6abe1
7
- data.tar.gz: 32c95446f19190b8e73d9c3ce83ff4bd5573f5787f844cf695551a2d32c0c159af8c514714c4648a99be4e66189910bde7f01557ea973f6e17aaba66ace7fce2
6
+ metadata.gz: 1c6badd15f529d426d771679f3e8ebbd690a705f66027caa6510bf01c2788b3968fd1c3523bfa3534d3dd048604b968c8c01059e5a2c6d2148130aebd77d8530
7
+ data.tar.gz: e4567e0f5259ceb1b840f4c10c50fac526e972932e22340a5456fc1f394872c04b5f5651b63859bff40fc4e40da19e9040db6c51a70b6beb27559fcbe1597987
@@ -0,0 +1,22 @@
1
+ name: Dependabot auto-merge
2
+ on: pull_request
3
+
4
+ permissions:
5
+ contents: write
6
+ pull-requests: write
7
+
8
+ jobs:
9
+ dependabot:
10
+ runs-on: ubuntu-latest
11
+ if: ${{ github.actor == 'dependabot[bot]' }}
12
+ steps:
13
+ - name: Dependabot metadata
14
+ id: metadata
15
+ uses: dependabot/fetch-metadata@v1.3.3
16
+ with:
17
+ github-token: "${{ secrets.GITHUB_TOKEN }}"
18
+ - name: Enable auto-merge for Dependabot PRs
19
+ run: gh pr merge --auto --merge "$PR_URL"
20
+ env:
21
+ PR_URL: ${{github.event.pull_request.html_url}}
22
+ GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
@@ -1,14 +1,14 @@
1
1
  name: Main
2
2
  on:
3
3
  - push
4
- - pull_request_target
4
+ - pull_request
5
5
  jobs:
6
6
  ci:
7
7
  strategy:
8
8
  fail-fast: false
9
9
  matrix:
10
10
  ruby:
11
- - '2.7'
11
+ - '2.7.0'
12
12
  - '3.0'
13
13
  - '3.1'
14
14
  - head
@@ -40,20 +40,3 @@ jobs:
40
40
  run: |
41
41
  bundle exec rake stree:check
42
42
  bundle exec rubocop
43
-
44
- automerge:
45
- name: AutoMerge
46
- needs:
47
- - ci
48
- - check
49
- runs-on: ubuntu-latest
50
- if: github.event_name == 'pull_request_target' && github.actor == 'dependabot[bot]'
51
- steps:
52
- - uses: actions/github-script@v3
53
- with:
54
- script: |
55
- github.pulls.merge({
56
- owner: context.payload.repository.owner.login,
57
- repo: context.payload.repository.name,
58
- pull_number: context.payload.pull_request.number
59
- })
data/CHANGELOG.md CHANGED
@@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.5.0] - 2022-08-26
10
+
11
+ ### Added
12
+
13
+ - [#148](https://github.com/ruby-syntax-tree/syntax_tree/pull/148) - Support Ruby 2.7.0 (previously we only supported back to 2.7.3).
14
+ - [#152](https://github.com/ruby-syntax-tree/syntax_tree/pull/152) - Support the `-e` inline script option for the `stree` CLI.
15
+
16
+ ### Changed
17
+
18
+ - [#141](https://github.com/ruby-syntax-tree/syntax_tree/pull/141) - Use `q.format` for `SyntaxTree.format` so that the main node gets pushed onto the stack for checking parent nodes.
19
+ - [#147](https://github.com/ruby-syntax-tree/syntax_tree/pull/147) - Fix rightward assignment token management such that `in` and `=>` stay the same regardless of their context.
20
+
9
21
  ## [3.4.0] - 2022-08-19
10
22
 
11
23
  ### Added
@@ -332,7 +344,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
332
344
 
333
345
  - 🎉 Initial release! 🎉
334
346
 
335
- [unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v3.4.0...HEAD
347
+ [unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v3.5.0...HEAD
348
+ [3.5.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v3.4.0...v3.5.0
336
349
  [3.4.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v3.3.0...v3.4.0
337
350
  [3.3.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v3.2.1...v3.3.0
338
351
  [3.2.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v3.2.0...v3.2.1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- syntax_tree (3.4.0)
4
+ syntax_tree (3.5.0)
5
5
  prettier_print
6
6
 
7
7
  GEM
@@ -10,7 +10,7 @@ GEM
10
10
  ast (2.4.2)
11
11
  docile (1.4.0)
12
12
  json (2.6.2)
13
- minitest (5.16.2)
13
+ minitest (5.16.3)
14
14
  parallel (1.22.1)
15
15
  parser (3.1.2.1)
16
16
  ast (~> 2.4.1)
@@ -19,7 +19,7 @@ GEM
19
19
  rake (13.0.6)
20
20
  regexp_parser (2.5.0)
21
21
  rexml (3.2.5)
22
- rubocop (1.35.0)
22
+ rubocop (1.35.1)
23
23
  json (~> 2.3)
24
24
  parallel (~> 1.10)
25
25
  parser (>= 3.1.2.1)
data/Rakefile CHANGED
@@ -12,8 +12,17 @@ end
12
12
 
13
13
  task default: :test
14
14
 
15
- SOURCE_FILES =
16
- FileList[%w[Gemfile Rakefile syntax_tree.gemspec lib/**/*.rb test/*.rb]]
15
+ configure = ->(task) do
16
+ task.source_files =
17
+ FileList[%w[Gemfile Rakefile syntax_tree.gemspec lib/**/*.rb test/*.rb]]
17
18
 
18
- SyntaxTree::Rake::CheckTask.new { |t| t.source_files = SOURCE_FILES }
19
- SyntaxTree::Rake::WriteTask.new { |t| t.source_files = SOURCE_FILES }
19
+ # Since Syntax Tree supports back to Ruby 2.7.0, we need to make sure that we
20
+ # format our code such that it's compatible with that version. This actually
21
+ # has very little effect on the output, the only change at the moment is that
22
+ # Ruby < 2.7.3 didn't allow a newline before the closing brace of a hash
23
+ # pattern.
24
+ task.target_ruby_version = Gem::Version.new("2.7.0")
25
+ end
26
+
27
+ SyntaxTree::Rake::CheckTask.new(&configure)
28
+ SyntaxTree::Rake::WriteTask.new(&configure)
@@ -53,18 +53,23 @@ module SyntaxTree
53
53
  end
54
54
  end
55
55
 
56
- # An item of work that corresponds to the stdin content.
57
- class STDINItem
56
+ # An item of work that corresponds to a script content passed via the
57
+ # command line.
58
+ class ScriptItem
59
+ FILEPATH = :script
60
+
61
+ attr_reader :source
62
+
63
+ def initialize(source)
64
+ @source = source
65
+ end
66
+
58
67
  def handler
59
68
  HANDLERS[".rb"]
60
69
  end
61
70
 
62
71
  def filepath
63
- :stdin
64
- end
65
-
66
- def source
67
- $stdin.read
72
+ FILEPATH
68
73
  end
69
74
  end
70
75
 
@@ -191,7 +196,7 @@ module SyntaxTree
191
196
 
192
197
  source = item.source
193
198
  formatted = item.handler.format(source, options.print_width)
194
- File.write(filepath, formatted) if filepath != :stdin
199
+ File.write(filepath, formatted) if item.filepath != :script
195
200
 
196
201
  color = source == formatted ? Color.gray(filepath) : filepath
197
202
  delta = ((Time.now - start) * 1000).round
@@ -206,25 +211,25 @@ module SyntaxTree
206
211
  # The help message displayed if the input arguments are not correctly
207
212
  # ordered or formatted.
208
213
  HELP = <<~HELP
209
- #{Color.bold("stree ast [--plugins=...] [--print-width=NUMBER] FILE")}
214
+ #{Color.bold("stree ast [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE")}
210
215
  Print out the AST corresponding to the given files
211
216
 
212
- #{Color.bold("stree check [--plugins=...] [--print-width=NUMBER] FILE")}
217
+ #{Color.bold("stree check [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE")}
213
218
  Check that the given files are formatted as syntax tree would format them
214
219
 
215
- #{Color.bold("stree debug [--plugins=...] [--print-width=NUMBER] FILE")}
220
+ #{Color.bold("stree debug [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE")}
216
221
  Check that the given files can be formatted idempotently
217
222
 
218
- #{Color.bold("stree doc [--plugins=...] FILE")}
223
+ #{Color.bold("stree doc [--plugins=...] [-e SCRIPT] FILE")}
219
224
  Print out the doc tree that would be used to format the given files
220
225
 
221
- #{Color.bold("stree format [--plugins=...] [--print-width=NUMBER] FILE")}
226
+ #{Color.bold("stree format [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE")}
222
227
  Print out the formatted version of the given files
223
228
 
224
- #{Color.bold("stree json [--plugins=...] FILE")}
229
+ #{Color.bold("stree json [--plugins=...] [-e SCRIPT] FILE")}
225
230
  Print out the JSON representation of the given files
226
231
 
227
- #{Color.bold("stree match [--plugins=...] FILE")}
232
+ #{Color.bold("stree match [--plugins=...] [-e SCRIPT] FILE")}
228
233
  Print out a pattern-matching Ruby expression that would match the given files
229
234
 
230
235
  #{Color.bold("stree help")}
@@ -236,7 +241,7 @@ module SyntaxTree
236
241
  #{Color.bold("stree version")}
237
242
  Output the current version of syntax tree
238
243
 
239
- #{Color.bold("stree write [--plugins=...] [--print-width=NUMBER] FILE")}
244
+ #{Color.bold("stree write [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE")}
240
245
  Read, format, and write back the source of the given files
241
246
 
242
247
  --plugins=...
@@ -244,20 +249,30 @@ module SyntaxTree
244
249
 
245
250
  --print-width=NUMBER
246
251
  The maximum line width to use when formatting.
252
+
253
+ -e SCRIPT
254
+ Parse an inline Ruby string.
247
255
  HELP
248
256
 
249
257
  # This represents all of the options that can be passed to the CLI. It is
250
258
  # responsible for parsing the list and then returning the file paths at the
251
259
  # end.
252
260
  class Options
253
- attr_reader :print_width
261
+ attr_reader :plugins, :print_width, :scripts, :target_ruby_version
254
262
 
255
263
  def initialize(print_width: DEFAULT_PRINT_WIDTH)
264
+ @plugins = []
256
265
  @print_width = print_width
266
+ @scripts = []
267
+ @target_ruby_version = nil
257
268
  end
258
269
 
270
+ # TODO: This function causes a couple of side-effects that I really don't
271
+ # like to have here. It mutates the global state by requiring the plugins,
272
+ # and mutates the global options hash by adding the target ruby version.
273
+ # That should be done on a config-by-config basis, not here.
259
274
  def parse(arguments)
260
- parser.parse(arguments)
275
+ parser.parse!(arguments)
261
276
  end
262
277
 
263
278
  private
@@ -275,7 +290,8 @@ module SyntaxTree
275
290
  # require "syntax_tree/haml"
276
291
  #
277
292
  opts.on("--plugins=PLUGINS") do |plugins|
278
- plugins.split(",").each { |plugin| require "syntax_tree/#{plugin}" }
293
+ @plugins = plugins.split(",")
294
+ @plugins.each { |plugin| require "syntax_tree/#{plugin}" }
279
295
  end
280
296
 
281
297
  # If there is a print width specified on the command line, then
@@ -283,6 +299,17 @@ module SyntaxTree
283
299
  opts.on("--print-width=NUMBER", Integer) do |print_width|
284
300
  @print_width = print_width
285
301
  end
302
+
303
+ # If there is a script specified on the command line, then parse
304
+ # it and add it to the list of scripts to run.
305
+ opts.on("-e SCRIPT") { |script| @scripts << script }
306
+
307
+ # If there is a target ruby version specified on the command line,
308
+ # parse that out and use it when formatting.
309
+ opts.on("--target-ruby-version=VERSION") do |version|
310
+ @target_ruby_version = Gem::Version.new(version)
311
+ Formatter::OPTIONS[:target_ruby_version] = @target_ruby_version
312
+ end
286
313
  end
287
314
  end
288
315
  end
@@ -361,7 +388,7 @@ module SyntaxTree
361
388
 
362
389
  # If we're not reading from stdin and the user didn't supply and
363
390
  # filepaths to be read, then we exit with the usage message.
364
- if $stdin.tty? && arguments.empty?
391
+ if $stdin.tty? && arguments.empty? && options.scripts.empty?
365
392
  warn(HELP)
366
393
  return 1
367
394
  end
@@ -371,7 +398,7 @@ module SyntaxTree
371
398
 
372
399
  # If we're reading from stdin, then we'll just add the stdin object to
373
400
  # the queue. Otherwise, we'll add each of the filepaths to the queue.
374
- if $stdin.tty? || arguments.any?
401
+ if $stdin.tty? && (arguments.any? || options.scripts.any?)
375
402
  arguments.each do |pattern|
376
403
  Dir
377
404
  .glob(pattern)
@@ -379,8 +406,9 @@ module SyntaxTree
379
406
  queue << FileItem.new(filepath) if File.file?(filepath)
380
407
  end
381
408
  end
409
+ options.scripts.each { |script| queue << ScriptItem.new(script) }
382
410
  else
383
- queue << STDINItem.new
411
+ queue << ScriptItem.new($stdin.read)
384
412
  end
385
413
 
386
414
  # At the end, we're going to return whether or not this worker ever
@@ -14,7 +14,11 @@ module SyntaxTree
14
14
  # Note that we're keeping this in a global-ish hash instead of just
15
15
  # overriding methods on classes so that other plugins can reference this if
16
16
  # necessary. For example, the RBS plugin references the quote style.
17
- OPTIONS = { quote: "\"", trailing_comma: false }
17
+ OPTIONS = {
18
+ quote: "\"",
19
+ trailing_comma: false,
20
+ target_ruby_version: Gem::Version.new(RUBY_VERSION)
21
+ }
18
22
 
19
23
  COMMENT_PRIORITY = 1
20
24
  HEREDOC_PRIORITY = 2
@@ -23,14 +27,15 @@ module SyntaxTree
23
27
 
24
28
  # These options are overridden in plugins to we need to make sure they are
25
29
  # available here.
26
- attr_reader :quote, :trailing_comma
30
+ attr_reader :quote, :trailing_comma, :target_ruby_version
27
31
  alias trailing_comma? trailing_comma
28
32
 
29
33
  def initialize(
30
34
  source,
31
35
  *args,
32
36
  quote: OPTIONS[:quote],
33
- trailing_comma: OPTIONS[:trailing_comma]
37
+ trailing_comma: OPTIONS[:trailing_comma],
38
+ target_ruby_version: OPTIONS[:target_ruby_version]
34
39
  )
35
40
  super(*args)
36
41
 
@@ -40,13 +45,14 @@ module SyntaxTree
40
45
  # Memoizing these values per formatter to make access faster.
41
46
  @quote = quote
42
47
  @trailing_comma = trailing_comma
48
+ @target_ruby_version = target_ruby_version
43
49
  end
44
50
 
45
51
  def self.format(source, node)
46
- formatter = new(source, [])
47
- node.format(formatter)
48
- formatter.flush
49
- formatter.output.join
52
+ q = new(source, [])
53
+ q.format(node)
54
+ q.flush
55
+ q.output.join
50
56
  end
51
57
 
52
58
  def format(node, stackable: true)
@@ -2132,8 +2132,7 @@ module SyntaxTree
2132
2132
  in [
2133
2133
  Paren[
2134
2134
  contents: {
2135
- body: [ArrayLiteral[contents: { parts: [_, _, *] }] => array]
2136
- }
2135
+ body: [ArrayLiteral[contents: { parts: [_, _, *] }] => array] }
2137
2136
  ]
2138
2137
  ]
2139
2138
  # Here we have a single argument that is a set of parentheses wrapping
@@ -5116,8 +5115,13 @@ module SyntaxTree
5116
5115
  q.breakable
5117
5116
  contents.call
5118
5117
  end
5119
- q.breakable
5120
- q.text("}")
5118
+
5119
+ if q.target_ruby_version < Gem::Version.new("2.7.3")
5120
+ q.text(" }")
5121
+ else
5122
+ q.breakable
5123
+ q.text("}")
5124
+ end
5121
5125
  end
5122
5126
  end
5123
5127
  end
@@ -5204,8 +5208,7 @@ module SyntaxTree
5204
5208
  false
5205
5209
  in {
5206
5210
  statements: { body: [truthy] },
5207
- consequent: Else[statements: { body: [falsy] }]
5208
- }
5211
+ consequent: Else[statements: { body: [falsy] }] }
5209
5212
  ternaryable?(truthy) && ternaryable?(falsy)
5210
5213
  else
5211
5214
  false
@@ -910,7 +910,12 @@ module SyntaxTree
910
910
  location: keyword.location.to(consequent.location)
911
911
  )
912
912
  else
913
- operator = find_token(Kw, "in", consume: false) || find_token(Op, "=>")
913
+ operator =
914
+ if (keyword = find_token(Kw, "in", consume: false))
915
+ tokens.delete(keyword)
916
+ else
917
+ find_token(Op, "=>")
918
+ end
914
919
 
915
920
  RAssign.new(
916
921
  value: value,
@@ -39,16 +39,22 @@ module SyntaxTree
39
39
  # Defaults to 80.
40
40
  attr_accessor :print_width
41
41
 
42
+ # The target Ruby version to use for formatting.
43
+ # Defaults to Gem::Version.new(RUBY_VERSION).
44
+ attr_accessor :target_ruby_version
45
+
42
46
  def initialize(
43
47
  name = :"stree:check",
44
48
  source_files = ::Rake::FileList["lib/**/*.rb"],
45
49
  plugins = [],
46
- print_width = DEFAULT_PRINT_WIDTH
50
+ print_width = DEFAULT_PRINT_WIDTH,
51
+ target_ruby_version = Gem::Version.new(RUBY_VERSION)
47
52
  )
48
53
  @name = name
49
54
  @source_files = source_files
50
55
  @plugins = plugins
51
56
  @print_width = print_width
57
+ @target_ruby_version = target_ruby_version
52
58
 
53
59
  yield self if block_given?
54
60
  define_task
@@ -64,10 +70,15 @@ module SyntaxTree
64
70
  def run_task
65
71
  arguments = ["check"]
66
72
  arguments << "--plugins=#{plugins.join(",")}" if plugins.any?
73
+
67
74
  if print_width != DEFAULT_PRINT_WIDTH
68
75
  arguments << "--print-width=#{print_width}"
69
76
  end
70
77
 
78
+ if target_ruby_version != Gem::Version.new(RUBY_VERSION)
79
+ arguments << "--target-ruby-version=#{target_ruby_version}"
80
+ end
81
+
71
82
  SyntaxTree::CLI.run(arguments + Array(source_files))
72
83
  end
73
84
  end
@@ -39,16 +39,22 @@ module SyntaxTree
39
39
  # Defaults to 80.
40
40
  attr_accessor :print_width
41
41
 
42
+ # The target Ruby version to use for formatting.
43
+ # Defaults to Gem::Version.new(RUBY_VERSION).
44
+ attr_accessor :target_ruby_version
45
+
42
46
  def initialize(
43
47
  name = :"stree:write",
44
48
  source_files = ::Rake::FileList["lib/**/*.rb"],
45
49
  plugins = [],
46
- print_width = DEFAULT_PRINT_WIDTH
50
+ print_width = DEFAULT_PRINT_WIDTH,
51
+ target_ruby_version = Gem::Version.new(RUBY_VERSION)
47
52
  )
48
53
  @name = name
49
54
  @source_files = source_files
50
55
  @plugins = plugins
51
56
  @print_width = print_width
57
+ @target_ruby_version = target_ruby_version
52
58
 
53
59
  yield self if block_given?
54
60
  define_task
@@ -64,10 +70,15 @@ module SyntaxTree
64
70
  def run_task
65
71
  arguments = ["write"]
66
72
  arguments << "--plugins=#{plugins.join(",")}" if plugins.any?
73
+
67
74
  if print_width != DEFAULT_PRINT_WIDTH
68
75
  arguments << "--print-width=#{print_width}"
69
76
  end
70
77
 
78
+ if target_ruby_version != Gem::Version.new(RUBY_VERSION)
79
+ arguments << "--target-ruby-version=#{target_ruby_version}"
80
+ end
81
+
71
82
  SyntaxTree::CLI.run(arguments + Array(source_files))
72
83
  end
73
84
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SyntaxTree
4
- VERSION = "3.4.0"
4
+ VERSION = "3.5.0"
5
5
  end
data/syntax_tree.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  .reject { |f| f.match(%r{^(test|spec|features)/}) }
20
20
  end
21
21
 
22
- spec.required_ruby_version = ">= 2.7.3"
22
+ spec.required_ruby_version = ">= 2.7.0"
23
23
 
24
24
  spec.bindir = "exe"
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syntax_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Newton
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-19 00:00:00.000000000 Z
11
+ date: 2022-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prettier_print
@@ -103,6 +103,7 @@ extensions: []
103
103
  extra_rdoc_files: []
104
104
  files:
105
105
  - ".github/dependabot.yml"
106
+ - ".github/workflows/auto-merge.yml"
106
107
  - ".github/workflows/gh-pages.yml"
107
108
  - ".github/workflows/main.yml"
108
109
  - ".gitignore"
@@ -153,7 +154,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
153
154
  requirements:
154
155
  - - ">="
155
156
  - !ruby/object:Gem::Version
156
- version: 2.7.3
157
+ version: 2.7.0
157
158
  required_rubygems_version: !ruby/object:Gem::Requirement
158
159
  requirements:
159
160
  - - ">="