QutBioacoustics/baw-workers

View on GitHub
lib/baw-workers/resque_job_id.rb

Summary

Maintainability
A
25 mins
Test Coverage
module BawWorkers
  # Create and manage resque job ids.
  class ResqueJobId
    class << self

      # Create a payload with an id based on the class and args.
      # WARNING: The order of of values in args is important.
      # @param [String] klass
      # @param [Hash] args
      # @return [Hash] payload
      def create_payload(klass, args = {})
        resque_status_id = create_id_props(klass, args)
        payload = {class: normalise_class(klass), args: [resque_status_id] + normalise_args(args)}
        normalise(payload)
      end

      # Get an id from payload (name of class, args hash).
      # WARNING: The order of of values in args is important.
      # @param [Hash] payload
      # @return [String] id
      def create_id_payload(payload)
        klass = get_class(payload)
        args = get_args(payload)

        create_id_props(klass, args)
      end

      # Create an id from class and args.
      # WARNING: The order of of values in args is important.
      # @param [String] klass
      # @param [Hash] args
      # @return [String] id
      def create_id_props(klass, args = {})
        normalised_class = normalise_class(klass)
        normalised_args = normalise_args(args)

        generate(normalised_class, normalised_args)
      end

      # Get the class from a payload.
      # @param [Hash] payload
      # @return [String] class name
      def get_class(payload)
        payload[:class] || payload['class']
      end

      # Get the args from a payload.
      # @param [Hash] payload
      # @return [Hash, Array] args
      def get_args(payload)
        payload[:args] || payload['args']
      end

      # Normalise the class.
      # @param [Class] klass
      # @return [String] normalised class representation
      def normalise_class(klass)
        normalise(klass.to_s)
      end

      # Normalise the class.
      # @param [Hash] args
      # @return [Array] normalised args array
      def normalise_args(args = {})
        normalise(args.to_a)
      end

      # Normalise an object.
      # @param [Object] value
      # @return [Object] normalised object
      def normalise(value)
        Resque.decode(Resque.encode(value))
      end

      # Create an id from class and args.
      # Class and args must have already been normalised.
      # @param [String] klass
      # @param [Array<Hash, Object>] args
      # @return [String] unique id
      def generate(klass, args = [])

        # HACK: I don't know what this ever sorts, but it is important that it doesn't work - sometimes
        args.map! do |arg|
          if arg.is_a?(Hash) then
            arg.sort
          else
            arg
          end
        end

        # payload must not include id itself - otherwise id will not match
        modified_args = args.deep_dup
        if modified_args.size > 0 && modified_args[0].is_a?(String)
          modified_args.delete_at(0)
        end

        # ensure args are not nested in another array
        if modified_args.size == 1 && modified_args[0].is_a?(Array) && modified_args[0][0].is_a?(Array)
          modified_args = modified_args[0]
        end

        # sort the arg array by the first item in each sub-array
        modified_args = modified_args.sort{ |a, b|
          a[0] <=> b[0]
        }

        id = Digest::MD5.hexdigest Resque.encode(class: klass, args: modified_args)
        id
      end

    end
  end
end