2018-02-19 23:40:07 +05:30 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								require_relative  " ./extend/formula_cop "  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								module  RuboCop  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  module  Cop 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    module  NewFormulaAudit 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      # This cop checks for correct order of `depends_on` in a Formula 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      # 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      # precedence order: 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      # build-time > run-time > normal > recommended > optional 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      class  DependencyOrder  <  FormulaCop 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def  audit_formula ( _node ,  _class_node ,  _parent_class_node ,  body_node ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          check_dependency_nodes_order ( body_node ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          [ :devel ,  :head ,  :stable ] . each  do  | block_name | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            block  =  find_block ( body_node ,  block_name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            next  unless  block 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            check_dependency_nodes_order ( block . body ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def  check_dependency_nodes_order ( parent_node ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          return  if  parent_node . nil? 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          dependency_nodes  =  fetch_depends_on_nodes ( parent_node ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          ordered  =  dependency_nodes . sort  {  | a ,  b |  sort_by_dependency_name ( a ,  b )  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          ordered  =  sort_dependencies_by_type ( ordered ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          sort_conditional_dependencies! ( ordered ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          verify_order_in_source ( ordered ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Match all `depends_on` nodes among childnodes of given parent node 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def  fetch_depends_on_nodes ( parent_node ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          parent_node . each_child_node . select  {  | x |  depends_on_node? ( x )  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def  sort_by_dependency_name ( a ,  b ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          a_name  =  dependency_name ( a ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          b_name  =  dependency_name ( b ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  a_name  <  b_name 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            - 1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          elsif  a_name  >  b_name 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Separate dependencies according to precedence order: 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-28 20:54:39 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        # build-time > test > normal > recommended > optional 
							 
						 
					
						
							
								
									
										
										
										
											2018-02-19 23:40:07 +05:30 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        def  sort_dependencies_by_type ( dependency_nodes ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-28 20:54:39 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          unsorted_deps  =  dependency_nodes . to_a 
							 
						 
					
						
							
								
									
										
										
										
											2018-02-19 23:40:07 +05:30 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								          ordered  =  [ ] 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-28 20:54:39 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          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  } ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-02-19 23:40:07 +05:30 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # `depends_on :apple if build.with? "foo"` should always be defined 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        #  after `depends_on :foo` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # This method reorders dependencies array according to above rule 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        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 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              idx1  =  pos  if  match_nodes  &&  ! match_nodes . empty? 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              next  unless  idx1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              idx2  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              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 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Verify actual order of sorted `depends_on` nodes in source code 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Else raise RuboCop problem 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        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 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Node pattern method to match 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # `depends_on` variants 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def_node_matcher  :depends_on_node? ,  << ~ EOS 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { ( if  _  ( send  nil ?  :depends_on  ... )  nil ?) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								           ( send  nil ?  :depends_on  ... ) } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        EOS 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def_node_search  :buildtime_dependency? ,  " (sym :build) " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def_node_search  :recommended_dependency? ,  " (sym :recommended) " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-03-19 10:11:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        def_node_search  :test_dependency? ,  " (sym :test) " 
							 
						 
					
						
							
								
									
										
										
										
											2018-02-19 23:40:07 +05:30 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def_node_search  :optional_dependency? ,  " (sym :optional) " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-03-19 10:11:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        def_node_search  :negate_normal_dependency? ,  " (sym {:build :recommended :test :optional}) " 
							 
						 
					
						
							
								
									
										
										
										
											2018-02-19 23:40:07 +05:30 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Node pattern method to extract `name` in `depends_on :name` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def_node_search  :dependency_name_node ,  << ~ EOS 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { ( send  nil ?  :depends_on  { ( hash  ( pair  $_  _ ) )  $ ( { str  sym }  _ ) } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								           ( if  _  ( send  nil ?  :depends_on  { ( hash  ( pair  $_  _ ) )  $ ( { str  sym }  _ ) } )  nil ?) } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        EOS 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Node pattern method to extract `name` in `build.with? :name` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def_node_search  :build_with_dependency_node ,  << ~ EOS 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          ( send  ( send  nil ?  :build )  :with?  $ ( { str  sym }  _ ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        EOS 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def  insert_after! ( arr ,  idx1 ,  idx2 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          arr . insert ( idx2 + 1 ,  arr . delete_at ( idx1 ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        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 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def  dependency_name ( dependency_node ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          match_node  =  dependency_name_node ( dependency_node ) . to_a . first 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          string_content ( match_node )  if  match_node 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        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 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        private 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def  component_problem ( c1 ,  c2 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          offending_node ( c1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          problem  " dependency  \" #{ dependency_name ( c1 ) } \"  (line  #{ line_number ( c1 ) } ) should be put before dependency  \" #{ dependency_name ( c2 ) } \"  (line  #{ line_number ( c2 ) } ) " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Reorder two nodes in the source, using the corrector instance in autocorrect method 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        def  reorder_components ( corrector ,  node1 ,  node2 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          indentation  =  "   "  *  ( start_column ( node2 )  -  line_start_column ( node2 ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          line_breaks  =  " \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          corrector . insert_before ( node2 . source_range ,  node1 . source  +  line_breaks  +  indentation ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          corrector . remove ( range_with_surrounding_space ( range :  node1 . source_range ,  side :  :left ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  end 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								end