From 6c8dbf41730910dd7ae0438742e8b05e0ca92cd2 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Tue, 13 Aug 2013 19:27:02 +0200 Subject: [PATCH] Make Stdout provide data in chunks --- app/models/asciicast.rb | 12 +-------- app/models/stdout.rb | 34 +++++++++-------------- spec/fixtures/stdout.decompressed | 1 + spec/fixtures/stdout.time.decompressed | 3 +++ spec/models/asciicast_spec.rb | 10 ++++--- spec/models/stdout_spec.rb | 37 +++++++++++--------------- 6 files changed, 39 insertions(+), 58 deletions(-) create mode 100644 spec/fixtures/stdout.decompressed create mode 100644 spec/fixtures/stdout.time.decompressed diff --git a/app/models/asciicast.rb b/app/models/asciicast.rb index c30a0a2..c0f0cce 100644 --- a/app/models/asciicast.rb +++ b/app/models/asciicast.rb @@ -56,17 +56,7 @@ class Asciicast < ActiveRecord::Base end def stdout - @stdout ||= Stdout.new(read_stdout_data, read_stdout_timing) - end - - private - - def read_stdout_data - stdout_data.decompressed - end - - def read_stdout_timing - TimingParser.parse(stdout_timing.decompressed) + @stdout ||= Stdout.new(stdout_data, stdout_timing) end end diff --git a/app/models/stdout.rb b/app/models/stdout.rb index 482d16e..2e76703 100644 --- a/app/models/stdout.rb +++ b/app/models/stdout.rb @@ -1,40 +1,30 @@ class Stdout include Enumerable - attr_reader :data, :timing + attr_reader :data_file, :timing_file - def initialize(data, timing) - @data = data - @timing = timing + def initialize(data_file, timing_file) + @data_file = data_file + @timing_file = timing_file end def each - offset = 0 - - timing.each do |line| - delay, size = line - yield(delay, bytes[offset...offset+size]) - offset += size + File.open(data_file.decompressed_path, 'rb') do |file| + File.foreach(timing_file.decompressed_path) do |line| + delay, size = TimingParser.parse_line(line) + yield(delay, file.read(size).force_encoding('utf-8')) + end end end - def bytes_until(seconds) - bytes = [] + def each_until(seconds) time = 0 - each do |delay, frame_bytes| + each do |delay, frame_data| time += delay break if time > seconds - bytes.concat(frame_bytes) + yield(delay, frame_data) end - - bytes - end - - private - - def bytes - @bytes ||= data.bytes end end diff --git a/spec/fixtures/stdout.decompressed b/spec/fixtures/stdout.decompressed new file mode 100644 index 0000000..b134021 --- /dev/null +++ b/spec/fixtures/stdout.decompressed @@ -0,0 +1 @@ +foobarbazquxżółć diff --git a/spec/fixtures/stdout.time.decompressed b/spec/fixtures/stdout.time.decompressed new file mode 100644 index 0000000..ff76756 --- /dev/null +++ b/spec/fixtures/stdout.time.decompressed @@ -0,0 +1,3 @@ +0.5 6 +1.0 7 +2.0 7 diff --git a/spec/models/asciicast_spec.rb b/spec/models/asciicast_spec.rb index d89dd0e..793d6cd 100644 --- a/spec/models/asciicast_spec.rb +++ b/spec/models/asciicast_spec.rb @@ -84,17 +84,21 @@ describe Asciicast do end describe '#stdout' do + let(:asciicast) { stub_model(Asciicast) } + let(:data_file) { double('data_file') } + let(:timing_file) { double('timing_file') } let(:stdout) { double('stdout') } before do - allow(asciicast.stdout_data).to receive(:decompressed) { 'foo' } - allow(asciicast.stdout_timing).to receive(:decompressed) { '123.0 45' } + allow(asciicast).to receive(:stdout_data) { data_file } + allow(asciicast).to receive(:stdout_timing) { timing_file } allow(Stdout).to receive(:new) { stdout } end it 'creates a new Stdout instance' do asciicast.stdout - expect(Stdout).to have_received(:new).with('foo', [[123.0, 45]]) + + expect(Stdout).to have_received(:new).with(data_file, timing_file) end it 'returns created Stdout instance' do diff --git a/spec/models/stdout_spec.rb b/spec/models/stdout_spec.rb index 84e3a2b..be22d1e 100644 --- a/spec/models/stdout_spec.rb +++ b/spec/models/stdout_spec.rb @@ -3,31 +3,24 @@ require 'spec_helper' describe Stdout do - let(:stdout) { Stdout.new(data, timing) } - let(:data) { 'foobarbazquxżółć' } - let(:timing) { [[0.5, 6], [1.0, 7], [2.0, 7]] } - - describe '#bytes_until' do - subject { stdout.bytes_until(1.7) } - - it { should eq([102, 111, 111, 98, 97, 114, 98, 97, 122, 113, 117, 120, 197]) } - end + let(:stdout) { Stdout.new(data_file, timing_file) } + let(:data_file) { double('data_file', :decompressed_path => 'spec/fixtures/stdout.decompressed') } + let(:timing_file) { double('timing_file', :decompressed_path => 'spec/fixtures/stdout.time.decompressed') } describe '#each' do - it 'yields for each frame with delay and frame bytes' do - frames = [] - stdout.each do |delay, bytes| - frames << [delay, bytes] - end - - expect(frames[0][0]).to eq(0.5) - expect(frames[0][1]).to eq([102, 111, 111, 98, 97, 114]) - - expect(frames[1][0]).to eq(1.0) - expect(frames[1][1]).to eq([98, 97, 122, 113, 117, 120, 197]) + it 'yields for each frame with delay and data' do + expect { |b| stdout.each(&b) }. + to yield_successive_args([0.5, 'foobar'], + [1.0, "bazqux\xC5"], + [2.0, "\xBCółć"]) + end + end - expect(frames[2][0]).to eq(2.0) - expect(frames[2][1]).to eq([188, 195, 179, 197, 130, 196, 135]) + describe '#each_until' do + it 'yields for each frame with delay and data until given time (in seconds)' do + expect { |b| stdout.each_until(1.7, &b) }. + to yield_successive_args([0.5, 'foobar'], [1.0, "bazqux\xC5"]) end end + end