class Sequencer::Sequence
Attributes
directory[R]
pattern[R]
Public Class Methods
new(directory, filenames)
click to toggle source
# File lib/sequencer.rb, line 118 def initialize(directory, filenames) raise "Cannot create a Sequence with no files" if filenames.empty? @directory, @filenames = directory, natural_sort(filenames) @directory.freeze @filenames.freeze detect_gaps! detect_pattern! end
Public Instance Methods
<=>(another)
click to toggle source
# File lib/sequencer.rb, line 283 def <=>(another) to_paths <=> another.to_paths end
bulk_rename(with_pattern, into_directory = nil, &operation)
click to toggle source
Apply a bulk rename
# File lib/sequencer.rb, line 235 def bulk_rename(with_pattern, into_directory = nil, &operation) # Check if the pattern includes a number. If it doesnt, add one and the # extension unless with_pattern.include?("%") padz = last_frame_no.to_s.length with_pattern = [with_pattern, ".%0#{padz}d", File.extname(pattern)].join end rename_map = @filenames.inject({}) do | map, filename | frame_no = filename.scan(NUMBERS_AT_END).flatten.shift.to_i map.merge(filename => (with_pattern % frame_no)) end destination = into_directory || directory # Ensure it's there if (!File.exist?(destination)) raise "The destination #{destination} does not exist" end # Ensure it's a dir if (!File.directory?(destination)) raise "The destination #{destination} is not a directory" end # Ensure we will not produce dupes if (rename_map.values.uniq.length != rename_map.length) raise "This would would produce non-unique files" end if (error = (rename_map.keys & rename_map.values)).any? raise "This would overwrite old files with the renamed ones (#{error[0..1]}.join(',')..)" end if (error = (Dir.entries(destination) & rename_map.values)).any? raise "Files that will be created by the rename are already in place (#{error[0..1]}.join(',')..)" end rename_map.each_pair do | from_path, to_path | src, dest = File.join(directory, from_path), File.join(destination, to_path) File.rename(src, dest) #yield(src, dest) end self.class.new(destination, rename_map.values) end
each() { |f| ... }
click to toggle source
Yields the filename of each file to the block
# File lib/sequencer.rb, line 205 def each @filenames.each {|f| yield(f) } end
each_path() { |join| ... }
click to toggle source
Yield each absolute path to a file in the sequence to the block
# File lib/sequencer.rb, line 210 def each_path @filenames.each{|f| yield(File.join(@directory, f))} end
expected_frames()
click to toggle source
# File lib/sequencer.rb, line 176 def expected_frames @expected_frames ||= ((@ranges[-1].end - @ranges[0].begin) + 1) end
file_count()
click to toggle source
Returns the actual file count in the sequence
# File lib/sequencer.rb, line 194 def file_count @file_count ||= @filenames.length end
Also aliased as: length
first_frame_no()
click to toggle source
Returns the number of the first frame in the sequence
# File lib/sequencer.rb, line 225 def first_frame_no @ranges[0].begin end
gap_count()
click to toggle source
# File lib/sequencer.rb, line 180 def gap_count @ranges.length - 1 end
gaps?()
click to toggle source
Returns true if this sequence has gaps
# File lib/sequencer.rb, line 133 def gaps? @ranges.length > 1 end
include?(base_filename)
click to toggle source
Check if this sequencer includes a file
# File lib/sequencer.rb, line 200 def include?(base_filename) @filenames.include?(base_filename) end
inspect()
click to toggle source
# File lib/sequencer.rb, line 142 def inspect '#<%s>' % to_s end
last_frame_no()
click to toggle source
Returns the number of the last frame in the sequence
# File lib/sequencer.rb, line 230 def last_frame_no @ranges[-1].end end
missing_frames()
click to toggle source
Returns the number of frames that the sequence should contain to be continuous
# File lib/sequencer.rb, line 189 def missing_frames expected_frames - file_count end
numbered?()
click to toggle source
Returns true if the files in the sequence can have numbers
# File lib/sequencer.rb, line 128 def numbered? @numbered ||= !!(@filenames[0] =~ NUMBERS_AT_END) end
segment_count()
click to toggle source
# File lib/sequencer.rb, line 184 def segment_count @ranges.length end
single_file?()
click to toggle source
Tells whether this is a single frame sequence
# File lib/sequencer.rb, line 138 def single_file? @filenames.length == 1 end
to_a()
click to toggle source
Returns the array of filenames
# File lib/sequencer.rb, line 215 def to_a @filenames.dup end
to_paths()
click to toggle source
Returns paths to the files
# File lib/sequencer.rb, line 220 def to_paths @filenames.map{|f| File.join(@directory, f) } end
to_s()
click to toggle source
# File lib/sequencer.rb, line 163 def to_s return @filenames[0] if (!numbered? || single_file?) printable = unless single_file? @ranges.map do | r | "%d..%d" % [r.begin, r.end] end.join(', ') else @ranges[0].begin end @inspect_pattern % "[#{printable}]" end
to_sequences()
click to toggle source
If this Sequence
has gaps, this method will return an array of all subsequences that it contains
s # => #<broken_seq.[123..568, 578..702].tif> s.to_sequences # => [#<broken_seq.[123..568].tif>, #<broken_seq.[578..702].tif>]
# File lib/sequencer.rb, line 149 def to_sequences return [self] unless gaps? last_offset = 0 @ranges.map do | frame_range | frames_in_seg = frame_range.end - frame_range.begin seg_filenames = @filenames[last_offset..(last_offset + frames_in_seg)] last_offset = last_offset + frames_in_seg + 1 s = self.class.new(@directory, seg_filenames) end end
Private Instance Methods
detect_gaps!()
click to toggle source
# File lib/sequencer.rb, line 322 def detect_gaps! only_numbers = @filenames.map do | f | f.scan(NUMBERS_AT_END).flatten.shift.to_i end @ranges = to_ranges(only_numbers) end
detect_pattern!()
click to toggle source
# File lib/sequencer.rb, line 293 def detect_pattern! unless numbered? @inspect_pattern = "%s" @pattern = @filenames[0] else @inspect_pattern = @filenames[0].gsub(NUMBERS_AT_END) do ["%s", $2].join end highest_padding = nil @pattern = @filenames[-1].gsub(NUMBERS_AT_END) do highest_padding = $1.length ["%0#{$1.length}d", $2].join end # Look at the first file in the sequence. lowest_padding = @filenames[0].scan(NUMBERS_AT_END).flatten.shift.length if lowest_padding < highest_padding # Natural numbering @pattern = @filenames[0].gsub(NUMBERS_AT_END) do ["%d", $2].join end end end @inspect_pattern.freeze @pattern.freeze end
natural_sort(ar)
click to toggle source
# File lib/sequencer.rb, line 289 def natural_sort(ar) ar.sort_by {|e| e.scan(NUMBERS_AT_END).flatten.shift.to_i } end
to_ranges(array)
click to toggle source
# File lib/sequencer.rb, line 329 def to_ranges(array) array.compact.sort.uniq.inject([]) do | result, elem | result = [elem..elem] if result.length.zero? if [result[-1].end, result[-1].end.succ].include?(elem) result[-1] = result[-1].begin..elem else result.push(elem..elem) end result end end