file_pipeline 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.rdoc +12 -10
- data/lib/file_pipeline/errors/failed_modification_error.rb +45 -13
- data/lib/file_pipeline/versioned_file.rb +42 -75
- data/lib/file_pipeline/versions/history.rb +106 -0
- data/lib/file_pipeline/versions.rb +22 -0
- data/lib/file_pipeline.rb +1 -0
- metadata +6 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 3b25bf4205819b6d0df2fcbb9a879c7855fc2b0a3cb973774049f44a7d6965b8
         | 
| 4 | 
            +
              data.tar.gz: 1191020063c4bb7669e9dfd88a03d539c7b081cd2f422decd87ac6bca288c86e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8ccb8dabb09322d7c3b6b258c8e4e06edb3a7774e36c1fc26421794b8c53915b219a85c8c9bf07da2bf203cd949a8fc484a1db1cb8ddf6d8443a5c2ba724d4ff
         | 
| 7 | 
            +
              data.tar.gz: 3e5a2ec367ab3a2d7280c9d6daaa41f6e3cadcba9b1b73bfdb891d4fef781bade2e4e5ffe970aee76e175ce43ea3ae82d967367f18b29f59dbffec180825262e
         | 
    
        data/README.rdoc
    CHANGED
    
    | @@ -54,7 +54,7 @@ instructions on how to create custom operations). | |
| 54 54 | 
             
            ==== Basic set up with default operations
         | 
| 55 55 |  | 
| 56 56 | 
             
            To define an operation, pass the class name of the operation in underscore
         | 
| 57 | 
            -
            notation  | 
| 57 | 
            +
            notation without the containing module name, and any options to
         | 
| 58 58 | 
             
            {#define_operation}[rdoc-ref:FilePipeline::Pipeline#define_operation].
         | 
| 59 59 |  | 
| 60 60 | 
             
            The example below adds an instance of 
         | 
| @@ -87,8 +87,9 @@ call <tt>#define_operation</tt> with the desired operations and options. | |
| 87 87 |  | 
| 88 88 | 
             
            When file operations are to be used that are not included in the gem, place
         | 
| 89 89 | 
             
            the source files for the class definitions in one or more directories and
         | 
| 90 | 
            -
            initialize the Pipeline object with the  | 
| 91 | 
            -
            be added to the | 
| 90 | 
            +
            initialize the Pipeline object with the paths to those directories. The
         | 
| 91 | 
            +
            directories will be added to the
         | 
| 92 | 
            +
            {source directories}[rdoc-ref:FilePipeline.source_directories].
         | 
| 92 93 |  | 
| 93 94 | 
             
            Directories are added to the source directories in reverse order, so that
         | 
| 94 95 | 
             
            directories added later will have precedence when searching source files. The
         | 
| @@ -103,7 +104,7 @@ finally in the included default operations. | |
| 103 104 |  | 
| 104 105 | 
             
            The basename for source files _must_ be the class name in underscore notation
         | 
| 105 106 | 
             
            without the containing module name. If, for example, the operation is
         | 
| 106 | 
            -
            <tt>FileOperations::MyOperation</tt>, the source file basename  | 
| 107 | 
            +
            <tt>FileOperations::MyOperation</tt>, the source file basename has to be
         | 
| 107 108 | 
             
            <tt>'my_operation.rb'</tt>
         | 
| 108 109 |  | 
| 109 110 | 
             
              my_pipeline = FilePipeline::Pipeline.new('~/custom_operations',
         | 
| @@ -146,7 +147,7 @@ VersionedFile provides access to a files metadata via the | |
| 146 147 | 
             
            {#metadata}[rdoc-ref:FilePipeline::VersionedFile#metadata] method of the 
         | 
| 147 148 | 
             
            versioned file instance.
         | 
| 148 149 |  | 
| 149 | 
            -
             | 
| 150 | 
            +
            Metadata for the original file, the current (latest) or an arbitrary version can
         | 
| 150 151 | 
             
            be accessed:
         | 
| 151 152 |  | 
| 152 153 | 
             
              image = FilePipeline::VersionedFile.new('~/image.jpg')
         | 
| @@ -167,12 +168,13 @@ versions available, pass the <tt>:for_version</tt> option with the symbol | |
| 167 168 |  | 
| 168 169 | 
             
            Some file operations can comprise metadata; many image processing libraries
         | 
| 169 170 | 
             
            will not preserve all _Exif_ tags and their values when converting images to
         | 
| 170 | 
            -
            a different format, but only write a  | 
| 171 | 
            -
             | 
| 171 | 
            +
            a different format, but only write a subset of tags to the file they create.
         | 
| 172 | 
            +
            In these cases, the 
         | 
| 172 173 | 
             
            {ExifRestoration}[rdoc-ref:FilePipeline::FileOperations::ExifRestoration]
         | 
| 173 | 
            -
            operation can be used to try to restore the tags that have been discarded | 
| 174 | 
            -
             | 
| 175 | 
            -
            not write back to the file | 
| 174 | 
            +
            operation can be used to try to restore the tags that have been discarded. The
         | 
| 175 | 
            +
            operation uses Exiftool to write tags, and Exiftool will not write all tags.
         | 
| 176 | 
            +
            It will store any tags and their values that it could not write back to the file
         | 
| 177 | 
            +
            and return them as captured data.
         | 
| 176 178 |  | 
| 177 179 | 
             
            Likewise, if the 
         | 
| 178 180 | 
             
            {ExifRedaction}[rdoc-ref:FilePipeline::FileOperations::ExifRedaction] is applied
         | 
| @@ -8,32 +8,64 @@ module FilePipeline | |
| 8 8 | 
             
                  # The file opration that caused the error.
         | 
| 9 9 | 
             
                  attr_reader :info
         | 
| 10 10 |  | 
| 11 | 
            -
                  #  | 
| 11 | 
            +
                  # Returns a new instance.
         | 
| 12 | 
            +
                  #
         | 
| 13 | 
            +
                  # ===== Arguments
         | 
| 14 | 
            +
                  #
         | 
| 15 | 
            +
                  # * +msg+ - error message for the exception. If none provided, the 
         | 
| 16 | 
            +
                  #   instance will be initialized with the #default_message.
         | 
| 17 | 
            +
                  #
         | 
| 18 | 
            +
                  # ===== Options
         | 
| 19 | 
            +
                  #
         | 
| 20 | 
            +
                  # * <tt>info</tt> - a FileOperations::Results object or an object.
         | 
| 21 | 
            +
                  # * <tt>file</tt> - path to the file thas was being processed.
         | 
| 12 22 | 
             
                  def initialize(msg = nil, info: nil, file: nil)
         | 
| 13 23 | 
             
                    @file = file
         | 
| 14 24 | 
             
                    @info = info
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                    if info.respond_to?(:operation) && info.respond_to?(:log)
         | 
| 17 | 
            -
                      msg ||= "#{@info.operation&.name} with options"\
         | 
| 18 | 
            -
                              " #{@info.operation&.options} failed on #{file}."
         | 
| 19 | 
            -
                      if original_error
         | 
| 20 | 
            -
                        msg += "\nException raised by the operation:"\
         | 
| 21 | 
            -
                               " #{original_error.inspect}. Backtrace:\n"
         | 
| 22 | 
            -
                        msg += original_backtrace if original_backtrace
         | 
| 23 | 
            -
                      end
         | 
| 24 | 
            -
                    else
         | 
| 25 | 
            -
                      msg ||= 'Operation failed' unless info
         | 
| 26 | 
            -
                    end
         | 
| 25 | 
            +
                    msg ||= default_message
         | 
| 27 26 | 
             
                    super msg
         | 
| 28 27 | 
             
                  end
         | 
| 29 28 |  | 
| 29 | 
            +
                  # Returns the backtrace of the error that caused the exception.
         | 
| 30 30 | 
             
                  def original_backtrace
         | 
| 31 31 | 
             
                    original_error&.backtrace&.join("\n")
         | 
| 32 32 | 
             
                  end
         | 
| 33 33 |  | 
| 34 | 
            +
                  # Returns the error that caused the exception.
         | 
| 34 35 | 
             
                  def original_error
         | 
| 35 36 | 
             
                    @info.log.find { |item| item.is_a? Exception }
         | 
| 36 37 | 
             
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  private
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  # Appends the backtrace of the error that caused the exception to the 
         | 
| 42 | 
            +
                  # #default_message.
         | 
| 43 | 
            +
                  def append_backtrace(str)
         | 
| 44 | 
            +
                    return str + "\n" unless original_backtrace
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    str + " Backtrace:\n#{original_backtrace}"
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  # Appends the message of the error that caused the exception to the 
         | 
| 50 | 
            +
                  # #default_message.
         | 
| 51 | 
            +
                  def append_error(str)
         | 
| 52 | 
            +
                    return str unless original_error
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    str += "\nException raised by the operation:"\
         | 
| 55 | 
            +
                      " #{original_error.inspect}."
         | 
| 56 | 
            +
                    append_backtrace str
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  # Returns a String with the #message for +self+.
         | 
| 60 | 
            +
                  def default_message
         | 
| 61 | 
            +
                    if info&.respond_to?(:operation) && info&.respond_to?(:log)
         | 
| 62 | 
            +
                      msg = "#{info.operation&.name} with options"\
         | 
| 63 | 
            +
                        " #{info.operation&.options} failed on #{@file}."
         | 
| 64 | 
            +
                      append_error msg
         | 
| 65 | 
            +
                    else
         | 
| 66 | 
            +
                      'Operation failed'
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
                  end
         | 
| 37 69 | 
             
                end
         | 
| 38 70 | 
             
              end
         | 
| 39 71 | 
             
            end
         | 
| @@ -19,6 +19,35 @@ module FilePipeline | |
| 19 19 | 
             
                # by #finalize is not replacing the original.
         | 
| 20 20 | 
             
                attr_reader :target_suffix
         | 
| 21 21 |  | 
| 22 | 
            +
                extend Forwardable
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                # Returns a two-dimesnional array, where each nested array has two items;
         | 
| 25 | 
            +
                # the file operation object and data captured by the operartion (if any).
         | 
| 26 | 
            +
                #
         | 
| 27 | 
            +
                # <tt>[[description_object, data_or_nil], ...]</tt>
         | 
| 28 | 
            +
                delegate captured_data: :history
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                # Returns any data captured by <tt>operation_name</tt>.
         | 
| 31 | 
            +
                #
         | 
| 32 | 
            +
                # If multiple instances of one operation class have modified the file,
         | 
| 33 | 
            +
                # pass any +options+ the specific instance of the operation was initialized
         | 
| 34 | 
            +
                # with as the optional second argument.
         | 
| 35 | 
            +
                delegate captured_data_for: :history
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                # Returns an array with all data captured by operations with +tag+.
         | 
| 38 | 
            +
                #
         | 
| 39 | 
            +
                # Tags are defined in FileOperations::CapturedDataTags
         | 
| 40 | 
            +
                delegate captured_data_with: :history
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                # Returns an array of triplets (arryas with three items each): the name of
         | 
| 43 | 
            +
                # the file operation class (a string), options (a hash), and the actual log
         | 
| 44 | 
            +
                # (an array).
         | 
| 45 | 
            +
                delegate log: :history
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                # Returns an array with paths to the version files of +self+ (excluding
         | 
| 48 | 
            +
                # #original).
         | 
| 49 | 
            +
                delegate versions: :history
         | 
| 50 | 
            +
             | 
| 22 51 | 
             
                # Returns a new instance with +file+ as the #original.
         | 
| 23 52 | 
             
                #
         | 
| 24 53 | 
             
                # ===== Arguments
         | 
| @@ -41,23 +70,10 @@ module FilePipeline | |
| 41 70 |  | 
| 42 71 | 
             
                  @original = file
         | 
| 43 72 | 
             
                  @basename = File.basename(file, '.*')
         | 
| 44 | 
            -
                  @history =  | 
| 73 | 
            +
                  @history = Versions::History.new
         | 
| 45 74 | 
             
                  @directory = nil
         | 
| 46 75 | 
             
                  @target_suffix = target_suffix
         | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
                # Copies the file with path _src_ to <em>/dir/filename</em>.
         | 
| 50 | 
            -
                def self.copy(src, dir, filename)
         | 
| 51 | 
            -
                  dest = FilePipeline.path(dir, filename)
         | 
| 52 | 
            -
                  FileUtils.cp src, dest
         | 
| 53 | 
            -
                  dest
         | 
| 54 | 
            -
                end
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                # Moves the file with path _src_ to <em>/dir/filename</em>.
         | 
| 57 | 
            -
                def self.move(src, dir, filename)
         | 
| 58 | 
            -
                  dest = FilePipeline.path(dir, filename)
         | 
| 59 | 
            -
                  FileUtils.mv src, dest
         | 
| 60 | 
            -
                  dest
         | 
| 76 | 
            +
                  history[original] = nil
         | 
| 61 77 | 
             
                end
         | 
| 62 78 |  | 
| 63 79 | 
             
                # Adds a new version to #history and returns _self_.
         | 
| @@ -80,37 +96,6 @@ module FilePipeline | |
| 80 96 | 
             
                  raise e
         | 
| 81 97 | 
             
                end
         | 
| 82 98 |  | 
| 83 | 
            -
                # Returns a two-dimesnional array, where each nested array has two items;
         | 
| 84 | 
            -
                # the file operation object and data captured by the operartion (if any).
         | 
| 85 | 
            -
                #
         | 
| 86 | 
            -
                # <tt>[[description_object, data_or_nil], ...]</tt>
         | 
| 87 | 
            -
                def captured_data
         | 
| 88 | 
            -
                  filter_history :data
         | 
| 89 | 
            -
                end
         | 
| 90 | 
            -
             | 
| 91 | 
            -
                # Returns any data captured by <tt>operation_name</tt>.
         | 
| 92 | 
            -
                #
         | 
| 93 | 
            -
                # If multiple instances of one operation class have modified the file,
         | 
| 94 | 
            -
                # pass any +options+ the specific instance of the operation was initialized
         | 
| 95 | 
            -
                # with as the optional second argument.
         | 
| 96 | 
            -
                def captured_data_for(operation_name, **options)
         | 
| 97 | 
            -
                  raw_data = captured_data.filter do |operation, _|
         | 
| 98 | 
            -
                    operation.name == operation_name &&
         | 
| 99 | 
            -
                      options.all? { |k, v| operation.options[k] == v }
         | 
| 100 | 
            -
                  end
         | 
| 101 | 
            -
                  raw_data.map(&:last)
         | 
| 102 | 
            -
                end
         | 
| 103 | 
            -
             | 
| 104 | 
            -
                # Returns an array with all data captured by operations with +tag+ has.
         | 
| 105 | 
            -
                #
         | 
| 106 | 
            -
                # Tags are defined in FileOperations::CapturedDataTags
         | 
| 107 | 
            -
                def captured_data_with(tag)
         | 
| 108 | 
            -
                  return unless changed?
         | 
| 109 | 
            -
             | 
| 110 | 
            -
                  captured_data.select { |operation, _| operation.captured_data_tag == tag }
         | 
| 111 | 
            -
                               .map(&:last)
         | 
| 112 | 
            -
                end
         | 
| 113 | 
            -
             | 
| 114 99 | 
             
                # Returns +true+ if there are #versions (file has been modified).
         | 
| 115 100 | 
             
                #
         | 
| 116 101 | 
             
                # *Warning:* It will also return +true+ if the file has been cloned.
         | 
| @@ -122,7 +107,7 @@ module FilePipeline | |
| 122 107 | 
             
                # the file to history, but no FileOperations::Results.
         | 
| 123 108 | 
             
                def clone
         | 
| 124 109 | 
             
                  filename = FilePipeline.new_basename + current_extension
         | 
| 125 | 
            -
                  clone_file =  | 
| 110 | 
            +
                  clone_file = Versions.copy(current, directory, filename)
         | 
| 126 111 | 
             
                  self << clone_file
         | 
| 127 112 | 
             
                end
         | 
| 128 113 |  | 
| @@ -161,19 +146,11 @@ module FilePipeline | |
| 161 146 | 
             
                  yield(self) if block_given?
         | 
| 162 147 | 
             
                  filename = overwrite ? replacing_trarget : preserving_taget
         | 
| 163 148 | 
             
                  FileUtils.rm original if overwrite
         | 
| 164 | 
            -
                  @original =  | 
| 149 | 
            +
                  @original = Versions.copy(current, original_dir, filename)
         | 
| 165 150 | 
             
                ensure
         | 
| 166 151 | 
             
                  reset
         | 
| 167 152 | 
             
                end
         | 
| 168 153 |  | 
| 169 | 
            -
                # Returns an array of triplets (arryas with three items each): the name of
         | 
| 170 | 
            -
                # the file operation class (a string), options (a hash), and the actual log
         | 
| 171 | 
            -
                # (an array).
         | 
| 172 | 
            -
                def log
         | 
| 173 | 
            -
                  filter_history(:log)
         | 
| 174 | 
            -
                    .map { |operation, info| [operation.name, operation.options, info] }
         | 
| 175 | 
            -
                end
         | 
| 176 | 
            -
             | 
| 177 154 | 
             
                # Returns the Exif metadata
         | 
| 178 155 | 
             
                #
         | 
| 179 156 | 
             
                # ===== Options
         | 
| @@ -186,10 +163,12 @@ module FilePipeline | |
| 186 163 | 
             
                #--
         | 
| 187 164 | 
             
                # TODO: when file is not an image file, this should return other metadata
         | 
| 188 165 | 
             
                # than exif.
         | 
| 189 | 
            -
                # TODO: implement the option to return metadata for a specif version index
         | 
| 190 166 | 
             
                #++
         | 
| 191 167 | 
             
                def metadata(for_version: :current)
         | 
| 192 | 
            -
                   | 
| 168 | 
            +
                  if %i[current original].include? for_version
         | 
| 169 | 
            +
                    file = public_send(for_version)
         | 
| 170 | 
            +
                  end
         | 
| 171 | 
            +
                  file ||= for_version
         | 
| 193 172 | 
             
                  read_exif(file).first
         | 
| 194 173 | 
             
                end
         | 
| 195 174 |  | 
| @@ -218,29 +197,15 @@ module FilePipeline | |
| 218 197 | 
             
                # Returns a hash into which all captured data from file operations with the
         | 
| 219 198 | 
             
                # FileOperations::CapturedDataTags::DROPPED_EXIF_DATA has been merged.
         | 
| 220 199 | 
             
                def recovered_metadata
         | 
| 200 | 
            +
                  return unless changed?
         | 
| 221 201 | 
             
                  captured_data_with(FileOperations::CapturedDataTags::DROPPED_EXIF_DATA)
         | 
| 222 202 | 
             
                    &.reduce({}) { |recovered, data| recovered.merge data }
         | 
| 223 203 | 
             
                end
         | 
| 224 204 |  | 
| 225 | 
            -
                # Returns an array with paths to the version files of +self+ (excluding
         | 
| 226 | 
            -
                # #original).
         | 
| 227 | 
            -
                def versions
         | 
| 228 | 
            -
                  history.keys
         | 
| 229 | 
            -
                end
         | 
| 230 | 
            -
             | 
| 231 205 | 
             
                alias touch clone
         | 
| 232 206 |  | 
| 233 207 | 
             
                private
         | 
| 234 208 |  | 
| 235 | 
            -
                # item = :data or :log
         | 
| 236 | 
            -
                def filter_history(item)
         | 
| 237 | 
            -
                  history.inject([]) do |results, (_, info)|
         | 
| 238 | 
            -
                    next results unless info.respond_to?(item) && info.public_send(item)
         | 
| 239 | 
            -
             | 
| 240 | 
            -
                    results << [info.operation, info.public_send(item)]
         | 
| 241 | 
            -
                  end
         | 
| 242 | 
            -
                end
         | 
| 243 | 
            -
             | 
| 244 209 | 
             
                # Returns the filename for a target file that will not overwrite the
         | 
| 245 210 | 
             
                # original.
         | 
| 246 211 | 
             
                def preserving_taget
         | 
| @@ -256,16 +221,18 @@ module FilePipeline | |
| 256 221 | 
             
                # Deletes the work directory and resets #versions
         | 
| 257 222 | 
             
                def reset
         | 
| 258 223 | 
             
                  FileUtils.rm_r directory, force: true
         | 
| 259 | 
            -
                   | 
| 224 | 
            +
                  history.clear!
         | 
| 260 225 | 
             
                end
         | 
| 261 226 |  | 
| 262 227 | 
             
                # Validates if file exists and has been stored in #directory.
         | 
| 263 228 | 
             
                def validate(file)
         | 
| 229 | 
            +
                  return current unless file
         | 
| 230 | 
            +
             | 
| 264 231 | 
             
                  raise Errors::MissingVersionFileError, file: file unless File.exist? file
         | 
| 265 232 |  | 
| 266 233 | 
             
                  return file if File.dirname(file) == directory
         | 
| 267 234 |  | 
| 268 | 
            -
                   | 
| 235 | 
            +
                  Versions.move file, directory, File.basename(file)
         | 
| 269 236 | 
             
                end
         | 
| 270 237 |  | 
| 271 238 | 
             
                # Creates the directory containing all version files. Directory name is
         | 
| @@ -0,0 +1,106 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FilePipeline
         | 
| 4 | 
            +
              module Versions
         | 
| 5 | 
            +
                # History objects keep track of a VersionedFile instances versions names and
         | 
| 6 | 
            +
                # any associated logs or data for each version.
         | 
| 7 | 
            +
                class History
         | 
| 8 | 
            +
                  # Returns a new instance.
         | 
| 9 | 
            +
                  def initialize
         | 
| 10 | 
            +
                    @entries = {}
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  # Retrieves the _results_ object for the <tt>version_name</tt>.
         | 
| 14 | 
            +
                  def [](version_name)
         | 
| 15 | 
            +
                    @entries[version_name]
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  # Associates the +results+ with the <tt>version_name</tt>.
         | 
| 19 | 
            +
                  def []=(version_name, results)
         | 
| 20 | 
            +
                    entry = @entries.fetch version_name, []
         | 
| 21 | 
            +
                    entry << results
         | 
| 22 | 
            +
                    @entries[version_name] = entry.compact
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  # Returns a two-dimensional array, where each nested array has two items:
         | 
| 26 | 
            +
                  # * the file operation object
         | 
| 27 | 
            +
                  # * data captured by the operartion (if any).
         | 
| 28 | 
            +
                  #
         | 
| 29 | 
            +
                  # <tt>[[file_operation_object, data_or_nil], ...]</tt>
         | 
| 30 | 
            +
                  def captured_data
         | 
| 31 | 
            +
                    filter :data
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  # Returns any data captured by <tt>operation_name</tt>.
         | 
| 35 | 
            +
                  #
         | 
| 36 | 
            +
                  # If multiple instances of one operation class have modified the file,
         | 
| 37 | 
            +
                  # pass any +options+ the specific instance of the operation was
         | 
| 38 | 
            +
                  # initialized with as the optional second argument.
         | 
| 39 | 
            +
                  def captured_data_for(operation_name, **options)
         | 
| 40 | 
            +
                    return if empty?
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    captured_data.filter { |op, _| matches? op, operation_name, options }
         | 
| 43 | 
            +
                                 .map(&:last)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  # Returns an array with all data captured by operations with +tag+.
         | 
| 47 | 
            +
                  # Returns an empty array if there is no data for +tag+.
         | 
| 48 | 
            +
                  #
         | 
| 49 | 
            +
                  # Tags are defined in FileOperations::CapturedDataTags
         | 
| 50 | 
            +
                  def captured_data_with(tag)
         | 
| 51 | 
            +
                    captured_data.filter { |op, _| op.captured_data_tag == tag }
         | 
| 52 | 
            +
                                 .map(&:last)
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  # Clears all history entries (version names and associated results).
         | 
| 56 | 
            +
                  def clear!
         | 
| 57 | 
            +
                    @entries.clear
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  # Returns +true+ if +self+ has no entries (version names and associated
         | 
| 61 | 
            +
                  # results), +true+ otherwise.
         | 
| 62 | 
            +
                  def empty?
         | 
| 63 | 
            +
                    @entries.empty?
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  # Returns an array of triplets (arryas with three items each):
         | 
| 67 | 
            +
                  #  * Name of the file operation class (String).
         | 
| 68 | 
            +
                  #  * Options for the file operation instance (Hash).
         | 
| 69 | 
            +
                  #  * The log (Array).
         | 
| 70 | 
            +
                  def log
         | 
| 71 | 
            +
                    filter(:log).map { |op, results| [op.name, op.options, results] }
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  # Returns a two-dimensional Array where every nested Array will consist
         | 
| 75 | 
            +
                  # of the version name (file path) at index +0+ and +nil+ or an Array with
         | 
| 76 | 
            +
                  # all _results_ objects for the version at index +1+:
         | 
| 77 | 
            +
                  #
         | 
| 78 | 
            +
                  # <tt>[version_name, [results1, ...]]</tt>
         | 
| 79 | 
            +
                  def to_a
         | 
| 80 | 
            +
                    @entries.to_a
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  # Returns an array with paths to the version files of +self+ (excluding
         | 
| 84 | 
            +
                  # #original).
         | 
| 85 | 
            +
                  def versions
         | 
| 86 | 
            +
                    @entries.keys
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  private
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  # Filters entries in self by +item+ (<tt>:log</tt> or <tt>:data</tt>).
         | 
| 92 | 
            +
                  def filter(item)
         | 
| 93 | 
            +
                    @entries.values.flatten.select(&item).map do |results|
         | 
| 94 | 
            +
                      [results.operation, results.public_send(item)]
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                  # Returns +true+ if +name+ matches the _name_ attribute of +operation+ and
         | 
| 99 | 
            +
                  # +options+ matches the options the operation instance is initialized
         | 
| 100 | 
            +
                  # with.
         | 
| 101 | 
            +
                  def matches?(operation, name, opts)
         | 
| 102 | 
            +
                    operation.name == name && opts.all? { |k, v| operation.options[k] == v }
         | 
| 103 | 
            +
                  end
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
              end
         | 
| 106 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require_relative 'versions/history'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module FilePipeline
         | 
| 6 | 
            +
              # Module that contains classes to work with VersionedFile.
         | 
| 7 | 
            +
              module Versions
         | 
| 8 | 
            +
                # Copies the file with path _src_ to <em>/dir/filename</em>.
         | 
| 9 | 
            +
                def self.copy(src, dir, filename)
         | 
| 10 | 
            +
                  dest = FilePipeline.path(dir, filename)
         | 
| 11 | 
            +
                  FileUtils.cp src, dest
         | 
| 12 | 
            +
                  dest
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                # Moves the file with path _src_ to <em>/dir/filename</em>.
         | 
| 16 | 
            +
                def self.move(src, dir, filename)
         | 
| 17 | 
            +
                  dest = FilePipeline.path(dir, filename)
         | 
| 18 | 
            +
                  FileUtils.mv src, dest
         | 
| 19 | 
            +
                  dest
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
    
        data/lib/file_pipeline.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: file_pipeline
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.7
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Martin Stein
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2019- | 
| 11 | 
            +
            date: 2019-12-09 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: multi_exiftool
         | 
| @@ -38,7 +38,7 @@ dependencies: | |
| 38 38 | 
             
                - - "~>"
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 40 | 
             
                    version: 2.0.16
         | 
| 41 | 
            -
            description: The file_pipeline gem provides a framework  | 
| 41 | 
            +
            description: The file_pipeline gem provides a framework for nondestructive application
         | 
| 42 42 | 
             
              of file operation batches to files.
         | 
| 43 43 | 
             
            email: loveablelobster@fastmail.fm
         | 
| 44 44 | 
             
            executables: []
         | 
| @@ -65,6 +65,8 @@ files: | |
| 65 65 | 
             
            - lib/file_pipeline/file_operations/results.rb
         | 
| 66 66 | 
             
            - lib/file_pipeline/pipeline.rb
         | 
| 67 67 | 
             
            - lib/file_pipeline/versioned_file.rb
         | 
| 68 | 
            +
            - lib/file_pipeline/versions.rb
         | 
| 69 | 
            +
            - lib/file_pipeline/versions/history.rb
         | 
| 68 70 | 
             
            homepage: https://github.com/loveablelobster/file_pipeline
         | 
| 69 71 | 
             
            licenses:
         | 
| 70 72 | 
             
            - MIT
         | 
| @@ -77,7 +79,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 77 79 | 
             
              requirements:
         | 
| 78 80 | 
             
              - - ">="
         | 
| 79 81 | 
             
                - !ruby/object:Gem::Version
         | 
| 80 | 
            -
                  version: ' | 
| 82 | 
            +
                  version: '2.6'
         | 
| 81 83 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 82 84 | 
             
              requirements:
         | 
| 83 85 | 
             
              - - ">="
         |