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

Inherits:
RuboCop::Cop::FormulaCop show all
Defined in:
Library/Homebrew/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, #block_size, #caveats_strings, #check_precedence, #class_name, #component_precedes?, #depends_on?, #depends_on_name_type?, #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, #formula_tap, #get_checksum_node, #method_called?, #method_called_ever?, #method_called_in_block?, #method_name, #node_equals?, #offending_node, #on_class, #parameters, #parameters_passed?, #size, #versioned_formula?

Methods included from HelperFunctions

#line_number, #line_start_column, #problem, #regex_match_group, #source_buffer, #start_column, #string_content

Instance Method Details

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


14
15
16
17
18
19
20
21
22
23
24
# File 'Library/Homebrew/rubocops/dependency_order.rb', line 14

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

#autocorrect(_node) ⇒ Object


154
155
156
157
158
159
160
# File 'Library/Homebrew/rubocops/dependency_order.rb', line 154

def autocorrect(_node)
  succeeding_node = @offensive_nodes[0]
  preceding_node = @offensive_nodes[1]
  lambda do |corrector|
    reorder_components(corrector, succeeding_node, preceding_node)
  end
end

#build_with_dependency_name(node) ⇒ Object


143
144
145
146
147
# File 'Library/Homebrew/rubocops/dependency_order.rb', line 143

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


33
34
35
36
37
38
# File 'Library/Homebrew/rubocops/dependency_order.rb', line 33

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


26
27
28
29
30
31
# File 'Library/Homebrew/rubocops/dependency_order.rb', line 26

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


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

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


40
41
42
43
44
45
# File 'Library/Homebrew/rubocops/dependency_order.rb', line 40

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


139
140
141
# File 'Library/Homebrew/rubocops/dependency_order.rb', line 139

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.


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

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


49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'Library/Homebrew/rubocops/dependency_order.rb', line 49

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.


91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'Library/Homebrew/rubocops/dependency_order.rb', line 91

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

    @offensive_nodes = [dependency_node_1, dependency_node_2]
    component_problem dependency_node_1, dependency_node_2
  end
end