timecode 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/History.txt +6 -1
  2. data/lib/timecode.rb +12 -22
  3. data/test/test_timecode.rb +121 -19
  4. metadata +2 -2
data/History.txt CHANGED
@@ -1,6 +1,11 @@
1
+ === 0.1.4 / 2000-01-01
2
+
3
+ * Expanded test coverage
4
+ * Some formatting/doc improvements
5
+
1
6
  === 0.1.3 / 2008-12-25
2
7
 
3
- * Implement the format FFmpeg uses
8
+ * Implement the format FFmpeg uses (fractional seconds instead of frames)
4
9
 
5
10
  === 0.1.2 / 2008-12-25
6
11
 
data/lib/timecode.rb CHANGED
@@ -12,13 +12,15 @@
12
12
  # :mapping => [%w(source_tc_frames total), %w(tape_fps fps)]
13
13
 
14
14
  class Timecode
15
- VERSION = '0.1.3'
15
+ VERSION = '0.1.4'
16
16
 
17
17
  include Comparable
18
18
 
19
19
  DEFAULT_FPS = 25.0
20
20
  ALLOWED_FPS_DELTA = 0.001
21
21
  COMPLETE_TC_RE = /^(\d{1,2}):(\d{1,2}):(\d{1,2}):(\d{1,2})$/
22
+ WITH_FRACTIONS_OF_SECOND = "%02d:%02d:%02d.%02d"
23
+ WITH_FRAMES = "%02d:%02d:%02d:%02d"
22
24
 
23
25
  # All Timecode lib errors inherit from this
24
26
  class Error < RuntimeError; end
@@ -44,19 +46,9 @@ class Timecode
44
46
  # Well well...
45
47
  class MethodRequiresTimecode < ArgumentError; end
46
48
 
47
- # Initialize a new Timecode. If a string is passed, it will be parsed, an integer
49
+ # Initialize a new Timecode object with a certain amount of frames and a framerate
48
50
  # will be interpreted as the total number of frames
49
- def self.new(total_or_string = 0, fps = DEFAULT_FPS)
50
- if total_or_string.nil?
51
- new(0, fps)
52
- elsif total_or_string.is_a?(String)
53
- parse(total_or_string, fps)
54
- else
55
- super(total_or_string, fps)
56
- end
57
- end
58
-
59
- def initialize(total = 0, fps = DEFAULT_FPS) # :nodoc:
51
+ def initialize(total = 0, fps = DEFAULT_FPS)
60
52
  raise RangeError, "Timecode cannot be negative" if total.to_f < 0
61
53
  raise WrongFramerate, "FPS cannot be zero" if fps.zero?
62
54
 
@@ -188,7 +180,7 @@ class Timecode
188
180
  to_f
189
181
  end
190
182
 
191
- #get FPS
183
+ # get FPS
192
184
  def fps
193
185
  @fps
194
186
  end
@@ -231,16 +223,13 @@ class Timecode
231
223
  # Convert to different framerate based on the total frames. Therefore,
232
224
  # 1 second of PAL video will convert to 25 frames of NTSC (this
233
225
  # is suitable for PAL to film TC conversions and back).
234
- # It does not account for pulldown or anything in that sense, because
235
- # then you need to think about cadences and such
236
226
  def convert(new_fps)
237
- raise NonPositiveFps, "FPS cannot be less than 0" if new_fps < 1
238
- self.class.new((total/fps)*new_fps, new_fps)
227
+ self.class.new(@total, new_fps)
239
228
  end
240
229
 
241
230
  # get formatted SMPTE timecode
242
231
  def to_s
243
- "%02d:%02d:%02d:%02d" % value_parts
232
+ WITH_FRAMES % value_parts
244
233
  end
245
234
 
246
235
  # get total frames as float
@@ -286,9 +275,10 @@ class Timecode
286
275
  self.class.new(@total + 1, @fps)
287
276
  end
288
277
 
289
- # Slice the timespan in pieces
278
+ # Get the number of times a passed timecode fits into this time span (if performed with Timecode) or
279
+ # a Timecode that multiplied by arg will give this one
290
280
  def /(arg)
291
- Timecode.new(@total/arg, @fps)
281
+ arg.is_a?(Timecode) ? (@total / arg.total) : Timecode.new(@total /arg, @fps)
292
282
  end
293
283
 
294
284
  # Timecodes can be compared to each other
@@ -307,7 +297,7 @@ class Timecode
307
297
  def with_frames_as_fraction
308
298
  vp = value_parts.dup
309
299
  vp[-1] = (100.0 / @fps) * vp[-1]
310
- "%02d:%02d:%02d.%02d" % vp
300
+ WITH_FRACTIONS_OF_SECOND % vp
311
301
  end
312
302
  alias_method :with_fractional_seconds, :with_frames_as_fraction
313
303
 
@@ -1,9 +1,6 @@
1
1
  require 'test/unit'
2
- require 'rubygems'
3
- require 'timecode'
2
+ require File.dirname(__FILE__) + '/../lib/timecode'
4
3
 
5
- # for Fixnum#hours
6
- require 'active_support'
7
4
 
8
5
  class TimecodeTest < Test::Unit::TestCase
9
6
 
@@ -29,6 +26,10 @@ class TimecodeTest < Test::Unit::TestCase
29
26
  assert t1 == t2
30
27
  end
31
28
 
29
+ def test_to_i_is_total
30
+ assert_equal 10, Timecode.new(10).to_i
31
+ end
32
+
32
33
  def test_inspect
33
34
  tc = Timecode.new(10, 25)
34
35
  assert_equal "#<Timecode:00:00:00:10 (10F@25.00)>", tc.inspect
@@ -39,7 +40,8 @@ class TimecodeTest < Test::Unit::TestCase
39
40
  end
40
41
 
41
42
  def test_basics
42
- five_seconds_of_pal = 5.seconds * 25
43
+ five_seconds_of_pal = 5 * 25
44
+
43
45
  tc = Timecode.new(five_seconds_of_pal, 25)
44
46
  assert_equal 0, tc.hours
45
47
  assert_equal 0, tc.minutes
@@ -48,7 +50,7 @@ class TimecodeTest < Test::Unit::TestCase
48
50
  assert_equal five_seconds_of_pal, tc.total
49
51
  assert_equal "00:00:05:00", tc.to_s
50
52
 
51
- one_and_a_half_hour_of_hollywood = 90.minutes * 24
53
+ one_and_a_half_hour_of_hollywood = (90 * 60) * 24
52
54
 
53
55
  film_tc = Timecode.new(one_and_a_half_hour_of_hollywood, 24)
54
56
  assert_equal 1, film_tc.hours
@@ -65,7 +67,7 @@ class TimecodeTest < Test::Unit::TestCase
65
67
  tc + film_tc
66
68
  end
67
69
 
68
- two_seconds_and_five_frames_of_pal = ((2.seconds * 25) + 5)
70
+ two_seconds_and_five_frames_of_pal = ((2 * 25) + 5)
69
71
  pal_tc = Timecode.new(two_seconds_and_five_frames_of_pal, 25)
70
72
  assert_nothing_raised do
71
73
  added_tc = pal_tc + tc
@@ -80,15 +82,81 @@ class TimecodeTest < Test::Unit::TestCase
80
82
 
81
83
  def test_zero
82
84
  assert Timecode.new(0).zero?
85
+ assert Timecode.parse("00:00:00:00").zero?
83
86
  assert !Timecode.new(1).zero?
84
87
  assert !Timecode.new(1000).zero?
85
88
  end
86
89
 
90
+ def test_timecode_rangeable
91
+ r = Timecode.new(10)...Timecode.new(20)
92
+ assert_equal 10, r.to_a.length
93
+ assert_equal Timecode.new(14), r.to_a[4]
94
+ end
95
+
96
+ def test_frame_interval
97
+ tc = Timecode.new(10)
98
+ assert_in_delta tc.frame_interval, 0.04, 0.0001
99
+
100
+ tc = Timecode.new(10, 30)
101
+ assert_in_delta tc.frame_interval, 0.03333, 0.0001
102
+ end
103
+ end
104
+
105
+ class ConversionTest < Test::Unit::TestCase
106
+ def test_convert_25_at_24
107
+ tc = Timecode.new(40, 25)
108
+ at24 = tc.convert(24)
109
+ assert_equal tc.total, at24.total
110
+ end
111
+ end
112
+
113
+ class CalculationsTest < Test::Unit::TestCase
87
114
  def test_plus
88
115
  a, b = Timecode.new(24, 25.000000000000001), Timecode.new(22, 25.000000000000002)
89
116
  assert_equal Timecode.new(24 + 22, 25.000000000000001), (a + b)
90
117
  end
91
118
 
119
+ def test_plus_with_different_framerates_should_raise
120
+ assert_raise(Timecode::WrongFramerate) { Timecode.new(10, 25) + Timecode.new(10, 30) }
121
+ end
122
+
123
+ def test_plus_with_int_gives_a_timecode
124
+ assert_equal Timecode.new(10), Timecode.new(5) + 5
125
+ end
126
+
127
+ def test_min
128
+ a, b = Timecode.new(10), Timecode.new(4)
129
+ assert_equal Timecode.new(6), a - b
130
+ end
131
+
132
+ def test_min_with_int_gives_a_timecode
133
+ assert_equal Timecode.new(10), Timecode.new(15) - 5
134
+ end
135
+
136
+ def test_min_with_different_framerates_should_raise
137
+ assert_raise(Timecode::WrongFramerate) { Timecode.new(10, 25) - Timecode.new(10, 30) }
138
+ end
139
+
140
+ def test_mult
141
+ assert_equal Timecode.new(100), Timecode.new(10) * 10
142
+ end
143
+
144
+ def test_mult_by_neg_number_should_raise
145
+ assert_raise(Timecode::RangeError) { Timecode.new(10) * -200 }
146
+ end
147
+
148
+ def test_div_by_int_gives_a_timecode
149
+ v = Timecode.new(200) / 20
150
+ assert_kind_of Timecode, v
151
+ assert_equal Timecode.new(10), v
152
+ end
153
+
154
+ def test_div_by_timecode_gives_an_int
155
+ v = Timecode.new(200) / Timecode.new(20)
156
+ assert_kind_of Numeric, v
157
+ assert_equal 10, v
158
+ end
159
+
92
160
  def test_tc_with_frames_as_fraction
93
161
  tc = Timecode.new(100 -1, fps = 25)
94
162
  assert_equal 24, tc.frames
@@ -100,7 +168,43 @@ class TimecodeTest < Test::Unit::TestCase
100
168
  tc = Timecode.new(25, 12.5)
101
169
  assert_equal "00:00:02:00", tc.to_s
102
170
  end
171
+
172
+ def test_from_seconds
173
+ fraction = 7.1
174
+ tc = Timecode.from_seconds(fraction, 10)
175
+ assert_equal "00:00:07:01", tc.to_s
176
+
177
+ fraction = 7.5
178
+ tc = Timecode.from_seconds(fraction, 10)
179
+ assert_equal "00:00:07:05", tc.to_s
180
+
181
+ fraction = 7.16
182
+ tc = Timecode.from_seconds(fraction, 12.5)
183
+ assert_equal "00:00:07:02", tc.to_s
184
+ end
185
+
186
+ end
187
+
188
+ class TestAt < Test::Unit::TestCase
103
189
 
190
+ def test_at_disallows_more_than_99_hrs
191
+ assert_nothing_raised { Timecode.at(99,0,0,0) }
192
+ assert_raise(Timecode::RangeError) { Timecode.at(100,0,0,0) }
193
+ end
194
+
195
+ def test_at_disallows_more_than_59_mins
196
+ assert_raise(Timecode::RangeError) { Timecode.at(1,60,0,0) }
197
+ end
198
+
199
+ def test_at_disallows_more_than_59_secs
200
+ assert_raise(Timecode::RangeError) { Timecode.at(1,0,60,0) }
201
+ end
202
+
203
+ def test_at_disallows_more_frames_than_framerate
204
+ assert_raise(Timecode::RangeError) { Timecode.at(1,0,60,25, 25) }
205
+ assert_raise(Timecode::RangeError) { Timecode.at(1,0,60,32, 30) }
206
+ end
207
+
104
208
  end
105
209
 
106
210
  class TestParsing < Test::Unit::TestCase
@@ -178,18 +282,16 @@ class TestParsing < Test::Unit::TestCase
178
282
  # assert_equal Timecode.new(17), tc
179
283
  # end
180
284
 
181
- def test_from_seconds
182
- fraction = 7.1
183
- tc = Timecode.from_seconds(fraction, 10)
184
- assert_equal "00:00:07:01", tc.to_s
185
-
186
- fraction = 7.5
187
- tc = Timecode.from_seconds(fraction, 10)
188
- assert_equal "00:00:07:05", tc.to_s
189
-
190
- fraction = 7.16
191
- tc = Timecode.from_seconds(fraction, 12.5)
192
- assert_equal "00:00:07:02", tc.to_s
285
+ def test_soft_parse_does_not_raise_and_createz_zeroed_tc
286
+ assert_nothing_raised do
287
+ tc = Timecode.soft_parse("Meaningless nonsense", 25)
288
+ assert tc.zero?
289
+ end
290
+ end
291
+
292
+ def test_parse_raoses_on_improper_format
293
+ assert_raise(Timecode::CannotParse) { Timecode.parse("Meaningless nonsense", 25) }
294
+ assert_raise(Timecode::CannotParse) { Timecode.parse("", 25) }
193
295
  end
194
296
  end
195
297
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timecode
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-12-28 00:00:00 +01:00
12
+ date: 2009-01-01 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency