3
\$\begingroup\$

Please review my code and help on How can I make it better calculation in method and class definition with SOLID ruby principles??

The application has a static JSON file which contains:

{
  "homes": {
    "person_a": "windows+tables",
    "person_b": "lights+tables",
    "person_c": "doors+curtains"
 }
}

The application should, for each user request, calculate quotes for the 3 insurers. The business requirement is as follows:

The quote is a 10% of the rate if 2 covers are matched or 20% if just 1 cover is matched and that is the biggest requested, 25% if it is the second biggest or 30% if is the third.

the request from user is as follow

{:curtains=>20, :tables=>30, :windows=>50}

The system should not return a quote if the value is zero(0)

For eg: the application will return the result for the above user request

{
    person_a: 8 (10% of 80 (two matches on windows and tables))
    person_b: 7.5 (25% of 30 (one match on tables, the 2nd biggest cover))
    insurer_c: 6 (30% of 20 (one match on curtains, the 3rd biggest cover)

}

This is my solution:


require_relative './rules'

module Coverage
  class CalculateQuotes
    def initialize(quotes)
      @quotes = quotes
    end

    def calculate_rates
      result = []
      @insurer = Coverage::Rules.parse_file ## which will give {
                                        #"insurer_rates": {
                                       #"person_a": "windows+tables",
                                       # "person_b": "lights+tables",
                                       #"person_c": "doors+curtains"
                                      # }}
      @insurer[:insurer_rates].each do |k, v|
        @match_covers = match_cover(v.split("+"))
        result << [k, calculate_rate ]
      end
    end

    def match_cover(covers)
      covers = covers.map { |x| x.to_sym }
      @quotes.select { |k,v| covers.include?(k) }
    end

    def calculate_rate
      premium    = 0.0
      persentage = get_percentage_by_match_covers
      @match_covers.values.each do |v|
        premium += v * persentage
      end
      premium == 0 ? nil : premium
    end

    def get_percentage_by_match_covers
      if @match_covers.size == 2
        0.1
      elsif @match_covers.size == 1
        only_1_match_covers
      else
        0
      end
    end

    def only_1_match_covers
      index = position_of_customer_request
      case index
      when 0
        0.2
      when 1
        0.25
      when 2
        0.3
      else
        raise StandardError
      end
    end

    def position_of_customer_request
      (@quotes.to_a.reverse).index(@match_covers.to_a.flatten)
    end
  end
end


request = {:windows=>50, :contents=>30, :engine=>20}

Coverage::CalculateQuotes.new(request).calculate_rates
````
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Ruby Hash

Rather than using a verbose case statement:

 case index
      when 0
        0.2
      when 1
        0.25
      when 2
        0.3

You could use a Hash:

rates = {0 => 0.2, 1 => 0.25, 2 => 0.3}

And the case can be replaced with:

rates[index]

Rubocop Report

Use symbols as procs when possible.

covers = covers.map { |x| x.to_sym }

This is a compact alternative:

covers = covers.map(&:to_sym)

Identify unused block arguments.

@quotes.select { |k,v| covers.include?(k) }

Use an underscore to identify unused block arguments:

@quotes.select { |k, _v| covers.include?(k) }

Numeric predicates should use predicate methods instead of comparison operators if possible

premium == 0 ? nil : premium

Use the predicate method zero instead:

premium.zero? ? nil : premium
\$\endgroup\$
1
  • \$\begingroup\$ Thanks rubocop changes I will do finally when my code gets finalize. I am looking strong ruby code review which will calculate the percentage in a different way and some refactor to my class definition \$\endgroup\$
    – max mitch
    Commented Aug 15, 2019 at 21:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.