Class: RuboCop::Cop::FormulaAudit::DependencyOrder

Inherits:
RuboCop::Cop::FormulaCop show all
Extended by:
AutoCorrector
Defined in:
rubocops/dependency_order.rb

Overview

This cop checks for correct order of depends_on in formulae.

precedence order: build-time > test > normal > recommended > optional

Instance Attribute Summary

Attributes inherited from RuboCop::Cop::FormulaCop

#file_path

Instance Method Summary collapse

Methods inherited from RuboCop::Cop::FormulaCop

#audit_comments, #audit_urls, #caveats_strings, #depends_on?, #depends_on_name_type?, #formula_tap, #get_checksum_node, #on_class, #tap_style_exception?, #versioned_formula?

Methods included from HelperFunctions

#block_size, #check_precedence, #class_name, #component_precedes?, #end_column, #expression_negated?, #find_all_blocks, #find_block, #find_blocks, #find_const, #find_every_func_call_by_name, #find_every_method_call_by_name, #find_instance_call, #find_instance_method_call, #find_method_calls_by_name, #find_method_def, #find_method_with_args, #find_node_method_by_name, #find_strings, #format_component, #line_number, #line_start_column, #method_called?, #method_called_ever?, #method_called_in_block?, #method_name, #node_equals?, #offending_node, #parameters, #parameters_passed?, #problem, #regex_match_group, #size, #source_buffer, #start_column, #string_content

Instance Method Details

#audit_formula(_node, _class_node, _parent_class_node, body_node) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
# File 'rubocops/dependency_order.rb', line 16

def audit_formula(_node, _class_node, _parent_class_node, body_node)
  check_dependency_nodes_order(body_node)
  check_uses_from_macos_nodes_order(body_node)
  [:head, :stable].each do |block_name|
    block = find_block(body_node, block_name)
    next unless block

    check_dependency_nodes_order(block.body)
    check_uses_from_macos_nodes_order(block.body)
  end
end

#build_with_dependency_name(node) ⇒ Object



154
155
156
157
158
# File 'rubocops/dependency_order.rb', line 154

def build_with_dependency_name(node)
  match_nodes = build_with_dependency_node(node)
  match_nodes = match_nodes.to_a.delete_if(&:nil?)
  match_nodes.map { |n| string_content(n) } unless match_nodes.empty?
end

#check_dependency_nodes_order(parent_node) ⇒ Object



35
36
37
38
39
40
# File 'rubocops/dependency_order.rb', line 35

def check_dependency_nodes_order(parent_node)
  return if parent_node.nil?

  dependency_nodes = parent_node.each_child_node.select { |x| depends_on_node?(x) }
  ensure_dependency_order(dependency_nodes)
end

#check_uses_from_macos_nodes_order(parent_node) ⇒ Object



28
29
30
31
32
33
# File 'rubocops/dependency_order.rb', line 28

def check_uses_from_macos_nodes_order(parent_node)
  return if parent_node.nil?

  dependency_nodes = parent_node.each_child_node.select { |x| uses_from_macos_node?(x) }
  ensure_dependency_order(dependency_nodes)
end

#dependency_name(dependency_node) ⇒ Object



160
161
162
163
# File 'rubocops/dependency_order.rb', line 160

def dependency_name(dependency_node)
  match_node = dependency_name_node(dependency_node).to_a.first
  string_content(match_node) if match_node
end

#ensure_dependency_order(nodes) ⇒ Object



42
43
44
45
46
47
# File 'rubocops/dependency_order.rb', line 42

def ensure_dependency_order(nodes)
  ordered = nodes.sort_by { |node| dependency_name(node).downcase }
  ordered = sort_dependencies_by_type(ordered)
  sort_conditional_dependencies!(ordered)
  verify_order_in_source(ordered)
end

#insert_after!(arr, idx1, idx2) ⇒ Object



150
151
152
# File 'rubocops/dependency_order.rb', line 150

def insert_after!(arr, idx1, idx2)
  arr.insert(idx2+1, arr.delete_at(idx1))
end

#sort_conditional_dependencies!(ordered) ⇒ Object

depends_on :apple if build.with? "foo" should always be defined after depends_on :foo. This method reorders the dependencies array according to the above rule.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'rubocops/dependency_order.rb', line 68

def sort_conditional_dependencies!(ordered)
  length = ordered.size
  idx = 0
  while idx < length
    idx1, idx2 = nil
    ordered.each_with_index do |dep, pos|
      idx = pos+1
      match_nodes = build_with_dependency_name(dep)
      next if !match_nodes || match_nodes.empty?

      idx1 = pos
      ordered.drop(idx1+1).each_with_index do |dep2, pos2|
        next unless match_nodes.index(dependency_name(dep2))

        idx2 = pos2 if idx2.nil? || pos2 > idx2
      end
      break if idx2
    end
    insert_after!(ordered, idx1, idx2+idx1) if idx2
  end
  ordered
end

#sort_dependencies_by_type(dependency_nodes) ⇒ Object

Separate dependencies according to precedence order: build-time > test > normal > recommended > optional



51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'rubocops/dependency_order.rb', line 51

def sort_dependencies_by_type(dependency_nodes)
  unsorted_deps = dependency_nodes.to_a
  ordered = []
  ordered.concat(unsorted_deps.select { |dep| buildtime_dependency? dep })
  unsorted_deps -= ordered
  ordered.concat(unsorted_deps.select { |dep| test_dependency? dep })
  unsorted_deps -= ordered
  ordered.concat(unsorted_deps.reject { |dep| negate_normal_dependency? dep })
  unsorted_deps -= ordered
  ordered.concat(unsorted_deps.select { |dep| recommended_dependency? dep })
  unsorted_deps -= ordered
  ordered.concat(unsorted_deps.select { |dep| optional_dependency? dep })
end

#verify_order_in_source(ordered) ⇒ Object

Verify actual order of sorted depends_on nodes in source code; raise RuboCop problem otherwise.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'rubocops/dependency_order.rb', line 93

def verify_order_in_source(ordered)
  ordered.each_with_index do |node_1, idx|
    l1 = line_number(node_1)
    l2 = nil
    node_2 = nil
    ordered.drop(idx + 1).each do |test_node|
      l2 = line_number(test_node)
      node_2 = test_node if l2 < l1
    end
    next unless node_2

    offending_node(node_1)

    problem "dependency \"#{dependency_name(node_1)}\" (line #{l1}) should be put before dependency "\
            "\"#{dependency_name(node_2)}\" (line #{l2})" do |corrector|
      indentation = " " * (start_column(node_2) - line_start_column(node_2))
      line_breaks = "\n"
      corrector.insert_before(node_2.source_range,
                              node_1.source + line_breaks + indentation)
      corrector.remove(range_with_surrounding_space(range: node_1.source_range, side: :left))
    end
  end
end