Class: Sequencer::Sequence

Inherits:
Object
  • Object
show all
Includes:
Comparable, Enumerable
Defined in:
lib/sequencer.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(directory, filenames) ⇒ Sequence

Returns a new instance of Sequence



118
119
120
121
122
123
124
125
# 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

Instance Attribute Details

#directoryObject (readonly)

Returns the value of attribute directory



116
117
118
# File 'lib/sequencer.rb', line 116

def directory
  @directory
end

#patternObject (readonly)

Returns the value of attribute pattern



115
116
117
# File 'lib/sequencer.rb', line 115

def pattern
  @pattern
end

Instance Method Details

#<=>(another) ⇒ Object



283
284
285
# File 'lib/sequencer.rb', line 283

def <=>(another)
  to_paths <=> another.to_paths
end

#bulk_rename(with_pattern, into_directory = nil, &operation) ⇒ Object

Apply a bulk rename



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# 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

#eachObject

Yields the filename of each file to the block



205
206
207
# File 'lib/sequencer.rb', line 205

def each
  @filenames.each {|f| yield(f) }
end

#each_pathObject

Yield each absolute path to a file in the sequence to the block



210
211
212
# File 'lib/sequencer.rb', line 210

def each_path
  @filenames.each{|f| yield(File.join(@directory, f))}
end

#expected_framesObject



176
177
178
# File 'lib/sequencer.rb', line 176

def expected_frames
  @expected_frames ||= ((@ranges[-1].end - @ranges[0].begin) + 1)
end

#file_countObject Also known as: length

Returns the actual file count in the sequence



194
195
196
# File 'lib/sequencer.rb', line 194

def file_count
  @file_count ||= @filenames.length
end

#first_frame_noObject

Returns the number of the first frame in the sequence



225
226
227
# File 'lib/sequencer.rb', line 225

def first_frame_no
  @ranges[0].begin
end

#gap_countObject



180
181
182
# File 'lib/sequencer.rb', line 180

def gap_count
  @ranges.length - 1
end

#gaps?Boolean

Returns true if this sequence has gaps

Returns:

  • (Boolean)


133
134
135
# File 'lib/sequencer.rb', line 133

def gaps?
  @ranges.length > 1
end

#include?(base_filename) ⇒ Boolean

Check if this sequencer includes a file

Returns:

  • (Boolean)


200
201
202
# File 'lib/sequencer.rb', line 200

def include?(base_filename)
  @filenames.include?(base_filename)
end

#inspectObject



142
143
144
# File 'lib/sequencer.rb', line 142

def inspect
  '#<%s>' % to_s
end

#last_frame_noObject

Returns the number of the last frame in the sequence



230
231
232
# File 'lib/sequencer.rb', line 230

def last_frame_no
  @ranges[-1].end
end

#missing_framesObject

Returns the number of frames that the sequence should contain to be continuous



189
190
191
# File 'lib/sequencer.rb', line 189

def missing_frames
  expected_frames - file_count
end

#numbered?Boolean

Returns true if the files in the sequence can have numbers

Returns:

  • (Boolean)


128
129
130
# File 'lib/sequencer.rb', line 128

def numbered?
  @numbered ||= !!(@filenames[0] =~ NUMBERS_AT_END)
end

#segment_countObject



184
185
186
# File 'lib/sequencer.rb', line 184

def segment_count
  @ranges.length
end

#single_file?Boolean

Tells whether this is a single frame sequence

Returns:

  • (Boolean)


138
139
140
# File 'lib/sequencer.rb', line 138

def single_file?
  @filenames.length == 1
end

#to_aObject

Returns the array of filenames



215
216
217
# File 'lib/sequencer.rb', line 215

def to_a
  @filenames.dup
end

#to_pathsObject

Returns paths to the files



220
221
222
# File 'lib/sequencer.rb', line 220

def to_paths
  @filenames.map{|f| File.join(@directory, f) }
end

#to_sObject



163
164
165
166
167
168
169
170
171
172
173
174
# 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_sequencesObject

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>]


149
150
151
152
153
154
155
156
157
158
159
160
# 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