network_executive 0.0.4 → 0.0.7

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.
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