<commit_before>require 'securerandom'

module Resque
  module Plugins
    module Status

      # Resque::Plugins::Status::Hash is a Hash object that has helper methods for dealing with
      # the common status attributes. It also has a number of class methods for
      # creating/updating/retrieving status objects from Redis
      class Hash < ::Hash

        # Create a status, generating a new UUID, passing the message to the status
        # Returns the UUID of the new status.
        def self.create(uuid, *messages)
          set(uuid, *messages)
          redis.zadd(set_key, Time.now.to_i, uuid)
          redis.zremrangebyscore(set_key, 0, Time.now.to_i - @expire_in) if @expire_in
          uuid
        end

        # Get a status by UUID. Returns a Resque::Plugins::Status::Hash
        def self.get(uuid)
          val = redis.get(status_key(uuid))
          val ? Resque::Plugins::Status::Hash.new(uuid, decode(val)) : nil
        end

        # Get multiple statuses by UUID. Returns array of Resque::Plugins::Status::Hash
        def self.mget(uuids)
          status_keys = uuids.map{|u| status_key(u)}
          vals = redis.mget(*status_keys)

          uuids.zip(vals).map do |uuid, val|
            val ? Resque::Plugins::Status::Hash.new(uuid, decode(val)) : nil
          end
        end

        # set a status by UUID. <tt>messages</tt> can be any number of strings or hashes
        # that are merged in order to create a single status.
        def self.set(uuid, *messages)
          val = Resque::Plugins::Status::Hash.new(uuid, *messages)
          redis.set(status_key(uuid), encode(val))
          if expire_in
            redis.expire(status_key(uuid), expire_in)
          end
          val
        end

        # clear statuses from redis passing an optional range. See `statuses` for info
        # about ranges
        def self.clear(range_start = nil, range_end = nil)
          status_ids(range_start, range_end).each do |id|
            remove(id)
          end
        end

        def self.clear_completed(range_start = nil, range_end = nil)
          status_ids(range_start, range_end).select do |id|
            get(id).completed?
          end.each do |id|
            remove(id)
          end
        end

        def self.clear_failed(range_start = nil, range_end = nil)
          status_ids(range_start, range_end).select do |id|
            get(id).failed?
          end.each do |id|
            remove(id)
          end
        end

        def self.remove(uuid)
          redis.del(status_key(uuid))
          redis.zrem(set_key, uuid)
        end

        def self.count
          redis.zcard(set_key)
        end

        # Return <tt>num</tt> Resque::Plugins::Status::Hash objects in reverse chronological order.
        # By default returns the entire set.
        # @param [Numeric] range_start The optional starting range
        # @param [Numeric] range_end The optional ending range
        # @example retuning the last 20 statuses
        #   Resque::Plugins::Status::Hash.statuses(0, 20)
        def self.statuses(range_start = nil, range_end = nil)
          ids = status_ids(range_start, range_end)
          ids.any? ? mget(ids).compact : []
        end

        # Return the <tt>num</tt> most recent status/job UUIDs in reverse chronological order.
        def self.status_ids(range_start = nil, range_end = nil)
          if range_end && range_start
            # Because we want a reverse chronological order, we need to get a range starting
            # by the higest negative number. The ordering is transparent from the API user's
            # perspective so we need to convert the passed params<commit_msg>More simple protection for nil data sets<commit_after>require 'securerandom'

module Resque
  module Plugins
    module Status

      # Resque::Plugins::Status::Hash is a Hash object that has helper methods for dealing with
      # the common status attributes. It also has a number of class methods for
      # creating/updating/retrieving status objects from Redis
      class Hash < ::Hash

        # Create a status, generating a new UUID, passing the message to the status
        # Returns the UUID of the new status.
        def self.create(uuid, *messages)
          set(uuid, *messages)
          redis.zadd(set_key, Time.now.to_i, uuid)
          redis.zremrangebyscore(set_key, 0, Time.now.to_i - @expire_in) if @expire_in
          uuid
        end

        # Get a status by UUID. Returns a Resque::Plugins::Status::Hash
        def self.get(uuid)
          val = redis.get(status_key(uuid))
          val ? Resque::Plugins::Status::Hash.new(uuid, decode(val)) : nil
        end

        # Get multiple statuses by UUID. Returns array of Resque::Plugins::Status::Hash
        def self.mget(uuids)
          return [] if uuids.empty?
          status_keys = uuids.map{|u| status_key(u)}
          vals = redis.mget(*status_keys)

          uuids.zip(vals).map do |uuid, val|
            val ? Resque::Plugins::Status::Hash.new(uuid, decode(val)) : nil
          end
        end

        # set a status by UUID. <tt>messages</tt> can be any number of strings or hashes
        # that are merged in order to create a single status.
        def self.set(uuid, *messages)
          val = Resque::Plugins::Status::Hash.new(uuid, *messages)
          redis.set(status_key(uuid), encode(val))
          if expire_in
            redis.expire(status_key(uuid), expire_in)
          end
          val
        end

        # clear statuses from redis passing an optional range. See `statuses` for info
        # about ranges
        def self.clear(range_start = nil, range_end = nil)
          status_ids(range_start, range_end).each do |id|
            remove(id)
          end
        end

        def self.clear_completed(range_start = nil, range_end = nil)
          status_ids(range_start, range_end).select do |id|
            get(id).completed?
          end.each do |id|
            remove(id)
          end
        end

        def self.clear_failed(range_start = nil, range_end = nil)
          status_ids(range_start, range_end).select do |id|
            get(id).failed?
          end.each do |id|
            remove(id)
          end
        end

        def self.remove(uuid)
          redis.del(status_key(uuid))
          redis.zrem(set_key, uuid)
        end

        def self.count
          redis.zcard(set_key)
        end

        # Return <tt>num</tt> Resque::Plugins::Status::Hash objects in reverse chronological order.
        # By default returns the entire set.
        # @param [Numeric] range_start The optional starting range
        # @param [Numeric] range_end The optional ending range
        # @example retuning the last 20 statuses
        #   Resque::Plugins::Status::Hash.statuses(0, 20)
        def self.statuses(range_start = nil, range_end = nil)
          ids = status_ids(range_start, range_end)
          mget(ids).compact || []
        end

        # Return the <tt>num</tt> most recent status/job UUIDs in reverse chronological order.
        def self.status_ids(range_start = nil, range_end = nil)
          if range_end && range_start
            # Because we want a reverse chronological order, we need to get a range starting
            # by the higest negative number. The ordering is transparent from the API user's
            # perspective so we need to convert the passed params
{'fraction_non_alphanumeric': 0.08682755831198598, 'fraction_numerical': 0.0016179048132668194, 'mean_word_length': 2.1286377056094477, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4718514', 'n_tokens_mistral': 2177, 'n_tokens_neox': 2124, 'n_words': 665}