rosette-proj/rosette-core

View on GitHub
lib/rosette/core/commands.rb

Summary

Maintainability
A
0 mins
Test Coverage
# encoding: UTF-8

require 'digest/sha1'

module Rosette
  module Core

    # Namespace for all Rosette commands.
    module Commands

      autoload :Errors,                     'rosette/core/commands/errors'

      autoload :CommitCommand,              'rosette/core/commands/git/commit_command'
      autoload :DiffBaseCommand,            'rosette/core/commands/git/diff_base_command'
      autoload :DiffCommand,                'rosette/core/commands/git/diff_command'
      autoload :ShowCommand,                'rosette/core/commands/git/show_command'
      autoload :StatusCommand,              'rosette/core/commands/git/status_command'
      autoload :FetchCommand,               'rosette/core/commands/git/fetch_command'
      autoload :SnapshotCommand,            'rosette/core/commands/git/snapshot_command'
      autoload :RepoSnapshotCommand,        'rosette/core/commands/git/repo_snapshot_command'
      autoload :WithRepoName,               'rosette/core/commands/git/with_repo_name'
      autoload :WithRef,                    'rosette/core/commands/git/with_ref'
      autoload :WithRefs,                   'rosette/core/commands/git/with_refs'
      autoload :WithNonMergeRef,            'rosette/core/commands/git/with_non_merge_ref'
      autoload :WithSnapshots,              'rosette/core/commands/git/with_snapshots'
      autoload :DiffEntry,                  'rosette/core/commands/git/diff_entry'

      autoload :WithLocale,                 'rosette/core/commands/translations/with_locale'
      autoload :ExportCommand,              'rosette/core/commands/translations/export_command'
      autoload :TranslationLookupCommand,   'rosette/core/commands/translations/translation_lookup_command'
      autoload :UntranslatedPhrasesCommand, 'rosette/core/commands/translations/untranslated_phrases_command'

      autoload :EnqueueCommitCommand,       'rosette/core/commands/queuing/enqueue_commit_command'
      autoload :RequeueCommitCommand,       'rosette/core/commands/queuing/requeue_commit_command'

      # Base class for all Rosette commands.
      #
      # @!attribute [r] configuration
      #   @return [Configurator] Rosette configuration.
      class Command
        attr_reader :configuration

        class << self
          # Validates a single field.
          #
          # @param [Symbol] field The field to validate.
          # @param [Hash] validator_hash The hash of options for this
          #   validation. For now, should just contain +:type+ which contains
          #   to a symbol corresponding to the type of validator to use.
          # @return [void]
          def validate(field, validator_hash)
            validators[field] << instantiate_validator(validator_hash)
          end

          # A hash of all the currently configured validators.
          #
          # @return [Hash<Symbol, Array<Validator>>] The hash of fields to
          #   valdiator instances.
          def validators
            @validators ||= Hash.new { |hash, key| hash[key] = [] }
          end

          private

          def instantiate_validator(validator_hash)
            validator_type = validator_hash.fetch(:type)
            validator_class_for(validator_type).new(validator_hash)
          end

          def validator_class_for(validator_type)
            klass = "#{Rosette::Core::StringUtils.camelize(validator_type.to_s)}Validator"
            if Rosette::Core::Validators.const_defined?(klass)
              Rosette::Core::Validators.const_get(klass)
            else
              raise TypeError, "couldn't find #{validator_type} validator"
            end
          end
        end

        # Creates a new command instance.
        #
        # @param [Configurator] configuration The Rosette configuration to use.
        def initialize(configuration)
          @configuration = configuration
        end

        # Gets the hash of current error messages.
        #
        # @return [Hash<Symbol, Array<String>>] The hash of current messages.
        #   The hash's keys are field names and the values are arrays of error
        #   messages for that field.
        def messages
          @messages ||= {}
        end

        # Returns true if the command's validators all pass, false otherwise.
        #
        # @raise [NotImplementedError]
        def valid?
          raise NotImplementedError, 'please use a Command subclass.'
        end

        protected

        def datastore
          configuration.datastore
        end

        def path_digest(paths)
          Digest::MD5.hexdigest(paths.join)
        end
      end

      # Base class for all of Rosette's git-based commands.
      class GitCommand < Command
        # Returns true if the command's validators all pass, false otherwise.
        # After this method is finished executing, the +messages+ hash will
        # have been populated with error messages per field.
        #
        # @return [Boolean]
        def valid?
          self.class.validators.all? do |name, validators|
            validators.all? do |validator|
              valid = validator.valid?(send(name), repo_name, configuration)
              messages[name] = validator.messages unless valid
              valid
            end
          end
        end

        protected

        def get_repo(name)
          configuration.get_repo(name)
        end
      end

    end
  end
end