rufo 0.11.0 → 0.12.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: 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