network_executive 0.0.4 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/README.md +53 -24
  2. data/app/assets/fonts/network_executive/league_gothic.css +13 -0
  3. data/app/assets/fonts/network_executive/league_gothic.svg +148 -0
  4. data/app/assets/fonts/network_executive/league_gothic.ttf +0 -0
  5. data/app/assets/fonts/network_executive/league_gothic.woff +0 -0
  6. data/app/assets/javascripts/network_executive/components/iframe_notifier.coffee +14 -0
  7. data/app/assets/javascripts/network_executive/components/namespace.coffee +1 -0
  8. data/app/assets/javascripts/network_executive/components/osd.coffee +65 -0
  9. data/app/assets/javascripts/network_executive/components/photo_player.coffee +55 -0
  10. data/app/assets/javascripts/network_executive/components/postman.coffee +23 -0
  11. data/app/assets/javascripts/network_executive/components/set_top_box.coffee +81 -0
  12. data/app/assets/javascripts/network_executive/components/tweet_player.coffee +95 -0
  13. data/app/assets/javascripts/network_executive/components/you_tube_player.coffee +85 -0
  14. data/app/assets/javascripts/network_executive/slideshow.coffee +6 -0
  15. data/app/assets/javascripts/network_executive/twitter.coffee +7 -0
  16. data/app/assets/javascripts/network_executive/you_tube.coffee +8 -0
  17. data/app/assets/javascripts/network_executive.coffee +10 -0
  18. data/app/assets/stylesheets/network_executive/{gui_components.css → components/gui_components.css} +0 -0
  19. data/app/assets/stylesheets/network_executive/{normalize.css → components/normalize.css} +0 -0
  20. data/app/assets/stylesheets/network_executive/{osd.css → components/osd.css} +6 -34
  21. data/app/assets/stylesheets/network_executive/components/osd_guide.css +43 -0
  22. data/app/assets/stylesheets/network_executive/components/photo_player.css +61 -0
  23. data/app/assets/stylesheets/network_executive/{smpte.css → components/smpte.css} +0 -0
  24. data/app/assets/stylesheets/network_executive/components/tweet_player.css +60 -0
  25. data/app/assets/stylesheets/network_executive/components/you_tube_player.css +12 -0
  26. data/app/assets/stylesheets/network_executive/off_air.css +5 -0
  27. data/app/assets/stylesheets/network_executive/slideshow.css +4 -0
  28. data/app/assets/stylesheets/network_executive/twitter.css +5 -0
  29. data/app/assets/stylesheets/network_executive/you_tube.css +3 -0
  30. data/app/assets/stylesheets/{network_executive/application.css → network_executive.css} +5 -5
  31. data/app/controllers/network_executive/components_controller.rb +4 -0
  32. data/app/controllers/network_executive/guide_controller.rb +41 -0
  33. data/app/controllers/network_executive/programs_controller.rb +9 -0
  34. data/app/helpers/network_executive/network_helper.rb +6 -0
  35. data/app/models/network_executive/channel.rb +15 -14
  36. data/app/models/network_executive/guide.rb +65 -0
  37. data/app/models/network_executive/program.rb +69 -5
  38. data/app/models/network_executive/viewer.rb +4 -0
  39. data/app/programs/network_executive/off_air.rb +18 -0
  40. data/app/views/network_executive/components/slideshow.html.erb +20 -0
  41. data/app/views/network_executive/components/twitter.html.erb +16 -0
  42. data/app/views/network_executive/components/you_tube.html.erb +13 -0
  43. data/app/views/network_executive/guide/index.html.erb +30 -0
  44. data/app/views/network_executive/network/index.html.erb +3 -3
  45. data/app/views/network_executive/programs/off_air.html.erb +13 -0
  46. data/config/routes.rb +7 -1
  47. data/lib/network_executive/channel_schedule.rb +65 -0
  48. data/lib/network_executive/components/photo_player.rb +48 -0
  49. data/lib/network_executive/components/tweet_player.rb +48 -0
  50. data/lib/network_executive/components/you_tube_player.rb +15 -0
  51. data/lib/network_executive/components.rb +3 -0
  52. data/lib/network_executive/engine.rb +29 -3
  53. data/lib/network_executive/off_air_schedule.rb +18 -0
  54. data/lib/network_executive/producer.rb +3 -3
  55. data/lib/network_executive/program_schedule.rb +96 -0
  56. data/lib/network_executive/program_schedule_proxy.rb +55 -0
  57. data/lib/network_executive/scheduled_program.rb +26 -0
  58. data/lib/network_executive/scheduling.rb +15 -21
  59. data/lib/network_executive/time_calculations.rb +10 -0
  60. data/lib/network_executive/version.rb +1 -1
  61. data/lib/network_executive.rb +2 -1
  62. data/network_executive.gemspec +5 -0
  63. data/spec/models/channel_spec.rb +30 -12
  64. data/spec/models/{lineup_spec.rb → guide_spec.rb} +28 -6
  65. data/spec/models/program_spec.rb +46 -3
  66. data/spec/models/viewer_spec.rb +9 -1
  67. data/spec/programs/off_air_spec.rb +9 -0
  68. data/spec/spec_helper.rb +3 -2
  69. data/spec/unit/channel_schedule_spec.rb +67 -0
  70. data/spec/unit/components/photo_player_spec.rb +76 -0
  71. data/spec/unit/components/tweet_player_spec.rb +68 -0
  72. data/spec/unit/components/you_tube_player_spec.rb +17 -0
  73. data/spec/unit/off_air_schedule_spec.rb +28 -0
  74. data/spec/unit/producer_spec.rb +2 -4
  75. data/spec/unit/program_schedule_proxy_spec.rb +102 -0
  76. data/spec/unit/program_schedule_spec.rb +191 -0
  77. data/spec/unit/scheduled_program_spec.rb +57 -0
  78. data/spec/unit/scheduling_spec.rb +61 -72
  79. data/vendor/assets/javascripts/bigtext.js +264 -0
  80. metadata +185 -44
  81. data/app/assets/javascripts/application.js +0 -13
  82. data/app/assets/javascripts/network_executive/osd.js +0 -62
  83. data/app/assets/javascripts/network_executive/set_top_box.js +0 -45
  84. data/app/controllers/network_executive/lineup_controller.rb +0 -11
  85. data/app/models/network_executive/channel_schedule.rb +0 -13
  86. data/app/models/network_executive/lineup.rb +0 -74
  87. data/app/models/network_executive/lineup_range.rb +0 -34
  88. data/app/models/network_executive/program_schedule.rb +0 -148
  89. data/app/views/network_executive/lineup/index.html.erb +0 -26
  90. data/spec/models/channel_schedule_spec.rb +0 -29
  91. data/spec/models/lineup_range_spec.rb +0 -65
  92. data/spec/models/program_schedule_spec.rb +0 -399
@@ -0,0 +1,10 @@
1
+ module NetworkExecutive
2
+ module TimeCalculations
3
+
4
+ # Rounds the specific time to the nearest interval
5
+ def floor( nearest )
6
+ Time.at( (self.to_f / nearest.to_i).floor * nearest.to_i )
7
+ end
8
+
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module NetworkExecutive
2
- VERSION = '0.0.4'
2
+ VERSION = '0.0.7'
3
3
  end
@@ -1,7 +1,8 @@
1
1
  require 'network_executive/version'
2
2
  require 'network_executive/configuration'
3
- require 'network_executive/engine'
3
+ require 'network_executive/components'
4
4
  require 'network_executive/station'
5
+ require 'network_executive/engine'
5
6
 
6
7
  module NetworkExecutive
7
8
 
@@ -19,9 +19,14 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.add_dependency 'activesupport', '~> 3.2.0'
21
21
  gem.add_dependency 'faye-websocket', '~> 0.4.6'
22
+ gem.add_dependency 'ice_cube', '~> 0.8.1'
22
23
 
24
+ gem.add_dependency 'twitter', '~> 4.0.0'
25
+
26
+ # TODO: Where should these live?
23
27
  gem.add_runtime_dependency 'sass-rails'
24
28
  gem.add_runtime_dependency 'uglifier'
29
+ gem.add_runtime_dependency 'coffee-rails'
25
30
 
26
31
  gem.add_development_dependency 'awesome_print'
27
32
  gem.add_development_dependency 'rails', '~> 3.2.8'
@@ -11,29 +11,47 @@ describe NetworkExecutive::Channel do
11
11
  subject { MyChannel.new }
12
12
 
13
13
  its(:name) { should == 'my_channel' }
14
+ its(:to_s) { should == 'my_channel' }
14
15
  its(:display_name) { should == 'my channel' }
15
- its(:to_s) { should == 'my channel' }
16
16
 
17
- describe '#show' do
18
- context 'for a program that exists' do
19
- let(:scheduled_double) { double('program', program_name:'name') }
20
- let(:program_double) { double('program') }
17
+ describe '#play' do
18
+ let(:program_double) { double('program', occurs_at?: starting ) }
19
+
20
+ context 'at a programs start time' do
21
+ let(:starting) { true }
21
22
 
22
23
  it 'should play the program' do
23
- NetworkExecutive::Program.stub( :find_by_name ).and_return program_double
24
+ program_double.should_receive( :play ).and_yield( {} )
24
25
 
25
- program_double.should_receive :play
26
26
  described_class.any_instance.should_receive :push
27
27
 
28
- subject.show scheduled_double
28
+ subject.play program_double
29
29
  end
30
30
  end
31
31
 
32
- context 'for a program that does not exist' do
33
- it 'should raise a ProgramNotFoundError' do
34
- program = double('scheduled_program', program_name:'noop')
32
+ context 'after a programs start time' do
33
+ let(:starting) { false }
34
+
35
+ it 'should update the program' do
36
+ program_double.should_receive( :update ).and_yield( {} )
37
+
38
+ described_class.any_instance.should_receive :push
39
+
40
+ subject.play program_double
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#play_whats_on' do
46
+ let(:program) { double('program') }
47
+
48
+ it 'should ask what is on and play the program' do
49
+ described_class.any_instance.should_receive( :whats_on? ).and_return program
50
+
51
+ program.should_receive( :play ).and_yield( {} )
35
52
 
36
- expect{ subject.show program }.to raise_error NetworkExecutive::ProgramNotFoundError
53
+ subject.play_whats_on do |m|
54
+ m.should == {}
37
55
  end
38
56
  end
39
57
  end
@@ -1,4 +1,4 @@
1
- describe NetworkExecutive::Lineup do
1
+ describe NetworkExecutive::Guide do
2
2
 
3
3
  let(:show) do
4
4
  show = double('show', program_name:'show 1')
@@ -7,7 +7,7 @@ describe NetworkExecutive::Lineup do
7
7
  let(:channel) do
8
8
  channel = double('channel', display_name:'channel a').as_null_object
9
9
 
10
- channel.stub(:whats_on?).and_yield( show ).and_return [ show ]
10
+ channel.stub(:whats_on_between?).and_return [ show ]
11
11
 
12
12
  channel
13
13
  end
@@ -25,6 +25,8 @@ describe NetworkExecutive::Lineup do
25
25
  end
26
26
 
27
27
  describe '#start_time' do
28
+ before { described_class.any_instance.stub(:generate) }
29
+
28
30
  context 'the default value' do
29
31
  subject { described_class.new.start_time }
30
32
 
@@ -45,6 +47,8 @@ describe NetworkExecutive::Lineup do
45
47
  end
46
48
 
47
49
  describe '#stop_time' do
50
+ before { described_class.any_instance.stub(:generate) }
51
+
48
52
  context 'the default value' do
49
53
  subject { described_class.new.stop_time }
50
54
 
@@ -64,6 +68,20 @@ describe NetworkExecutive::Lineup do
64
68
  end
65
69
  end
66
70
 
71
+ describe '#times' do
72
+ it 'should start with the start time' do
73
+ subject.times.first.should eq Time.now
74
+ end
75
+
76
+ it 'should contain 15 minute intervals' do
77
+ subject.times.size.should eq 6
78
+ end
79
+
80
+ it 'should end with 1.5 hours after start time' do
81
+ subject.times.last.should eq Time.now + 1.5.hours - 15.minutes
82
+ end
83
+ end
84
+
67
85
  describe '#channels' do
68
86
  subject { described_class.new[:channels] }
69
87
 
@@ -73,14 +91,18 @@ describe NetworkExecutive::Lineup do
73
91
  subject.first[:channel].should == channel
74
92
  end
75
93
 
76
- it 'should contain an array of scheduled programs' do
77
- subject.first[:schedule].should be_an Array
94
+ it 'should contain a collection of programs' do
95
+ subject.first[:programs].should be_an Array
78
96
  end
79
97
 
80
98
  it 'should ask the channel what is on' do
81
- args = [ Time.now, 1.5.hours.from_now, kind_of(Hash) ]
99
+ args = [
100
+ Time.now,
101
+ (Time.now + 1.5.hours),
102
+ 15.minutes
103
+ ]
82
104
 
83
- channels.first.should_receive(:whats_on?).with( *args )
105
+ channels.first.should_receive(:whats_on_between?).with( *args )
84
106
 
85
107
  subject
86
108
  end
@@ -11,14 +11,57 @@ describe NetworkExecutive::Program do
11
11
  subject { MyProgram.new }
12
12
 
13
13
  its(:name) { should == 'my_program' }
14
+ its(:display_name) { should == 'My Program' }
14
15
  its(:url) { should == '' }
15
- its(:play) { should == %q[{"name":"my_program","url":""}] }
16
+ its(:refresh) { should == :auto }
17
+ its(:onload) { should == {} }
18
+ its(:onupdate) { should == {} }
16
19
 
17
- describe '#as_json' do
18
- subject { MyProgram.new.as_json }
20
+ describe '#play' do
21
+ before { EM.stub( :defer ).and_yield }
22
+
23
+ it 'should return an EventSource payload' do
24
+ msg = nil
25
+
26
+ subject.play { |m| msg = m }
27
+
28
+ msg.should == %q[{"name":"my_program","url":"","onLoad":{},"refresh":"auto","event":"show:program"}]
29
+ end
30
+ end
31
+
32
+ describe '#onshow' do
33
+ subject { MyProgram.new.onshow }
19
34
 
20
35
  it { should include( name:'my_program' ) }
21
36
  it { should include( url: '' ) }
37
+ it { should include( onLoad: {} ) }
38
+ it { should include( refresh: :auto ) }
39
+ end
40
+
41
+ describe '#update' do
42
+ context 'when #refresh is set to :auto' do
43
+ it 'should play the program' do
44
+ subject.stub(:refresh).and_return :auto
45
+
46
+ subject.should_receive( :play )
47
+
48
+ subject.update
49
+ end
50
+ end
51
+
52
+ context 'when #refresh is NOT set to :auto' do
53
+ before { EM.stub(:defer).and_yield }
54
+
55
+ it 'should return the contents of #onupdate' do
56
+ subject.stub(:refresh).and_return 'zomg'
57
+
58
+ msg = nil
59
+
60
+ subject.update { |m| msg = m }
61
+
62
+ msg.should == %q[{"event":"update:program"}]
63
+ end
64
+ end
22
65
  end
23
66
 
24
67
  describe '.find_by_name' do
@@ -69,7 +69,7 @@ describe NetworkExecutive::Viewer do
69
69
  end
70
70
 
71
71
  describe '#tune_in' do
72
- let(:channel) { double('channel').as_null_object }
72
+ let(:channel) { double('channel', subscribe:true, play_whats_on:true) }
73
73
  let(:stream) { double('stream').as_null_object }
74
74
 
75
75
  before do
@@ -91,6 +91,14 @@ describe NetworkExecutive::Viewer do
91
91
 
92
92
  stream.onclose.should_not be_nil
93
93
  end
94
+
95
+ it 'should immediately play whatever is currently scheduled' do
96
+ channel.should_receive( :play_whats_on ).and_yield( {} )
97
+
98
+ stream.should_receive( :send ).with kind_of(Hash)
99
+
100
+ subject
101
+ end
94
102
  end
95
103
 
96
104
  describe '#tune_out' do
@@ -0,0 +1,9 @@
1
+ describe NetworkExecutive::OffAir do
2
+ it { should be_a NetworkExecutive::Program }
3
+
4
+ its(:display_name) { should == 'Off Air' }
5
+
6
+ its(:duration) { should == 15.minutes }
7
+
8
+ its(:url) { should == '/programs/off_air' }
9
+ end
data/spec/spec_helper.rb CHANGED
@@ -31,7 +31,8 @@ RSpec.configure do |config|
31
31
 
32
32
  Timecop.return
33
33
 
34
- NetworkExecutive::Network.channels.clear
35
- NetworkExecutive::Network.programming.clear
34
+ # Clear out any non-built-in instances
35
+ NetworkExecutive::Network.channels.reject! { |c| c.class.name.deconstantize != 'NetworkExecutive' }
36
+ NetworkExecutive::Network.programming.reject! { |p| p.class.name.deconstantize != 'NetworkExecutive' }
36
37
  end
37
38
  end
@@ -0,0 +1,67 @@
1
+ describe NetworkExecutive::ChannelSchedule do
2
+
3
+ let(:time) { Time.now.change(min:45, sec:0) }
4
+ let(:interval) { 15.minutes }
5
+ let(:schedule) { described_class.new }
6
+
7
+ let(:program_schedule) do
8
+ occ = double('occurrence').tap do |o|
9
+ o.stub(:start_time).and_return time + interval
10
+ o.stub(:duration).and_return 20.minutes
11
+ o.stub(:end_time).and_return time + interval + 20.minutes - 1
12
+ end
13
+
14
+ double('program_schedule').tap do |ps|
15
+ ps.stub(:occurring_at?).and_return false
16
+ ps.stub(:occurring_at?).with( time + 15.minutes).and_return true
17
+ ps.stub(:duration).and_return 20.minutes
18
+ ps.stub(:occurrence_at).and_return occ
19
+ end
20
+ end
21
+
22
+ describe '#add' do
23
+ subject do
24
+ schedule.add( 'foo', foo:'bar' )
25
+ end
26
+
27
+ it 'should prepend a ProgramSchedule' do
28
+ NetworkExecutive::ProgramSchedule
29
+ .should_receive( :new )
30
+ .with( 'foo', { foo:'bar' } )
31
+ .and_return( program_schedule )
32
+
33
+ described_class.any_instance.should_receive( :unshift ).with program_schedule
34
+
35
+ subject
36
+ end
37
+ end
38
+
39
+ describe '#whats_on_between?' do
40
+ let(:start) { time }
41
+ let(:stop) { start + 1.hour }
42
+
43
+ before do
44
+ schedule.unshift program_schedule
45
+ end
46
+
47
+ subject do
48
+ schedule.whats_on_between? start, stop, interval
49
+ end
50
+
51
+ it 'should start with 15-minutes of Off Air time' do
52
+ subject.first.program.should be_a NetworkExecutive::OffAirSchedule
53
+ subject.first.remainder.should == 15.minutes - 1
54
+ end
55
+
56
+ it 'should contain a scheduled program at the apporiate time' do
57
+ subject[1].program.should eq program_schedule
58
+ subject[1].remainder.should eq 20.minutes - 1
59
+ end
60
+
61
+ it 'should fill the remaining time slots of Off Air time' do
62
+ subject.last.program.should be_a NetworkExecutive::OffAirSchedule
63
+ subject.last.remainder.should == 25.minutes
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,76 @@
1
+ describe NetworkExecutive::Components::PhotoPlayer do
2
+
3
+ let(:klass) do
4
+ Class.new.send :include, described_class
5
+ end
6
+
7
+ before do
8
+ stub_const 'MyProgram', klass
9
+ end
10
+
11
+ subject { MyProgram.new }
12
+
13
+ its(:url) { should == '/slideshow' }
14
+ its(:refresh) { should be_false }
15
+ its(:onload) { should include(photos:[]) }
16
+ its(:photos) { should be_empty }
17
+
18
+ describe '#feed_url' do
19
+ it 'should raise' do
20
+ expect { subject.feed_url }.to raise_error NotImplementedError
21
+ end
22
+ end
23
+
24
+ describe '#feed' do
25
+ let(:request) { double('request').as_null_object }
26
+ let(:response) { double('response', body:'{}') }
27
+
28
+ before do
29
+ Net::HTTP::Get.stub(:new).and_return request
30
+ Net::HTTP.any_instance.stub(:request).and_return response
31
+ end
32
+
33
+ context 'with a HTTP feed URL' do
34
+ before do
35
+ subject.class.send(:define_method, :feed_url) do
36
+ 'http://example.org'
37
+ end
38
+ end
39
+
40
+ it 'should not use SSL' do
41
+ Net::HTTP.any_instance.should_receive(:use_ssl=).with( true ).never
42
+
43
+ subject.feed
44
+ end
45
+
46
+ it 'should parse JSON' do
47
+ subject.feed.should == {}
48
+ end
49
+ end
50
+
51
+ context 'with a HTTPS feed URL' do
52
+ before do
53
+ subject.class.send(:define_method, :feed_url) do
54
+ 'https://example.org'
55
+ end
56
+ end
57
+
58
+ it 'should use SSL' do
59
+ Net::HTTP.any_instance.should_receive(:use_ssl=).with true
60
+
61
+ subject.feed
62
+ end
63
+
64
+ it 'should not verify the certificate' do
65
+ Net::HTTP.any_instance.should_receive(:verify_mode=).with 0
66
+
67
+ subject.feed
68
+ end
69
+
70
+ it 'should parse JSON' do
71
+ subject.feed.should == {}
72
+ end
73
+ end
74
+ end
75
+
76
+ end
@@ -0,0 +1,68 @@
1
+ describe NetworkExecutive::Components::TweetPlayer do
2
+
3
+ let(:klass) do
4
+ Class.new do
5
+ def name; 'foo'; end
6
+ end.send :include, described_class
7
+ end
8
+
9
+ before do
10
+ stub_const 'MyProgram', klass
11
+ end
12
+
13
+ subject { MyProgram.new }
14
+
15
+ its(:url) { should == '/twitter' }
16
+
17
+ its(:refresh) { should be_false }
18
+
19
+ describe '#onload' do
20
+ it 'should include the Twitter search results' do
21
+ subject.class.should_receive( :tweets ).and_return( statuses: [] )
22
+
23
+ subject.onload.should include(:tweets)
24
+ end
25
+ end
26
+
27
+ describe '.tweets' do
28
+ it 'should delegate to the class' do
29
+ described_class.should_receive :tweets
30
+
31
+ described_class.tweets
32
+ end
33
+ end
34
+
35
+ describe '.client' do
36
+ it 'should be a Twitter Client' do
37
+ subject.class.client.should be_a Twitter::Client
38
+ end
39
+ end
40
+
41
+ describe '.configure' do
42
+ it 'should yield the client' do
43
+ arg = nil
44
+
45
+ subject.class.configure { |c| arg = c }
46
+
47
+ arg.should eq subject.class.client
48
+ end
49
+ end
50
+
51
+ describe '.search' do
52
+ it 'should configure the search query' do
53
+ subject.class.search 'search term', count: 4
54
+
55
+ subject.class.query.should eq [ 'search term', { count: 4 }]
56
+ end
57
+ end
58
+
59
+ describe '.tweets' do
60
+ it 'should search with the client instance' do
61
+ subject.class.search 'foo'
62
+
63
+ Twitter::Client.any_instance.should_receive( :search ).with 'foo'
64
+
65
+ subject.class.tweets
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,17 @@
1
+ describe NetworkExecutive::Components::YouTubePlayer do
2
+
3
+ let(:klass) do
4
+ Class.new.send :include, described_class
5
+ end
6
+
7
+ before do
8
+ stub_const 'MyProgram', klass
9
+ end
10
+
11
+ subject { MyProgram.new }
12
+
13
+ its(:url) { should == '/you_tube' }
14
+
15
+ its(:refresh) { should be_false }
16
+
17
+ end
@@ -0,0 +1,28 @@
1
+ describe NetworkExecutive::OffAirSchedule do
2
+
3
+ its(:program) { should be_a NetworkExecutive::OffAir }
4
+ its(:duration) { should == 59.seconds }
5
+
6
+ it 'should be subclass ProgramSchedule' do
7
+ subject.is_a? NetworkExecutive::ProgramSchedule
8
+ end
9
+
10
+ describe '#occurrence_at' do
11
+ let(:time) { Time.now.change(min:0, sec:0) }
12
+
13
+ subject { described_class.new.occurrence_at time }
14
+
15
+ it 'return build a ProgramSchedule Occurrence' do
16
+ args = [
17
+ time,
18
+ 59.seconds,
19
+ time + 59.seconds
20
+ ]
21
+
22
+ NetworkExecutive::ProgramSchedule::Occurrence.should_receive(:new).with( *args )
23
+
24
+ subject
25
+ end
26
+ end
27
+
28
+ end
@@ -41,17 +41,15 @@ describe NetworkExecutive::Producer do
41
41
 
42
42
  describe '.run_scheduled_programming' do
43
43
  let(:scheduled) { double('channel', whats_on?: true) }
44
- let(:unscheduled) { double('channel', whats_on?: nil) }
45
44
 
46
45
  before do
47
- NetworkExecutive::Network.stub(:channels).and_return [ scheduled, unscheduled ]
46
+ NetworkExecutive::Network.stub(:channels).and_return [ scheduled ]
48
47
  end
49
48
 
50
49
  subject { described_class.run_scheduled_programming }
51
50
 
52
51
  it 'should show all scheduled programming' do
53
- scheduled.should_receive :show
54
- unscheduled.should_receive( :show ).never
52
+ scheduled.should_receive :play
55
53
 
56
54
  subject
57
55
  end
@@ -0,0 +1,102 @@
1
+ describe NetworkExecutive::ProgramScheduleProxy do
2
+
3
+ describe '#initialize' do
4
+
5
+ context 'start time' do
6
+ context 'when specified' do
7
+ let(:time) { 1.hour.ago }
8
+
9
+ subject { described_class.new( time ) }
10
+
11
+ it 'should be the specified time' do
12
+ subject.start_time.should == time
13
+ end
14
+ end
15
+
16
+ context 'when unspecified' do
17
+ it 'should default to the beginning of the day' do
18
+ subject.start_time.should == Time.now.beginning_of_day
19
+ end
20
+ end
21
+ end
22
+
23
+ context 'duration' do
24
+ context 'when set' do
25
+ subject do
26
+ described_class.new( nil, 15.minutes ).duration
27
+ end
28
+
29
+ it 'should have the specified duration' do
30
+ subject.should == 15.minutes
31
+ end
32
+ end
33
+
34
+ context 'when not set' do
35
+ subject do
36
+ described_class.new.duration
37
+ end
38
+
39
+ it 'should default to a full day' do
40
+ subject.should == 24.hours
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'block evaluation' do
46
+ it 'should evaluate the block' do
47
+ evald = false
48
+
49
+ described_class.new { evald = true }
50
+
51
+ evald.should be_true
52
+ end
53
+ end
54
+ end
55
+
56
+ describe '#to_schedule' do
57
+ it 'should return the internal IceCube::Schedule instance' do
58
+ subject.to_schedule.should be_a IceCube::Schedule
59
+ end
60
+ end
61
+
62
+ describe '#respond_to_missing?' do
63
+ context 'when parsing a schedule block' do
64
+ # TODO: Not the best test setup in the world...
65
+ before { subject.instance_variable_set('@parsing_schedule', true) }
66
+
67
+ it 'should respond to anything that IceCube::Rule does' do
68
+ subject.respond_to_missing?( :minutely ).should be_true
69
+ end
70
+ end
71
+
72
+ context 'when outside a schedule parsing block' do
73
+ it 'should respond to anything that IceCube::Rule does' do
74
+ subject.respond_to_missing?( :all_occurrences ).should be_true
75
+ end
76
+ end
77
+ end
78
+
79
+ describe '#method_missing' do
80
+ context 'when parsing a schedule block' do
81
+ it 'should add a recurrence rule' do
82
+ IceCube::Schedule.any_instance.should_receive( :add_recurrence_rule )
83
+ .twice
84
+ .with kind_of( IceCube::Rule )
85
+
86
+ described_class.new do
87
+ minutely 30
88
+ minutely 45
89
+ end
90
+ end
91
+ end
92
+
93
+ context 'when outside a schedule parsing block' do
94
+ it 'should attempt to forward to the schedule' do
95
+ IceCube::Schedule.any_instance.should_receive( :all_occurrences )
96
+
97
+ described_class.new.all_occurrences
98
+ end
99
+ end
100
+ end
101
+
102
+ end