rufo 0.8.1 → 0.13.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: e8e977df730572c1448155a1bc4e3fd358a1abcdadf78c18700874e75e9c54aa
4
- data.tar.gz: 07a074f0137daf3c957dd2d6646efb72281b062b93a7df7b1981b3fdcdd3ca79
3
+ metadata.gz: 67f0bac262d71b5c91c9babdc6d975e88d1b7f04e903b8111f7ccf4f56aa2a35
4
+ data.tar.gz: c437092573d817e16b05bf2ddc6a1b5a084bc8a81a06836b2e84528f65db1dca
5
5
  SHA512:
6
- metadata.gz: 32de1903e674e7a21f34b0e092d2fd4af9fa9db9f4570611b9e50bb7ec1ba031df7b940dbc9797855688d3a6956dfa2830a0251bf4ec7296b6f4a7b5117ad5fd
7
- data.tar.gz: 9592effea9978267ab0dc2d641b8e033a7a4156723a68e0aaf2b1742f69b768329a6a8d4824fcd0fdaf1ed342279f59a1cb2e15c13514045d350ddbfcbce6060
6
+ metadata.gz: 4e14f22cc80b1566449f65c5b5eb7ceaa4b3f7ed9e98c9dbce35161830049d155c7cc83dd6fe5c3e965ebc085b7cda787b18d4a705b71daebdc1571060a7b545
7
+ data.tar.gz: a49e26fe230db7e7c42d6f0a8cb700dec11caac98dfc6bfdc7eda7a0cfe80c3fb7b5da675acf0fd29da6b70253c893183279fd1b042d1f6e450f66b1e6e29813
data/.circleci/config.yml CHANGED
@@ -28,6 +28,9 @@
28
28
  --format RspecJunitFormatter \
29
29
  --out test_results/rspec.xml \
30
30
  --format progress
31
+ - run:
32
+ name: Upload code coverage
33
+ command: bash <(curl -s https://codecov.io/bash) -f 'coverage/coverage.xml'
31
34
  - run:
32
35
  name: Run RuboCop
33
36
  command: |
@@ -53,55 +56,46 @@
53
56
  - store_test_results:
54
57
  path: test_results
55
58
 
56
-
57
59
  version: 2
58
60
  jobs:
59
- build-2-7-0:
61
+ build-3-0-1:
60
62
  <<: *dockerbuild
61
63
  docker:
62
- - image: circleci/ruby:2.7.0
64
+ - image: circleci/ruby:3.0.1
63
65
  environment:
64
66
  BUNDLE_JOBS: "3"
65
67
  BUNDLE_RETRY: "3"
66
68
  BUNDLE_PATH: /home/circleci/project/vendor/bundle
67
- build-2-6-3:
69
+ build-2-7-3:
68
70
  <<: *dockerbuild
69
71
  docker:
70
- - image: circleci/ruby:2.6.3
72
+ - image: circleci/ruby:2.7.3
71
73
  environment:
72
74
  BUNDLE_JOBS: "3"
73
75
  BUNDLE_RETRY: "3"
74
76
  BUNDLE_PATH: /home/circleci/project/vendor/bundle
75
- build-2-6-1:
77
+ build-2-6-7:
76
78
  <<: *dockerbuild
77
79
  docker:
78
- - image: circleci/ruby:2.6.1
80
+ - image: circleci/ruby:2.6.7
79
81
  environment:
80
82
  BUNDLE_JOBS: "3"
81
83
  BUNDLE_RETRY: "3"
82
- BUNDLE_PATH: vendor/bundle
83
- build-2-5-3:
84
- <<: *dockerbuild
85
- docker:
86
- - image: circleci/ruby:2.5.3
87
- environment:
88
- BUNDLE_JOBS: "3"
89
- BUNDLE_RETRY: "3"
90
- BUNDLE_PATH: vendor/bundle
91
- build-2-4-5:
84
+ BUNDLE_PATH: /home/circleci/project/vendor/bundle
85
+ build-2-6-1:
92
86
  <<: *dockerbuild
93
87
  docker:
94
- - image: circleci/ruby:2.4.5
88
+ - image: circleci/ruby:2.6.1
95
89
  environment:
96
90
  BUNDLE_JOBS: "3"
97
91
  BUNDLE_RETRY: "3"
98
92
  BUNDLE_PATH: vendor/bundle
93
+
99
94
  workflows:
100
95
  version: 2
101
96
  test:
102
97
  jobs:
103
- - build-2-7-0
104
- - build-2-6-3
98
+ - build-3-0-1
99
+ - build-2-7-3
100
+ - build-2-6-7
105
101
  - build-2-6-1
106
- - build-2-5-3
107
- - build-2-4-5
data/.gitignore CHANGED
@@ -11,4 +11,8 @@
11
11
 
12
12
  # rspec failure tracking
13
13
  .rspec_status
14
+ spec/examples.txt
15
+
14
16
  sample_code
17
+
18
+ .byebug_history
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
+ --require spec_helper
1
2
  --format documentation
2
- --color
data/.rubocop.yml CHANGED
@@ -2,7 +2,7 @@ AllCops:
2
2
  Exclude:
3
3
  - "spec/**/*"
4
4
  - "vendor/**/*"
5
- TargetRubyVersion: 2.4
5
+ TargetRubyVersion: 2.6
6
6
 
7
7
  Layout:
8
8
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -12,6 +12,88 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
12
12
 
13
13
  ### Added
14
14
 
15
+ ## [0.13.0] - 2021-05-07
16
+
17
+ ### Fixed
18
+
19
+ - Properly format comma when a heredoc is passed as a call argument
20
+ - Correctly interpret case statements with multiple when clauses in ERB files
21
+
22
+ ### Changed
23
+
24
+ - Dropped support for Ruby 2.4 and 2.5 as they are end of life.
25
+
26
+ ### Added
27
+
28
+ - Add Ruby 3.0.1 to test runs on CI.
29
+
30
+ ## [0.12.0] - 2020-03-08
31
+
32
+ ### Fixed
33
+
34
+ - File.read default encode UTF-8
35
+ - Handle case where the code is invalid but ripper does not raise an error.
36
+ - Removed implicit dependency on `rake`.
37
+ - Error when semicolon and then used in a case statement #230.
38
+
39
+ ### Changed
40
+
41
+ ### Added
42
+ - Code coverage tracking with codecov.io
43
+ - `node_modules` folders are now ignored.
44
+
45
+ ## [0.11.0] - 2020-02-09
46
+
47
+ ### Fixed
48
+ - Documentation for `trailing_commas`
49
+ - Handle empty string symbol for key in hash.
50
+
51
+ ### Added
52
+ - Support for escaped ERB template tags. For example `<%%%%= format :name %>`.
53
+
54
+ ## [0.10.0] - 2020-01-16
55
+
56
+ ### Fixed
57
+ - Squiggly heredoc closing tag indentation.
58
+ - Formatting .erb files from stdin.
59
+
60
+ ### Changed
61
+ - Method parameters are now no longer aligned with the method parenthesis. For example:
62
+ - ```ruby
63
+ def foo(
64
+ param
65
+ )
66
+ end
67
+
68
+ # Becomes:
69
+
70
+ def foo(
71
+ param
72
+ )
73
+ end
74
+ ```
75
+ - Multiline assignments are no longer aligned with variable indentation.
76
+ - ```ruby
77
+ a = if true
78
+ b
79
+ end
80
+
81
+ # Becomes:
82
+
83
+ a = if true
84
+ b
85
+ end
86
+ ```
87
+ ### Added
88
+
89
+ ## [0.9.0] - 2020-01-11
90
+
91
+ ### Added
92
+
93
+ - Support for trim style erb templates ending with `-%>`.
94
+ - Support for rails raw mode erb templates starting with `<%==`.
95
+ - Support for ruby 2.7 features. This includes beginless ranges `..10`, method argument forwarding `def forward(...); to(...); end` and keyword args not being allowed `def foo(*args, **nil)`.
96
+
15
97
  ## [0.8.1] - 2020-01-02
16
98
 
17
99
  ### Fixed
@@ -8,6 +8,7 @@ repos = {
8
8
  "spec/rspec/core/formatters/snippet_extractor_spec.rb",
9
9
  "spec/rspec/core/metadata_spec.rb",
10
10
  "spec/rspec/core/formatters/html_formatter_spec.rb",
11
+ "spec/rspec/core/formatters_spec.rb",
11
12
  ].join(","),
12
13
  },
13
14
  }
data/docs/settings.md CHANGED
@@ -23,7 +23,7 @@ See https://github.com/ruby-formatter/rufo/issues/2 for more context!
23
23
  - [parens_in_def](#parens_in_def)
24
24
  - [trailing_commas](#trailing_commas)
25
25
  - [quote_style](#quote_style)
26
- - [includes and excludes](#includes%20and%20excludes)
26
+ - [includes and excludes](#includes-and-excludes)
27
27
 
28
28
  ### align_case_when
29
29
 
@@ -116,8 +116,8 @@ With `:dynamic` it won't modify it.
116
116
 
117
117
  Use trailing commas in array and hash literals, and keyword arguments?
118
118
 
119
- - `:always`: (default) always put a trailing comma
120
- - `:never`: never put a trailing comma
119
+ - `true`: (default) always put a trailing comma
120
+ - `false`: never put a trailing comma
121
121
 
122
122
  Given this code:
123
123
 
@@ -153,7 +153,7 @@ foo(
153
153
  )
154
154
  ```
155
155
 
156
- With `:always`, the formatter will change it to:
156
+ With `true`, the formatter will change it to:
157
157
 
158
158
  ```ruby
159
159
  [
@@ -187,7 +187,7 @@ foo(
187
187
  )
188
188
  ```
189
189
 
190
- With `:never`, the formatter will change it to:
190
+ With `false`, the formatter will change it to:
191
191
 
192
192
  ```ruby
193
193
  [
@@ -284,5 +284,5 @@ Files can be excluded or included in formatting with rufo by specifying glob pat
284
284
  For example:
285
285
  ```
286
286
  includes [*.txt,*.text]
287
- excludes [*.rb]
287
+ excludes [**/*.erb]
288
288
  ```
data/lib/rufo.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Rufo
4
4
  class Bug < StandardError; end
5
+ class UnknownSyntaxError < StandardError; end
5
6
 
6
7
  class SyntaxError < StandardError
7
8
  attr_reader :lineno
@@ -25,4 +26,5 @@ require_relative "rufo/parser"
25
26
  require_relative "rufo/formatter"
26
27
  require_relative "rufo/erb_formatter"
27
28
  require_relative "rufo/version"
29
+ require_relative "rufo/file_list"
28
30
  require_relative "rufo/file_finder"
data/lib/rufo/command.rb CHANGED
@@ -35,17 +35,18 @@ class Rufo::Command
35
35
 
36
36
  def run(argv)
37
37
  status_code = if argv.empty?
38
- format_stdin
39
- else
40
- format_args argv
41
- end
38
+ format_stdin
39
+ else
40
+ format_args argv
41
+ end
42
42
  exit exit_code(status_code)
43
43
  end
44
44
 
45
45
  def format_stdin
46
46
  code = STDIN.read
47
47
 
48
- result = format(code, @filename_for_dot_rufo || Dir.getwd)
48
+ erb = @filename_for_dot_rufo && @filename_for_dot_rufo.end_with?(".erb")
49
+ result = format(code, @filename_for_dot_rufo || Dir.getwd, erb: erb)
49
50
 
50
51
  print(result) if !@want_check
51
52
 
@@ -53,10 +54,13 @@ class Rufo::Command
53
54
  rescue Rufo::SyntaxError => e
54
55
  logger.error("STDIN is invalid code. Error on line:#{e.lineno} #{e.message}")
55
56
  CODE_ERROR
56
- rescue => ex
57
+ rescue Rufo::UnknownSyntaxError
58
+ logger.error("STDIN is invalid code. Try running the code for a better error.")
59
+ CODE_ERROR
60
+ rescue => e
57
61
  logger.error("You've found a bug!")
58
62
  logger.error("Please report it to https://github.com/ruby-formatter/rufo/issues with code that triggers it\n")
59
- raise ex
63
+ raise e
60
64
  end
61
65
 
62
66
  def format_args(args)
@@ -95,7 +99,7 @@ class Rufo::Command
95
99
 
96
100
  def format_file(filename)
97
101
  logger.debug("Formatting: #{filename}")
98
- code = File.read(filename)
102
+ code = File.read(filename, encoding: "UTF-8")
99
103
 
100
104
  begin
101
105
  location = @filename_for_dot_rufo || File.dirname(filename)
@@ -121,11 +125,14 @@ class Rufo::Command
121
125
  rescue Rufo::SyntaxError => e
122
126
  logger.error("#{filename}:#{e.lineno} #{e.message}")
123
127
  CODE_ERROR
124
- rescue => ex
128
+ rescue Rufo::UnknownSyntaxError
129
+ logger.error("#{filename} is invalid code. Try running the code for a better error.")
130
+ CODE_ERROR
131
+ rescue => e
125
132
  logger.error("You've found a bug!")
126
133
  logger.error("It happened while trying to format the file #{filename}")
127
134
  logger.error("Please report it to https://github.com/ruby-formatter/rufo/issues with code that triggers it\n")
128
- raise ex
135
+ raise e
129
136
  end
130
137
 
131
138
  def format(code, dir, erb: false)
@@ -1,6 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
  require "erb"
3
3
 
4
+ class CustomScanner < ERB::Compiler::TrimScanner
5
+ def initialize(src)
6
+ super(src, "<>", false)
7
+ @scan_reg = /(.*?)(%>\r?\n|#{(stags + etags).join("|")}|\n|\z)/m
8
+ end
9
+
10
+ def stags
11
+ ["<%==", "<%+={0,2}"] + super
12
+ end
13
+
14
+ def etags
15
+ super + ["-%>"]
16
+ end
17
+ end
18
+
4
19
  class Rufo::ErbFormatter
5
20
  def self.format(code, **options)
6
21
  new(code, **options).format
@@ -9,9 +24,8 @@ class Rufo::ErbFormatter
9
24
  attr_reader :result
10
25
 
11
26
  def initialize(code, **options)
12
- compiler = ERB::Compiler.new("<>")
13
27
  @options = options
14
- @scanner = compiler.make_scanner(code)
28
+ @scanner = CustomScanner.new(code)
15
29
  @code_mode = false
16
30
  @current_lineno = 0
17
31
  @current_column = 0
@@ -97,6 +111,7 @@ class Rufo::ErbFormatter
97
111
  return "begin", nil if Ripper.sexp("begin #{code_str}")
98
112
  return "begin\n", "\nend" if Ripper.sexp("begin\n#{code_str}\nend")
99
113
  return "if a\n", "\nend" if Ripper.sexp("if a\n#{code_str}\nend")
114
+ return "case a\n", "\nend" if Ripper.sexp("case a\n#{code_str}\nend")
100
115
  raise_syntax_error!(code_str)
101
116
  end
102
117
 
@@ -1,6 +1,3 @@
1
- require "find"
2
- require "rake/file_list"
3
-
4
1
  class Rufo::FileFinder
5
2
  include Enumerable
6
3
 
@@ -31,12 +28,9 @@ class Rufo::FileFinder
31
28
  *EXTENSIONS,
32
29
  ]
33
30
 
34
- EXCLUDED_DIRS = [
35
- "vendor",
36
- ]
37
-
38
31
  EXCLUDE_PATTERNS = [
39
32
  "vendor/**/*",
33
+ "node_modules/**/*",
40
34
  ]
41
35
 
42
36
  def initialize(files_or_dirs, includes: [], excludes: [])
@@ -69,7 +63,7 @@ class Rufo::FileFinder
69
63
  end
70
64
 
71
65
  def build_file_list
72
- fl = Rake::FileList.new(*DEFAULT_PATTERNS)
66
+ fl = Rufo::FileList.new(*DEFAULT_PATTERNS)
73
67
  fl.exclude(*EXCLUDE_PATTERNS)
74
68
  fl.exclude(*excludes)
75
69
  fl.include(*includes)
@@ -0,0 +1,244 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is based on https://github.com/ruby/rake/blob/master/lib/rake/file_list.rb
4
+ # Git commit: 5b8f8fc41a5d7d7d6a5d767e48464c60884d3aee
5
+
6
+ module Rufo
7
+
8
+ ##
9
+ # A FileList is essentially an array with a few helper methods defined to
10
+ # make file manipulation a bit easier.
11
+ #
12
+ # FileLists are lazy. When given a list of glob patterns for possible files
13
+ # to be included in the file list, instead of searching the file structures
14
+ # to find the files, a FileList holds the pattern for latter use.
15
+ #
16
+ # This allows us to define a number of FileList to match any number of
17
+ # files, but only search out the actual files when then FileList itself is
18
+ # actually used. The key is that the first time an element of the
19
+ # FileList/Array is requested, the pending patterns are resolved into a real
20
+ # list of file names.
21
+ #
22
+ class FileList
23
+
24
+ # == Method Delegation
25
+ #
26
+ # The lazy evaluation magic of FileLists happens by implementing all the
27
+ # array specific methods to call +resolve+ before delegating the heavy
28
+ # lifting to an embedded array object (@items).
29
+ #
30
+ # In addition, there are two kinds of delegation calls. The regular kind
31
+ # delegates to the @items array and returns the result directly. Well,
32
+ # almost directly. It checks if the returned value is the @items object
33
+ # itself, and if so will return the FileList object instead.
34
+ #
35
+ # The second kind of delegation call is used in methods that normally
36
+ # return a new Array object. We want to capture the return value of these
37
+ # methods and wrap them in a new FileList object. We enumerate these
38
+ # methods in the +SPECIAL_RETURN+ list below.
39
+
40
+ # List of array methods (that are not in +Object+) that need to be
41
+ # delegated.
42
+ ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map(&:to_s)
43
+
44
+ # List of additional methods that must be delegated.
45
+ MUST_DEFINE = %w[inspect <=>]
46
+
47
+ # List of methods that should not be delegated here (we define special
48
+ # versions of them explicitly below).
49
+ MUST_NOT_DEFINE = %w[to_a to_ary partition * <<]
50
+
51
+ # List of delegated methods that return new array values which need
52
+ # wrapping.
53
+ SPECIAL_RETURN = %w[
54
+ map collect sort sort_by select find_all reject grep
55
+ compact flatten uniq values_at
56
+ + - & |
57
+ ]
58
+
59
+ DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).map(&:to_s).sort.uniq
60
+
61
+ # Now do the delegation.
62
+ DELEGATING_METHODS.each do |sym|
63
+ if SPECIAL_RETURN.include?(sym)
64
+ ln = __LINE__ + 1
65
+ class_eval %{
66
+ def #{sym}(*args, &block)
67
+ resolve
68
+ result = @items.send(:#{sym}, *args, &block)
69
+ self.class.new.import(result)
70
+ end
71
+ }, __FILE__, ln
72
+ else
73
+ ln = __LINE__ + 1
74
+ class_eval %{
75
+ def #{sym}(*args, &block)
76
+ resolve
77
+ result = @items.send(:#{sym}, *args, &block)
78
+ result.object_id == @items.object_id ? self : result
79
+ end
80
+ }, __FILE__, ln
81
+ end
82
+ end
83
+
84
+ GLOB_PATTERN = %r{[*?\[\{]}
85
+
86
+ # Create a file list from the globbable patterns given. If you wish to
87
+ # perform multiple includes or excludes at object build time, use the
88
+ # "yield self" pattern.
89
+ #
90
+ # Example:
91
+ # file_list = FileList.new('lib/**/*.rb', 'test/test*.rb')
92
+ #
93
+ # pkg_files = FileList.new('lib/**/*') do |fl|
94
+ # fl.exclude(/\bCVS\b/)
95
+ # end
96
+ #
97
+ def initialize(*patterns)
98
+ @pending_add = []
99
+ @pending = false
100
+ @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
101
+ @exclude_procs = DEFAULT_IGNORE_PROCS.dup
102
+ @items = []
103
+ patterns.each { |pattern| include(pattern) }
104
+ yield self if block_given?
105
+ end
106
+
107
+ # Add file names defined by glob patterns to the file list. If an array
108
+ # is given, add each element of the array.
109
+ #
110
+ # Example:
111
+ # file_list.include("*.java", "*.cfg")
112
+ # file_list.include %w( math.c lib.h *.o )
113
+ #
114
+ def include(*filenames)
115
+ filenames.each do |fn|
116
+ @pending_add << fn
117
+ end
118
+ @pending = true
119
+ self
120
+ end
121
+
122
+ alias :add :include
123
+
124
+ # Register a list of file name patterns that should be excluded from the
125
+ # list. Patterns may be regular expressions, glob patterns or regular
126
+ # strings. In addition, a block given to exclude will remove entries that
127
+ # return true when given to the block.
128
+ #
129
+ # Note that glob patterns are expanded against the file system. If a file
130
+ # is explicitly added to a file list, but does not exist in the file
131
+ # system, then an glob pattern in the exclude list will not exclude the
132
+ # file.
133
+ #
134
+ # Examples:
135
+ # FileList['a.c', 'b.c'].exclude("a.c") => ['b.c']
136
+ # FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c']
137
+ #
138
+ # If "a.c" is a file, then ...
139
+ # FileList['a.c', 'b.c'].exclude("a.*") => ['b.c']
140
+ #
141
+ # If "a.c" is not a file, then ...
142
+ # FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
143
+ #
144
+ def exclude(*patterns, &block)
145
+ patterns.each do |pat|
146
+ @exclude_patterns << pat
147
+ end
148
+ @exclude_procs << block if block_given?
149
+ resolve_exclude unless @pending
150
+ self
151
+ end
152
+
153
+ # Return the internal array object.
154
+ def to_a
155
+ resolve
156
+ @items
157
+ end
158
+
159
+ def <<(obj)
160
+ resolve
161
+ @items << obj
162
+ self
163
+ end
164
+
165
+ # Resolve all the pending adds now.
166
+ def resolve
167
+ if @pending
168
+ @pending = false
169
+ @pending_add.each do |fn| resolve_add(fn) end
170
+ @pending_add = []
171
+ resolve_exclude
172
+ end
173
+ self
174
+ end
175
+
176
+ def resolve_add(filename) # :nodoc:
177
+ case filename
178
+ when GLOB_PATTERN
179
+ add_matching(filename)
180
+ else
181
+ self << filename
182
+ end
183
+ end
184
+
185
+ private :resolve_add
186
+
187
+ def resolve_exclude # :nodoc:
188
+ reject! { |fn| excluded_from_list?(fn) }
189
+ self
190
+ end
191
+
192
+ private :resolve_exclude
193
+ # Convert a FileList to a string by joining all elements with a space.
194
+ def to_s
195
+ resolve
196
+ self.join(" ")
197
+ end
198
+
199
+ # Add matching glob patterns.
200
+ def add_matching(pattern)
201
+ self.class.glob(pattern).each do |fn|
202
+ self << fn unless excluded_from_list?(fn)
203
+ end
204
+ end
205
+
206
+ private :add_matching
207
+
208
+ # Should the given file name be excluded from the list?
209
+ def excluded_from_list?(filename)
210
+ return true if @exclude_patterns.any? do |pat|
211
+ case pat
212
+ when Regexp
213
+ filename =~ pat
214
+ when GLOB_PATTERN
215
+ flags = File::FNM_PATHNAME
216
+ flags |= File::FNM_EXTGLOB
217
+ File.fnmatch?(pat, filename, flags)
218
+ else
219
+ filename == pat
220
+ end
221
+ end
222
+ @exclude_procs.any? { |p| p.call(filename) }
223
+ end
224
+
225
+ DEFAULT_IGNORE_PATTERNS = [
226
+ /(^|[\/\\])CVS([\/\\]|$)/,
227
+ /(^|[\/\\])\.svn([\/\\]|$)/,
228
+ /\.bak$/,
229
+ /~$/,
230
+ ]
231
+ DEFAULT_IGNORE_PROCS = [
232
+ proc { |fn| fn =~ /(^|[\/\\])core$/ && !File.directory?(fn) },
233
+ ]
234
+
235
+ class << self
236
+ # Get a sorted list of files matching the pattern. This method
237
+ # should be preferred to Dir[pattern] and Dir.glob(pattern) because
238
+ # the files returned are guaranteed to be sorted.
239
+ def glob(pattern, *args)
240
+ Dir.glob(pattern, *args).sort
241
+ end
242
+ end
243
+ end
244
+ end
@@ -21,7 +21,10 @@ class Rufo::Formatter
21
21
 
22
22
  # sexp being nil means that the code is not valid.
23
23
  # Parse the code so we get better error messages.
24
- Rufo::Parser.parse(code) if @sexp.nil?
24
+ if @sexp.nil?
25
+ Rufo::Parser.parse(code)
26
+ raise Rufo::UnknownSyntaxError # Sometimes parsing does not raise an error
27
+ end
25
28
 
26
29
  @indent = 0
27
30
  @line = 0
@@ -209,7 +212,7 @@ class Rufo::Formatter
209
212
  when :@float
210
213
  # Float literal
211
214
  #
212
- # [:@int, "123.45", [1, 0]]
215
+ # [:@float, "123.45", [1, 0]]
213
216
  consume_token :on_float
214
217
  when :@rational
215
218
  # Rational literal
@@ -484,6 +487,8 @@ class Rufo::Formatter
484
487
  visit_begin_node(node)
485
488
  when :END
486
489
  visit_end_node(node)
490
+ when :args_forward
491
+ consume_op("...")
487
492
  else
488
493
  bug "Unhandled node: #{node.first}"
489
494
  end
@@ -885,19 +890,24 @@ class Rufo::Formatter
885
890
  def visit_assign_value(value)
886
891
  has_slash_newline, _first_space = skip_space_backslash
887
892
 
888
- sticky = indentable_value?(value)
889
-
890
893
  # Remove backslash after equal + newline (it's useless)
891
894
  if has_slash_newline
892
895
  skip_space_or_newline
893
- write_line
896
+ write_space
894
897
  indent(next_indent) do
895
- write_indent
896
898
  visit(value)
897
899
  end
898
900
  else
899
- indent_after_space value, sticky: sticky,
900
- want_space: true
901
+ if [:begin, :case, :if, :unless].include?(value.first)
902
+ skip_space_or_newline
903
+ write_space
904
+ indent(next_indent) do
905
+ visit value
906
+ end
907
+ else
908
+ indent_after_space value, sticky: false,
909
+ want_space: true
910
+ end
901
911
  end
902
912
  end
903
913
 
@@ -1116,11 +1126,14 @@ class Rufo::Formatter
1116
1126
 
1117
1127
  found_comma = comma?
1118
1128
 
1129
+ heredoc_needs_newline = true
1130
+
1119
1131
  if found_comma
1120
1132
  if needs_trailing_newline
1121
1133
  write "," if trailing_commas && !block_arg
1122
1134
 
1123
1135
  next_token
1136
+ heredoc_needs_newline = !newline?
1124
1137
  indent(next_indent) do
1125
1138
  consume_end_of_line
1126
1139
  end
@@ -1132,7 +1145,7 @@ class Rufo::Formatter
1132
1145
  end
1133
1146
 
1134
1147
  if newline? || comment?
1135
- if needs_trailing_newline
1148
+ if needs_trailing_newline && !@last_was_heredoc
1136
1149
  write "," if trailing_commas && want_trailing_comma
1137
1150
 
1138
1151
  indent(next_indent) do
@@ -1144,7 +1157,7 @@ class Rufo::Formatter
1144
1157
  end
1145
1158
  else
1146
1159
  if needs_trailing_newline && !found_comma
1147
- write "," if trailing_commas && want_trailing_comma
1160
+ write "," if trailing_commas && want_trailing_comma && !@last_was_heredoc
1148
1161
  consume_end_of_line
1149
1162
  write_indent
1150
1163
  end
@@ -1159,8 +1172,9 @@ class Rufo::Formatter
1159
1172
  call_info << @line
1160
1173
  end
1161
1174
 
1162
- if @last_was_heredoc
1175
+ if @last_was_heredoc && heredoc_needs_newline
1163
1176
  write_line
1177
+ write_indent
1164
1178
  end
1165
1179
  consume_token :on_rparen
1166
1180
  end
@@ -1193,9 +1207,6 @@ class Rufo::Formatter
1193
1207
  write current_token_value.rstrip
1194
1208
  next_token
1195
1209
  write_line
1196
- if @heredocs.last[1]
1197
- write_indent(next_indent)
1198
- end
1199
1210
  end
1200
1211
 
1201
1212
  printed = false
@@ -2029,6 +2040,7 @@ class Rufo::Formatter
2029
2040
  next_token
2030
2041
  skip_space
2031
2042
  skip_semicolons
2043
+ broken_across_line = false
2032
2044
 
2033
2045
  if empty_params?(params)
2034
2046
  skip_space_or_newline
@@ -2039,8 +2051,8 @@ class Rufo::Formatter
2039
2051
  write "("
2040
2052
 
2041
2053
  if newline? || comment?
2042
- column = @column
2043
- indent(column) do
2054
+ broken_across_line = true
2055
+ indent(next_indent) do
2044
2056
  consume_end_of_line
2045
2057
  write_indent
2046
2058
  visit params
@@ -2052,7 +2064,12 @@ class Rufo::Formatter
2052
2064
  end
2053
2065
 
2054
2066
  skip_space_or_newline
2067
+ consume_keyword("nil") if current_token[1] == :on_kw
2055
2068
  check :on_rparen
2069
+ if broken_across_line
2070
+ write_line
2071
+ write_indent
2072
+ end
2056
2073
  write ")"
2057
2074
  next_token
2058
2075
  end
@@ -2125,6 +2142,8 @@ class Rufo::Formatter
2125
2142
  case rest_param
2126
2143
  when 0, [:excessed_comma]
2127
2144
  write_params_comma
2145
+ when [:args_forward]
2146
+ consume_op "..."
2128
2147
  else
2129
2148
  # [:rest_param, [:@ident, "x", [1, 15]]]
2130
2149
  _, rest = rest_param
@@ -2377,7 +2396,7 @@ class Rufo::Formatter
2377
2396
  # [:dot2, left, right]
2378
2397
  _, left, right = node
2379
2398
 
2380
- visit left
2399
+ visit left unless left.nil?
2381
2400
  skip_space_or_newline
2382
2401
  consume_op(inclusive ? ".." : "...")
2383
2402
  skip_space_or_newline
@@ -2732,8 +2751,9 @@ class Rufo::Formatter
2732
2751
  # We have to be careful not to aumatically write a heredoc on next_token,
2733
2752
  # because we miss the chance to write a comma to separate elements
2734
2753
  first_space = skip_space_no_heredoc_check
2735
- wrote_comma = check_heredocs_in_literal_elements(is_last, wrote_comma)
2736
-
2754
+ indent(needed_indent) do
2755
+ wrote_comma = check_heredocs_in_literal_elements(is_last, wrote_comma)
2756
+ end
2737
2757
  next unless comma?
2738
2758
 
2739
2759
  unless is_last
@@ -2746,7 +2766,9 @@ class Rufo::Formatter
2746
2766
  next_token_no_heredoc_check
2747
2767
 
2748
2768
  first_space = skip_space_no_heredoc_check
2749
- wrote_comma = check_heredocs_in_literal_elements(is_last, wrote_comma)
2769
+ indent(needed_indent) do
2770
+ wrote_comma = check_heredocs_in_literal_elements(is_last, wrote_comma)
2771
+ end
2750
2772
 
2751
2773
  if newline? || comment?
2752
2774
  if is_last
@@ -2909,10 +2931,23 @@ class Rufo::Formatter
2909
2931
  visit_comma_separated_list conds
2910
2932
  skip_space
2911
2933
  end
2934
+ written_space = false
2935
+ if semicolon?
2936
+ inline = true
2937
+ skip_semicolons
2938
+
2939
+ if newline? || comment?
2940
+ inline = false
2941
+ else
2942
+ write ";"
2943
+ track_case_when
2944
+ write " "
2945
+ written_space = true
2946
+ end
2947
+ end
2912
2948
 
2913
- then_keyword = keyword?("then")
2914
- inline = then_keyword || semicolon?
2915
- if then_keyword
2949
+ if keyword?("then")
2950
+ inline = true
2916
2951
  next_token
2917
2952
 
2918
2953
  skip_space
@@ -2926,7 +2961,7 @@ class Rufo::Formatter
2926
2961
  # Cancel tracking of `case when ... then` on a nelwine.
2927
2962
  @case_when_positions.pop
2928
2963
  else
2929
- write_space
2964
+ write_space unless written_space
2930
2965
 
2931
2966
  write "then"
2932
2967
 
@@ -2949,16 +2984,6 @@ class Rufo::Formatter
2949
2984
 
2950
2985
  write_space
2951
2986
  end
2952
- elsif semicolon?
2953
- skip_semicolons
2954
-
2955
- if newline? || comment?
2956
- inline = false
2957
- else
2958
- write ";"
2959
- track_case_when
2960
- write " "
2961
- end
2962
2987
  end
2963
2988
 
2964
2989
  if inline
@@ -3845,6 +3870,7 @@ class Rufo::Formatter
3845
3870
  end
3846
3871
 
3847
3872
  def node_line(node, beginning: true)
3873
+ return if node.nil?
3848
3874
  # get line of node, it is only used in visit_hash right now,
3849
3875
  # so handling the following node types is enough.
3850
3876
  case node.first
data/lib/rufo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rufo
4
- VERSION = "0.8.1"
4
+ VERSION = "0.13.0"
5
5
  end
data/rufo.gemspec CHANGED
@@ -20,13 +20,16 @@ Gem::Specification.new do |spec|
20
20
  spec.bindir = "exe"
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
- spec.required_ruby_version = ">= 2.4.5"
23
+ spec.required_ruby_version = ">= 2.6.0"
24
24
 
25
25
  spec.add_development_dependency "bundler", ">= 1.15"
26
- spec.add_development_dependency "byebug", "~> 10.0.2"
26
+ spec.add_development_dependency "byebug", "~> 11.0.1"
27
27
  spec.add_development_dependency "guard-rspec", "~> 4.0"
28
- spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rake", "~> 13.0"
29
+ spec.add_development_dependency "rexml", "~> 3.2.5"
29
30
  spec.add_development_dependency "rspec", "~> 3.0"
30
31
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.1"
31
- spec.add_development_dependency "rubocop", "~> 0.63.1"
32
+ spec.add_development_dependency "rubocop", "~> 0.79.0"
33
+ spec.add_development_dependency "simplecov", "~> 0.18.5"
34
+ spec.add_development_dependency "simplecov-cobertura", "~> 1.3.1"
32
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ary Borenszweig
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-02 00:00:00.000000000 Z
11
+ date: 2021-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 10.0.2
33
+ version: 11.0.1
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 10.0.2
40
+ version: 11.0.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: guard-rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '10.0'
61
+ version: '13.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '10.0'
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rexml
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.2.5
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.2.5
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rspec
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +114,42 @@ dependencies:
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: 0.63.1
117
+ version: 0.79.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.79.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.18.5
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.18.5
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov-cobertura
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 1.3.1
104
146
  type: :development
105
147
  prerelease: false
106
148
  version_requirements: !ruby/object:Gem::Requirement
107
149
  requirements:
108
150
  - - "~>"
109
151
  - !ruby/object:Gem::Version
110
- version: 0.63.1
152
+ version: 1.3.1
111
153
  description: Fast and unobtrusive Ruby code formatter
112
154
  email:
113
155
  - asterite@gmail.com
@@ -140,6 +182,7 @@ files:
140
182
  - lib/rufo/dot_file.rb
141
183
  - lib/rufo/erb_formatter.rb
142
184
  - lib/rufo/file_finder.rb
185
+ - lib/rufo/file_list.rb
143
186
  - lib/rufo/formatter.rb
144
187
  - lib/rufo/logger.rb
145
188
  - lib/rufo/parser.rb
@@ -151,7 +194,7 @@ homepage: https://github.com/ruby-formatter/rufo
151
194
  licenses:
152
195
  - MIT
153
196
  metadata: {}
154
- post_install_message:
197
+ post_install_message:
155
198
  rdoc_options: []
156
199
  require_paths:
157
200
  - lib
@@ -159,15 +202,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
159
202
  requirements:
160
203
  - - ">="
161
204
  - !ruby/object:Gem::Version
162
- version: 2.4.5
205
+ version: 2.6.0
163
206
  required_rubygems_version: !ruby/object:Gem::Requirement
164
207
  requirements:
165
208
  - - ">="
166
209
  - !ruby/object:Gem::Version
167
210
  version: '0'
168
211
  requirements: []
169
- rubygems_version: 3.0.3
170
- signing_key:
212
+ rubygems_version: 3.2.17
213
+ signing_key:
171
214
  specification_version: 4
172
215
  summary: Ruby code formatter
173
216
  test_files: []