yalphabetize 0.0.0 → 0.4.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: e77cd0148a5d6e1d6c31b90a12d9d7cf85fbccea7e5efa6f4240c6f60759e69e
4
- data.tar.gz: d1c1b0c394f0c35a23b41fb05d1ebd39cfcf53f1bbc8c316a7dac4ee3d6fc046
3
+ metadata.gz: 7233124faca7d704c5fc49708d03df7bf821863a7ef1470d2525b00dadc13c80
4
+ data.tar.gz: 904ee4fb5f329b2b9be7fb33a1e7d4bebb3e15dddfee3b6928756e47aab4cf61
5
5
  SHA512:
6
- metadata.gz: 3478dcee26fe4f22d25bc81cc6f9bc874c8af9599c76971ae6c51b619c5ee6215600c161d34b36714f27e5a1b579c643f8679a770ce5e2470bf89d17203be085
7
- data.tar.gz: a1bdafe93d32883ebbd8ed601a83f5521ec7519597a02e8f0f6f325c17bb502b291350529c94dfd5b709e6eb83d8ace98a48c12a88a3c2e327e92b5b62341078
6
+ metadata.gz: 1021062eedb1e2f0a7ceefd6fa7783f55079d415097476b94cea6c399223a8af5a0e8311d560e423744ad35292707280641c81c3c8ebc0ff97baad2b1ec3f9fd
7
+ data.tar.gz: e633c877d5350bc007c0beb931c5eb7a322603b7cd0e4742c48ddc964b44d8da185cb444294c7d7e27e1ece707854948d94e9a534d03c5579eab770a1a6f97ef
data/bin/yalphabetize ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/yalphabetize'
5
+
6
+ exit Yalphabetize::CLI.call(ARGV)
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ class Aliaser
5
+ def initialize(stream_node)
6
+ @stream_node = stream_node
7
+ @aliases = {}
8
+ end
9
+
10
+ def call
11
+ nodes.each do |node|
12
+ next unless node.respond_to?(:anchor) && node.anchor
13
+
14
+ ensure_anchor_then_alias(node)
15
+ end
16
+ stream_node
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :stream_node, :aliases
22
+
23
+ def ensure_anchor_then_alias(node)
24
+ if node.alias?
25
+ aliases[node.anchor] ||= node
26
+ elsif aliases[node.anchor]
27
+ swap(node, aliases[node.anchor])
28
+ end
29
+ end
30
+
31
+ def swap(anchor_node, alias_node)
32
+ stream_node.each do |node|
33
+ node.children&.map! do |child_node|
34
+ convert_node(child_node, anchor_node, alias_node)
35
+ end
36
+ end
37
+ end
38
+
39
+ def nodes
40
+ stream_node.select do |node|
41
+ node.respond_to?(:anchor) && node.anchor
42
+ end
43
+ end
44
+
45
+ def convert_node(child_node, anchor_node, alias_node)
46
+ if child_node == anchor_node
47
+ alias_node
48
+ elsif child_node == alias_node
49
+ anchor_node
50
+ else
51
+ child_node
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ class Alphabetizer
5
+ def initialize(stream_node, order_checker_class:)
6
+ @stream_node = stream_node
7
+ @order_checker_class = order_checker_class
8
+ end
9
+
10
+ def call
11
+ transform(stream_node)
12
+ alphabetize(stream_node)
13
+ stream_node
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :stream_node, :order_checker_class
19
+
20
+ def alphabetize(node)
21
+ if node.mapping?
22
+ alphabetize_children(node)
23
+ unpair_children(node)
24
+ end
25
+
26
+ node.children&.each { |child_node| alphabetize(child_node) }
27
+ end
28
+
29
+ def alphabetize_children(node)
30
+ node.children.sort! do |a, b|
31
+ order_checker_class.compare(a.first.value, b.first.value)
32
+ end
33
+ end
34
+
35
+ def unpair_children(node)
36
+ children_clone = node.children.dup
37
+
38
+ children_clone.each do |slice|
39
+ node.children.push(*slice)
40
+ node.children.shift
41
+ end
42
+ end
43
+
44
+ def transform(node)
45
+ node.children&.each(&method(:transform))
46
+
47
+ return unless node.mapping?
48
+
49
+ pair_up_children(node)
50
+ end
51
+
52
+ def pair_up_children(node)
53
+ children_clone = node.children.dup
54
+
55
+ children_clone.each_slice(2) do |slice|
56
+ node.children.push(slice)
57
+ node.children.shift
58
+ node.children.shift
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ class CLI
5
+ def self.call(argv)
6
+ new(argv).call
7
+ end
8
+
9
+ def initialize(argv)
10
+ @argv = argv
11
+ end
12
+
13
+ def call
14
+ Yalphabetizer.call argv, options
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :argv
20
+
21
+ def options
22
+ OptionParser.parse!(argv)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Inspired by ERB::Compiler (https://github.com/ruby/erb/blob/b58b188028fbb403f75d48d62717373fc0908f7a/lib/erb.rb)
4
+
5
+ module Yalphabetize
6
+ class ErbCompiler
7
+ DEFAULT_STAGS = ['<%%', '<%=', '<%#', '<%', '%{', '{{'].freeze
8
+ DEFAULT_ETAGS = ['%%>', '%>', '}}', '}'].freeze
9
+
10
+ class Scanner
11
+ STAG_REG = /(.*?)(#{DEFAULT_STAGS.join('|')}|\z)/m.freeze
12
+ ETAG_REG = /(.*?)(#{DEFAULT_ETAGS.join('|')}|\z)/m.freeze
13
+
14
+ def initialize(src)
15
+ @src = src
16
+ @stag = nil
17
+ end
18
+
19
+ def scan
20
+ until scanner.eos?
21
+ scanner.scan(stag ? ETAG_REG : STAG_REG)
22
+ yield(scanner[1])
23
+ yield(scanner[2])
24
+ end
25
+ end
26
+
27
+ attr_accessor :stag
28
+
29
+ private
30
+
31
+ attr_reader :src
32
+
33
+ def scanner
34
+ @_scanner ||= StringScanner.new(src)
35
+ end
36
+ end
37
+
38
+ def initialize
39
+ @buffer = []
40
+ @content = []
41
+ end
42
+
43
+ def compile(string)
44
+ scanner = Scanner.new(string)
45
+ scanner.scan do |token|
46
+ next if token.nil?
47
+ next if token == ''
48
+
49
+ if scanner.stag.nil?
50
+ compile_stag(token, scanner)
51
+ else
52
+ compile_etag(token, scanner)
53
+ end
54
+ end
55
+ end
56
+
57
+ def compile_stag(stag, scanner)
58
+ case stag
59
+ when *DEFAULT_STAGS
60
+ scanner.stag = stag
61
+ buffer << stag
62
+ end
63
+ end
64
+
65
+ def compile_etag(etag, scanner)
66
+ buffer << etag
67
+
68
+ case etag
69
+ when *DEFAULT_ETAGS
70
+ content << buffer.join
71
+ self.buffer = []
72
+ scanner.stag = nil
73
+ end
74
+ end
75
+
76
+ attr_reader :content
77
+
78
+ private
79
+
80
+ attr_accessor :buffer
81
+ end
82
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ class FileYalphabetizer
5
+ def initialize(file_path, **options)
6
+ @file_path = file_path
7
+ @reader_class = options[:reader_class]
8
+ @offence_detector_class = options[:offence_detector_class]
9
+ @logger = options[:logger]
10
+ @autocorrect = options[:autocorrect]
11
+ @alphabetizer_class = options[:alphabetizer_class]
12
+ @writer_class = options[:writer_class]
13
+ @order_checker_class = options[:order_checker_class]
14
+ end
15
+
16
+ def call
17
+ if offences?
18
+ logger.log_offence(file_path)
19
+ autocorrect_file if autocorrect
20
+ else
21
+ logger.log_no_offence
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :file_path, :reader_class, :offence_detector_class, :logger, :autocorrect,
28
+ :alphabetizer_class, :writer_class, :order_checker_class
29
+
30
+ def autocorrect_file
31
+ alphabetize
32
+ handle_aliases
33
+ rewrite_yml_file
34
+ print_to_log
35
+ end
36
+
37
+ def offences?
38
+ offence_detector_class.new(stream_node, order_checker_class: order_checker_class).offences?
39
+ end
40
+
41
+ def alphabetize
42
+ alphabetizer_class.new(stream_node, order_checker_class: order_checker_class).call
43
+ end
44
+
45
+ def handle_aliases
46
+ Aliaser.new(stream_node).call
47
+ end
48
+
49
+ def rewrite_yml_file
50
+ writer_class.new(stream_node, file_path, interpolations_mapping).call
51
+ end
52
+
53
+ def print_to_log
54
+ logger.log_correction(file_path)
55
+ end
56
+
57
+ def reader
58
+ @_reader ||= reader_class.new(file_path)
59
+ end
60
+
61
+ def stream_node
62
+ @_stream_node ||= reader.to_ast
63
+ end
64
+
65
+ def interpolations_mapping
66
+ reader.interpolations_mapping
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ class Logger
5
+ DEFAULT_OUTPUT = $stdout
6
+
7
+ def initialize(output = DEFAULT_OUTPUT)
8
+ @output = output
9
+ @inspected_count = 0
10
+ @offences = {}
11
+ end
12
+
13
+ def initial_summary(file_paths)
14
+ output.puts "Inspecting #{file_paths.size} YAML files"
15
+ end
16
+
17
+ def log_offence(file_path)
18
+ @inspected_count += 1
19
+ offences[file_path] = :detected
20
+ output.print red 'O'
21
+ end
22
+
23
+ def log_no_offence
24
+ @inspected_count += 1
25
+ output.print green '.'
26
+ end
27
+
28
+ def final_summary
29
+ output.puts "\nInspected: #{inspected_count}"
30
+ output.puts send(list_offences_color, "Offences: #{offences.size}")
31
+
32
+ offences.each { |file_path, status| puts_offence(file_path, status) }
33
+ end
34
+
35
+ def offences?
36
+ @offences.any?
37
+ end
38
+
39
+ def log_correction(file_path)
40
+ offences[file_path] = :corrected
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :offences, :inspected_count, :output
46
+
47
+ def puts_offence(file_path, status)
48
+ case status
49
+ when :detected
50
+ output.puts yellow file_path
51
+ when :corrected
52
+ output.puts("#{yellow(file_path)} #{green('CORRECTED')}")
53
+ end
54
+ end
55
+
56
+ def list_offences_color
57
+ if offences?
58
+ :red
59
+ else
60
+ :green
61
+ end
62
+ end
63
+
64
+ def red(string)
65
+ with_color(31, string)
66
+ end
67
+
68
+ def yellow(string)
69
+ with_color(33, string)
70
+ end
71
+
72
+ def green(string)
73
+ with_color(32, string)
74
+ end
75
+
76
+ def with_color(color, string)
77
+ "\e[#{color}m#{string}\e[0m"
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ class OffenceDetector
5
+ def initialize(stream_node, order_checker_class:)
6
+ @stream_node = stream_node
7
+ @order_checker_class = order_checker_class
8
+ end
9
+
10
+ def offences?
11
+ !alphabetized?(stream_node)
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :stream_node, :order_checker_class
17
+
18
+ def alphabetized?(node)
19
+ return false if node.mapping? && !alphabetized_children?(node)
20
+
21
+ if node.children
22
+ each_child_also_alphabetized?(node.children)
23
+ else
24
+ true
25
+ end
26
+ end
27
+
28
+ def alphabetized_children?(node)
29
+ node.children.each_slice(2).each_cons(2).all? do |a, b|
30
+ order_checker_class.ordered?(a.first.value, b.first.value)
31
+ end
32
+ end
33
+
34
+ def each_child_also_alphabetized?(children)
35
+ children.flatten&.inject(true) { |bool, child_node| bool && alphabetized?(child_node) }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+
5
+ module Yalphabetize
6
+ class OptionParser
7
+ PARSER = ::OptionParser.new do |o|
8
+ o.banner = 'Usage: yalphabetize [options] [file1, file2, ...]'
9
+
10
+ o.on('-a', '--autocorrect', 'Automatically alphabetize inspected yaml files')
11
+ o.on('-h', '--help', 'Prints this help') do
12
+ puts o
13
+ Kernel.exit
14
+ end
15
+ end
16
+
17
+ def self.parse!(argv)
18
+ {}.tap { |options| PARSER.parse!(argv, into: options) }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # AaBb
4
+ module Yalphabetize
5
+ module OrderCheckers
6
+ class AlphabeticalThenCapitalizedFirst < Base
7
+ def self.compare(string, other_string)
8
+ alphabetical_comparison(string, other_string).nonzero? || string <=> other_string
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # aAbB
4
+ module Yalphabetize
5
+ module OrderCheckers
6
+ class AlphabeticalThenCapitalizedLast < Base
7
+ def self.compare(string, other_string)
8
+ alphabetical_comparison(string, other_string).nonzero? || string.swapcase <=> other_string.swapcase
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ module OrderCheckers
5
+ class Base
6
+ def self.ordered?(string, other_string)
7
+ !compare(string, other_string).positive?
8
+ end
9
+
10
+ private_class_method def self.alphabetical_comparison(string, other_string)
11
+ string.downcase <=> other_string.downcase
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ module OrderCheckers
5
+ class CapitalizedFirstThenAlphabetical < Base
6
+ def self.compare(string, other_string)
7
+ (string <=> other_string)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ module OrderCheckers
5
+ class CapitalizedLastThenAlphabetical < Base
6
+ def self.compare(string, other_string)
7
+ (string.swapcase <=> other_string.swapcase)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ module OrderCheckers
5
+ DEFAULT = CapitalizedFirstThenAlphabetical
6
+
7
+ TOKEN_MAPPING = {
8
+ 'abAB' => CapitalizedLastThenAlphabetical,
9
+ 'aAbB' => AlphabeticalThenCapitalizedLast,
10
+ 'AaBb' => AlphabeticalThenCapitalizedFirst,
11
+ 'ABab' => CapitalizedFirstThenAlphabetical
12
+ }.freeze
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'psych'
4
+
5
+ module Yalphabetize
6
+ class ParsingError < Psych::SyntaxError; end
7
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'psych'
4
+ require 'securerandom'
5
+
6
+ module Yalphabetize
7
+ class Reader
8
+ def initialize(path)
9
+ @path = path
10
+ @interpolations_mapping = {}
11
+ end
12
+
13
+ def to_ast
14
+ substitute_interpolations
15
+ stream_node
16
+ end
17
+
18
+ attr_reader :interpolations_mapping
19
+
20
+ private
21
+
22
+ attr_reader :path
23
+
24
+ def substitute_interpolations
25
+ erb_compiler = Yalphabetize::ErbCompiler.new
26
+ erb_compiler.compile(file)
27
+
28
+ erb_compiler.content.each do |interpolation|
29
+ uuid = SecureRandom.uuid
30
+ file.sub!(interpolation, uuid)
31
+ interpolations_mapping[uuid] = interpolation
32
+ end
33
+ end
34
+
35
+ def file
36
+ @_file ||= File.read(path)
37
+ end
38
+
39
+ def stream_node
40
+ @_stream_node ||= Psych.parse_stream file
41
+ rescue Psych::SyntaxError => e
42
+ raise Yalphabetize::ParsingError.new(
43
+ path,
44
+ e.line,
45
+ e.column,
46
+ e.offset,
47
+ e.problem,
48
+ e.context
49
+ )
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'psych'
4
+
5
+ module Yalphabetize
6
+ class SequenceIndenter
7
+ def self.call(content)
8
+ new(content).call
9
+ end
10
+
11
+ def initialize(content)
12
+ @content = content
13
+ end
14
+
15
+ def call
16
+ return unless Yalphabetize.config['indent_sequences']
17
+
18
+ find_lines_to_indent
19
+ indent!
20
+ file_lines.join
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :content
26
+
27
+ def find_lines_to_indent
28
+ @nodes_to_indent = []
29
+
30
+ stream_node.each do |node|
31
+ next if node.document?
32
+
33
+ block_sequence_nodes(node)&.each do |sequence_node|
34
+ @nodes_to_indent.push(*sequence_node.children)
35
+ end
36
+ end
37
+ end
38
+
39
+ def block_sequence_nodes(node)
40
+ node.children&.select { |child_node| child_node.sequence? && child_node.style == 1 }
41
+ end
42
+
43
+ def stream_node
44
+ Psych.parse_stream content
45
+ end
46
+
47
+ def indent!
48
+ @nodes_to_indent.each do |node|
49
+ file_lines[node.start_line..node.end_line].each do |line|
50
+ line.gsub!(line, " #{line}")
51
+ end
52
+ end
53
+ end
54
+
55
+ def file_lines
56
+ @_file_lines ||= content.each_line.to_a
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ class Version
5
+ STRING = '0.4.0'
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ class Writer
5
+ MAX_LINE_WIDTH = -1
6
+
7
+ def initialize(stream_node, path, interpolations_mapping)
8
+ @stream_node = stream_node
9
+ @path = path
10
+ @interpolations_mapping = interpolations_mapping
11
+ end
12
+
13
+ def call
14
+ indent_sequences
15
+ replace_interpolations
16
+
17
+ File.open(path, 'w') do |file|
18
+ file.write new_file_content
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :stream_node, :path, :interpolations_mapping
25
+
26
+ def new_file_content
27
+ @_new_file_content ||= stream_node.to_yaml(nil, line_width: MAX_LINE_WIDTH)
28
+ end
29
+
30
+ def replace_interpolations
31
+ interpolations_mapping.each do |uuid, interpolation|
32
+ new_file_content.sub!(uuid, interpolation)
33
+ end
34
+ end
35
+
36
+ def indent_sequences
37
+ @_new_file_content = SequenceIndenter.call(new_file_content)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yalphabetize
4
+ class Yalphabetizer
5
+ def self.call(args = [], options = {})
6
+ new(args, options).call
7
+ end
8
+
9
+ def initialize(args, options)
10
+ @args = args
11
+ @options = options
12
+ end
13
+
14
+ def call
15
+ initial_log
16
+ process_files
17
+ final_log
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :args, :options
23
+
24
+ def initial_log
25
+ logger.initial_summary(file_paths)
26
+ end
27
+
28
+ def process_files
29
+ file_paths.each(&method(:process_file))
30
+ end
31
+
32
+ def process_file(file_path)
33
+ file_yalphabetizer_class.new(
34
+ file_path,
35
+ reader_class: reader_class,
36
+ offence_detector_class: offence_detector_class,
37
+ logger: logger,
38
+ autocorrect: options[:autocorrect],
39
+ alphabetizer_class: alphabetizer_class,
40
+ writer_class: writer_class,
41
+ order_checker_class: order_checker_class
42
+ ).call
43
+ end
44
+
45
+ def file_paths
46
+ @_file_paths ||= finder.paths(only: only_paths, exclude: Yalphabetize.config['exclude'])
47
+ end
48
+
49
+ def only_paths
50
+ if args.any?
51
+ args
52
+ else
53
+ Yalphabetize.config['only']
54
+ end
55
+ end
56
+
57
+ def final_log
58
+ logger.final_summary
59
+ logger.offences? ? 1 : 0
60
+ end
61
+
62
+ def reader_class
63
+ Yalphabetize::Reader
64
+ end
65
+
66
+ def finder
67
+ Yalphabetize::YamlFinder
68
+ end
69
+
70
+ def alphabetizer_class
71
+ Yalphabetize::Alphabetizer
72
+ end
73
+
74
+ def writer_class
75
+ Yalphabetize::Writer
76
+ end
77
+
78
+ def offence_detector_class
79
+ Yalphabetize::OffenceDetector
80
+ end
81
+
82
+ def logger
83
+ @_logger ||= Yalphabetize::Logger.new
84
+ end
85
+
86
+ def file_yalphabetizer_class
87
+ Yalphabetize::FileYalphabetizer
88
+ end
89
+
90
+ def order_checker_class
91
+ OrderCheckers::TOKEN_MAPPING[Yalphabetize.config['sort_by']]
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module Yalphabetize
6
+ class YamlFinder
7
+ YAML_EXTENSIONS = %w[.yml .yaml].freeze
8
+
9
+ def self.paths(only:, exclude:)
10
+ if exclude.any?
11
+ new.paths(only) - new.paths(exclude)
12
+ else
13
+ new.paths(only)
14
+ end
15
+ end
16
+
17
+ def initialize
18
+ @files = []
19
+ end
20
+
21
+ def paths(paths)
22
+ if paths.empty?
23
+ files << files_in_dir
24
+ else
25
+ process_paths(paths)
26
+ end
27
+
28
+ files.flatten.select(&method(:valid?)).map { |f| File.expand_path(f) }.uniq
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :files
34
+
35
+ def process_paths(paths)
36
+ paths.uniq.each do |path|
37
+ files << if glob?(path)
38
+ files_in_glob(path)
39
+ elsif File.directory?(path)
40
+ files_in_dir(path)
41
+ else
42
+ path
43
+ end
44
+ end
45
+ end
46
+
47
+ def files_in_glob(glob)
48
+ files_in_dir([glob, glob.gsub('**/', '').gsub('**', '')].uniq)
49
+ end
50
+
51
+ def files_in_dir(dir = Dir.pwd)
52
+ return if `sh -c 'command -v git'`.empty?
53
+
54
+ output, _error, status = Open3.capture3(
55
+ 'git', 'ls-files', '-z', *Array(dir),
56
+ '--exclude-standard', '--others', '--cached', '--modified'
57
+ )
58
+
59
+ output.split("\0").uniq.map { |git_file| "#{Dir.pwd}/#{git_file}" } if status.success?
60
+ end
61
+
62
+ def valid?(path)
63
+ exists?(path) && yml?(path)
64
+ end
65
+
66
+ def exists?(path)
67
+ File.exist?(path)
68
+ end
69
+
70
+ def yml?(path)
71
+ YAML_EXTENSIONS.include? File.extname(path)
72
+ end
73
+
74
+ def glob?(path)
75
+ path.include?('*')
76
+ end
77
+ end
78
+ end
data/lib/yalphabetize.rb CHANGED
@@ -1,8 +1,46 @@
1
- class Yalphabetize
2
- def self.call
3
- {
4
- a: :b,
5
- c: :d
6
- }
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'yalphabetize/aliaser'
4
+ require_relative 'yalphabetize/alphabetizer'
5
+ require_relative 'yalphabetize/cli'
6
+ require_relative 'yalphabetize/erb_compiler'
7
+ require_relative 'yalphabetize/file_yalphabetizer'
8
+ require_relative 'yalphabetize/logger'
9
+ require_relative 'yalphabetize/offence_detector'
10
+ require_relative 'yalphabetize/option_parser'
11
+ require_relative 'yalphabetize/order_checkers/base'
12
+ require_relative 'yalphabetize/order_checkers/alphabetical_then_capitalized_first'
13
+ require_relative 'yalphabetize/order_checkers/alphabetical_then_capitalized_last'
14
+ require_relative 'yalphabetize/order_checkers/capitalized_last_then_alphabetical'
15
+ require_relative 'yalphabetize/order_checkers/capitalized_first_then_alphabetical'
16
+ require_relative 'yalphabetize/order_checkers'
17
+ require_relative 'yalphabetize/parsing_error'
18
+ require_relative 'yalphabetize/reader'
19
+ require_relative 'yalphabetize/sequence_indenter'
20
+ require_relative 'yalphabetize/version'
21
+ require_relative 'yalphabetize/writer'
22
+ require_relative 'yalphabetize/yalphabetizer'
23
+ require_relative 'yalphabetize/yaml_finder'
24
+
25
+ module Yalphabetize
26
+ class << self
27
+ DEFAULT_CONFIG = {
28
+ 'indent_sequences' => true,
29
+ 'exclude' => [],
30
+ 'only' => [],
31
+ 'sort_by' => 'ABab'
32
+ }.freeze
33
+
34
+ def config
35
+ @_config ||= begin
36
+ specified = if File.exist?('.yalphabetize.yml')
37
+ Psych.load_file('.yalphabetize.yml') || {}
38
+ else
39
+ {}
40
+ end
41
+
42
+ DEFAULT_CONFIG.merge(specified)
43
+ end
44
+ end
7
45
  end
8
46
  end
metadata CHANGED
@@ -1,26 +1,134 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yalphabetize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Jenkins
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-21 00:00:00.000000000 Z
12
- dependencies: []
13
- description:
14
- email:
15
- executables: []
11
+ date: 2022-01-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: psych
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: factory_bot
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email:
99
+ executables:
100
+ - yalphabetize
16
101
  extensions: []
17
102
  extra_rdoc_files: []
18
103
  files:
104
+ - bin/yalphabetize
19
105
  - lib/yalphabetize.rb
20
- homepage:
106
+ - lib/yalphabetize/aliaser.rb
107
+ - lib/yalphabetize/alphabetizer.rb
108
+ - lib/yalphabetize/cli.rb
109
+ - lib/yalphabetize/erb_compiler.rb
110
+ - lib/yalphabetize/file_yalphabetizer.rb
111
+ - lib/yalphabetize/logger.rb
112
+ - lib/yalphabetize/offence_detector.rb
113
+ - lib/yalphabetize/option_parser.rb
114
+ - lib/yalphabetize/order_checkers.rb
115
+ - lib/yalphabetize/order_checkers/alphabetical_then_capitalized_first.rb
116
+ - lib/yalphabetize/order_checkers/alphabetical_then_capitalized_last.rb
117
+ - lib/yalphabetize/order_checkers/base.rb
118
+ - lib/yalphabetize/order_checkers/capitalized_first_then_alphabetical.rb
119
+ - lib/yalphabetize/order_checkers/capitalized_last_then_alphabetical.rb
120
+ - lib/yalphabetize/parsing_error.rb
121
+ - lib/yalphabetize/reader.rb
122
+ - lib/yalphabetize/sequence_indenter.rb
123
+ - lib/yalphabetize/version.rb
124
+ - lib/yalphabetize/writer.rb
125
+ - lib/yalphabetize/yalphabetizer.rb
126
+ - lib/yalphabetize/yaml_finder.rb
127
+ homepage:
21
128
  licenses: []
22
- metadata: {}
23
- post_install_message:
129
+ metadata:
130
+ rubygems_mfa_required: 'true'
131
+ post_install_message:
24
132
  rdoc_options: []
25
133
  require_paths:
26
134
  - lib
@@ -35,8 +143,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
35
143
  - !ruby/object:Gem::Version
36
144
  version: '0'
37
145
  requirements: []
38
- rubygems_version: 3.0.3
39
- signing_key:
146
+ rubygems_version: 3.0.3.1
147
+ signing_key:
40
148
  specification_version: 4
41
149
  summary: Alphabetize your YAML files
42
150
  test_files: []