sequencer 1.0.3 → 1.0.5
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.
- data/.gemtest +0 -0
- data/History.txt +9 -1
- data/Manifest.txt +2 -1
- data/{README.txt → README.rdoc} +22 -6
- data/Rakefile +3 -2
- data/bin/rseqrename +6 -0
- data/lib/sequencer.rb +23 -10
- data/test/test_sequencer.rb +115 -81
- metadata +13 -40
data/.gemtest
ADDED
File without changes
|
data/History.txt
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
+
=== 1.0.5 / 2011-07-07
|
2
|
+
|
3
|
+
* Dicking around with testing frameworks that become obsolete is the worst thing ever.
|
4
|
+
|
5
|
+
=== 1.0.4 / 2010-10-26
|
6
|
+
|
7
|
+
* Add rseqrename binary that batch-renames sequences
|
8
|
+
|
1
9
|
=== 1.0.3 / 2010-10-26
|
2
10
|
|
3
|
-
* Add rseqpad binary that zero-pads
|
11
|
+
* Add rseqpad binary that zero-pads sequences
|
4
12
|
|
5
13
|
=== 1.0.2 / 2010-05-06
|
6
14
|
|
data/Manifest.txt
CHANGED
data/{README.txt → README.rdoc}
RENAMED
@@ -6,18 +6,34 @@
|
|
6
6
|
|
7
7
|
Simplifies working with image sequences
|
8
8
|
|
9
|
-
== FEATURES
|
9
|
+
== FEATURES:
|
10
10
|
|
11
11
|
* List all sequences in a directory interspersed with other file entries
|
12
12
|
* Detect sequence from single file
|
13
13
|
|
14
14
|
== SYNOPSIS:
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
From the terminal - go to a directory, and then:
|
17
|
+
|
18
|
+
$rseqls
|
19
|
+
|
20
|
+
Fussball_Shot[1..1, 3..3].sni
|
21
|
+
FinalLichtUitValSec_Shot1.[1..128].jpg
|
22
|
+
Fussball_Shot3_v02.sni
|
23
|
+
FinalLichtUitValSec_Shot1.0001.ifl
|
24
|
+
FinalLichtUitValSec.0001.ifl
|
25
|
+
FinalLichtUitValSec.[1..185].jpg
|
26
|
+
|
27
|
+
You also have <tt>rseqpad</tt> and <tt>rseqrename</tt> :-)
|
28
|
+
|
29
|
+
From code:
|
30
|
+
|
31
|
+
require "sequencer"
|
32
|
+
s = Sequencer.from_single_file("/RAID/Film/CONFORM.092183.dpx")
|
33
|
+
s.file_count #=> 3201
|
34
|
+
s.gaps? #=> true
|
35
|
+
s.missing_frames #=> 15, somebody was careless
|
36
|
+
s.pattern #=> "CONFORM.%06d.dpx", usable with printf right away
|
21
37
|
|
22
38
|
== INSTALL:
|
23
39
|
|
data/Rakefile
CHANGED
@@ -3,10 +3,11 @@ require 'rubygems'
|
|
3
3
|
require 'hoe'
|
4
4
|
require File.dirname(__FILE__) + "/lib/sequencer"
|
5
5
|
|
6
|
+
Hoe::RUBY_FLAGS.gsub!(/^-w/, '')
|
6
7
|
Hoe.spec 'sequencer' do | s |
|
7
|
-
s.
|
8
|
+
s.readme_file = 'README.rdoc'
|
9
|
+
s.extra_rdoc_files = FileList['*.rdoc']
|
8
10
|
s.developer('Julik Tarkhanov', 'me@julik.nl')
|
9
|
-
s.extra_dev_deps = {"test-spec" => ">=0"}
|
10
11
|
end
|
11
12
|
|
12
13
|
# vim: syntax=ruby
|
data/bin/rseqrename
ADDED
data/lib/sequencer.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Sequencer
|
2
|
-
VERSION = '1.0.
|
2
|
+
VERSION = '1.0.5'
|
3
3
|
NUMBERS_AT_END = /(\d+)([^\d]+)?$/
|
4
4
|
|
5
5
|
extend self
|
@@ -30,7 +30,8 @@ module Sequencer
|
|
30
30
|
|
31
31
|
# Detect a Sequence from a single file and return a handle to it
|
32
32
|
def from_single_file(path_to_single_file)
|
33
|
-
File.stat(path_to_single_file)
|
33
|
+
#File.stat(path_to_single_file)
|
34
|
+
|
34
35
|
frame_number = path_to_single_file.scan(NUMBERS_AT_END).flatten.shift
|
35
36
|
if frame_number =~ /^0/ # Assume that the input is padded and take the glob path
|
36
37
|
sequence_via_glob(path_to_single_file)
|
@@ -86,7 +87,7 @@ module Sequencer
|
|
86
87
|
attr_reader :directory
|
87
88
|
|
88
89
|
def initialize(directory, filenames)
|
89
|
-
raise "
|
90
|
+
raise "Cannot create a Sequence with no files" if filenames.empty?
|
90
91
|
@directory, @filenames = directory, natural_sort(filenames)
|
91
92
|
@directory.freeze
|
92
93
|
@filenames.freeze
|
@@ -202,9 +203,17 @@ module Sequencer
|
|
202
203
|
end
|
203
204
|
|
204
205
|
# Apply a bulk rename
|
205
|
-
def bulk_rename(with_pattern)
|
206
|
-
|
206
|
+
def bulk_rename(with_pattern, into_directory = nil, &operation)
|
207
|
+
# Check if the pattern includes a number. If it doesnt, add one and the
|
208
|
+
# extension
|
209
|
+
unless with_pattern.include?("%")
|
210
|
+
padz = last_frame_no.to_s.length
|
211
|
+
with_pattern = [with_pattern, ".%0#{padz}d", File.extname(pattern)].join
|
212
|
+
end
|
213
|
+
|
214
|
+
rename_map = @filenames.inject({}) do | map, filename |
|
207
215
|
frame_no = filename.scan(NUMBERS_AT_END).flatten.shift.to_i
|
216
|
+
|
208
217
|
map.merge(filename => (with_pattern % frame_no))
|
209
218
|
end
|
210
219
|
|
@@ -217,15 +226,19 @@ module Sequencer
|
|
217
226
|
raise "This would overwrite old files with the renamed ones (#{error[0..1]}.join(',')..)"
|
218
227
|
end
|
219
228
|
|
220
|
-
if (error = (Dir.entries(@directory)
|
229
|
+
if (error = (Dir.entries(@directory) & rename_map.values)).any?
|
221
230
|
raise "Files that will be created by the rename are already in place (#{error[0..1]}.join(',')..)"
|
222
231
|
end
|
223
232
|
|
233
|
+
destination = into_directory || directory
|
224
234
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
235
|
+
rename_map.each_pair do | from_path, to_path |
|
236
|
+
src, dest = File.join(directory, from_path), File.join(destination, to_path)
|
237
|
+
File.rename(src, dest)
|
238
|
+
#yield(src, dest)
|
239
|
+
end
|
240
|
+
|
241
|
+
self.class.new(destination, rename_map.values)
|
229
242
|
end
|
230
243
|
|
231
244
|
private
|
data/test/test_sequencer.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
require 'test/unit'
|
2
|
-
require '
|
3
|
-
require 'test/spec'
|
2
|
+
require 'set'
|
4
3
|
require 'fileutils'
|
5
4
|
require File.dirname(__FILE__) + '/../lib/sequencer'
|
6
5
|
|
7
|
-
TEST_DIR = File.dirname(__FILE__) + "/tmp"
|
6
|
+
TEST_DIR = File.expand_path(File.dirname(__FILE__)) + "/tmp"
|
8
7
|
|
9
8
|
def emit_test_dirs
|
10
9
|
start_f = 123
|
@@ -59,131 +58,166 @@ def teardown_test_dirs
|
|
59
58
|
FileUtils.rm_rf(TEST_DIR)
|
60
59
|
end
|
61
60
|
|
62
|
-
|
61
|
+
class Test_glob_and_padding_for < Test::Unit::TestCase
|
63
62
|
|
64
|
-
|
63
|
+
def test_returns_proper_glob_pattern_padding_for_a_path_with_extension
|
65
64
|
glob, pad = Sequencer.glob_and_padding_for("file.00001.gif")
|
66
|
-
|
67
|
-
|
65
|
+
assert_equal "file.[0-9][0-9][0-9][0-9][0-9].gif", glob
|
66
|
+
assert_equal 5, pad
|
68
67
|
end
|
69
|
-
|
70
|
-
|
68
|
+
|
69
|
+
def test_returns_proper_glob_pattern_and_padding_for_a_path_without_extension
|
71
70
|
glob, pad = Sequencer.glob_and_padding_for("file.00001")
|
72
|
-
|
73
|
-
|
71
|
+
assert_equal "file.[0-9][0-9][0-9][0-9][0-9]", glob
|
72
|
+
assert_equal 5, pad
|
74
73
|
end
|
75
74
|
|
76
|
-
|
75
|
+
def return_nil_for_a_file_that_is_not_in_the_sequence
|
77
76
|
glob, pad = Sequencer.glob_and_padding_for("file")
|
78
|
-
glob
|
77
|
+
assert_nil glob
|
79
78
|
end
|
80
79
|
end
|
81
80
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
81
|
+
class Sequencer_entries_should < Test::Unit::TestCase
|
82
|
+
def setup; emit_test_dirs; end
|
83
|
+
def teardown; teardown_test_dirs; end
|
84
|
+
|
85
|
+
def test_returns_entries_for_every_sequence_in_a_directory
|
86
86
|
entries = Sequencer.entries(TEST_DIR + "/many_seqs")
|
87
|
+
flunk "this test is not finished"
|
87
88
|
end
|
88
89
|
end
|
89
90
|
|
90
|
-
|
91
|
-
|
92
|
-
|
91
|
+
class A_Sequence_created_from_unpadded_files_should < Test::Unit::TestCase
|
92
|
+
def setup; emit_test_dirs; end
|
93
|
+
def teardown; teardown_test_dirs; end
|
93
94
|
|
94
|
-
|
95
|
+
def test_properly_created
|
95
96
|
s = Sequencer.from_single_file(TEST_DIR + "/natural_numbering/somefiles 5545168.png")
|
96
|
-
s
|
97
|
-
s.expected_frames
|
98
|
-
s.file_count
|
99
|
-
|
97
|
+
assert_not_nil s
|
98
|
+
assert_equal 30, s.expected_frames
|
99
|
+
assert_equal 30, s.file_count
|
100
|
+
assert_equal "somefiles %07d.png", s.pattern
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class A_Sequence_created_from_a_file_that_has_no_numbering_slot_should
|
105
|
+
def setup; @single = Sequencer::Sequence.new("/tmp", ["foo.tif"]); end
|
106
|
+
|
107
|
+
def test_report_a_pattern_that_is_the_name_as_filename
|
108
|
+
assert_equal 'foo.tif', @single.pattern
|
109
|
+
assert @single.single_file?
|
110
|
+
assert_equal 1, @single.expected_frames
|
111
|
+
assert_equal "#<foo.tif>", @single.inspect
|
100
112
|
end
|
101
113
|
end
|
102
114
|
|
103
|
-
|
104
|
-
|
115
|
+
class Sequencer_bulk_rename_should < Test::Unit::TestCase
|
116
|
+
def setup
|
117
|
+
emit_test_dirs
|
118
|
+
@with_gaps = Sequencer.from_single_file(TEST_DIR + "/sequence_and_sole_file/broken_seq.000245.tif")
|
119
|
+
end
|
120
|
+
|
121
|
+
def teardown
|
122
|
+
teardown_test_dirs
|
123
|
+
end
|
105
124
|
|
106
|
-
|
107
|
-
@
|
108
|
-
@
|
109
|
-
@
|
110
|
-
|
125
|
+
def test_return_a_new_Sequencer_with_right_parameters
|
126
|
+
res = @with_gaps.bulk_rename("another_base")
|
127
|
+
assert_equal @with_gaps.length, res.length
|
128
|
+
assert_equal @with_gaps.directory, res.directory
|
129
|
+
assert_equal "another_base.%03d.tif", res.pattern
|
130
|
+
|
131
|
+
assert File.exist?(res.to_paths[0])
|
132
|
+
assert File.exist?(res.to_paths[-1])
|
111
133
|
end
|
112
134
|
end
|
113
135
|
|
114
|
-
|
115
|
-
|
136
|
+
class A_Sequence_created_from_pad_numbered_files_should < Test::Unit::TestCase
|
137
|
+
def setup
|
116
138
|
emit_test_dirs
|
117
139
|
@gapless = Sequencer.from_single_file(TEST_DIR + "/sequence_and_sole_file/seq1.000245.tif")
|
118
140
|
@with_gaps = Sequencer.from_single_file(TEST_DIR + "/sequence_and_sole_file/broken_seq.000245.tif")
|
119
141
|
@single = Sequencer.from_single_file(TEST_DIR + "/sequence_and_sole_file/single_file.002123154.tif")
|
120
142
|
end
|
121
143
|
|
122
|
-
|
144
|
+
def teardown
|
145
|
+
teardown_test_dirs
|
146
|
+
end
|
123
147
|
|
124
|
-
|
125
|
-
@gapless
|
126
|
-
|
127
|
-
@gapless
|
128
|
-
|
148
|
+
def test_initialize_itself_from_one_path_to_a_file_in_the_sequence_without_gaps
|
149
|
+
assert_not_nil @gapless
|
150
|
+
assert_kind_of Sequencer::Sequence, @gapless
|
151
|
+
assert_respond_to @gapless, :gaps?
|
152
|
+
assert !@gapless.single_file?
|
129
153
|
|
130
|
-
|
131
|
-
@gapless.file_count
|
132
|
-
@gapless.length
|
133
|
-
@gapless.expected_frames
|
134
|
-
|
135
|
-
@gapless.pattern.should.equal 'seq1.%06d.tif'
|
154
|
+
assert !@gapless.gaps?, "this is a gapless sequence"
|
155
|
+
assert_equal 446, @gapless.file_count, "actual file count in sequence"
|
156
|
+
assert_equal 446, @gapless.length, "actual file count in sequence"
|
157
|
+
assert_equal 446, @gapless.expected_frames, "expected frame count in sequence"
|
158
|
+
assert_equal '#<seq1.[123..568].tif>', @gapless.inspect
|
136
159
|
|
137
160
|
files = @gapless.to_a
|
138
|
-
files.length
|
139
|
-
|
161
|
+
assert_equal 446, files.length
|
162
|
+
assert_equal 'seq1.000123.tif', files[0]
|
140
163
|
|
141
164
|
paths = @gapless.to_paths
|
142
|
-
paths.length
|
143
|
-
|
165
|
+
assert_equal 446, paths.length
|
166
|
+
assert_equal File.expand_path(File.dirname(__FILE__)) + "/tmp/sequence_and_sole_file/seq1.000123.tif", paths[0]
|
144
167
|
end
|
145
168
|
|
146
|
-
|
147
|
-
@with_gaps
|
148
|
-
|
149
|
-
|
169
|
+
def test_initialize_itself_from_one_path_to_a_file_in_the_sequence_with_gaps
|
170
|
+
assert_not_nil @with_gaps
|
171
|
+
assert_kind_of Sequencer::Sequence, @with_gaps
|
172
|
+
assert !@with_gaps.single_file?
|
150
173
|
|
151
|
-
@with_gaps.
|
152
|
-
@with_gaps.gap_count
|
153
|
-
@with_gaps.segment_count
|
154
|
-
@with_gaps.missing_frames
|
155
|
-
|
156
|
-
@with_gaps.
|
157
|
-
|
174
|
+
assert @with_gaps.gaps?
|
175
|
+
assert_equal 1, @with_gaps.gap_count
|
176
|
+
assert_equal 2, @with_gaps.segment_count
|
177
|
+
assert_equal 9, @with_gaps.missing_frames
|
178
|
+
assert_equal '#<broken_seq.[123..568, 578..702].tif>', @with_gaps.inspect
|
179
|
+
assert @with_gaps.include?("broken_seq.000123.tif")
|
180
|
+
assert !@with_gaps.include?("bogus.123.tif")
|
158
181
|
end
|
159
182
|
|
160
|
-
|
183
|
+
def test_return_subsequences_without_gaps
|
161
184
|
subseqs = @with_gaps.to_sequences
|
162
|
-
subseqs[0]
|
163
|
-
subseqs[1]
|
185
|
+
assert_kind_of Sequencer::Sequence, subseqs[0]
|
186
|
+
assert_kind_of Sequencer::Sequence, subseqs[1]
|
164
187
|
|
165
188
|
first_seq, second_seq = subseqs
|
166
|
-
first_seq.first_frame_no
|
167
|
-
first_seq.last_frame_no
|
168
|
-
second_seq.first_frame_no
|
169
|
-
second_seq.last_frame_no
|
189
|
+
assert_equal 123, first_seq.first_frame_no
|
190
|
+
assert_equal 568, first_seq.last_frame_no
|
191
|
+
assert_equal 578, second_seq.first_frame_no
|
192
|
+
assert_equal 702, second_seq.last_frame_no
|
170
193
|
|
171
|
-
|
172
|
-
|
194
|
+
assert_equal second_seq.directory, first_seq.directory
|
195
|
+
assert_equal @with_gaps.directory, first_seq.directory
|
173
196
|
end
|
174
197
|
|
175
|
-
|
198
|
+
def test_list_all_sequences_in_directory_and_subdirectories_using_the_pattern
|
176
199
|
s = Sequencer.from_glob(TEST_DIR + "/**/*.tif")
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
200
|
+
# Here we need to use a Set since Ruby does not
|
201
|
+
ref_set = Set.new([
|
202
|
+
"#<anotherS [228..312].tif>",
|
203
|
+
"#<seq1.[458..512].tif>",
|
204
|
+
"#<single.tif>",
|
205
|
+
"#<in_subdir [445..471].tif>",
|
206
|
+
"#<broken_seq.[123..568, 578..702].tif>",
|
207
|
+
"#<seq1.[123..568].tif>",
|
208
|
+
"#<single_file.002123154.tif>",
|
209
|
+
"#<somefile.tif>"
|
210
|
+
])
|
211
|
+
output_sequences = Set.new(s.map{|sequence| sequence.inspect })
|
212
|
+
assert_equal ref_set, output_sequences
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_initialize_itself_from_a_single_file
|
216
|
+
assert @single.single_file?
|
217
|
+
assert_equal '#<single_file.002123154.tif>', @single.inspect
|
218
|
+
assert !@single.gaps?
|
219
|
+
assert_equal 1, @single.expected_frames
|
220
|
+
assert_equal 1, @single.file_count
|
187
221
|
end
|
188
222
|
|
189
223
|
end
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequencer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 3
|
10
|
-
version: 1.0.3
|
4
|
+
prerelease:
|
5
|
+
version: 1.0.5
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Julik Tarkhanov
|
@@ -15,61 +10,45 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date:
|
13
|
+
date: 2011-07-07 00:00:00 +02:00
|
19
14
|
default_executable:
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
17
|
+
name: hoe
|
23
18
|
prerelease: false
|
24
19
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
20
|
none: false
|
26
21
|
requirements:
|
27
|
-
- -
|
22
|
+
- - ~>
|
28
23
|
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
24
|
+
version: "2.10"
|
33
25
|
type: :development
|
34
26
|
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: hoe
|
37
|
-
prerelease: false
|
38
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
-
none: false
|
40
|
-
requirements:
|
41
|
-
- - ">="
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
hash: 21
|
44
|
-
segments:
|
45
|
-
- 2
|
46
|
-
- 6
|
47
|
-
- 1
|
48
|
-
version: 2.6.1
|
49
|
-
type: :development
|
50
|
-
version_requirements: *id002
|
51
27
|
description: Simplifies working with image sequences
|
52
28
|
email:
|
53
29
|
- me@julik.nl
|
54
30
|
executables:
|
55
31
|
- rseqls
|
56
32
|
- rseqpad
|
33
|
+
- rseqrename
|
57
34
|
extensions: []
|
58
35
|
|
59
36
|
extra_rdoc_files:
|
60
37
|
- History.txt
|
61
38
|
- Manifest.txt
|
62
|
-
- README.
|
39
|
+
- README.rdoc
|
63
40
|
files:
|
64
41
|
- .autotest
|
65
42
|
- History.txt
|
66
43
|
- Manifest.txt
|
67
|
-
- README.
|
44
|
+
- README.rdoc
|
68
45
|
- Rakefile
|
69
46
|
- bin/rseqls
|
70
47
|
- bin/rseqpad
|
48
|
+
- bin/rseqrename
|
71
49
|
- lib/sequencer.rb
|
72
50
|
- test/test_sequencer.rb
|
51
|
+
- .gemtest
|
73
52
|
has_rdoc: true
|
74
53
|
homepage: http://guerilla-di.org/sequencer
|
75
54
|
licenses: []
|
@@ -77,7 +56,7 @@ licenses: []
|
|
77
56
|
post_install_message:
|
78
57
|
rdoc_options:
|
79
58
|
- --main
|
80
|
-
- README.
|
59
|
+
- README.rdoc
|
81
60
|
require_paths:
|
82
61
|
- lib
|
83
62
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -85,23 +64,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
64
|
requirements:
|
86
65
|
- - ">="
|
87
66
|
- !ruby/object:Gem::Version
|
88
|
-
hash: 3
|
89
|
-
segments:
|
90
|
-
- 0
|
91
67
|
version: "0"
|
92
68
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
69
|
none: false
|
94
70
|
requirements:
|
95
71
|
- - ">="
|
96
72
|
- !ruby/object:Gem::Version
|
97
|
-
hash: 3
|
98
|
-
segments:
|
99
|
-
- 0
|
100
73
|
version: "0"
|
101
74
|
requirements: []
|
102
75
|
|
103
76
|
rubyforge_project: sequencer
|
104
|
-
rubygems_version: 1.
|
77
|
+
rubygems_version: 1.6.2
|
105
78
|
signing_key:
|
106
79
|
specification_version: 3
|
107
80
|
summary: Simplifies working with image sequences
|