isort 0.2.0 ā 0.2.1
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 +4 -4
- data/isort-0.2.0.gem +0 -0
- data/lib/isort/file_processor.rb +426 -0
- data/lib/isort/import_block.rb +164 -0
- data/lib/isort/import_statement.rb +126 -0
- data/lib/isort/parser.rb +173 -0
- data/lib/isort/section.rb +197 -0
- data/lib/isort/syntax_validator.rb +75 -0
- data/lib/isort/version.rb +1 -1
- data/lib/isort/wrap_modes.rb +240 -0
- data/test_local.rb +106 -0
- metadata +11 -1
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Isort
|
|
4
|
+
# Wrap modes for handling long import lines
|
|
5
|
+
module WrapModes
|
|
6
|
+
# Mode 0: Grid - wraps with opening parenthesis on first line
|
|
7
|
+
# require 'a', 'b', 'c',
|
|
8
|
+
# 'd', 'e'
|
|
9
|
+
GRID = 0
|
|
10
|
+
|
|
11
|
+
# Mode 1: Vertical - one import per line after opening paren
|
|
12
|
+
# require(
|
|
13
|
+
# 'a',
|
|
14
|
+
# 'b',
|
|
15
|
+
# 'c',
|
|
16
|
+
# )
|
|
17
|
+
VERTICAL = 1
|
|
18
|
+
|
|
19
|
+
# Mode 2: Hanging indent - continuation lines have extra indent
|
|
20
|
+
# require 'a', 'b', 'c',
|
|
21
|
+
# 'd', 'e'
|
|
22
|
+
HANGING_INDENT = 2
|
|
23
|
+
|
|
24
|
+
# Mode 3: Vertical hanging indent - combines vertical and hanging
|
|
25
|
+
# require(
|
|
26
|
+
# 'a',
|
|
27
|
+
# 'b',
|
|
28
|
+
# 'c',
|
|
29
|
+
# )
|
|
30
|
+
VERTICAL_HANGING_INDENT = 3
|
|
31
|
+
|
|
32
|
+
# Mode 4: Vertical grid - like grid but vertical
|
|
33
|
+
# require(
|
|
34
|
+
# 'a', 'b',
|
|
35
|
+
# 'c', 'd',
|
|
36
|
+
# )
|
|
37
|
+
VERTICAL_GRID = 4
|
|
38
|
+
|
|
39
|
+
# Mode 5: Vertical grid grouped - groups related imports
|
|
40
|
+
# require('a', 'b',
|
|
41
|
+
# 'c', 'd')
|
|
42
|
+
VERTICAL_GRID_GROUPED = 5
|
|
43
|
+
|
|
44
|
+
# Mode 6: Vertical grid grouped with trailing comma
|
|
45
|
+
VERTICAL_GRID_GROUPED_NO_WRAP = 6
|
|
46
|
+
|
|
47
|
+
# Mode 7: NOQA - single line with comment to disable linting
|
|
48
|
+
NOQA = 7
|
|
49
|
+
|
|
50
|
+
# Default mode
|
|
51
|
+
DEFAULT = VERTICAL_HANGING_INDENT
|
|
52
|
+
|
|
53
|
+
# All available modes
|
|
54
|
+
MODES = {
|
|
55
|
+
grid: GRID,
|
|
56
|
+
vertical: VERTICAL,
|
|
57
|
+
hanging_indent: HANGING_INDENT,
|
|
58
|
+
vertical_hanging_indent: VERTICAL_HANGING_INDENT,
|
|
59
|
+
vertical_grid: VERTICAL_GRID,
|
|
60
|
+
vertical_grid_grouped: VERTICAL_GRID_GROUPED,
|
|
61
|
+
vertical_grid_grouped_no_wrap: VERTICAL_GRID_GROUPED_NO_WRAP,
|
|
62
|
+
noqa: NOQA
|
|
63
|
+
}.freeze
|
|
64
|
+
|
|
65
|
+
class << self
|
|
66
|
+
# Get mode by name or number
|
|
67
|
+
def get(mode)
|
|
68
|
+
case mode
|
|
69
|
+
when Integer
|
|
70
|
+
mode
|
|
71
|
+
when Symbol, String
|
|
72
|
+
MODES[mode.to_sym] || DEFAULT
|
|
73
|
+
else
|
|
74
|
+
DEFAULT
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Format a multi-import line according to the wrap mode
|
|
79
|
+
# for formatting long autoload statements or future multi-require support
|
|
80
|
+
def format_line(imports, mode: DEFAULT, line_length: 79, indent: "")
|
|
81
|
+
mode = get(mode)
|
|
82
|
+
|
|
83
|
+
case mode
|
|
84
|
+
when GRID
|
|
85
|
+
format_grid(imports, line_length, indent)
|
|
86
|
+
when VERTICAL
|
|
87
|
+
format_vertical(imports, indent)
|
|
88
|
+
when HANGING_INDENT
|
|
89
|
+
format_hanging_indent(imports, line_length, indent)
|
|
90
|
+
when VERTICAL_HANGING_INDENT
|
|
91
|
+
format_vertical_hanging_indent(imports, indent)
|
|
92
|
+
when VERTICAL_GRID
|
|
93
|
+
format_vertical_grid(imports, line_length, indent)
|
|
94
|
+
when VERTICAL_GRID_GROUPED
|
|
95
|
+
format_vertical_grid_grouped(imports, line_length, indent)
|
|
96
|
+
when NOQA
|
|
97
|
+
format_noqa(imports, indent)
|
|
98
|
+
else
|
|
99
|
+
format_vertical_hanging_indent(imports, indent)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Check if a line needs wrapping based on line length
|
|
104
|
+
def needs_wrapping?(line, max_length: 79)
|
|
105
|
+
line.length > max_length
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Split a long import line into multiple lines
|
|
109
|
+
# Currently used for comments/documentation, as Ruby imports are typically single-line
|
|
110
|
+
def wrap_comment(comment, max_length: 79, indent: "")
|
|
111
|
+
return [comment] if comment.length <= max_length
|
|
112
|
+
|
|
113
|
+
words = comment.split(/\s+/)
|
|
114
|
+
lines = []
|
|
115
|
+
current_line = indent.dup
|
|
116
|
+
|
|
117
|
+
words.each do |word|
|
|
118
|
+
if current_line.length + word.length + 1 > max_length && current_line != indent
|
|
119
|
+
lines << current_line.rstrip
|
|
120
|
+
current_line = "#{indent}# #{word}"
|
|
121
|
+
else
|
|
122
|
+
current_line += current_line == indent ? "# #{word}" : " #{word}"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
lines << current_line.rstrip unless current_line.strip.empty?
|
|
127
|
+
lines
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def format_grid(imports, line_length, indent)
|
|
133
|
+
return imports.first if imports.size == 1
|
|
134
|
+
|
|
135
|
+
lines = []
|
|
136
|
+
current_line = indent.dup
|
|
137
|
+
|
|
138
|
+
imports.each_with_index do |imp, idx|
|
|
139
|
+
separator = idx < imports.size - 1 ? ", " : ""
|
|
140
|
+
potential = current_line + imp + separator
|
|
141
|
+
|
|
142
|
+
if potential.length > line_length && current_line != indent
|
|
143
|
+
lines << current_line.rstrip.chomp(",")
|
|
144
|
+
current_line = "#{indent}#{imp}#{separator}"
|
|
145
|
+
else
|
|
146
|
+
current_line = potential
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
lines << current_line.rstrip
|
|
151
|
+
lines.join("\n")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def format_vertical(imports, indent)
|
|
155
|
+
inner_indent = "#{indent} "
|
|
156
|
+
result = ["#{indent}("]
|
|
157
|
+
imports.each do |imp|
|
|
158
|
+
result << "#{inner_indent}#{imp},"
|
|
159
|
+
end
|
|
160
|
+
result << "#{indent})"
|
|
161
|
+
result.join("\n")
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def format_hanging_indent(imports, line_length, indent)
|
|
165
|
+
continuation_indent = "#{indent} "
|
|
166
|
+
lines = []
|
|
167
|
+
current_line = indent.dup
|
|
168
|
+
|
|
169
|
+
imports.each_with_index do |imp, idx|
|
|
170
|
+
separator = idx < imports.size - 1 ? ", " : ""
|
|
171
|
+
|
|
172
|
+
if idx == 0
|
|
173
|
+
current_line += imp + separator
|
|
174
|
+
elsif current_line.length + imp.length + separator.length > line_length
|
|
175
|
+
lines << current_line.rstrip.chomp(",")
|
|
176
|
+
current_line = "#{continuation_indent}#{imp}#{separator}"
|
|
177
|
+
else
|
|
178
|
+
current_line += imp + separator
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
lines << current_line.rstrip
|
|
183
|
+
lines.join("\n")
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def format_vertical_hanging_indent(imports, indent)
|
|
187
|
+
inner_indent = "#{indent} "
|
|
188
|
+
result = ["#{indent}("]
|
|
189
|
+
imports.each do |imp|
|
|
190
|
+
result << "#{inner_indent}#{imp},"
|
|
191
|
+
end
|
|
192
|
+
result << "#{indent})"
|
|
193
|
+
result.join("\n")
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def format_vertical_grid(imports, line_length, indent)
|
|
197
|
+
inner_indent = "#{indent} "
|
|
198
|
+
result = ["#{indent}("]
|
|
199
|
+
current_line = inner_indent.dup
|
|
200
|
+
|
|
201
|
+
imports.each_with_index do |imp, idx|
|
|
202
|
+
separator = idx < imports.size - 1 ? ", " : ","
|
|
203
|
+
|
|
204
|
+
if current_line.length + imp.length + separator.length > line_length && current_line != inner_indent
|
|
205
|
+
result << current_line.rstrip
|
|
206
|
+
current_line = "#{inner_indent}#{imp}#{separator}"
|
|
207
|
+
else
|
|
208
|
+
current_line += current_line == inner_indent ? "#{imp}#{separator}" : " #{imp}#{separator}"
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
result << current_line.rstrip unless current_line.strip.empty?
|
|
213
|
+
result << "#{indent})"
|
|
214
|
+
result.join("\n")
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def format_vertical_grid_grouped(imports, line_length, indent)
|
|
218
|
+
inner_indent = "#{indent} "
|
|
219
|
+
current_line = "#{indent}("
|
|
220
|
+
|
|
221
|
+
imports.each_with_index do |imp, idx|
|
|
222
|
+
separator = idx < imports.size - 1 ? ", " : ""
|
|
223
|
+
|
|
224
|
+
if current_line.length + imp.length + separator.length > line_length
|
|
225
|
+
current_line += "\n#{inner_indent}#{imp}#{separator}"
|
|
226
|
+
else
|
|
227
|
+
current_line += imp + separator
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
current_line + ")"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def format_noqa(imports, indent)
|
|
235
|
+
line = imports.join(", ")
|
|
236
|
+
"#{indent}#{line} # noqa"
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
data/test_local.rb
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Quick script to test isort locally
|
|
5
|
+
# Usage: bundle exec ruby test_local.rb
|
|
6
|
+
|
|
7
|
+
$LOAD_PATH.unshift File.expand_path("lib", __dir__)
|
|
8
|
+
require "isort"
|
|
9
|
+
require "tempfile"
|
|
10
|
+
|
|
11
|
+
puts "=" * 60
|
|
12
|
+
puts "Testing isort locally"
|
|
13
|
+
puts "=" * 60
|
|
14
|
+
|
|
15
|
+
# Create a test file with unsorted imports
|
|
16
|
+
test_content = <<~RUBY
|
|
17
|
+
require 'yaml'
|
|
18
|
+
require_relative 'helper'
|
|
19
|
+
require 'json'
|
|
20
|
+
include Enumerable
|
|
21
|
+
require 'csv'
|
|
22
|
+
extend ActiveSupport::Concern
|
|
23
|
+
require_relative 'version'
|
|
24
|
+
|
|
25
|
+
class MyApp
|
|
26
|
+
def run
|
|
27
|
+
puts "Hello"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
RUBY
|
|
31
|
+
|
|
32
|
+
tempfile = Tempfile.new(["test_isort", ".rb"])
|
|
33
|
+
tempfile.write(test_content)
|
|
34
|
+
tempfile.flush
|
|
35
|
+
|
|
36
|
+
puts "\nš Original file:"
|
|
37
|
+
puts "-" * 40
|
|
38
|
+
puts test_content
|
|
39
|
+
|
|
40
|
+
puts "\nš Running --check mode:"
|
|
41
|
+
puts "-" * 40
|
|
42
|
+
processor = Isort::FileProcessor.new(tempfile.path)
|
|
43
|
+
would_change = processor.check
|
|
44
|
+
puts would_change ? "File needs sorting" : "File is already sorted"
|
|
45
|
+
|
|
46
|
+
puts "\nš Running --diff mode:"
|
|
47
|
+
puts "-" * 40
|
|
48
|
+
diff_output = processor.diff
|
|
49
|
+
if diff_output
|
|
50
|
+
puts diff_output
|
|
51
|
+
else
|
|
52
|
+
puts "No changes needed"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
puts "\nā
Running sort:"
|
|
56
|
+
puts "-" * 40
|
|
57
|
+
processor2 = Isort::FileProcessor.new(tempfile.path)
|
|
58
|
+
changed = processor2.process
|
|
59
|
+
|
|
60
|
+
puts "\nš Sorted file:"
|
|
61
|
+
puts "-" * 40
|
|
62
|
+
puts File.read(tempfile.path)
|
|
63
|
+
|
|
64
|
+
puts "\nš Testing idempotency (running again):"
|
|
65
|
+
puts "-" * 40
|
|
66
|
+
processor3 = Isort::FileProcessor.new(tempfile.path)
|
|
67
|
+
changed_again = processor3.process
|
|
68
|
+
puts changed_again ? "File changed (NOT idempotent!)" : "No changes (idempotent ā)"
|
|
69
|
+
|
|
70
|
+
# Test skip directive
|
|
71
|
+
puts "\nš« Testing skip directive:"
|
|
72
|
+
puts "-" * 40
|
|
73
|
+
skip_content = <<~RUBY
|
|
74
|
+
require 'yaml' # isort:skip
|
|
75
|
+
require 'json'
|
|
76
|
+
require 'csv'
|
|
77
|
+
RUBY
|
|
78
|
+
|
|
79
|
+
tempfile2 = Tempfile.new(["test_skip", ".rb"])
|
|
80
|
+
tempfile2.write(skip_content)
|
|
81
|
+
tempfile2.flush
|
|
82
|
+
|
|
83
|
+
puts "Original:"
|
|
84
|
+
puts skip_content
|
|
85
|
+
Isort::FileProcessor.new(tempfile2.path).process
|
|
86
|
+
puts "\nAfter sorting (yaml should stay first due to skip):"
|
|
87
|
+
puts File.read(tempfile2.path)
|
|
88
|
+
|
|
89
|
+
# Test section-based grouping
|
|
90
|
+
puts "\nš¦ Section-based grouping:"
|
|
91
|
+
puts "-" * 40
|
|
92
|
+
puts "Imports are grouped by section:"
|
|
93
|
+
puts " 1. stdlib (json, csv, yaml...)"
|
|
94
|
+
puts " 2. thirdparty (rails, active_support...)"
|
|
95
|
+
puts " 3. firstparty (include, extend, autoload, using)"
|
|
96
|
+
puts " 4. localfolder (require_relative)"
|
|
97
|
+
|
|
98
|
+
# Cleanup
|
|
99
|
+
tempfile.close
|
|
100
|
+
tempfile.unlink
|
|
101
|
+
tempfile2.close
|
|
102
|
+
tempfile2.unlink
|
|
103
|
+
|
|
104
|
+
puts "\n" + "=" * 60
|
|
105
|
+
puts "All tests completed!"
|
|
106
|
+
puts "=" * 60
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: isort
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- abhinvv1
|
|
@@ -87,11 +87,20 @@ files:
|
|
|
87
87
|
- README.md
|
|
88
88
|
- Rakefile
|
|
89
89
|
- exe/isort
|
|
90
|
+
- isort-0.2.0.gem
|
|
90
91
|
- lib/isort.rb
|
|
92
|
+
- lib/isort/file_processor.rb
|
|
93
|
+
- lib/isort/import_block.rb
|
|
94
|
+
- lib/isort/import_statement.rb
|
|
95
|
+
- lib/isort/parser.rb
|
|
96
|
+
- lib/isort/section.rb
|
|
97
|
+
- lib/isort/syntax_validator.rb
|
|
91
98
|
- lib/isort/version.rb
|
|
99
|
+
- lib/isort/wrap_modes.rb
|
|
92
100
|
- sample.rb
|
|
93
101
|
- sig/isort.rbs
|
|
94
102
|
- sig/isort/file_sorter.rbs
|
|
103
|
+
- test_local.rb
|
|
95
104
|
homepage: https://github.com/abhinvv1/isort
|
|
96
105
|
licenses:
|
|
97
106
|
- MIT
|
|
@@ -99,6 +108,7 @@ metadata:
|
|
|
99
108
|
homepage_uri: https://github.com/abhinvv1/isort
|
|
100
109
|
source_code_uri: https://github.com/abhinvv1/isort
|
|
101
110
|
changelog_uri: https://github.com/abhinvv1/isort
|
|
111
|
+
github_repo: ssh://github.com/abhinvv1/isort
|
|
102
112
|
post_install_message:
|
|
103
113
|
rdoc_options: []
|
|
104
114
|
require_paths:
|