voot 0.1.0 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4f0b1b7d1b82d3b452c84daabe479a407bd86e14
4
- data.tar.gz: c89d119e5d1365d2943e597311c567b44f063f82
3
+ metadata.gz: 4663014318069925f156ecc91d0375178add107a
4
+ data.tar.gz: d462fa6bf6fed6bcbd8b292a46b981c2255bbdb2
5
5
  SHA512:
6
- metadata.gz: e784362950fbe7b40259284438202fffbb250297340e71ebd07ec978dc78f13ee5b22f74c6d4321dc3b398b6f764da59e8fe5b770f203231d70e4f930a5b8f71
7
- data.tar.gz: 4e19b0731cb1d9507d6d3e322fdd07c7737ea6a099f71341a5e2e024563f6b0e9854ffa42f8ab60d8ab4e573e994a2f541c3ff853de856497fbce77bf2ef426a
6
+ metadata.gz: 473e633f0c06fd79742ae767d30170f0a4e6bda3ca9ba98c961ecd8b845f6634550e4f4164a42c553a5709658a3fc9ca663d91808056d2a39df0eff1bd02bfb1
7
+ data.tar.gz: d8e8f6032846b150ba72b99e2300acadc1ec3f24c4be8c0245726d0668165acab2251f1102c4d9f2412302abb15a9f2fca582241fa0604f53ca483283cc1a88c
data/Guardfile CHANGED
@@ -5,7 +5,7 @@ guard 'bundler' do
5
5
  watch(/^.+\.gemspec/)
6
6
  end
7
7
 
8
- guard :rspec do
8
+ guard :rspec, cli: "--fail-fast" do
9
9
  watch(%r{^spec/.+_spec\.rb$})
10
10
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
11
11
  watch('spec/spec_helper.rb') { "spec" }
data/README.md CHANGED
@@ -4,6 +4,16 @@
4
4
 
5
5
  Voot lets you read and write WebVTT files with great ease.
6
6
 
7
+ ## Usage
8
+
9
+ > vtt = Voot.load("~/Movies/My Indian Films/manty-poothon.vtt")
10
+ => #<Voot::Vtt>
11
+ > vtt.cues.length
12
+ => 1
13
+ > vtt.cues.first.payload
14
+ => "You are those knights and whatever, let me marry Srivani or we will dance"
15
+
16
+
7
17
  ## Installation
8
18
 
9
19
  Add this line to your application's Gemfile:
@@ -1,5 +1,17 @@
1
1
  require "voot/version"
2
2
  require "voot/vtt"
3
+ require "voot/parser"
4
+ require "voot/transform"
3
5
 
4
6
  module Voot
7
+ def self.load(path)
8
+ transform = Voot::Transform.new
9
+ parser = Voot::Parser.new
10
+ vtt_contents = File.read(path)
11
+ parse_tree = parser.parse(vtt_contents)
12
+
13
+ transform.apply(parse_tree).tap do |vtt|
14
+ vtt.path = path
15
+ end
16
+ end
5
17
  end
@@ -15,11 +15,9 @@ module Voot
15
15
  end
16
16
 
17
17
  def to_webvtt
18
- if has_identifier?
19
- "#{identifier}\n#{cue_timing.to_webvtt}\n#{payload}"
20
- else
21
- "#{cue_timing.to_webvtt}\n#{payload}"
22
- end
18
+ output = ""
19
+ output << identifier << "\n" if has_identifier?
20
+ output << cue_timing.to_webvtt << "\n" << payload
23
21
  end
24
22
  end
25
23
  end
@@ -4,7 +4,13 @@ module Voot
4
4
  class CueList < Array
5
5
 
6
6
  def to_webvtt
7
- map(&:to_webvtt).join("\n\n")
7
+ sorted_cues.map(&:to_webvtt).join("\n\n")
8
+ end
9
+
10
+ private
11
+
12
+ def sorted_cues
13
+ sort_by { |cue| cue.cue_timing.start_timestamp }
8
14
  end
9
15
  end
10
16
  end
@@ -1,32 +1,20 @@
1
+ require "voot/timestamp"
2
+
1
3
  module Voot
2
4
  class CueTiming
3
- attr_reader :start_seconds, :end_seconds
5
+ attr_reader :start_timestamp, :stop_timestamp
4
6
 
5
- def initialize(options = {})
6
- @start_seconds = options.fetch(:start_seconds)
7
- @end_seconds = options.fetch(:end_seconds)
7
+ def initialize(start_timestamp, stop_timestamp)
8
+ @start_timestamp = start_timestamp
9
+ @stop_timestamp = stop_timestamp
8
10
  end
9
11
 
10
12
  def to_webvtt
11
- "#{format_timestamp(start_seconds)} --> #{format_timestamp(end_seconds)}"
12
- end
13
-
14
- private
15
-
16
- def format_timestamp(seconds)
17
- "#{format_minutes(seconds)}:#{format_seconds(seconds)}.#{format_subseconds(seconds)}"
18
- end
19
-
20
- def format_minutes(seconds)
21
- (seconds.to_i / 60).to_s.rjust(2, "0")
22
- end
23
-
24
- def format_seconds(seconds)
25
- (seconds.to_i % 60).to_s.rjust(2, "0")
13
+ start_timestamp.to_webvtt << " --> " << stop_timestamp.to_webvtt
26
14
  end
27
15
 
28
- def format_subseconds(seconds)
29
- ((seconds * 1000).round % 1000).to_s.rjust(3, "0")
16
+ def cover?(seconds)
17
+ seconds.between?(start_timestamp.seconds_since_origin, stop_timestamp.seconds_since_origin)
30
18
  end
31
19
  end
32
20
  end
@@ -0,0 +1,43 @@
1
+ require "parslet"
2
+
3
+ module Voot
4
+ class Parser < Parslet::Parser
5
+ rule(:line_break) { match("[\r\n]|\r\n") }
6
+ rule(:whitespace) { match("[\s\t]") }
7
+ rule(:section_separator) { line_break.repeat(2) }
8
+
9
+ rule(:header_string) { (line_break.absent? >> any).repeat }
10
+ rule(:header) { str("WEBVTT") >> whitespace.repeat >> header_string.as(:header) }
11
+
12
+ rule(:digit) { match("[0-9]") }
13
+ rule(:colon) { match("[:]") }
14
+ rule(:period) { match("[.]") }
15
+
16
+ rule(:hours) { digit.repeat(2).as(:hours) >> colon }
17
+ rule(:minutes) { digit.repeat(2, 2).as(:minutes) >> colon }
18
+ rule(:seconds) { digit.repeat(2, 2).as(:seconds) >> period }
19
+ rule(:subseconds) { digit.repeat(3, 3).as(:subseconds) }
20
+
21
+ rule(:timestamp_without_hours) { minutes >> seconds >> subseconds }
22
+ rule(:timestamp_with_hours) { hours >> minutes >> seconds >> subseconds }
23
+
24
+ rule(:timestamp) { timestamp_without_hours | timestamp_with_hours }
25
+
26
+ rule(:timing_delimiter) { str("-->") }
27
+ rule(:cue_timing) { timestamp.as(:start) >> whitespace.repeat(1) >> timing_delimiter >> whitespace.repeat(1) >> timestamp.as(:stop) }
28
+
29
+ rule(:cue_identifier) { (line_break.absent? >> timing_delimiter.absent? >> any).repeat.as(:identifier) }
30
+
31
+ rule(:cue_payload) { (section_separator.absent? >> any).repeat.as(:payload) }
32
+
33
+ rule(:cue_without_identifier) { cue_timing >> line_break >> cue_payload }
34
+ rule(:cue_with_identifier) { cue_identifier >> line_break >> cue_timing >> line_break >> cue_payload }
35
+
36
+ rule(:cue) { cue_without_identifier | cue_with_identifier }
37
+ rule(:cue_list) { (section_separator >> cue).repeat }
38
+
39
+ rule(:file_body) { header >> cue_list.as(:cues) >> line_break.repeat }
40
+
41
+ root(:file_body)
42
+ end
43
+ end
@@ -0,0 +1,49 @@
1
+ module Voot
2
+ class Timestamp
3
+ include Comparable
4
+
5
+ attr_reader :seconds_since_origin
6
+
7
+ def initialize(seconds_since_origin)
8
+ @seconds_since_origin = seconds_since_origin.to_f.round(3)
9
+ end
10
+
11
+ def <=>(other)
12
+ if other.is_a?(Numeric)
13
+ seconds_since_origin <=> other
14
+ else
15
+ seconds_since_origin <=> other.seconds_since_origin
16
+ end
17
+ end
18
+
19
+ def hours
20
+ seconds_since_origin.to_i / 3600
21
+ end
22
+
23
+ def minutes
24
+ seconds_without_hours.to_i / 60
25
+ end
26
+
27
+ def seconds
28
+ seconds_since_origin.to_i % 60
29
+ end
30
+
31
+ def milliseconds
32
+ milliseconds_since_origin.round % 1000
33
+ end
34
+
35
+ def to_webvtt
36
+ "%02d:%02d:%02d.%03d" % [hours, minutes, seconds, milliseconds]
37
+ end
38
+
39
+ private
40
+
41
+ def milliseconds_since_origin
42
+ seconds_since_origin * 1000
43
+ end
44
+
45
+ def seconds_without_hours
46
+ seconds_since_origin % 3600
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ require "parslet"
2
+
3
+ module Voot
4
+ class Transform < Parslet::Transform
5
+ rule(:minutes => simple(:minutes), :seconds => simple(:seconds), :subseconds => simple(:subseconds)) do
6
+ Voot::Timestamp.new((minutes.to_i * 60) + seconds.to_i + (subseconds.to_i / 1000.0))
7
+ end
8
+
9
+ rule(:hours => simple(:hours), :minutes => simple(:minutes), :seconds => simple(:seconds), :subseconds => simple(:subseconds)) do
10
+ Voot::Timestamp.new((hours.to_i * 3600) + (minutes.to_i * 60) + seconds.to_i + (subseconds.to_i / 1000.0))
11
+ end
12
+
13
+ rule(:start => simple(:start_timestamp), :stop => simple(:stop_timestamp), :payload => simple(:payload)) do
14
+ cue_timing = Voot::CueTiming.new(start_timestamp, stop_timestamp)
15
+ Voot::Cue.new(cue_timing: cue_timing, payload: payload.to_s)
16
+ end
17
+
18
+ rule(:start => simple(:start_timestamp), :stop => simple(:stop_timestamp), :payload => simple(:payload), :identifier => simple(:identifier)) do
19
+ cue_timing = Voot::CueTiming.new(start_timestamp, stop_timestamp)
20
+ Voot::Cue.new(cue_timing: cue_timing, payload: payload.to_s, identifier: identifier.to_s)
21
+ end
22
+
23
+ rule(:header => sequence(:header), :cues => sequence(:cues)) do
24
+ vtt = Voot::Vtt.new
25
+ cues.each { |cue| vtt.cues << cue }
26
+ vtt
27
+ end
28
+
29
+ rule(:header => simple(:header), :cues => sequence(:cues)) do
30
+ vtt = Voot::Vtt.new(header: header)
31
+ cues.each { |cue| vtt.cues << cue }
32
+ vtt
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,3 @@
1
1
  module Voot
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -2,11 +2,10 @@ require "voot/cue_list"
2
2
 
3
3
  module Voot
4
4
  class Vtt
5
- attr_reader :path
6
- attr_accessor :header
5
+ attr_accessor :header, :path
7
6
 
8
7
  def initialize(options = {})
9
- @path = options.fetch(:path)
8
+ @path = options[:path]
10
9
  @header = options[:header]
11
10
  end
12
11
 
@@ -11,12 +11,36 @@ describe Voot::CueList do
11
11
  context "when the list has an item in it" do
12
12
  before { cue_list << create_cue("reasonably priced", 0, 0) }
13
13
 
14
- its(:to_webvtt) { should == "00:00.000 --> 00:00.000\nreasonably priced" }
14
+ its(:to_webvtt) { should == "00:00:00.000 --> 00:00:00.000\nreasonably priced" }
15
15
 
16
16
  context "when the list has multiple items" do
17
17
  before { cue_list << create_cue("toiletries", 1, 1) }
18
18
 
19
- its(:to_webvtt) { should include "00:01.000 --> 00:01.000\ntoiletries" }
19
+ its(:to_webvtt) { should include "00:00:01.000 --> 00:00:01.000\ntoiletries" }
20
+
21
+ it "separates cues with a double newline" do
22
+ cue_list.to_webvtt.should == <<-ALL_THE_CUES.strip
23
+ 00:00:00.000 --> 00:00:00.000
24
+ reasonably priced
25
+
26
+ 00:00:01.000 --> 00:00:01.000
27
+ toiletries
28
+ ALL_THE_CUES
29
+ end
30
+
31
+ it "orders the cues by start time" do
32
+ cue_list << create_cue("hair spray", 0.5, 1)
33
+ cue_list.to_webvtt.should == <<-ALL_THE_CUES.strip
34
+ 00:00:00.000 --> 00:00:00.000
35
+ reasonably priced
36
+
37
+ 00:00:00.500 --> 00:00:01.000
38
+ hair spray
39
+
40
+ 00:00:01.000 --> 00:00:01.000
41
+ toiletries
42
+ ALL_THE_CUES
43
+ end
20
44
  end
21
45
  end
22
46
  end
@@ -3,7 +3,7 @@ require "spec_helper"
3
3
  describe Voot::Cue do
4
4
  let(:identifier) { "taco massacre" }
5
5
  let(:payload) { "tasty" }
6
- let(:cue_timing) { Voot::CueTiming.new(start_seconds: 0, end_seconds: 1) }
6
+ let(:cue_timing) { create_timing(0, 1) }
7
7
 
8
8
  subject(:cue) do
9
9
  Voot::Cue.new(
@@ -33,13 +33,13 @@ describe Voot::Cue do
33
33
 
34
34
  describe "#to_webvtt" do
35
35
  context "when the identifier is set" do
36
- its(:to_webvtt) { should == "taco massacre\n00:00.000 --> 00:01.000\ntasty" }
36
+ its(:to_webvtt) { should == "taco massacre\n00:00:00.000 --> 00:00:01.000\ntasty" }
37
37
  end
38
38
 
39
39
  context "when the identifier is not set" do
40
40
  let(:identifier) { nil }
41
41
 
42
- its(:to_webvtt) { should == "00:00.000 --> 00:01.000\ntasty" }
42
+ its(:to_webvtt) { should == "00:00:00.000 --> 00:00:01.000\ntasty" }
43
43
  end
44
44
  end
45
45
  end
@@ -1,15 +1,15 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Voot::CueTiming do
4
- let(:start_seconds) { 1.0001 }
5
- let(:end_seconds) { 65.0009 }
6
-
7
- subject(:cue_timing) do
8
- Voot::CueTiming.new(
9
- start_seconds: start_seconds,
10
- end_seconds: end_seconds
11
- )
12
- end
4
+ let(:start_timestamp) { Voot::Timestamp.new(1.0001) }
5
+ let(:stop_timestamp) { Voot::Timestamp.new(65.0009) }
6
+
7
+ subject(:cue_timing) { Voot::CueTiming.new(start_timestamp, stop_timestamp) }
13
8
 
14
- its(:to_webvtt) { should == "00:01.000 --> 01:05.001" }
9
+ its(:to_webvtt) { should == "00:00:01.000 --> 00:01:05.001" }
10
+
11
+ describe "#cover?" do
12
+ it { should cover 1.000 }
13
+ it { should cover 65.001 }
14
+ end
15
15
  end
@@ -0,0 +1,82 @@
1
+ require "spec_helper"
2
+
3
+ describe Voot::Parser do
4
+ subject(:parser) { Voot::Parser.new }
5
+
6
+ it { should parse("WEBVTT") }
7
+ it { should parse("WEBVTT\n\n") }
8
+
9
+ describe "#header" do
10
+ specify { parser.header.should parse("WEBVTT").as(header: []) }
11
+ specify { parser.header.should parse("WEBVTT - goose hugs").as(header: "- goose hugs") }
12
+ end
13
+
14
+ describe "#subseconds" do
15
+ specify { parser.subseconds.should parse("164").as(subseconds: "164") }
16
+ end
17
+
18
+ describe "#seconds" do
19
+ specify { parser.seconds.should parse("66.").as(seconds: "66") }
20
+ end
21
+
22
+ describe "#minutes" do
23
+ specify { parser.minutes.should parse("01:").as(minutes: "01") }
24
+ end
25
+
26
+ describe "#hours" do
27
+ specify { parser.hours.should parse("13:").as(hours: "13") }
28
+ specify { parser.hours.should parse("9000:").as(hours: "9000") }
29
+ end
30
+
31
+ describe "#timestamp_without_hours" do
32
+ specify { parser.timestamp_without_hours.should parse("01:33.007").as(minutes: "01", seconds: "33", subseconds: "007") }
33
+ end
34
+
35
+ describe "#timestamp_with_hours" do
36
+ specify { parser.timestamp_with_hours.should parse("11:59:59.999").as(hours: "11", minutes: "59", seconds: "59", subseconds: "999") }
37
+ end
38
+
39
+ describe "#timestamp" do
40
+ specify { parser.timestamp.should parse("01:33.007").as(minutes: "01", seconds: "33", subseconds: "007") }
41
+ specify { parser.timestamp.should parse("11:59:59.999").as(hours: "11", minutes: "59", seconds: "59", subseconds: "999") }
42
+ end
43
+
44
+ describe "#timing_delimiter" do
45
+ specify { parser.timing_delimiter.should parse("-->") }
46
+ end
47
+
48
+ describe "#cue_timing" do
49
+ specify { parser.cue_timing.should parse("01:33.007 -->\t 11:59:59.999").as(start: anything, stop: anything) }
50
+ end
51
+
52
+ describe "#cue_identifier" do
53
+ specify { parser.cue_identifier.should_not parse("drugboats --> ahoy") }
54
+ specify { parser.cue_identifier.should_not parse("puppet\npals") }
55
+ specify { parser.cue_identifier.should parse("evil squid cult").as(identifier: "evil squid cult") }
56
+ end
57
+
58
+ describe "#cue_payload" do
59
+ specify { parser.cue_payload.should parse("once upon a dingus").as(payload: "once upon a dingus") }
60
+ specify { parser.cue_payload.should parse("there were\nan prancess").as(payload: "there were\nan prancess") }
61
+ specify { parser.cue_payload.should_not parse("whare is\n\nlazy prance") }
62
+ end
63
+
64
+ describe "#cue_without_identifier" do
65
+ specify { parser.cue_without_identifier.should parse("00:00.000 --> 00:30.000\nget to the choppa?").as(start: anything, stop: anything, payload: anything) }
66
+ end
67
+
68
+ describe "#cue_with_identifier" do
69
+ specify { parser.cue_with_identifier.should parse("777\n00:00.000 --> 00:30.000\njhonny paints the wall").as(identifier: anything, start: anything, stop: anything, payload: anything) }
70
+ end
71
+
72
+ describe "#cue" do
73
+ specify { parser.cue.should parse("the hablet\n00:00.000 --> 00:30.000\nwelcam ashire\nbalbo").as(identifier: anything, start: anything, stop: anything, payload: anything) }
74
+ specify { parser.cue.should parse("04:00.000 --> 55:30.000\n(tom belmadal sings)").as(start: anything, stop: anything, payload: anything) }
75
+ end
76
+
77
+ describe "#file_body" do
78
+ specify { parser.file_body.should parse("WEBVTT").as(header: [], cues: []) }
79
+ specify { parser.file_body.should parse("WEBVTT\n\n00:00.000 --> 00:00.000\nhi").as(header: [], cues: [anything]) }
80
+ specify { parser.file_body.should parse("WEBVTT\n\n00:00.000 --> 00:00.000\nlike\n\n00:01.000 --> 00:01.000\nwut").as(header: [], cues: [anything, anything]) }
81
+ end
82
+ end
@@ -0,0 +1,91 @@
1
+ require "spec_helper"
2
+
3
+ describe Voot::Timestamp do
4
+ subject(:timestamp) { Voot::Timestamp.new(seconds) }
5
+
6
+ describe "#<=>" do
7
+ let(:seconds) { 1.1 }
8
+
9
+ context "when comparing against the number of seconds" do
10
+ it { should == seconds }
11
+ end
12
+
13
+ context "when comparing against another timestamp" do
14
+ let(:other) { double(:timestamp, seconds_since_origin: seconds) }
15
+
16
+ it { should == other }
17
+ end
18
+ end
19
+
20
+ describe "#seconds_since_origin" do
21
+ context "when the seconds can round up" do
22
+ let(:seconds) { 0.0005 }
23
+
24
+ it "rounds the seconds to the nearest millisecond" do
25
+ timestamp.seconds_since_origin.should == 0.001
26
+ end
27
+ end
28
+
29
+ context "when the seconds can round up" do
30
+ let(:seconds) { 0.0014 }
31
+
32
+ it "rounds the seconds to the nearest millisecond" do
33
+ timestamp.seconds_since_origin.should == 0.001
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "#hours" do
39
+ let(:seconds) { 3600 }
40
+
41
+ it "returns the number of hours in the timestamp" do
42
+ timestamp.hours.should == 1
43
+ end
44
+ end
45
+
46
+ describe "#minutes" do
47
+ let(:seconds) { 120 }
48
+
49
+ it "returns the number of minutes in the timestamp" do
50
+ timestamp.minutes.should == 2
51
+ end
52
+ end
53
+
54
+ describe "#seconds" do
55
+ let(:seconds) { 3 }
56
+
57
+ it "returns the number of seconds in the timestamp" do
58
+ timestamp.seconds.should == 3
59
+ end
60
+ end
61
+
62
+ describe "#milliseconds" do
63
+ let(:seconds) { 0.004 }
64
+
65
+ it "returns the number of milliseconds in the timestamp" do
66
+ timestamp.milliseconds.should == 4
67
+ end
68
+
69
+ context "when milliseconds can round up" do
70
+ let(:seconds) { 0.0045 }
71
+
72
+ it "returns the rounded-up number of milliseconds in the timestamp" do
73
+ timestamp.milliseconds.should == 5
74
+ end
75
+ end
76
+
77
+ context "when milliseconds can round down" do
78
+ let(:seconds) { 0.0031 }
79
+
80
+ it "returns the rounded-down number of milliseconds in the timestamp" do
81
+ timestamp.milliseconds.should == 3
82
+ end
83
+ end
84
+ end
85
+
86
+ describe "#to_webvtt" do
87
+ let(:seconds) { 3723.004 }
88
+
89
+ its(:to_webvtt) { should == "01:02:03.004" }
90
+ end
91
+ end
@@ -0,0 +1,72 @@
1
+ require "spec_helper"
2
+
3
+ describe Voot::Transform do
4
+ let(:cue_timing) { create_timing(61.001, 3661.001) }
5
+ let(:parser) { Voot::Parser.new }
6
+
7
+ subject(:transformed) { Voot::Transform.new.apply(parsed_input) }
8
+
9
+ describe "#timestamp" do
10
+ let(:parsed_input) { parser.timestamp.parse(input_string) }
11
+
12
+ context "when the timestamp does not have hours" do
13
+ let(:input_string) { "01:01.001" }
14
+
15
+ it { should == 61.001 }
16
+ end
17
+
18
+ context "when the timestamp has hours" do
19
+ let(:input_string) { "01:01:01.001" }
20
+
21
+ it { should == 3661.001 }
22
+ end
23
+ end
24
+
25
+ describe "#cue_timing" do
26
+ let(:input_string) { cue_timing.to_webvtt }
27
+ let(:parsed_input) { parser.cue_timing.parse(input_string) }
28
+
29
+ it { should == {start: 61.001, stop: 3661.001} }
30
+ end
31
+
32
+ describe "#cue" do
33
+ let(:parsed_input) { parser.cue.parse(cue.to_webvtt) }
34
+
35
+ context "when there is an identifier" do
36
+ let(:cue) { Voot::Cue.new(cue_timing: cue_timing, identifier: "ferdo", payload: "hes also too an habblet") }
37
+
38
+ its(:identifier) { should == "ferdo" }
39
+ its(:payload) { should == "hes also too an habblet" }
40
+ its(:cue_timing) { should cover 61.001 }
41
+ its(:cue_timing) { should cover 3661.001 }
42
+ end
43
+
44
+ context "when there is no identifier" do
45
+ let(:cue) { Voot::Cue.new(cue_timing: cue_timing, payload: "gordolf he is a beard") }
46
+
47
+ its(:identifier) { should be_nil }
48
+ its(:payload) { should == "gordolf he is a beard" }
49
+ its(:cue_timing) { should cover 61.001 }
50
+ its(:cue_timing) { should cover 3661.001 }
51
+ end
52
+ end
53
+
54
+ describe "#file_body" do
55
+ let(:vtt) { Voot::Vtt.new.tap { |vtt| vtt.cues << cue } }
56
+ let(:cue) { Voot::Cue.new(cue_timing: cue_timing, payload: "borgomar is a dumb") }
57
+ let(:parsed_input) { parser.file_body.parse(vtt.to_webvtt) }
58
+
59
+ context "when the header is not set" do
60
+
61
+ its(:header) { should be_nil }
62
+ its(:cues) { should have(1).cue }
63
+ end
64
+
65
+ context "when the header is set" do
66
+ before { vtt.header = "lerd of rang" }
67
+
68
+ its(:header) { should == "lerd of rang" }
69
+ its(:cues) { should have(1).cue }
70
+ end
71
+ end
72
+ end
@@ -19,7 +19,7 @@ describe Voot::Vtt do
19
19
  context "when the file exists" do
20
20
  let(:pesky_user_data) { "hey guys tacos are great right" }
21
21
 
22
- before { File.write(vtt_path, pesky_user_data) }
22
+ before { File.open(vtt_path, "w") { |file| file << pesky_user_data } }
23
23
 
24
24
  it "clobbers the file content" do
25
25
  expect do
@@ -65,7 +65,7 @@ describe Voot::Vtt do
65
65
  context "when there is a cue" do
66
66
  before { vtt.cues << create_cue("not the drill!", 0, 2) }
67
67
 
68
- its(:to_webvtt) { should == "WEBVTT\n\n00:00.000 --> 00:02.000\nnot the drill!" }
68
+ its(:to_webvtt) { should == "WEBVTT\n\n00:00:00.000 --> 00:00:02.000\nnot the drill!" }
69
69
  end
70
70
  end
71
71
  end
@@ -0,0 +1,51 @@
1
+ require "spec_helper"
2
+
3
+ describe Voot do
4
+ let(:voot_path) { Tempfile.new("voot").path }
5
+
6
+ describe ".load" do
7
+ subject { Voot.load(voot_path) }
8
+
9
+ context "when the file is empty" do
10
+ it "fails to parse" do
11
+ expect { Voot.load(voot_path) }.to raise_error(Parslet::ParseFailed)
12
+ end
13
+ end
14
+
15
+ context "when the file does not contain a webvtt header" do
16
+ before { File.open(voot_path, "w") { |file| file << "taco thursdays yo" } }
17
+
18
+ it "fails to parse" do
19
+ expect { Voot.load(voot_path) }.to raise_error(Parslet::ParseFailed)
20
+ end
21
+ end
22
+
23
+ context "when the file contains a webvtt header" do
24
+ before { File.open(voot_path, "w") { |file| file << "WEBVTT" } }
25
+
26
+ its(:cues) { should be_empty }
27
+ its(:header) { should be_nil }
28
+ its(:path) { should == voot_path }
29
+ end
30
+
31
+ context "when the file contains a header" do
32
+ before { File.open(voot_path, "w") { |file| file << "WEBVTT presents bob ross classics" } }
33
+
34
+ its(:header) { should == "presents bob ross classics" }
35
+ end
36
+
37
+ context "when the file contains a junk-filled header" do
38
+ before { File.open(voot_path, "w") { |file| file << "WEBVTT\ni liek ppokemans" } }
39
+
40
+ it "fails to parse" do
41
+ expect { Voot.load(voot_path) }.to raise_error(Parslet::ParseFailed)
42
+ end
43
+ end
44
+
45
+ context "when the file contains cues" do
46
+ before { File.open(voot_path, "w") { |file| file << "WEBVTT\n\n00:00.000 --> 00:00.000\ndrugboat" } }
47
+
48
+ it { should have(1).cues }
49
+ end
50
+ end
51
+ end
@@ -1,6 +1,8 @@
1
1
  $:<< File.expand_path("../../lib", __FILE__)
2
2
 
3
3
  require "voot"
4
+ require "tempfile"
5
+ require "parslet/rig/rspec"
4
6
 
5
7
  Dir.glob(File.expand_path("../support/**/*.rb", __FILE__)) { |f| require f }
6
8
 
@@ -1,6 +1,12 @@
1
1
  module CueHelper
2
+ def create_timing(start, stop)
3
+ start_timestamp = Voot::Timestamp.new(start)
4
+ stop_timestamp = Voot::Timestamp.new(stop)
5
+ Voot::CueTiming.new(start_timestamp, stop_timestamp)
6
+ end
7
+
2
8
  def create_cue(payload, start, stop)
3
- cue_timing = Voot::CueTiming.new(start_seconds: start, end_seconds: stop)
9
+ cue_timing = create_timing(start, stop)
4
10
  Voot::Cue.new(cue_timing: cue_timing, payload: payload)
5
11
  end
6
12
  end
@@ -18,6 +18,8 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = `git ls-files -- spec`.split("\n")
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "parslet"
22
+
21
23
  spec.add_development_dependency "rspec"
22
24
  spec.add_development_dependency "guard-rspec"
23
25
  spec.add_development_dependency "guard-bundler"
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: voot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Doc Ritezel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-30 00:00:00.000000000 Z
11
+ date: 2013-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: parslet
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -87,13 +101,20 @@ files:
87
101
  - lib/voot/cue.rb
88
102
  - lib/voot/cue_list.rb
89
103
  - lib/voot/cue_timing.rb
104
+ - lib/voot/parser.rb
105
+ - lib/voot/timestamp.rb
106
+ - lib/voot/transform.rb
90
107
  - lib/voot/version.rb
91
108
  - lib/voot/vtt.rb
92
109
  - script/ci.sh
93
110
  - spec/lib/voot/cue_list_spec.rb
94
111
  - spec/lib/voot/cue_spec.rb
95
112
  - spec/lib/voot/cue_timing_spec.rb
113
+ - spec/lib/voot/parser_spec.rb
114
+ - spec/lib/voot/timestamp_spec.rb
115
+ - spec/lib/voot/transform_spec.rb
96
116
  - spec/lib/voot/vtt_spec.rb
117
+ - spec/lib/voot_spec.rb
97
118
  - spec/spec_helper.rb
98
119
  - spec/support/cue_helper.rb
99
120
  - voot.gemspec
@@ -125,6 +146,10 @@ test_files:
125
146
  - spec/lib/voot/cue_list_spec.rb
126
147
  - spec/lib/voot/cue_spec.rb
127
148
  - spec/lib/voot/cue_timing_spec.rb
149
+ - spec/lib/voot/parser_spec.rb
150
+ - spec/lib/voot/timestamp_spec.rb
151
+ - spec/lib/voot/transform_spec.rb
128
152
  - spec/lib/voot/vtt_spec.rb
153
+ - spec/lib/voot_spec.rb
129
154
  - spec/spec_helper.rb
130
155
  - spec/support/cue_helper.rb