rails_best_practices 1.9.1 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.rvmrc +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +10 -2
- data/README.md +33 -27
- data/lib/rails_best_practices/analyzer.rb +13 -13
- data/lib/rails_best_practices/core/check.rb +7 -6
- data/lib/rails_best_practices/core/checking_visitor.rb +1 -1
- data/lib/rails_best_practices/core/runner.rb +2 -3
- data/lib/rails_best_practices/core_ext/sexp.rb +18 -17
- data/lib/rails_best_practices/lexicals.rb +1 -0
- data/lib/rails_best_practices/lexicals/long_line_check.rb +31 -0
- data/lib/rails_best_practices/prepares/config_prepare.rb +1 -1
- data/lib/rails_best_practices/reviews.rb +2 -0
- data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +2 -2
- data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +1 -1
- data/lib/rails_best_practices/reviews/hash_syntax_review.rb +63 -0
- data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +1 -1
- data/lib/rails_best_practices/reviews/move_code_into_model_review.rb +1 -1
- data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +1 -1
- data/lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb +1 -1
- data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +1 -1
- data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +1 -1
- data/lib/rails_best_practices/reviews/protect_mass_assignment_review.rb +15 -6
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +4 -2
- data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +8 -4
- data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +2 -1
- data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +52 -8
- data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +14 -2
- data/lib/rails_best_practices/reviews/use_before_filter_review.rb +8 -3
- data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +2 -1
- data/lib/rails_best_practices/reviews/use_observer_review.rb +1 -1
- data/lib/rails_best_practices/reviews/use_parentheses_in_method_def_review.rb +33 -0
- data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +16 -6
- data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +9 -6
- data/lib/rails_best_practices/reviews/use_scope_access_review.rb +8 -3
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.yml +28 -25
- data/rake_rubies.sh +1 -1
- data/spec/rails_best_practices/analyzer_spec.rb +1 -1
- data/spec/rails_best_practices/core/check_spec.rb +7 -7
- data/spec/rails_best_practices/core/checking_visitor_spec.rb +7 -7
- data/spec/rails_best_practices/core/error_spec.rb +12 -12
- data/spec/rails_best_practices/core_ext/sexp_spec.rb +103 -85
- data/spec/rails_best_practices/lexicals/long_line_check_spec.rb +47 -0
- data/spec/rails_best_practices/lexicals/remove_tab_check_spec.rb +1 -1
- data/spec/rails_best_practices/lexicals/remove_trailing_whitespace_check_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/config_prepare_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/controller_prepare_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/helper_prepare_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/mailer_prepare_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +4 -4
- data/spec/rails_best_practices/prepares/route_prepare_spec.rb +54 -54
- data/spec/rails_best_practices/prepares/schema_prepare_spec.rb +6 -6
- data/spec/rails_best_practices/reviews/add_model_virtual_attribute_review_spec.rb +4 -4
- data/spec/rails_best_practices/reviews/always_add_db_index_review_spec.rb +46 -46
- data/spec/rails_best_practices/reviews/dry_bundler_in_capistrano_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/hash_syntax_review_spec.rb +67 -0
- data/spec/rails_best_practices/reviews/isolate_seed_data_review_spec.rb +8 -8
- data/spec/rails_best_practices/reviews/keep_finders_on_their_own_model_review_spec.rb +9 -9
- data/spec/rails_best_practices/reviews/law_of_demeter_review_spec.rb +7 -7
- data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/move_code_into_model_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/move_finder_to_named_scope_review_spec.rb +13 -13
- data/spec/rails_best_practices/reviews/move_model_logic_into_model_review_spec.rb +2 -2
- data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb +26 -26
- data/spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb +11 -2
- data/spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb +8 -8
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb +2 -2
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +25 -10
- data/spec/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/restrict_auto_generated_routes_review_spec.rb +28 -28
- data/spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb +4 -4
- data/spec/rails_best_practices/reviews/simplify_render_in_views_review_spec.rb +15 -7
- data/spec/rails_best_practices/reviews/use_before_filter_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_model_association_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_observer_review_spec.rb +5 -5
- data/spec/rails_best_practices/reviews/use_parenthesis_in_method_def_spec.rb +41 -0
- data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb +8 -8
- data/spec/rails_best_practices/reviews/use_scope_access_review_spec.rb +9 -9
- data/spec/spec_helper.rb +1 -1
- metadata +36 -29
- data/.rspec.example +0 -2
- data/.rvmrc.example +0 -2
| @@ -50,7 +50,7 @@ module RailsBestPractices | |
| 50 50 | 
             
                    def other_finder?(node)
         | 
| 51 51 | 
             
                      FINDERS.include?(node[1].message.to_s) &&
         | 
| 52 52 | 
             
                        :call == node[1].subject.sexp_type &&
         | 
| 53 | 
            -
                        node.arguments.grep_nodes_count(: | 
| 53 | 
            +
                        node.arguments.grep_nodes_count(sexp_type: :bare_assoc_hash) > 0
         | 
| 54 54 | 
             
                    end
         | 
| 55 55 | 
             
                end
         | 
| 56 56 | 
             
              end
         | 
| @@ -32,7 +32,7 @@ module RailsBestPractices | |
| 32 32 | 
             
                  # if there are multiple call and assignment nodes who have the same subject,
         | 
| 33 33 | 
             
                  # and the subject is a variable, then the conditional statement nodes should be moved into model.
         | 
| 34 34 | 
             
                  def start_if(node)
         | 
| 35 | 
            -
                    node.conditional_statement.grep_nodes(: | 
| 35 | 
            +
                    node.conditional_statement.grep_nodes(sexp_type: :call) { |child_node| remember_variable_use_count(child_node) }
         | 
| 36 36 |  | 
| 37 37 | 
             
                    variable_use_count.each do |variable_node, count|
         | 
| 38 38 | 
             
                      add_error "move code into model (#{variable_node} use_count > #{@use_count})" if count > @use_count
         | 
| @@ -41,7 +41,7 @@ module RailsBestPractices | |
| 41 41 | 
             
                    def finder?(node)
         | 
| 42 42 | 
             
                      FINDERS.include?(node[1].message.to_s) &&
         | 
| 43 43 | 
             
                        :call == node[1].sexp_type &&
         | 
| 44 | 
            -
                        node.arguments.grep_nodes_count(: | 
| 44 | 
            +
                        node.arguments.grep_nodes_count(sexp_type: :bare_assoc_hash) > 0
         | 
| 45 45 | 
             
                    end
         | 
| 46 46 | 
             
                end
         | 
| 47 47 | 
             
              end
         | 
| @@ -34,7 +34,7 @@ module RailsBestPractices | |
| 34 34 | 
             
                  # and the subject is a variable,
         | 
| 35 35 | 
             
                  # then these method calls and attribute assignments should be moved into model.
         | 
| 36 36 | 
             
                  def start_def(node)
         | 
| 37 | 
            -
                    node.grep_nodes(: | 
| 37 | 
            +
                    node.grep_nodes(sexp_type: [:call, :assign]) do |child_node|
         | 
| 38 38 | 
             
                      remember_variable_use_count(child_node)
         | 
| 39 39 | 
             
                    end
         | 
| 40 40 |  | 
| @@ -66,7 +66,7 @@ module RailsBestPractices | |
| 66 66 | 
             
                    def recursively_check(node)
         | 
| 67 67 | 
             
                      shallow = @shallow_nodes.include? node
         | 
| 68 68 | 
             
                      if [:command_call, :command].include?(node[1].sexp_type) && ["resources", "resource"].include?(node[1].message.to_s)
         | 
| 69 | 
            -
                        hash_node = node[1].arguments.grep_node(: | 
| 69 | 
            +
                        hash_node = node[1].arguments.grep_node(sexp_type: :bare_assoc_hash)
         | 
| 70 70 | 
             
                        shallow = (hash_node && "true" == hash_node.hash_value("shallow").to_s) unless shallow
         | 
| 71 71 | 
             
                        @counter += 1
         | 
| 72 72 | 
             
                        node.block.statements.each do |stmt_node|
         | 
| @@ -95,7 +95,7 @@ module RailsBestPractices | |
| 95 95 | 
             
                    # then calculate the count of call nodes, whose message is get, post, update or delete,
         | 
| 96 96 | 
             
                    # it is just the count of member and collection custom routes.
         | 
| 97 97 | 
             
                    def member_and_collection_count_for_rails3(node)
         | 
| 98 | 
            -
                      "resources" == node[1].message.to_s ? node.grep_nodes_count(: | 
| 98 | 
            +
                      "resources" == node[1].message.to_s ? node.grep_nodes_count(sexp_type: :command, message: VERBS) : 0
         | 
| 99 99 | 
             
                    end
         | 
| 100 100 | 
             
                end
         | 
| 101 101 | 
             
              end
         | 
| @@ -25,7 +25,8 @@ module RailsBestPractices | |
| 25 25 | 
             
                  # and if not use devise or authlogic,
         | 
| 26 26 | 
             
                  # then it should add attr_accessible or attr_protected to protect mass assignment.
         | 
| 27 27 | 
             
                  def start_class(node)
         | 
| 28 | 
            -
                    if !whitelist_attributes_config? && !rails_builtin?(node) && !devise?(node) && | 
| 28 | 
            +
                    if !whitelist_attributes_config? && !rails_builtin?(node) && !devise?(node) &&
         | 
| 29 | 
            +
                        !authlogic?(node) && is_active_record?(node)
         | 
| 29 30 | 
             
                      add_error "protect mass assignment"
         | 
| 30 31 | 
             
                    end
         | 
| 31 32 | 
             
                  end
         | 
| @@ -36,17 +37,25 @@ module RailsBestPractices | |
| 36 37 | 
             
                    end
         | 
| 37 38 |  | 
| 38 39 | 
             
                    def rails_builtin?(node)
         | 
| 39 | 
            -
                      node.grep_node(: | 
| 40 | 
            -
                      node.grep_node(: | 
| 40 | 
            +
                      node.grep_node(sexp_type: [:vcall, :var_ref], to_s: "attr_accessible").present? ||
         | 
| 41 | 
            +
                      node.grep_node(sexp_type: :command, message: %w(attr_accessible attr_protected)).present?
         | 
| 41 42 | 
             
                    end
         | 
| 42 43 |  | 
| 43 44 | 
             
                    def devise?(node)
         | 
| 44 | 
            -
                      node.grep_node(: | 
| 45 | 
            +
                      node.grep_node(sexp_type: :command, message: "devise").present?
         | 
| 45 46 | 
             
                    end
         | 
| 46 47 |  | 
| 47 48 | 
             
                    def authlogic?(node)
         | 
| 48 | 
            -
                     node.grep_node(: | 
| 49 | 
            -
                     node.grep_node(: | 
| 49 | 
            +
                     node.grep_node(sexp_type: [:vcall, :var_ref], to_s: "acts_as_authentic").present? ||
         | 
| 50 | 
            +
                     node.grep_node(sexp_type: :fcall, message: "acts_as_authentic").present?
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                    def is_active_record?(node)
         | 
| 54 | 
            +
                      node.grep_node(sexp_type: [:const_path_ref, :@const], to_s: "ActiveRecord::Base").present?
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    def is_active_record?(node)
         | 
| 58 | 
            +
                      node.grep_node(:sexp_type => [:const_path_ref, :@const], :to_s => "ActiveRecord::Base").present?
         | 
| 50 59 | 
             
                    end
         | 
| 51 60 | 
             
                end
         | 
| 52 61 | 
             
              end
         | 
| @@ -63,7 +63,8 @@ module RailsBestPractices | |
| 63 63 | 
             
                    end
         | 
| 64 64 | 
             
                  end
         | 
| 65 65 |  | 
| 66 | 
            -
                  # mark key method and value method for options_from_collection_for_select and | 
| 66 | 
            +
                  # mark key method and value method for options_from_collection_for_select and
         | 
| 67 | 
            +
                  # option_groups_from_collection_for_select.
         | 
| 67 68 | 
             
                  def start_method_add_arg(node)
         | 
| 68 69 | 
             
                    arguments = node.arguments.all
         | 
| 69 70 | 
             
                    case node.message.to_s
         | 
| @@ -99,7 +100,8 @@ module RailsBestPractices | |
| 99 100 | 
             
                        human_attribute_name
         | 
| 100 101 | 
             
                        assign_attributes
         | 
| 101 102 | 
             
                        to_xml to_json to_param
         | 
| 102 | 
            -
                        before_save before_create before_update before_destroy after_save after_create | 
| 103 | 
            +
                        before_save before_create before_update before_destroy after_save after_create
         | 
| 104 | 
            +
                        after_update after_destroy after_find after_initialize
         | 
| 103 105 | 
             
                        method_missing
         | 
| 104 106 | 
             
                      ).map { |method_name| "*\##{method_name}" }
         | 
| 105 107 | 
             
                    end
         | 
    
        data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb
    CHANGED
    
    | @@ -3,9 +3,11 @@ require 'rails_best_practices/reviews/review' | |
| 3 3 |  | 
| 4 4 | 
             
            module RailsBestPractices
         | 
| 5 5 | 
             
              module Reviews
         | 
| 6 | 
            -
                # Review a controller file to make sure that complex model creation should not exist in | 
| 6 | 
            +
                # Review a controller file to make sure that complex model creation should not exist in
         | 
| 7 | 
            +
                # controller, should be replaced with factory method.
         | 
| 7 8 | 
             
                #
         | 
| 8 | 
            -
                # See the best practice details here | 
| 9 | 
            +
                # See the best practice details here
         | 
| 10 | 
            +
                # http://rails-bestpractices.com/posts/6-replace-complex-creation-with-factory-method.
         | 
| 9 11 | 
             
                #
         | 
| 10 12 | 
             
                # Implementation:
         | 
| 11 13 | 
             
                #
         | 
| @@ -28,7 +30,8 @@ module RailsBestPractices | |
| 28 30 | 
             
                    @assigns_count = options['attribute_assignment_count'] || 2
         | 
| 29 31 | 
             
                  end
         | 
| 30 32 |  | 
| 31 | 
            -
                  # check method define node to see if there are multiple assignments, more than | 
| 33 | 
            +
                  # check method define node to see if there are multiple assignments, more than
         | 
| 34 | 
            +
                  # @assigns_count, on one variable before save.
         | 
| 32 35 | 
             
                  #
         | 
| 33 36 | 
             
                  # it wll check every attrasgn nodes in method define node,
         | 
| 34 37 | 
             
                  # if there are multiple assign nodes who have the same subject,
         | 
| @@ -58,7 +61,8 @@ module RailsBestPractices | |
| 58 61 | 
             
                      if ["save", "save!"].include? node.message.to_s
         | 
| 59 62 | 
             
                        variable = node.subject.to_s
         | 
| 60 63 | 
             
                        if variable_use_count[variable].to_i > @assigns_count
         | 
| 61 | 
            -
                           | 
| 64 | 
            +
                          hint = "#{variable} attribute_assignment_count > #{@assigns_count}"
         | 
| 65 | 
            +
                          add_error "replace complex creation with factory method (#{hint})"
         | 
| 62 66 | 
             
                        end
         | 
| 63 67 | 
             
                      end
         | 
| 64 68 | 
             
                    end
         | 
    
        data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb
    CHANGED
    
    | @@ -5,7 +5,8 @@ module RailsBestPractices | |
| 5 5 | 
             
              module Reviews
         | 
| 6 6 | 
             
                # Review a partail view file to make sure there is no instance variable.
         | 
| 7 7 | 
             
                #
         | 
| 8 | 
            -
                # See the best practice details here | 
| 8 | 
            +
                # See the best practice details here
         | 
| 9 | 
            +
                # http://rails-bestpractices.com/posts/27-replace-instance-variable-with-local-variable.
         | 
| 9 10 | 
             
                #
         | 
| 10 11 | 
             
                # Implementation:
         | 
| 11 12 | 
             
                #
         | 
| @@ -28,31 +28,57 @@ module RailsBestPractices | |
| 28 28 | 
             
                  def initialize
         | 
| 29 29 | 
             
                    super
         | 
| 30 30 | 
             
                    @namespaces = []
         | 
| 31 | 
            +
                    @resource_controllers = []
         | 
| 31 32 | 
             
                  end
         | 
| 32 33 |  | 
| 33 34 | 
             
                  # check if the generated routes have the corresponding actions in controller for rails3 routes.
         | 
| 34 35 | 
             
                  def start_command(node)
         | 
| 35 36 | 
             
                    if "resources" == node.message.to_s
         | 
| 36 37 | 
             
                      check_resources(node)
         | 
| 38 | 
            +
                      @resource_controllers << node.arguments.all.first.to_s
         | 
| 37 39 | 
             
                    elsif "resource" == node.message.to_s
         | 
| 38 40 | 
             
                      check_resource(node)
         | 
| 41 | 
            +
                      @resource_controllers << node.arguments.all.first.to_s
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  def end_command(node)
         | 
| 46 | 
            +
                    if "resources" == node.message.to_s
         | 
| 47 | 
            +
                      @resource_controllers.pop
         | 
| 48 | 
            +
                    elsif "resource" == node.message.to_s
         | 
| 49 | 
            +
                      @resource_controllers.pop
         | 
| 39 50 | 
             
                    end
         | 
| 40 51 | 
             
                  end
         | 
| 41 52 |  | 
| 42 53 | 
             
                  # remember the namespace.
         | 
| 43 54 | 
             
                  def start_method_add_block(node)
         | 
| 44 | 
            -
                     | 
| 55 | 
            +
                    case node.message.to_s
         | 
| 56 | 
            +
                    when "namespace"
         | 
| 57 | 
            +
                      return unless check_method_add_block?(node)
         | 
| 45 58 | 
             
                      @namespaces << node.arguments.all.first.to_s
         | 
| 59 | 
            +
                    when "resources", "resource"
         | 
| 60 | 
            +
                      return unless check_method_add_block?(node)
         | 
| 61 | 
            +
                      @resource_controllers << node.arguments.all.first.to_s
         | 
| 62 | 
            +
                    else
         | 
| 46 63 | 
             
                    end
         | 
| 47 64 | 
             
                  end
         | 
| 48 65 |  | 
| 49 66 | 
             
                  # end of namespace call.
         | 
| 50 67 | 
             
                  def end_method_add_block(node)
         | 
| 51 | 
            -
                     | 
| 68 | 
            +
                    return unless check_method_add_block?(node)
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    case node.message.to_s
         | 
| 71 | 
            +
                    when "namespace"
         | 
| 52 72 | 
             
                      @namespaces.pop
         | 
| 73 | 
            +
                    when "resources", "resource"
         | 
| 74 | 
            +
                      @resource_controllers.pop
         | 
| 53 75 | 
             
                    end
         | 
| 54 76 | 
             
                  end
         | 
| 55 77 |  | 
| 78 | 
            +
                  def check_method_add_block?(node)
         | 
| 79 | 
            +
                    :command == node[1].sexp_type || (:command_call == node[1].sexp_type && "map" != node.subject.to_s)
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
             | 
| 56 82 | 
             
                  # check if the generated routes have the corresponding actions in controller for rails2 routes.
         | 
| 57 83 | 
             
                  alias_method :start_command_call, :start_command
         | 
| 58 84 |  | 
| @@ -63,8 +89,9 @@ module RailsBestPractices | |
| 63 89 | 
             
                      return unless Prepares.controllers.include? controller_name
         | 
| 64 90 | 
             
                      resources_methods = resources_methods(node)
         | 
| 65 91 | 
             
                      unless resources_methods.all? { |meth| Prepares.controller_methods.has_method?(controller_name, meth) }
         | 
| 66 | 
            -
                         | 
| 67 | 
            -
                         | 
| 92 | 
            +
                        prepared_method_names = Prepares.controller_methods.get_methods(controller_name).map(&:method_name)
         | 
| 93 | 
            +
                        only_methods = (resources_methods & prepared_method_names).map { |meth| ":#{meth}" }.join(", ")
         | 
| 94 | 
            +
                        add_error "restrict auto-generated routes #{friendly_route_name(node)} (only: [#{only_methods}])"
         | 
| 68 95 | 
             
                      end
         | 
| 69 96 | 
             
                    end
         | 
| 70 97 |  | 
| @@ -74,8 +101,9 @@ module RailsBestPractices | |
| 74 101 | 
             
                      return unless Prepares.controllers.include? controller_name
         | 
| 75 102 | 
             
                      resource_methods = resource_methods(node)
         | 
| 76 103 | 
             
                      unless resource_methods.all? { |meth| Prepares.controller_methods.has_method?(controller_name, meth) }
         | 
| 77 | 
            -
                         | 
| 78 | 
            -
                         | 
| 104 | 
            +
                        prepared_method_names = Prepares.controller_methods.get_methods(controller_name).map(&:method_name)
         | 
| 105 | 
            +
                        only_methods = (resource_methods & prepared_method_names).map { |meth| ":#{meth}" }.join(", ")
         | 
| 106 | 
            +
                        add_error "restrict auto-generated routes #{friendly_route_name(node)} (only: [#{only_methods}])"
         | 
| 79 107 | 
             
                      end
         | 
| 80 108 | 
             
                    end
         | 
| 81 109 |  | 
| @@ -113,7 +141,11 @@ module RailsBestPractices | |
| 113 141 | 
             
                        if hash_key_exist?(option_node, "only")
         | 
| 114 142 | 
             
                          option_node.hash_value("only").to_s == "none" ? [] : Array(option_node.hash_value("only").to_object)
         | 
| 115 143 | 
             
                        elsif hash_key_exist?(option_node, "except")
         | 
| 116 | 
            -
                          option_node.hash_value("except").to_s == "all" | 
| 144 | 
            +
                          if option_node.hash_value("except").to_s == "all"
         | 
| 145 | 
            +
                            []
         | 
| 146 | 
            +
                          else 
         | 
| 147 | 
            +
                            (methods - Array(option_node.hash_value("except").to_object))
         | 
| 148 | 
            +
                          end
         | 
| 117 149 | 
             
                        else
         | 
| 118 150 | 
             
                          methods
         | 
| 119 151 | 
             
                        end
         | 
| @@ -131,7 +163,11 @@ module RailsBestPractices | |
| 131 163 | 
             
                        if hash_key_exist?(option_node, "only")
         | 
| 132 164 | 
             
                          option_node.hash_value("only").to_s == "none" ? [] : Array(option_node.hash_value("only").to_object)
         | 
| 133 165 | 
             
                        elsif hash_key_exist?(option_node, "except")
         | 
| 134 | 
            -
                          option_node.hash_value("except").to_s == "all" | 
| 166 | 
            +
                          if option_node.hash_value("except").to_s == "all"
         | 
| 167 | 
            +
                            []
         | 
| 168 | 
            +
                          else 
         | 
| 169 | 
            +
                            (methods - Array(option_node.hash_value("except").to_object))
         | 
| 170 | 
            +
                          end
         | 
| 135 171 | 
             
                        else
         | 
| 136 172 | 
             
                          methods
         | 
| 137 173 | 
             
                        end
         | 
| @@ -147,6 +183,14 @@ module RailsBestPractices | |
| 147 183 | 
             
                    def hash_key_exist?(node, key)
         | 
| 148 184 | 
             
                      node.hash_keys && node.hash_keys.include?(key)
         | 
| 149 185 | 
             
                    end
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                    def friendly_route_name(node)
         | 
| 188 | 
            +
                      if @resource_controllers.last == node.arguments.to_s
         | 
| 189 | 
            +
                        [@namespaces.join("/"), @resource_controllers.join("/")].delete_if(&:blank?).join("/")
         | 
| 190 | 
            +
                      else
         | 
| 191 | 
            +
                        [@namespaces.join("/"), @resource_controllers.join("/"), node.arguments.to_s].delete_if(&:blank?).join("/")
         | 
| 192 | 
            +
                      end
         | 
| 193 | 
            +
                    end
         | 
| 150 194 | 
             
                end
         | 
| 151 195 | 
             
              end
         | 
| 152 196 | 
             
            end
         | 
| @@ -16,6 +16,8 @@ module RailsBestPractices | |
| 16 16 | 
             
                  interesting_nodes :command
         | 
| 17 17 | 
             
                  interesting_files VIEW_FILES
         | 
| 18 18 |  | 
| 19 | 
            +
                  VALID_KEYS = %w(object collection locals)
         | 
| 20 | 
            +
             | 
| 19 21 | 
             
                  def url
         | 
| 20 22 | 
             
                    "http://rails-bestpractices.com/posts/61-simplify-render-in-views"
         | 
| 21 23 | 
             
                  end
         | 
| @@ -27,12 +29,22 @@ module RailsBestPractices | |
| 27 29 | 
             
                    if "render" == node.message.to_s
         | 
| 28 30 | 
             
                      hash_node =  node.arguments.all.first
         | 
| 29 31 | 
             
                      if hash_node && :bare_assoc_hash == hash_node.sexp_type &&
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                        !hash_node.hash_value("partial").to_s.include?('/')
         | 
| 32 | 
            +
                          include_partial?(hash_node) && valid_hash?(hash_node)
         | 
| 32 33 | 
             
                        add_error 'simplify render in views'
         | 
| 33 34 | 
             
                      end
         | 
| 34 35 | 
             
                    end
         | 
| 35 36 | 
             
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  protected
         | 
| 39 | 
            +
                    def include_partial?(hash_node)
         | 
| 40 | 
            +
                      hash_node.hash_keys.include?("partial") && !hash_node.hash_value("partial").to_s.include?('/')
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    def valid_hash?(hash_node)
         | 
| 44 | 
            +
                      keys = hash_node.hash_keys
         | 
| 45 | 
            +
                      keys.delete("partial")
         | 
| 46 | 
            +
                      (keys - VALID_KEYS).empty?
         | 
| 47 | 
            +
                    end
         | 
| 36 48 | 
             
                end
         | 
| 37 49 | 
             
              end
         | 
| 38 50 | 
             
            end
         | 
| @@ -3,7 +3,8 @@ require 'rails_best_practices/reviews/review' | |
| 3 3 |  | 
| 4 4 | 
             
            module RailsBestPractices
         | 
| 5 5 | 
             
              module Reviews
         | 
| 6 | 
            -
                # Review a controller file to make sure to use before_filter to remove duplicated first code | 
| 6 | 
            +
                # Review a controller file to make sure to use before_filter to remove duplicated first code
         | 
| 7 | 
            +
                # line in different action.
         | 
| 7 8 | 
             
                #
         | 
| 8 9 | 
             
                # See the best practice detailed here http://rails-bestpractices.com/posts/22-use-before_filter.
         | 
| 9 10 | 
             
                #
         | 
| @@ -34,12 +35,16 @@ module RailsBestPractices | |
| 34 35 | 
             
                    @first_sentences = {}
         | 
| 35 36 |  | 
| 36 37 | 
             
                    node.body.statements.each do |statement_node|
         | 
| 37 | 
            -
                       | 
| 38 | 
            +
                      var_ref_or_vcall_included = [:var_ref, :vcall].include?(statement_node.sexp_type)
         | 
| 39 | 
            +
                      private_or_protected_included = ["protected", "private"].include?(statement_node.to_s)
         | 
| 40 | 
            +
                      break if var_ref_or_vcall_included && private_or_protected_included
         | 
| 38 41 | 
             
                      remember_first_sentence(statement_node) if :def == statement_node.sexp_type
         | 
| 39 42 | 
             
                    end
         | 
| 40 43 | 
             
                    @first_sentences.each do |first_sentence, def_nodes|
         | 
| 41 44 | 
             
                      if def_nodes.size > @customize_count
         | 
| 42 | 
            -
                        add_error "use before_filter for #{def_nodes.map { |node| node.method_name.to_s }.join(',')}", | 
| 45 | 
            +
                        add_error "use before_filter for #{def_nodes.map { |node| node.method_name.to_s }.join(',')}",
         | 
| 46 | 
            +
                          node.file,
         | 
| 47 | 
            +
                          def_nodes.map(&:line).join(',')
         | 
| 43 48 | 
             
                      end
         | 
| 44 49 | 
             
                    end
         | 
| 45 50 | 
             
                  end
         | 
    
        data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb
    CHANGED
    
    | @@ -6,7 +6,8 @@ module RailsBestPractices | |
| 6 6 | 
             
              module Reviews
         | 
| 7 7 | 
             
                # Make sure to use multipart/alternative as content_type of email.
         | 
| 8 8 | 
             
                #
         | 
| 9 | 
            -
                # See the best practice details here | 
| 9 | 
            +
                # See the best practice details here
         | 
| 10 | 
            +
                # http://rails-bestpractices.com/posts/41-use-multipart-alternative-as-content_type-of-email.
         | 
| 10 11 | 
             
                #
         | 
| 11 12 | 
             
                # Implementation:
         | 
| 12 13 | 
             
                #
         | 
| @@ -82,7 +82,7 @@ module RailsBestPractices | |
| 82 82 | 
             
                    #
         | 
| 83 83 | 
             
                    # then the call node is actionmailer deliver call.
         | 
| 84 84 | 
             
                    def deliver_mailer?(node)
         | 
| 85 | 
            -
                      node.grep_nodes(: | 
| 85 | 
            +
                      node.grep_nodes(sexp_type: :call) do |child_node|
         | 
| 86 86 | 
             
                        # rails2 actionmailer deliver
         | 
| 87 87 | 
             
                        return true if child_node.message.to_s =~ /^deliver_/ && mailers.include?(child_node.subject.to_s)
         | 
| 88 88 | 
             
                        # rails3 actionmailer deliver
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
            require 'rails_best_practices/reviews/review'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module RailsBestPractices
         | 
| 5 | 
            +
              module Reviews
         | 
| 6 | 
            +
                # Check if method definition has parentheses around parameters.
         | 
| 7 | 
            +
                #
         | 
| 8 | 
            +
                # Review process:
         | 
| 9 | 
            +
                #   check def node in all files,
         | 
| 10 | 
            +
                #   if params node with values, but not wrapped by paren node,
         | 
| 11 | 
            +
                #   then it should use parentheses around parameters.
         | 
| 12 | 
            +
                class UseParenthesesInMethodDefReview < Review
         | 
| 13 | 
            +
                  interesting_nodes :def
         | 
| 14 | 
            +
                  interesting_files ALL_FILES
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  # check def node to see if parameters are wrapped by parentheses.
         | 
| 17 | 
            +
                  def start_def(node)
         | 
| 18 | 
            +
                    if no_parentheses_around_parameters?(node) && has_parameters?(node)
         | 
| 19 | 
            +
                      add_error("use parentheses around parameters in method definitions")
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  protected
         | 
| 24 | 
            +
                    def no_parentheses_around_parameters?(def_node)
         | 
| 25 | 
            +
                      :parent != def_node[2][0]
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    def has_parameters?(def_node)
         | 
| 29 | 
            +
                      :params == def_node[2][0] && !def_node[2][1..-1].compact.empty?
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -38,11 +38,17 @@ module RailsBestPractices | |
| 38 38 | 
             
                  #
         | 
| 39 39 | 
             
                  # then the call node can use query attribute instead.
         | 
| 40 40 | 
             
                  def start_if(node)
         | 
| 41 | 
            -
                    all_conditions = node.conditional_statement == node.conditional_statement.all_conditions | 
| 41 | 
            +
                    all_conditions = if node.conditional_statement == node.conditional_statement.all_conditions
         | 
| 42 | 
            +
                      [node.conditional_statement]
         | 
| 43 | 
            +
                    else
         | 
| 44 | 
            +
                      node.conditional_statement.all_conditions
         | 
| 45 | 
            +
                    end
         | 
| 42 46 | 
             
                    all_conditions.each do |condition_node|
         | 
| 43 47 | 
             
                      if query_attribute_node = query_attribute_node(condition_node)
         | 
| 44 48 | 
             
                        subject_node = query_attribute_node.subject
         | 
| 45 | 
            -
                        add_error "use query attribute (#{subject_node.subject}.#{subject_node.message}?)", | 
| 49 | 
            +
                        add_error "use query attribute (#{subject_node.subject}.#{subject_node.message}?)",
         | 
| 50 | 
            +
                          node.file,
         | 
| 51 | 
            +
                          query_attribute_node.line
         | 
| 46 52 | 
             
                      end
         | 
| 47 53 | 
             
                    end
         | 
| 48 54 | 
             
                  end
         | 
| @@ -51,11 +57,13 @@ module RailsBestPractices | |
| 51 57 | 
             
                  alias_method :start_elsif, :start_if
         | 
| 52 58 |  | 
| 53 59 | 
             
                  private
         | 
| 54 | 
            -
                    # recursively check conditional statement nodes to see if there is a call node that may be | 
| 60 | 
            +
                    # recursively check conditional statement nodes to see if there is a call node that may be
         | 
| 61 | 
            +
                    # possible query attribute.
         | 
| 55 62 | 
             
                    def query_attribute_node(conditional_statement_node)
         | 
| 56 63 | 
             
                      case conditional_statement_node.sexp_type
         | 
| 57 64 | 
             
                      when :and, :or
         | 
| 58 | 
            -
                        node = query_attribute_node(conditional_statement_node[1]) || | 
| 65 | 
            +
                        node = query_attribute_node(conditional_statement_node[1]) ||
         | 
| 66 | 
            +
                          query_attribute_node(conditional_statement_node[2])
         | 
| 59 67 | 
             
                        node.file = conditional_statement_code.file
         | 
| 60 68 | 
             
                        return node
         | 
| 61 69 | 
             
                      when :not
         | 
| @@ -83,7 +91,7 @@ module RailsBestPractices | |
| 83 91 | 
             
                    def possible_query_attribute?(node)
         | 
| 84 92 | 
             
                      return false unless :call == node.subject.sexp_type
         | 
| 85 93 | 
             
                      variable_node = variable(node)
         | 
| 86 | 
            -
                      message_node = node.grep_node(: | 
| 94 | 
            +
                      message_node = node.grep_node(subject: variable_node.to_s).message
         | 
| 87 95 |  | 
| 88 96 | 
             
                      is_model?(variable_node) && model_attribute?(variable_node, message_node.to_s) &&
         | 
| 89 97 | 
             
                        (QUERY_METHODS.include?(node.message.to_s) || compare_with_empty_string?(node))
         | 
| @@ -106,7 +114,9 @@ module RailsBestPractices | |
| 106 114 |  | 
| 107 115 | 
             
                    # check if the node is with node type :binary, node message :== and node argument is empty string.
         | 
| 108 116 | 
             
                    def compare_with_empty_string?(node)
         | 
| 109 | 
            -
                      :binary == node.sexp_type && | 
| 117 | 
            +
                      :binary == node.sexp_type &&
         | 
| 118 | 
            +
                        ["==", "!="].include?(node.message.to_s) &&
         | 
| 119 | 
            +
                        s(:string_literal, s(:string_content)) == node.argument
         | 
| 110 120 | 
             
                    end
         | 
| 111 121 | 
             
                end
         | 
| 112 122 | 
             
              end
         |