rufo 0.0.2 → 0.0.3

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
  SHA1:
3
- metadata.gz: 4254f11d5e797cb76d947f8e5ae0e9fddd0fc281
4
- data.tar.gz: b3937d7d503a7faf716e6deebf2f228feae26a36
3
+ metadata.gz: f651b0e7deb5c6d36cbe7632aa761954e7d49939
4
+ data.tar.gz: 20b7c26c352e682cf72547fdeebf25d31b467aa4
5
5
  SHA512:
6
- metadata.gz: 2b7110b0fc44a623f5c473b6be8b6a80bb7dede05a551a5fa8b1408f264c18281ceba1078ff991f0cda1deffa15b92369676c42254414af9ac46f3b2f3f4a07a
7
- data.tar.gz: 80d832ba0b8798af6de39fe9adeaa10c6ab0c4f09350c5b3205684e2e34b658d54cbb64f9723240833f46eaa111c44da87c165a46ab80da823e69a99be8a221d
6
+ metadata.gz: b9f40a5d0fd5ad07143ccc49fafddce8bd72cad15ada182f8cdf03b239a956f5a4072fe0df639d53a3c88d928a12058a360158b1a3b61462e073b2d9973cdfb1
7
+ data.tar.gz: 122c69242308b0999954d684ae4cfb4a0020d5ec9b68de7f76ce449a47076d659d8062f8c69fe9da80057031e07caddcc19f8a0fb653cd1e7ee0be3619d990c9
data/.rufo ADDED
@@ -0,0 +1,5 @@
1
+ align_comments true
2
+ align_assignments true
3
+ align_hash_keys true
4
+ convert_brace_to_do true
5
+ indent_size 2
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Rufo
2
2
 
3
- **Ru**by **fo**rmatter (in development)
3
+ **Ru**by **fo**rmatter
4
4
 
5
5
  ## Installation
6
6
 
@@ -20,10 +20,61 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
+ ### Format files or directories
24
+
25
+ ```
26
+ $ rufo file names or dir names
27
+ ```
28
+
29
+ ### Format STDIN
30
+
31
+ ```
32
+ $ cat file.rb | rufo
23
33
  ```
24
- $ rufo file.rb
34
+
35
+ ### Check that no formatting changes are produced
36
+
37
+ ```
38
+ $ rufo --check file names or dir names
39
+ ```
40
+
41
+ This will print one line for each file that isn't correctly formatted
42
+ according to **rufo**, and will exit with exit code 1.
43
+
44
+ ## Editor support
45
+
46
+ - Sublime Text: [sublime-rufo](https://github.com/asterite/sublime-rufo)
47
+
48
+ ## Configuration
49
+
50
+ Rufo follows most (if not all) of the conventions found in this [Ruby style guide](https://github.com/bbatsov/ruby-style-guide). It does a bit more than that, and it can also be configured a bit.
51
+
52
+ To configure it, place a `.rufo` file in your project. When formatting a file or a directory
53
+ via the `rufo` program, a `.rufo` file will try to be found in that directory or parent directories.
54
+
55
+ The `.rufo` file is a Ruby file that is evaluated in the context of the formatter. These are the
56
+ available configurations:
57
+
58
+ ```ruby
59
+ # Whether to align successive comments (default: true)
60
+ align_comments true
61
+
62
+ # Whether to align successive assignments (default: true)
63
+ align_assignments true
64
+
65
+ # Whether to align successive hash keys (default: true)
66
+ align_hash_keys true
67
+
68
+ # Whether to convert multiline `{ ... }` block to `do ... end` (default: true)
69
+ convert_brace_to_do true
70
+
71
+ # The indent size (default: 2)
72
+ indent_size 2
25
73
  ```
26
74
 
75
+ As time passes there might be more configurations available. Please open an
76
+ issue if you need something else to be configurable.
77
+
27
78
  ## Development
28
79
 
29
80
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -2,6 +2,7 @@ require "rufo/version"
2
2
 
3
3
  module Rufo
4
4
  class Bug < Exception; end
5
+
5
6
  class SyntaxError < Exception; end
6
7
 
7
8
  def self.format(code, **options)
@@ -1,27 +1,127 @@
1
+ require "optionparser"
2
+
1
3
  module Rufo::Command
2
4
  def self.run
5
+ want_check = parse_options
6
+
3
7
  if ARGV.empty?
4
- format_stdin
8
+ format_stdin want_check
9
+ else
10
+ format_args ARGV, want_check
11
+ end
12
+ rescue Rufo::SyntaxError
13
+ STDERR.puts "Error: the given text is not a valid ruby program (it has syntax errors)"
14
+ exit 1
15
+ end
16
+
17
+ def self.format_stdin(want_check)
18
+ code = STDIN.read
19
+ result = format(code, Dir.getwd)
20
+
21
+ if want_check
22
+ exit 1 if result != code
5
23
  else
6
- format_file ARGV[0]
24
+ print result
7
25
  end
8
26
  rescue Rufo::Bug => ex
9
- STDERR.puts "You've found a bug! Please report it to https://github.com/asterite/rufo/issues with code that triggers it"
27
+ STDERR.puts "You've found a bug!"
28
+ STDERR.puts "Please report it to https://github.com/asterite/rufo/issues with code that triggers it"
29
+ STDERR.puts
30
+ raise ex
31
+ end
32
+
33
+ def self.format_args(args, want_check)
34
+ files = []
35
+
36
+ args.each do |arg|
37
+ if Dir.exist?(arg)
38
+ files.concat Dir["#{arg}/**/*.rb"]
39
+ elsif File.exist?(arg)
40
+ files << arg
41
+ else
42
+ STDERR.puts "Error: file or directory not found: #{arg}"
43
+ end
44
+ end
45
+
46
+ changed = false
47
+
48
+ files.each do |file|
49
+ changed ||= format_file file, want_check
50
+ end
51
+
52
+ exit 1 if changed
53
+ end
54
+
55
+ def self.format_file(filename, want_check)
56
+ code = File.read(filename)
57
+ result = format(code, File.dirname(filename))
58
+
59
+ if code != result
60
+ if want_check
61
+ STDERR.puts "Error: formatting #{filename} produced changes"
62
+ else
63
+ File.write(filename, result)
64
+ puts "Format: #{filename}"
65
+ end
66
+
67
+ return true
68
+ end
69
+
70
+ false
71
+ rescue Rufo::Bug => ex
72
+ STDERR.puts "You've found a bug!"
73
+ STDERR.puts "It happened while trying to format the file #{filename}"
74
+ STDERR.puts "Please report it to https://github.com/asterite/rufo/issues with code that triggers it"
10
75
  STDERR.puts
11
76
  raise ex
12
- rescue Rufo::SyntaxError
13
- STDERR.puts "Error: the given text is not a valid ruby program (it has syntax errors)"
14
77
  end
15
78
 
16
- def self.format_stdin
17
- code = STDIN.read
18
- result = Rufo.format(code)
19
- print result
79
+ def self.format(code, dir)
80
+ formatter = Rufo::Formatter.new(code)
81
+
82
+ dot_rufo = find_dot_rufo(dir)
83
+ if dot_rufo
84
+ begin
85
+ formatter.instance_eval(File.read(dot_rufo))
86
+ rescue => ex
87
+ STDERR.puts "Error evaluating #{dot_rufo}"
88
+ raise ex
89
+ end
90
+ end
91
+
92
+ formatter.format
93
+ formatter.result
20
94
  end
21
95
 
22
- def self.format_file(filename)
23
- code = File.read(filename)
24
- result = Rufo.format(code)
25
- File.write(filename, result)
96
+ def self.find_dot_rufo(dir)
97
+ dir = File.expand_path(dir)
98
+ file = File.join(dir, ".rufo")
99
+ if File.exist?(file)
100
+ return file
101
+ end
102
+
103
+ parent_dir = File.dirname(dir)
104
+ return if parent_dir == dir
105
+
106
+ find_dot_rufo(parent_dir)
107
+ end
108
+
109
+ def self.parse_options
110
+ want_check = false
111
+
112
+ OptionParser.new do |opts|
113
+ opts.banner = "Usage: rufo files or dirs [options]"
114
+
115
+ opts.on("-c", "--check", "Only check formating changes") do
116
+ want_check = true
117
+ end
118
+
119
+ opts.on("-h", "--help", "Show this help") do
120
+ puts opts
121
+ exit
122
+ end
123
+ end.parse!
124
+
125
+ want_check
26
126
  end
27
127
  end
@@ -7,36 +7,20 @@ class Rufo::Formatter
7
7
  formatter.result
8
8
  end
9
9
 
10
- # The indent size (default: 2)
11
- attr_accessor :indent_size
12
-
13
- # Whether to align successive comments (default: true)
14
- attr_accessor :align_comments
15
-
16
- # Whether to convert multiline `{ ... }` block
17
- # to `do ... end` (default: true)
18
- attr_accessor :convert_brace_to_do
19
-
20
- # Whether to align successive assignments (default: true)
21
- attr_accessor :align_assignments
22
-
23
- # Whether to align successive hash keys (default: true)
24
- attr_accessor :align_hash_keys
25
-
26
10
  def initialize(code, **options)
27
- @code = code
11
+ @code = code
28
12
  @tokens = Ripper.lex(code).reverse!
29
- @sexp = Ripper.sexp(code)
13
+ @sexp = Ripper.sexp(code)
30
14
 
31
15
  unless @sexp
32
16
  raise ::Rufo::SyntaxError.new
33
17
  end
34
18
 
35
- @indent = 0
36
- @line = 0
37
- @column = 0
19
+ @indent = 0
20
+ @line = 0
21
+ @column = 0
38
22
  @last_was_newline = false
39
- @output = ""
23
+ @output = ""
40
24
 
41
25
  # The column of a `obj.method` call, so we can align
42
26
  # calls to that dot
@@ -64,11 +48,37 @@ class Rufo::Formatter
64
48
  @hash_keys_positions = []
65
49
 
66
50
  # Settings
67
- @indent_size = options.fetch(:indent_size, 2)
68
- @align_comments = options.fetch(:align_comments, true)
51
+ @indent_size = options.fetch(:indent_size, 2)
52
+ @align_comments = options.fetch(:align_comments, true)
69
53
  @convert_brace_to_do = options.fetch(:convert_brace_to_do, true)
70
- @align_assignments = options.fetch(:align_assignments, true)
71
- @align_hash_keys = options.fetch(:align_hash_keys, true)
54
+ @align_assignments = options.fetch(:align_assignments, true)
55
+ @align_hash_keys = options.fetch(:align_hash_keys, true)
56
+ end
57
+
58
+ # The indent size (default: 2)
59
+ def indent_size(value)
60
+ @indent_size = value
61
+ end
62
+
63
+ # Whether to align successive comments (default: true)
64
+ def align_comments(value)
65
+ @align_comments = value
66
+ end
67
+
68
+ # Whether to convert multiline `{ ... }` block
69
+ # to `do ... end` (default: true)
70
+ def convert_brace_to_do(value)
71
+ @convert_brace_to_do = value
72
+ end
73
+
74
+ # Whether to align successive assignments (default: true)
75
+ def align_assignments(value)
76
+ @align_assignments = value
77
+ end
78
+
79
+ # Whether to align successive hash keys (default: true)
80
+ def align_hash_keys(value)
81
+ @align_hash_keys = value
72
82
  end
73
83
 
74
84
  def format
@@ -105,7 +115,7 @@ class Rufo::Formatter
105
115
  when :@tstring_content
106
116
  # [:@tstring_content, "hello ", [1, 1]]
107
117
  heredoc, tilde = @current_heredoc
108
- column = node[2][0]
118
+ column = node[2][0]
109
119
 
110
120
  # For heredocs with tilde we sometimes need to align the contents
111
121
  if heredoc && tilde && @last_was_newline
@@ -306,7 +316,7 @@ class Rufo::Formatter
306
316
  # Don't indent if this exp is in the same line as the previous
307
317
  # one (this happens when there's a semicolon between the exps)
308
318
  unless line_before_endline && line_before_endline == @line
309
- write_indent
319
+ write_indent
310
320
  end
311
321
  end
312
322
 
@@ -340,7 +350,7 @@ class Rufo::Formatter
340
350
  def visit_string_literal(node)
341
351
  # [:string_literal, [:string_content, exps]]
342
352
  heredoc = current_token_kind == :on_heredoc_beg
343
- tilde = current_token_value.include?("~")
353
+ tilde = current_token_value.include?("~")
344
354
 
345
355
  if heredoc
346
356
  write current_token_value.rstrip
@@ -423,7 +433,7 @@ class Rufo::Formatter
423
433
  pieces.each_with_index do |piece, i|
424
434
  visit piece
425
435
  unless last?(i, pieces)
426
- consume_op "::"
436
+ consume_op "::"
427
437
  skip_space_or_newline
428
438
  end
429
439
  end
@@ -454,7 +464,7 @@ class Rufo::Formatter
454
464
  check :on_op
455
465
 
456
466
  before = op[1][0...-1]
457
- after = op[1][-1]
467
+ after = op[1][-1]
458
468
 
459
469
  write before
460
470
  track_assignment before.size
@@ -491,6 +501,10 @@ class Rufo::Formatter
491
501
  end
492
502
  end
493
503
 
504
+ def track_comment
505
+ @comments_positions << [@line, @column, 0, nil, 0]
506
+ end
507
+
494
508
  def track_assignment(offset = 0)
495
509
  track_alignment @assignments_positions, offset
496
510
  end
@@ -607,8 +621,8 @@ class Rufo::Formatter
607
621
  def visit_call_without_receiver(node)
608
622
  # foo(arg1, ..., argN)
609
623
  #
610
- # [:method_add_arg,
611
- # [:fcall, [:@ident, "foo", [1, 0]]],
624
+ # [:method_add_arg,
625
+ # [:fcall, [:@ident, "foo", [1, 0]]],
612
626
  # [:arg_paren, [:args_add_block, [[:@int, "1", [1, 6]]], false]]]
613
627
  _, name, args = node
614
628
 
@@ -724,7 +738,7 @@ class Rufo::Formatter
724
738
  @current_heredoc = [heredoc, tilde]
725
739
  visit_string_literal_end(heredoc)
726
740
  @current_heredoc = nil
727
- printed = true
741
+ printed = true
728
742
  end
729
743
  end
730
744
 
@@ -987,7 +1001,7 @@ class Rufo::Formatter
987
1001
  end
988
1002
 
989
1003
  def visit_mlhs_paren(node)
990
- # [:mlhs_paren,
1004
+ # [:mlhs_paren,
991
1005
  # [[:mlhs_paren, [:@ident, "x", [1, 12]]]]
992
1006
  # ]
993
1007
  _, args = node
@@ -1026,7 +1040,7 @@ class Rufo::Formatter
1026
1040
  if inside_call
1027
1041
  if newline? || comment?
1028
1042
  needs_indent = true
1029
- base_column = next_indent
1043
+ base_column = next_indent
1030
1044
  consume_end_of_line
1031
1045
  write_indent(base_column)
1032
1046
  else
@@ -1431,7 +1445,7 @@ class Rufo::Formatter
1431
1445
  write_indent(next_indent)
1432
1446
  else
1433
1447
  next_token
1434
- write_space " "
1448
+ write_space " "
1435
1449
  end
1436
1450
  end
1437
1451
  end
@@ -1482,11 +1496,11 @@ class Rufo::Formatter
1482
1496
  _, key, value = node
1483
1497
 
1484
1498
  visit key
1485
-
1499
+
1486
1500
  skip_space_or_newline
1487
1501
  consume_space
1488
1502
 
1489
- track_hash_key
1503
+ track_hash_key
1490
1504
 
1491
1505
  # Don't output `=>` for keys that are `label: value`
1492
1506
  unless key[0] == :@label
@@ -1577,7 +1591,7 @@ class Rufo::Formatter
1577
1591
 
1578
1592
  if args
1579
1593
  indent(needed_indent) do
1580
- visit args
1594
+ visit args
1581
1595
  end
1582
1596
  end
1583
1597
 
@@ -1603,7 +1617,7 @@ class Rufo::Formatter
1603
1617
  end
1604
1618
 
1605
1619
  def visit_setter(node)
1606
- # foo.bar
1620
+ # foo.bar
1607
1621
  # (followed by `=`, though not included in this node)
1608
1622
  #
1609
1623
  # [:field, receiver, :".", name]
@@ -1926,7 +1940,7 @@ class Rufo::Formatter
1926
1940
  end
1927
1941
 
1928
1942
  then_keyword = keyword?("then")
1929
- inline = then_keyword || semicolon?
1943
+ inline = then_keyword || semicolon?
1930
1944
  if then_keyword
1931
1945
  next_token
1932
1946
  skip_space
@@ -1989,7 +2003,7 @@ class Rufo::Formatter
1989
2003
  def skip_space_or_newline(want_semicolon = false)
1990
2004
  found_newline = false
1991
2005
  found_comment = false
1992
- last = nil
2006
+ last = nil
1993
2007
 
1994
2008
  while true
1995
2009
  case current_token_kind
@@ -1997,7 +2011,7 @@ class Rufo::Formatter
1997
2011
  next_token
1998
2012
  when :on_nl, :on_ignored_nl
1999
2013
  next_token
2000
- last = :newline
2014
+ last = :newline
2001
2015
  found_newline = true
2002
2016
  when :on_semicolon
2003
2017
  if !found_newline && !found_comment
@@ -2017,7 +2031,7 @@ class Rufo::Formatter
2017
2031
  end
2018
2032
  next_token
2019
2033
  found_comment = true
2020
- last = :comment
2034
+ last = :comment
2021
2035
  else
2022
2036
  break
2023
2037
  end
@@ -2048,9 +2062,9 @@ class Rufo::Formatter
2048
2062
  # If the value has newlines, we need to adjust line and column
2049
2063
  number_of_lines = value.count("\n")
2050
2064
  if number_of_lines > 0
2051
- @line += number_of_lines
2052
- last_line_index = value.rindex("\n")
2053
- @column = value.size - (last_line_index + 1)
2065
+ @line += number_of_lines
2066
+ last_line_index = value.rindex("\n")
2067
+ @column = value.size - (last_line_index + 1)
2054
2068
  @last_was_newline = @column == 0
2055
2069
  end
2056
2070
  end
@@ -2074,15 +2088,15 @@ class Rufo::Formatter
2074
2088
  end
2075
2089
 
2076
2090
  # Consume and print an end of line, handling semicolons and comments
2077
- #
2091
+ #
2078
2092
  # - at_prefix: are we at a point before an expression? (if so, we don't need a space before the first comment)
2079
2093
  # - want_semicolon: do we want do print a semicolon to separate expressions?
2080
2094
  # - want_multiline: do we want multiple lines to appear, or at most one?
2081
2095
  def consume_end_of_line(at_prefix = false, want_semicolon = false, want_multiline = true)
2082
- found_newline = false # Did we find any newline during this method?
2083
- last = nil # Last token kind found
2084
- multilple_lines = false # Did we pass through more than one newline?
2085
- last_comment_has_newline = false # Does the last comment has a newline?
2096
+ found_newline = false # Did we find any newline during this method?
2097
+ last = nil # Last token kind found
2098
+ multilple_lines = false # Did we pass through more than one newline?
2099
+ last_comment_has_newline = false # Does the last comment has a newline?
2086
2100
 
2087
2101
  while true
2088
2102
  case current_token_kind
@@ -2137,13 +2151,13 @@ class Rufo::Formatter
2137
2151
  # If we didn't find any newline yet, this is the first comment,
2138
2152
  # so append a space if needed (for example after an expression)
2139
2153
  write_space " " unless at_prefix
2140
- @comments_positions << [@line, @column, @indent, nil]
2154
+ track_comment
2141
2155
  end
2142
2156
  end
2143
2157
  last_comment_has_newline = current_token_value.end_with?("\n")
2144
2158
  write current_token_value.rstrip
2145
2159
  next_token
2146
- last = :comment
2160
+ last = :comment
2147
2161
  multilple_lines = false
2148
2162
  else
2149
2163
  break
@@ -2154,17 +2168,17 @@ class Rufo::Formatter
2154
2168
  # either we didn't find a newline and we are at the end of a line (and we didn't just pass a semicolon),
2155
2169
  # or the last thing was a comment (from which we removed the newline)
2156
2170
  # or we just passed multiple lines (but printed only one)
2157
- if (!found_newline && !at_prefix && !(want_semicolon && last == :semicolon)) ||
2158
- last == :comment ||
2159
- (multilple_lines && want_multiline)
2160
- write_line
2171
+ if (!found_newline && !at_prefix && !(want_semicolon && last == :semicolon)) ||
2172
+ last == :comment ||
2173
+ (multilple_lines && want_multiline)
2174
+ write_line
2161
2175
  end
2162
2176
  end
2163
2177
 
2164
2178
  def indent(value = nil)
2165
2179
  if value
2166
2180
  old_indent = @indent
2167
- @indent = value
2181
+ @indent = value
2168
2182
  yield
2169
2183
  @indent = old_indent
2170
2184
  else
@@ -2204,7 +2218,7 @@ class Rufo::Formatter
2204
2218
  def write(value)
2205
2219
  @output << value
2206
2220
  @last_was_newline = false
2207
- @column += value.size
2221
+ @column += value.size
2208
2222
  end
2209
2223
 
2210
2224
  def write_space(value)
@@ -2215,15 +2229,15 @@ class Rufo::Formatter
2215
2229
  def write_line
2216
2230
  @output << "\n"
2217
2231
  @last_was_newline = true
2218
- @column = 0
2219
- @line += 1
2232
+ @column = 0
2233
+ @line += 1
2220
2234
  end
2221
2235
 
2222
2236
  def write_indent(indent = @indent)
2223
2237
  indent.times do
2224
2238
  @output << " "
2225
2239
  end
2226
- @column += indent
2240
+ @column += indent
2227
2241
  @last_was_newline = false
2228
2242
  end
2229
2243
 
@@ -2328,7 +2342,7 @@ class Rufo::Formatter
2328
2342
  end
2329
2343
 
2330
2344
  def push_call(call)
2331
- old_call = @current_call
2345
+ old_call = @current_call
2332
2346
  @current_call = call
2333
2347
 
2334
2348
  # A call can specify hash arguments so it acts as a
@@ -2341,7 +2355,7 @@ class Rufo::Formatter
2341
2355
  end
2342
2356
 
2343
2357
  def push_hash(node)
2344
- old_hash = @current_hash
2358
+ old_hash = @current_hash
2345
2359
  @current_hash = node
2346
2360
  yield
2347
2361
  @current_hash = old_hash
@@ -2373,18 +2387,19 @@ class Rufo::Formatter
2373
2387
  next if comments.size == 1
2374
2388
 
2375
2389
  max_column = comments.map { |l, c| c }.max
2390
+
2376
2391
  comments.each do |(line, column, _, _, offset)|
2377
2392
  next if column == max_column
2378
2393
 
2379
- split_index = column
2394
+ split_index = column
2380
2395
  split_index -= offset if offset
2381
2396
 
2382
2397
  target_line = lines[line]
2383
2398
 
2384
2399
  before = target_line[0...split_index]
2385
- after = target_line[split_index..-1]
2400
+ after = target_line[split_index..-1]
2386
2401
 
2387
- filler = " " * (max_column - column)
2402
+ filler = " " * (max_column - column)
2388
2403
  lines[line] = "#{before}#{filler}#{after}"
2389
2404
  end
2390
2405
  end
@@ -2395,4 +2410,4 @@ class Rufo::Formatter
2395
2410
  def result
2396
2411
  @output
2397
2412
  end
2398
- end
2413
+ end
@@ -1,3 +1,3 @@
1
1
  module Rufo
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ary Borenszweig
@@ -62,6 +62,7 @@ extra_rdoc_files: []
62
62
  files:
63
63
  - ".gitignore"
64
64
  - ".rspec"
65
+ - ".rufo"
65
66
  - ".travis.yml"
66
67
  - Gemfile
67
68
  - LICENSE.txt