<commit_before>require 'net/http/post/multipart'
require 'fileutils'
require 'rmagick'

module Processors
  module Images
    
    def self.included(base)
      base.class_eval do
        attr_reader :directory, :id, :uri

        def errors
          @errors ||= []
        end
      end
    end
  
    def images?
      !images.empty?
    end

    def images
      Dir.glob(File.join directory, '*.{jpeg,JPEG,jpg,JPG}')
    end

    def process_images
      join && upload if id
    end

    def join_groups
      @join_groups ||= group_images_to_join
    end

    private

    def join
      join_groups.each_value do |images|
        image = Magick::ImageList.new *images
        joined_image_path = images[0].gsub(/-[a-z]*\.(?i)JPE?G/, '_joined.jpg')

        if image.append(false).write(joined_image_path)
          images.each { |image| delete(image) }
        end
      end
    end

    def group_images_to_join(join_groups={})
      images = Dir.glob(File.join directory, '*-[a-z]*\.{jpeg,JPEG,jpg,JPG}')
      ('a'..'z').each do |letter|
        images.each do |image|
          (1..9).each do |n|
            if File.basename(image) =~ /-(#{letter}{#{n}})\./
              key = letter * n
              join_groups[key] = [] unless join_groups[key]
              join_groups[key] << image
            end
          end
        end
      end
      join_groups
    end

    def upload
      images.each do |image|
        begin
          uri_path  = '/upload/tear_sheets'
          upload_io = UploadIO.new(image, 'image/jpeg')
          multipart = Net::HTTP::Post::Multipart.new(uri_path, 'issue_id' => id.to_s, 'tear_sheet[image]' => upload_io)
        
          response = Net::HTTP.start(uri.host, uri.port) do |http|
            multipart.basic_auth uri.user, uri.password
            http.request multipart
          end
              
          if error = parse_response(response)
            errors << error
          else
            delete(image)
          end
        rescue => error
          errors << "Error creating tear sheet '#{File.basename(image)}', error: #{error.class}, message: #{error.message}"
        end
      end
    end

    def parse_response(response)
      case response.code
      when '200'
        nil
      when '422'
        "Invalid image, response: #{response.body}"
      else
        "Unknown response, issue: #{id}, response: #{response.body}, code: #{response.code}"
      end
    end

    def delete(image)
      FileUtils.rm(image) and return nil
    end

  end
end<commit_msg>Remove whitespace<commit_after>require 'net/http/post/multipart'
require 'fileutils'
require 'rmagick'

module Processors
  module Images

    def self.included(base)
      base.class_eval do
        attr_reader :directory, :id, :uri

        def errors
          @errors ||= []
        end
      end
    end

    def images?
      !images.empty?
    end

    def images
      Dir.glob(File.join directory, '*.{jpeg,JPEG,jpg,JPG}')
    end

    def process_images
      join && upload if id
    end

    def join_groups
      @join_groups ||= group_images_to_join
    end

    private

    def join
      join_groups.each_value do |images|
        image = Magick::ImageList.new *images
        joined_image_path = images[0].gsub(/-[a-z]*\.(?i)JPE?G/, '_joined.jpg')

        if image.append(false).write(joined_image_path)
          images.each { |image| delete(image) }
        end
      end
    end

    def group_images_to_join(join_groups={})
      images = Dir.glob(File.join directory, '*-[a-z]*\.{jpeg,JPEG,jpg,JPG}')
      ('a'..'z').each do |letter|
        images.each do |image|
          (1..9).each do |n|
            if File.basename(image) =~ /-(#{letter}{#{n}})\./
              key = letter * n
              join_groups[key] = [] unless join_groups[key]
              join_groups[key] << image
            end
          end
        end
      end
      join_groups
    end

    def upload
      images.each do |image|
        begin
          uri_path  = '/upload/tear_sheets'
          upload_io = UploadIO.new(image, 'image/jpeg')
          multipart = Net::HTTP::Post::Multipart.new(uri_path, 'issue_id' => id.to_s, 'tear_sheet[image]' => upload_io)

          response = Net::HTTP.start(uri.host, uri.port) do |http|
            multipart.basic_auth uri.user, uri.password
            http.request multipart
          end

          if error = parse_response(response)
            errors << error
          else
            delete(image)
          end
        rescue => error
          errors << "Error creating tear sheet '#{File.basename(image)}', error: #{error.class}, message: #{error.message}"
        end
      end
    end

    def parse_response(response)
      case response.code
      when '200'
        nil
      when '422'
        "Invalid image, response: #{response.body}"
      else
        "Unknown response, issue: #{id}, response: #{response.body}, code: #{response.code}"
      end
    end

    def delete(image)
      FileUtils.rm(image) and return nil
    end

  end
end
{'fraction_non_alphanumeric': 0.11969877130400317, 'fraction_numerical': 0.0035671819262782403, 'mean_word_length': 1.887299771167048, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 9, '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': '3805205', 'n_tokens_mistral': 1601, 'n_tokens_neox': 1558, 'n_words': 364}