rufo 0.11.0 → 0.12.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: 8880f0f88e4def3cc19a1fa8a54b7fe7f5393e6cdb93f47a19c1565a7564ed2f
4
- data.tar.gz: 74f522f20caa7d57bc9607d3dc6100b1a48758cc72a18dcaf85c0ab5e1c66e9b
3
+ metadata.gz: 87b9e11a2d83bf366134074b750fca515da61d65c626ad4a85cb029b3246f314
4
+ data.tar.gz: 5f2caf3f22b5b7e8411e7a35f9e73c27bfd7a92f7f8246f3099ed98ecacef359
5
5
  SHA512:
6
- metadata.gz: c6de4f9c31d85b4bbcc39c8873c7fc677da69b07c1600620811253d44fa8e67e51a1ecdbd7156c81523f6b2285bccb038e5dbf99a3b09104a48ab253edf43da5
7
- data.tar.gz: a7d27577fcedab3672924b89aeb15ddd117ed31802fda6e8b987c0bcaa8449adce45f573ce2c74c381ef39fba7c97d0d9efefc8de5f321d87d9cbeccdd245672
6
+ metadata.gz: 00742ceee28433e130ccceffd31ee41a8a827135d3f986f552d42821e62acc6b5a7c795771c5bdea5ec46069374a1ca014f964ca21fcd425240ffeedc101b72f
7
+ data.tar.gz: ade0daa5611c2cbe51f9bf59de4df7750aaac6ecec829eaad97b9f478cba2d5f5a4671ac054c9d2850f5b1758b07881b51474e94a1cbe754f02a6348ccaa1607
@@ -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,7 +56,6 @@
53
56
  - store_test_results:
54
57
  path: test_results
55
58
 
56
-
57
59
  version: 2
58
60
  jobs:
59
61
  build-2-7-0:
@@ -96,6 +98,7 @@ jobs:
96
98
  BUNDLE_JOBS: "3"
97
99
  BUNDLE_RETRY: "3"
98
100
  BUNDLE_PATH: vendor/bundle
101
+
99
102
  workflows:
100
103
  version: 2
101
104
  test:
@@ -12,6 +12,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
12
12
 
13
13
  ### Added
14
14
 
15
+ ## [0.12.0] - 2020-03-08
16
+
17
+ ### Fixed
18
+ - File.read default encode UTF-8
19
+ - Handle case where the code is invalid but ripper does not raise an error.
20
+ - Removed implicit dependency on `rake`.
21
+ - Error when semicolon and then used in a case statement #230.
22
+
23
+ ### Changed
24
+
25
+ ### Added
26
+ - Code coverage tracking with codecov.io
27
+ - `node_modules` folders are now ignored.
28
+
15
29
  ## [0.11.0] - 2020-02-09
16
30
 
17
31
  ### Fixed
@@ -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"
@@ -54,6 +54,9 @@ class Rufo::Command
54
54
  rescue Rufo::SyntaxError => e
55
55
  logger.error("STDIN is invalid code. Error on line:#{e.lineno} #{e.message}")
56
56
  CODE_ERROR
57
+ rescue Rufo::UnknownSyntaxError
58
+ logger.error("STDIN is invalid code. Try running the code for a better error.")
59
+ CODE_ERROR
57
60
  rescue => e
58
61
  logger.error("You've found a bug!")
59
62
  logger.error("Please report it to https://github.com/ruby-formatter/rufo/issues with code that triggers it\n")
@@ -96,7 +99,7 @@ class Rufo::Command
96
99
 
97
100
  def format_file(filename)
98
101
  logger.debug("Formatting: #{filename}")
99
- code = File.read(filename)
102
+ code = File.read(filename, encoding: "UTF-8")
100
103
 
101
104
  begin
102
105
  location = @filename_for_dot_rufo || File.dirname(filename)
@@ -122,6 +125,9 @@ class Rufo::Command
122
125
  rescue Rufo::SyntaxError => e
123
126
  logger.error("#{filename}:#{e.lineno} #{e.message}")
124
127
  CODE_ERROR
128
+ rescue Rufo::UnknownSyntaxError
129
+ logger.error("#{filename} is invalid code. Try running the code for a better error.")
130
+ CODE_ERROR
125
131
  rescue => e
126
132
  logger.error("You've found a bug!")
127
133
  logger.error("It happened while trying to format the file #{filename}")
@@ -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
@@ -2924,10 +2927,23 @@ class Rufo::Formatter
2924
2927
  visit_comma_separated_list conds
2925
2928
  skip_space
2926
2929
  end
2930
+ written_space = false
2931
+ if semicolon?
2932
+ inline = true
2933
+ skip_semicolons
2934
+
2935
+ if newline? || comment?
2936
+ inline = false
2937
+ else
2938
+ write ";"
2939
+ track_case_when
2940
+ write " "
2941
+ written_space = true
2942
+ end
2943
+ end
2927
2944
 
2928
- then_keyword = keyword?("then")
2929
- inline = then_keyword || semicolon?
2930
- if then_keyword
2945
+ if keyword?("then")
2946
+ inline = true
2931
2947
  next_token
2932
2948
 
2933
2949
  skip_space
@@ -2941,7 +2957,7 @@ class Rufo::Formatter
2941
2957
  # Cancel tracking of `case when ... then` on a nelwine.
2942
2958
  @case_when_positions.pop
2943
2959
  else
2944
- write_space
2960
+ write_space unless written_space
2945
2961
 
2946
2962
  write "then"
2947
2963
 
@@ -2964,16 +2980,6 @@ class Rufo::Formatter
2964
2980
 
2965
2981
  write_space
2966
2982
  end
2967
- elsif semicolon?
2968
- skip_semicolons
2969
-
2970
- if newline? || comment?
2971
- inline = false
2972
- else
2973
- write ";"
2974
- track_case_when
2975
- write " "
2976
- end
2977
2983
  end
2978
2984
 
2979
2985
  if inline
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rufo
4
- VERSION = "0.11.0"
4
+ VERSION = "0.12.0"
5
5
  end
@@ -29,4 +29,6 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency "rspec", "~> 3.0"
30
30
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.1"
31
31
  spec.add_development_dependency "rubocop", "~> 0.79.0"
32
+ spec.add_development_dependency "simplecov", "~> 0.18.5"
33
+ spec.add_development_dependency "simplecov-cobertura", "~> 1.3.1"
32
34
  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.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ary Borenszweig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-02-09 00:00:00.000000000 Z
11
+ date: 2020-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,6 +108,34 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: 0.79.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.18.5
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.18.5
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov-cobertura
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 1.3.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 1.3.1
111
139
  description: Fast and unobtrusive Ruby code formatter
112
140
  email:
113
141
  - asterite@gmail.com
@@ -140,6 +168,7 @@ files:
140
168
  - lib/rufo/dot_file.rb
141
169
  - lib/rufo/erb_formatter.rb
142
170
  - lib/rufo/file_finder.rb
171
+ - lib/rufo/file_list.rb
143
172
  - lib/rufo/formatter.rb
144
173
  - lib/rufo/logger.rb
145
174
  - lib/rufo/parser.rb
@@ -166,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
195
  - !ruby/object:Gem::Version
167
196
  version: '0'
168
197
  requirements: []
169
- rubygems_version: 3.0.3
198
+ rubygems_version: 3.1.2
170
199
  signing_key:
171
200
  specification_version: 4
172
201
  summary: Ruby code formatter