ruby-grape/grape

View on GitHub
lib/grape/exceptions/base.rb

Summary

Maintainability
A
25 mins
Test Coverage
# frozen_string_literal: true

module Grape
  module Exceptions
    class Base < StandardError
      BASE_MESSAGES_KEY = 'grape.errors.messages'
      BASE_ATTRIBUTES_KEY = 'grape.errors.attributes'
      FALLBACK_LOCALE = :en

      attr_reader :status, :headers

      def initialize(status: nil, message: nil, headers: nil, **_options)
        super(message)

        @status  = status
        @headers = headers
      end

      def [](index)
        send index
      end

      protected

      # TODO: translate attribute first
      # if BASE_ATTRIBUTES_KEY.key respond to a string message, then short_message is returned
      # if BASE_ATTRIBUTES_KEY.key respond to a Hash, means it may have problem , summary and resolution
      def compose_message(key, **attributes)
        short_message = translate_message(key, **attributes)
        if short_message.is_a? Hash
          @problem = problem(key, **attributes)
          @summary = summary(key, **attributes)
          @resolution = resolution(key, **attributes)
          [['Problem', @problem], ['Summary', @summary], ['Resolution', @resolution]].each_with_object(+'') do |detail_array, message|
            message << "\n#{detail_array[0]}:\n  #{detail_array[1]}" unless detail_array[1].blank?
            message
          end
        else
          short_message
        end
      end

      def problem(key, **attributes)
        translate_message(:"#{key}.problem", **attributes)
      end

      def summary(key, **attributes)
        translate_message(:"#{key}.summary", **attributes)
      end

      def resolution(key, **attributes)
        translate_message(:"#{key}.resolution", **attributes)
      end

      def translate_attributes(keys, **options)
        keys.map do |key|
          translate("#{BASE_ATTRIBUTES_KEY}.#{key}", default: key, **options)
        end.join(', ')
      end

      def translate_message(key, **options)
        case key
        when Symbol
          translate("#{BASE_MESSAGES_KEY}.#{key}", default: '', **options)
        when Proc
          key.call
        else
          key
        end
      end

      def translate(key, **options)
        options = options.dup
        options[:default] &&= options[:default].to_s
        message = ::I18n.translate(key, **options)
        message.presence || fallback_message(key, **options)
      end

      def fallback_message(key, **options)
        if ::I18n.enforce_available_locales && ::I18n.available_locales.exclude?(FALLBACK_LOCALE)
          key
        else
          ::I18n.translate(key, locale: FALLBACK_LOCALE, **options)
        end
      end
    end
  end
end