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 +4 -4
- data/.circleci/config.yml +16 -22
- data/.gitignore +4 -0
- data/.rspec +1 -1
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +82 -0
- data/bin/verify-sample-code +1 -0
- data/docs/settings.md +6 -6
- data/lib/rufo.rb +2 -0
- data/lib/rufo/command.rb +17 -10
- data/lib/rufo/erb_formatter.rb +17 -2
- data/lib/rufo/file_finder.rb +2 -8
- data/lib/rufo/file_list.rb +244 -0
- data/lib/rufo/formatter.rb +60 -34
- data/lib/rufo/version.rb +1 -1
- data/rufo.gemspec +7 -4
- metadata +56 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67f0bac262d71b5c91c9babdc6d975e88d1b7f04e903b8111f7ccf4f56aa2a35
|
4
|
+
data.tar.gz: c437092573d817e16b05bf2ddc6a1b5a084bc8a81a06836b2e84528f65db1dca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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-
|
61
|
+
build-3-0-1:
|
60
62
|
<<: *dockerbuild
|
61
63
|
docker:
|
62
|
-
- image: circleci/ruby:
|
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-
|
69
|
+
build-2-7-3:
|
68
70
|
<<: *dockerbuild
|
69
71
|
docker:
|
70
|
-
- image: circleci/ruby:2.
|
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-
|
77
|
+
build-2-6-7:
|
76
78
|
<<: *dockerbuild
|
77
79
|
docker:
|
78
|
-
- image: circleci/ruby:2.6.
|
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-
|
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.
|
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-
|
104
|
-
- build-2-
|
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
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
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
|
data/bin/verify-sample-code
CHANGED
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
|
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
|
-
- `:
|
120
|
-
- `:
|
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
|
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
|
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 [
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
135
|
+
raise e
|
129
136
|
end
|
130
137
|
|
131
138
|
def format(code, dir, erb: false)
|
data/lib/rufo/erb_formatter.rb
CHANGED
@@ -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 =
|
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
|
|
data/lib/rufo/file_finder.rb
CHANGED
@@ -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 =
|
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
|
data/lib/rufo/formatter.rb
CHANGED
@@ -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
|
-
|
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
|
-
# [:@
|
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
|
-
|
896
|
+
write_space
|
894
897
|
indent(next_indent) do
|
895
|
-
write_indent
|
896
898
|
visit(value)
|
897
899
|
end
|
898
900
|
else
|
899
|
-
|
900
|
-
|
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
|
-
|
2043
|
-
indent(
|
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
|
-
|
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
|
-
|
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
|
-
|
2914
|
-
|
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
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.
|
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", "~>
|
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", "~>
|
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.
|
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.
|
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:
|
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:
|
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:
|
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: '
|
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: '
|
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.
|
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:
|
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.
|
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.
|
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: []
|