<commit_before>require 'guid'

require 'attached/storage'
require 'attached/storage/error'

require 'attached/processor'
require 'attached/processor/error'

module Attached
  
  class Attachment
    
    
    attr_reader :file
    attr_reader :name
    attr_reader :instance
    attr_reader :queue
    attr_reader :purge
    attr_reader :errors
    attr_reader :path
    attr_reader :styles
    attr_reader :default
    attr_reader :medium
    attr_reader :credentials
    attr_reader :processors
    attr_reader :processor
    attr_reader :aliases
    attr_reader :alias
    attr_reader :storage
    attr_reader :host
    
    
    # A default set of options that can be extended to customize the path, storage or credentials.
    #
    # Usage:
    #
    #   Attached::Attachment.options = { :storage => :fs, :path => ":name/:style/:identifier:extension" }
    
    def self.options
      @options ||= {
        :path        => ":name/:style/:identifier:extension",
        :default     => :original,
        :medium      => :local,
        :credentials => {},
        :styles      => {},
        :processors  => [],
        :aliases     => [],
      }
    end
    
    
    # Initialize a new attachment by providing a name and the instance the attachment is associated with.
    #
    # Parameters:
    # 
    # * name        - The name for the attachment such as 'avatar' or 'photo'
    # * instance    - The instance the attachment is attached to
    #
    # Options:
    #
    # * :path        - The location where the attachment is stored
    # * :styles      - A hash containing optional parameters including extension and identifier
    # * :credentials - A file, hash, or path used to authenticate with the specified storage medium
    # * :medium      - A symbol or subclass of 'Attached::Storage::Base' to be used
    # * :processor   - A symbol or subclass of 'Attached::Processor::Base' to be used
    # * :alias       - A string representing a fully qualified host alias
    # * :processors  - An array of processors 
    # * :aliases     - An array of aliases
    
    def initialize(name, instance, options = {})
      options      = self.class.options.merge(options)
      
      @name        = name
      @instance    = instance
      
      @queue = {}
      @purge = []
      @errors = []
      
      @path        = options[:path]
      @styles      = options[:styles]
      @default     = options[:default]
      @medium      = options[:medium]
      @credentials = options[:credentials]
      @processors  = options[:processors]
      @processor   = options[:processor]
      @aliases     = options[:aliases]
      @alias       = options[:alias]
      
      @processors  = self.processors + [self.processor] if self.processor
      @aliases     = self.aliases + [self.alias] if self.alias
      
      @storage     = Attached::Storage.storage(self.medium, self.credentials)
      
      @host        = self.storage.host
    end
    
    
    # Check if an attachment has been modified.
    #
    # Usage:
    #
    #   @object.avatar.changed?
    
    def changed?
      instance.changed.include? "#{name}_identifier"
    end
    
    def file?
      not identifier.blank?
    end
    
    
    # Assign an attachment to a file.
    #
    # Usage:
    #
    #   @object.avatar.assign(...)
    
    def assign(file, identifier = "#{Guid.new}")
      
      if file.is_a?(Attached::Attachment)
        file = file.file
      end
      
      @file = file.respond_to?(:tempfile) ? file.tempfile : file
      
      extension ||= File.extname(file.original_filename) if file.respond_to?(:original_filename)
      extension ||= File.extname(file.path) if file.respond_to?(:path)
      
      @purge = [self.path, *self.styles.map { |style, options| self.path(style) }] if file?
      
      instance_set :size, file.size
      instance_set :extension, extension
      instance_set :identifier, identifier
      
      process
      
    ensure
      file.close if file.respond_to?(:close)<commit_msg>removed close call as it breaks some functionality<commit_after>require 'guid'

require 'attached/storage'
require 'attached/storage/error'

require 'attached/processor'
require 'attached/processor/error'

module Attached
  
  class Attachment
    
    
    attr_reader :file
    attr_reader :name
    attr_reader :instance
    attr_reader :queue
    attr_reader :purge
    attr_reader :errors
    attr_reader :path
    attr_reader :styles
    attr_reader :default
    attr_reader :medium
    attr_reader :credentials
    attr_reader :processors
    attr_reader :processor
    attr_reader :aliases
    attr_reader :alias
    attr_reader :storage
    attr_reader :host
    
    
    # A default set of options that can be extended to customize the path, storage or credentials.
    #
    # Usage:
    #
    #   Attached::Attachment.options = { :storage => :fs, :path => ":name/:style/:identifier:extension" }
    
    def self.options
      @options ||= {
        :path        => ":name/:style/:identifier:extension",
        :default     => :original,
        :medium      => :local,
        :credentials => {},
        :styles      => {},
        :processors  => [],
        :aliases     => [],
      }
    end
    
    
    # Initialize a new attachment by providing a name and the instance the attachment is associated with.
    #
    # Parameters:
    # 
    # * name        - The name for the attachment such as 'avatar' or 'photo'
    # * instance    - The instance the attachment is attached to
    #
    # Options:
    #
    # * :path        - The location where the attachment is stored
    # * :styles      - A hash containing optional parameters including extension and identifier
    # * :credentials - A file, hash, or path used to authenticate with the specified storage medium
    # * :medium      - A symbol or subclass of 'Attached::Storage::Base' to be used
    # * :processor   - A symbol or subclass of 'Attached::Processor::Base' to be used
    # * :alias       - A string representing a fully qualified host alias
    # * :processors  - An array of processors 
    # * :aliases     - An array of aliases
    
    def initialize(name, instance, options = {})
      options      = self.class.options.merge(options)
      
      @name        = name
      @instance    = instance
      
      @queue = {}
      @purge = []
      @errors = []
      
      @path        = options[:path]
      @styles      = options[:styles]
      @default     = options[:default]
      @medium      = options[:medium]
      @credentials = options[:credentials]
      @processors  = options[:processors]
      @processor   = options[:processor]
      @aliases     = options[:aliases]
      @alias       = options[:alias]
      
      @processors  = self.processors + [self.processor] if self.processor
      @aliases     = self.aliases + [self.alias] if self.alias
      
      @storage     = Attached::Storage.storage(self.medium, self.credentials)
      
      @host        = self.storage.host
    end
    
    
    # Check if an attachment has been modified.
    #
    # Usage:
    #
    #   @object.avatar.changed?
    
    def changed?
      instance.changed.include? "#{name}_identifier"
    end
    
    def file?
      not identifier.blank?
    end
    
    
    # Assign an attachment to a file.
    #
    # Usage:
    #
    #   @object.avatar.assign(...)
    
    def assign(file, identifier = "#{Guid.new}")
      
      if file.is_a?(Attached::Attachment)
        file = file.file
      end
      
      @file = file.respond_to?(:tempfile) ? file.tempfile : file
      
      extension ||= File.extname(file.original_filename) if file.respond_to?(:original_filename)
      extension ||= File.extname(file.path) if file.respond_to?(:path)
      
      @purge = [self.path, *self.styles.map { |style, options| self.path(style) }] if file?
      
      instance_set :size, file.size
      instance_set :extension, extension
      instance_set :identifier, identifier
      
      process
{'fraction_non_alphanumeric': 0.10154690618762476, 'fraction_numerical': 0.0, 'mean_word_length': 2.1013539651837525, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 21, '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': '1176228', 'n_tokens_mistral': 2302, 'n_tokens_neox': 2299, 'n_words': 620}