dhhxu/projectscope

View on GitHub
app/models/code_climate_metric.rb

Summary

Maintainability
A
50 mins
Test Coverage
class CodeClimateMetric < ActiveRecord::Base
    belongs_to :project
    
    require 'httparty'
    require 'url_helper'
    
    # validates :url, url: true
    validate :url_appropriate
    
    def get_data
        if self.url and self.url != ''
            gpa_hsh = get_gpa
            cov_hsh = get_coverage
            update_score
        end
    end
    
    def score_color
        if self.score == nil
            color = "#cccccc"
        elsif self.score >= 0.8
            color = "#bff000"
        elsif self.score >= 0.6
            color = "#ffff99"
        elsif self.score >= 0.4
            color = "#ffb84d"
        else
            color = "#ff6633"
        end
        "background-color:#{color}"
    end
    
    def update_score
        # attributes gpa and coverage will exist
        # Score is in interval [0, 1]
        w_gpa = 0.5
        w_cov = 1.0 - w_gpa
        
        gpa = self.gpa || 0.0
        cov = self.coverage || 0
        
        gpa_norm = gpa / 4.0
        cov_norm = cov / 100.0
        score = w_gpa * gpa_norm + w_cov * cov_norm
        self.update(score: score)
        # trending?
    end
    
    def get_gpa
        hsh = parse_response(gpa_badge_url)
        gpa = hsh[:stat]
        
        if gpa
            gpa = gpa.to_f
            if self.gpa == nil
                self.update(gpa: gpa)
            elsif self.gpa != gpa
                self.update(gpa: gpa)
                # save trends?
            end
        end
        hsh[:stat] = self.gpa
        hsh
    end
    
    def get_coverage
        hsh = parse_response(coverage_badge_url)
        cov = hsh[:stat]
    
        if cov and cov != "unknown"
            cov = cov.to_i
            if self.coverage == nil
                self.update(coverage: cov)
            elsif self.coverage != cov
                self.update(coverage: cov)
                # save trends?
            end
        end
        hsh[:stat] = self.coverage
        hsh
    end
    
    def parse_response(url)
        if self.url == ''
            # special case for empty CC URL
            return {:stat => nil, :color => nil}
        end
        begin
            response = HTTParty.get(url)
            color_regex = /path fill="([^"]+)"\s/
            if response.body =~ color_regex
                color = $1 
            else
                color = nil
            end
            
            stat_regex = /fill-opacity=".3">.*?fill-opacity=".3">([^<]+)/
            if response.body =~ stat_regex
                stat = $1 
            else
                stat = nil
            end
            return {:stat => stat, :color => color}
        rescue Errno::ECONNREFUSED
            {:stat => nil, :color => nil}
        end
    end
    
    def coverage_url
        if not self.url == ''
            fix_url
            self.url + '/coverage' 
        else
            ''
        end
    end
    
    def gpa_badge_url
        if not self.url == ''
            fix_url
            self.url + '/badges/gpa.svg'
        else
            ''
        end
    end
    
    def coverage_badge_url
        if not self.url == ''
            fix_url
            self.url + '/badges/coverage.svg'
        else
            ''
        end
    end
    
    private
    
    def fix_url
        # only works in the case there is a single trailing '/'
        # e.g. codeclimate.com/github/dhhxu/projectscope/
        if self.url.length > 1 and self.url[-1] == '/'
            self.update(url: self.url[0..-2])
        end
    end
    
    # permits empty urls if a project does not have a Code Climate link
    def url_appropriate
        if self.url and self.url.length > 0
            errors.add :url, "Invalid URL" unless
                UrlHelper.url_exist? self.url
        elsif self.url == nil
            errors.add :url, "Invalid URL" 
        end
    end
end