poms 0.0.10 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/Guardfile +4 -4
- data/Rakefile +6 -6
- data/lib/poms.rb +65 -44
- data/lib/poms/base.rb +1 -0
- data/lib/poms/broadcast.rb +7 -6
- data/lib/poms/builder.rb +36 -29
- data/lib/poms/builderless/broadcast.rb +2 -1
- data/lib/poms/builderless/clip.rb +1 -1
- data/lib/poms/connect.rb +5 -7
- data/lib/poms/has_ancestors.rb +20 -8
- data/lib/poms/has_base_attributes.rb +11 -2
- data/lib/poms/merged_series.rb +27 -0
- data/lib/poms/poms_error.rb +5 -0
- data/lib/poms/schedule_event.rb +7 -9
- data/lib/poms/season.rb +2 -2
- data/lib/poms/series.rb +4 -4
- data/lib/poms/version.rb +2 -1
- data/lib/poms/views.rb +6 -2
- data/poms.gemspec +21 -20
- data/spec/fabricators/poms_fabricator.rb +8 -3
- data/spec/fixtures/vcr_cassettes/poms/merged_series/is_enumerable.yml +46 -0
- data/spec/fixtures/vcr_cassettes/poms/merged_series/turns_the_json_into_a_hash.yml +46 -0
- data/spec/integration/poms_spec.rb +1 -2
- data/spec/lib/poms/broadcast_spec.rb +11 -6
- data/spec/lib/poms/builder_spec.rb +36 -2
- data/spec/lib/poms/merged_series_spec.rb +28 -0
- data/spec/lib/poms/schedule_event_spec.rb +3 -3
- data/spec/lib/poms/views_spec.rb +6 -6
- data/spec/lib/poms_spec.rb +35 -32
- data/spec/spec_helper.rb +4 -2
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4333611e09f4d9d9e64bc14b1df3bbce76593022
|
4
|
+
data.tar.gz: 95ca2bb08c7d0ea5268b19d043e3d09079f251c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a3ad89078d35c87c4859a495558598a16ed81b8d3f178d4f0548f20db8d86cb957c746e9d23f5464dd3b1f643d8611b19e4c511531210649de0462151f7e8bd
|
7
|
+
data.tar.gz: 5d1b7e1e13d6dc8d0aeb1d411fa540049cc4958887f3683a153c6b05dab3f60b1b2698d8af6eb2982c3aa418deedeaf9fff805f5cd2a1e1510e3488dd5e88cf0
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
poms (0.0
|
4
|
+
poms (1.0.0)
|
5
5
|
activesupport
|
6
6
|
|
7
7
|
GEM
|
@@ -60,7 +60,7 @@ GEM
|
|
60
60
|
method_source (~> 0.8.1)
|
61
61
|
slop (~> 3.4)
|
62
62
|
rainbow (2.0.0)
|
63
|
-
rake (10.
|
63
|
+
rake (10.1.0)
|
64
64
|
rb-fsevent (0.9.4)
|
65
65
|
rb-inotify (0.9.5)
|
66
66
|
ffi (>= 0.5.0)
|
data/Guardfile
CHANGED
@@ -4,9 +4,9 @@
|
|
4
4
|
guard :rspec do
|
5
5
|
watch(%r{^spec/.+_spec\.rb$})
|
6
6
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
-
watch('spec/spec_helper.rb') {
|
7
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
8
8
|
|
9
|
-
watch(%r{^spec/support/(.+)\.rb$}) {
|
10
|
-
watch('config/routes.rb') {
|
11
|
-
watch('app/controllers/application_controller.rb') {
|
9
|
+
watch(%r{^spec/support/(.+)\.rb$}) { 'spec' }
|
10
|
+
watch('config/routes.rb') { 'spec/routing' }
|
11
|
+
watch('app/controllers/application_controller.rb') { 'spec/controllers' }
|
12
12
|
end
|
data/Rakefile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
3
|
|
4
4
|
RSpec::Core::RakeTask.new
|
5
5
|
|
6
|
-
task :
|
7
|
-
task :
|
6
|
+
task default: :spec
|
7
|
+
task test: :spec
|
8
8
|
|
9
|
-
desc
|
9
|
+
desc 'Open an irb session preloaded with this library'
|
10
10
|
task :console do
|
11
|
-
sh
|
11
|
+
sh 'irb -rubygems -I lib -r poms.rb'
|
12
12
|
end
|
data/lib/poms.rb
CHANGED
@@ -12,21 +12,26 @@ require 'poms/views'
|
|
12
12
|
require 'poms/fields'
|
13
13
|
require 'poms/builderless/broadcast'
|
14
14
|
require 'poms/builderless/clip'
|
15
|
+
require 'poms/merged_series'
|
16
|
+
require 'poms/poms_error'
|
15
17
|
|
18
|
+
# Module that allows interfacing with the POMS CouchDB service.
|
19
|
+
# rubocop:disable Metrics/ModuleLength
|
16
20
|
module Poms
|
17
21
|
extend Poms::Views
|
18
22
|
extend Poms::Fields
|
19
23
|
extend self
|
20
24
|
|
21
|
-
|
22
25
|
URL = 'http://docs.poms.omroep.nl'
|
23
26
|
MEDIA_PATH = '/media/'
|
24
|
-
BROADCASTS_VIEW_PATH =
|
27
|
+
BROADCASTS_VIEW_PATH =
|
28
|
+
'/media/_design/media/_view/broadcasts-by-broadcaster-and-start'
|
25
29
|
ANCESTOR_AND_TYPE_PATH = '/media/_design/media/_view/by-ancestor-and-type'
|
26
|
-
ANCESTOR_AND_SORTDATE_PATH =
|
27
|
-
|
30
|
+
ANCESTOR_AND_SORTDATE_PATH =
|
31
|
+
'/media/_design/media/_view/by-ancestor-and-sortdate'
|
32
|
+
CHANNEL_AND_START_PATH =
|
33
|
+
'/media/_design/media/_view/broadcasts-by-channel-and-start'
|
28
34
|
VALID_CHANNELS = /^NED(1|2|3)$/
|
29
|
-
# ?startkey=[\"Zapp\",1369755130000]&endkey=[\"Zapp\",1370964770000]&reduce=false&include_docs=true
|
30
35
|
|
31
36
|
def fetch(mid)
|
32
37
|
return nil if mid.nil?
|
@@ -42,7 +47,9 @@ module Poms
|
|
42
47
|
def fetch_playlist_clips(mid)
|
43
48
|
uri = Poms::Views.by_group(mid)
|
44
49
|
playlist_hash = get_bare_json(uri)
|
45
|
-
playlist_hash['rows'].map
|
50
|
+
playlist_hash['rows'].map do |hash|
|
51
|
+
Poms::Builderless::Clip.new(hash['doc'])
|
52
|
+
end
|
46
53
|
end
|
47
54
|
|
48
55
|
def fetch_raw_json(mid)
|
@@ -55,36 +62,42 @@ module Poms
|
|
55
62
|
get_bare_json(uri)
|
56
63
|
end
|
57
64
|
|
58
|
-
def upcoming_broadcasts(zender, start_time = Time.now,
|
59
|
-
|
65
|
+
def upcoming_broadcasts(zender, start_time = Time.now,
|
66
|
+
end_time = Time.now + 7.days)
|
67
|
+
view_params = broadcast_view_params(zender, start_time, end_time)
|
68
|
+
uri = [BROADCASTS_VIEW_PATH, view_params].join
|
60
69
|
hash = get_json(uri)
|
61
|
-
hash['rows'].map {|item| Poms::Builder.process_hash item['doc']}
|
70
|
+
hash['rows'].map { |item| Poms::Builder.process_hash item['doc'] }
|
62
71
|
end
|
63
72
|
|
64
|
-
def fetch_descendants_for_serie(mid, type='BROADCAST')
|
65
|
-
uri = [ANCESTOR_AND_TYPE_PATH, ancestor_type_params(mid, type)
|
66
|
-
hash = get_json(uri) || {'rows' => []}
|
67
|
-
hash['rows'].map {|item| Poms::Builder.process_hash item['doc']}
|
73
|
+
def fetch_descendants_for_serie(mid, type = 'BROADCAST')
|
74
|
+
uri = [ANCESTOR_AND_TYPE_PATH, ancestor_type_params(mid, type)].join
|
75
|
+
hash = get_json(uri) || { 'rows' => [] }
|
76
|
+
hash['rows'].map { |item| Poms::Builder.process_hash item['doc'] }
|
68
77
|
end
|
69
78
|
|
70
79
|
alias_method :fetch_broadcasts_for_serie, :fetch_descendants_for_serie
|
71
80
|
|
72
|
-
def fetch_descendants_by_date_for_serie(mid, start_time=1.week.ago)
|
73
|
-
|
74
|
-
|
75
|
-
hash
|
81
|
+
def fetch_descendants_by_date_for_serie(mid, start_time = 1.week.ago)
|
82
|
+
view_params = ancestor_sortdate_params(mid, start_time)
|
83
|
+
uri = [ANCESTOR_AND_SORTDATE_PATH, view_params].join
|
84
|
+
hash = get_json(uri) || { 'rows' => [] }
|
85
|
+
hash['rows'].map { |item| Poms::Builder.process_hash item['doc'] }
|
76
86
|
end
|
77
87
|
|
78
|
-
def fetch_descendant_mids(mid, type='BROADCAST')
|
79
|
-
|
80
|
-
|
81
|
-
hash
|
88
|
+
def fetch_descendant_mids(mid, type = 'BROADCAST')
|
89
|
+
view_params = ancestor_type_params(mid, type)
|
90
|
+
uri = [ANCESTOR_AND_TYPE_PATH, view_params, '&include_docs=false'].join
|
91
|
+
hash = get_json(uri) || { 'rows' => [] }
|
92
|
+
hash['rows'].map { |item| item['id'] }
|
82
93
|
end
|
83
94
|
|
84
|
-
def fetch_broadcasts_by_channel_and_start(channel, start_time=1.week.ago,
|
85
|
-
|
95
|
+
def fetch_broadcasts_by_channel_and_start(channel, start_time = 1.week.ago,
|
96
|
+
end_time = Time.now)
|
97
|
+
view_params = channel_params(channel, start_time, end_time)
|
98
|
+
uri = [CHANNEL_AND_START_PATH, view_params].join
|
86
99
|
hash = get_json(uri)
|
87
|
-
hash['rows'].map {|item| Poms::Builder.process_hash item['doc']}
|
100
|
+
hash['rows'].map { |item| Poms::Builder.process_hash item['doc'] }
|
88
101
|
end
|
89
102
|
|
90
103
|
def fetch_current_broadcast(channel)
|
@@ -95,39 +108,48 @@ module Poms
|
|
95
108
|
end
|
96
109
|
|
97
110
|
def fetch_current_broadcast_and_key(channel)
|
98
|
-
hash = get_json(channel_and_start_uri(
|
99
|
-
|
111
|
+
hash = get_json(channel_and_start_uri(
|
112
|
+
channel, Time.now, 1.day.ago, limit: 1, descending: true)
|
113
|
+
)
|
114
|
+
{ key: get_first_key(hash), broadcast: get_first_broadcast(hash) }
|
100
115
|
end
|
101
116
|
|
102
117
|
def fetch_next_broadcast(channel)
|
103
|
-
hash = get_json(channel_and_start_uri(
|
118
|
+
hash = get_json(channel_and_start_uri(
|
119
|
+
channel, Time.now, 1.day.from_now, limit: 1)
|
120
|
+
)
|
104
121
|
get_first_broadcast(hash)
|
105
122
|
end
|
106
123
|
|
107
124
|
def fetch_next_broadcast_and_key(channel)
|
108
|
-
hash = get_json(channel_and_start_uri(
|
109
|
-
|
125
|
+
hash = get_json(channel_and_start_uri(
|
126
|
+
channel, Time.now, 1.day.from_now, limit: 1)
|
127
|
+
)
|
128
|
+
{ key: get_first_key(hash), broadcast: get_first_broadcast(hash) }
|
110
129
|
end
|
111
130
|
|
112
|
-
# private
|
113
131
|
def broadcast_view_params(zender, start_time, end_time)
|
114
132
|
zender = zender.capitalize
|
115
|
-
"?startkey=[\"#{zender}\",#{start_time.to_i * 1000}]
|
133
|
+
"?startkey=[\"#{zender}\",#{start_time.to_i * 1000}]" \
|
134
|
+
"&endkey=[\"#{zender}\",#{end_time.to_i * 1000}]" \
|
135
|
+
'&reduce=false&include_docs=true'
|
116
136
|
end
|
117
137
|
|
118
138
|
def ancestor_type_params(mid, type)
|
119
139
|
"?reduce=false&key=[\"#{mid}\",\"#{type}\"]&include_docs=true"
|
120
140
|
end
|
121
141
|
|
122
|
-
def ancestor_sortdate_params(mid, start_time=1.month.ago)
|
142
|
+
def ancestor_sortdate_params(mid, start_time = 1.month.ago)
|
123
143
|
end_time_i = 1.week.from_now.to_i * 1000
|
124
144
|
start_time_i = start_time.to_i * 1000
|
125
|
-
"?reduce=false&startkey=[\"#{mid}\",#{start_time_i}]
|
145
|
+
"?reduce=false&startkey=[\"#{mid}\",#{start_time_i}]" \
|
146
|
+
"&endkey=[\"#{mid}\",#{end_time_i}]&include_docs=true"
|
126
147
|
end
|
127
148
|
|
128
|
-
|
129
149
|
def channel_params(channel, start_time, end_time)
|
130
|
-
"?startkey=[\"#{channel}\",#{start_time.to_i * 1000}]
|
150
|
+
"?startkey=[\"#{channel}\",#{start_time.to_i * 1000}]" \
|
151
|
+
"&endkey=[\"#{channel}\",#{end_time.to_i * 1000}]" \
|
152
|
+
'&reduce=false&include_docs=true'
|
131
153
|
end
|
132
154
|
|
133
155
|
def get_json(uri)
|
@@ -137,17 +159,16 @@ module Poms
|
|
137
159
|
private
|
138
160
|
|
139
161
|
def get_bare_json(uri)
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
nil
|
145
|
-
end
|
162
|
+
JSON.parse(open(uri).read)
|
163
|
+
rescue OpenURI::HTTPError => e
|
164
|
+
raise e unless e.message.match(/404/)
|
165
|
+
nil
|
146
166
|
end
|
147
167
|
|
148
|
-
def channel_and_start_uri(channel, start_time, end_time, options={})
|
168
|
+
def channel_and_start_uri(channel, start_time, end_time, options = {})
|
149
169
|
query_options = options.blank? ? '' : "&#{options.to_query}"
|
150
|
-
|
170
|
+
view_params = channel_params(channel, start_time, end_time)
|
171
|
+
[CHANNEL_AND_START_PATH, view_params, query_options].join
|
151
172
|
end
|
152
173
|
|
153
174
|
def get_first_broadcast(hash)
|
@@ -159,5 +180,5 @@ module Poms
|
|
159
180
|
rows = hash['rows']
|
160
181
|
rows.empty? ? [] : rows.first['key']
|
161
182
|
end
|
162
|
-
|
163
183
|
end
|
184
|
+
# rubocop:enable Metrics/ModuleLength
|
data/lib/poms/base.rb
CHANGED
data/lib/poms/broadcast.rb
CHANGED
@@ -2,12 +2,12 @@ require 'poms/has_ancestors'
|
|
2
2
|
require 'poms/has_base_attributes'
|
3
3
|
|
4
4
|
module Poms
|
5
|
+
# POMS wrapper for an episode of a Serie.
|
5
6
|
class Broadcast < Poms::Builder::NestedOpenStruct
|
6
|
-
|
7
7
|
include Poms::HasAncestors
|
8
8
|
include Poms::HasBaseAttributes
|
9
9
|
|
10
|
-
def initialize
|
10
|
+
def initialize(hash)
|
11
11
|
super
|
12
12
|
process_schedule_events
|
13
13
|
end
|
@@ -16,7 +16,9 @@ module Poms
|
|
16
16
|
if schedule_events
|
17
17
|
schedule_events.select! { |e| e.channel.match Poms::VALID_CHANNELS }
|
18
18
|
end
|
19
|
-
self.schedule_events = schedule_events.map
|
19
|
+
self.schedule_events = schedule_events.map do |e|
|
20
|
+
Poms::ScheduleEvent.new e.marshal_dump
|
21
|
+
end if schedule_events
|
20
22
|
end
|
21
23
|
|
22
24
|
def series_mid
|
@@ -24,10 +26,10 @@ module Poms
|
|
24
26
|
end
|
25
27
|
|
26
28
|
def odi_streams
|
27
|
-
return [] if locations.nil?
|
29
|
+
return [] if locations.nil? || locations.empty?
|
28
30
|
odi_streams = locations.select { |l| l.program_url.match(/^odi/) }
|
29
31
|
streams = odi_streams.map do |l|
|
30
|
-
l.program_url.match(
|
32
|
+
l.program_url.match(%r{^[\w+]+\:\/\/[\w\.]+\/video\/(\w+)\/\w+})[1]
|
31
33
|
end
|
32
34
|
streams.uniq
|
33
35
|
end
|
@@ -50,5 +52,4 @@ module Poms
|
|
50
52
|
|
51
53
|
class Strand < Broadcast
|
52
54
|
end
|
53
|
-
|
54
55
|
end
|
data/lib/poms/builder.rb
CHANGED
@@ -2,65 +2,72 @@ require 'ostruct'
|
|
2
2
|
require 'active_support/all'
|
3
3
|
|
4
4
|
module Poms
|
5
|
+
# Builds the correct object based on the result from POMS.
|
5
6
|
class Builder
|
6
7
|
SUPPORTED_CLASSES = %w(Broadcast Season Series Views Typeless)
|
7
8
|
|
8
9
|
def self.process_hash(hash)
|
9
10
|
return unless hash
|
10
|
-
underscored_hash = {}
|
11
|
-
|
12
|
-
class_name = (underscored_hash['type'] || "Typeless").capitalize
|
13
|
-
class_name = pomsify_class_name(class_name)
|
14
|
-
begin
|
15
|
-
klass = Poms.const_get class_name
|
16
|
-
rescue NameError
|
17
|
-
# c = Class.new(Poms::NestedOpenStruct)
|
18
|
-
klass = Poms.const_set class_name, Class.new(Poms::Builder::NestedOpenStruct)
|
11
|
+
underscored_hash = hash.each_with_object({}) do |(k, v), res|
|
12
|
+
res[k.underscore] = v
|
19
13
|
end
|
14
|
+
class_name = pomsify_class_name(underscored_hash['type'])
|
15
|
+
klass = poms_class(class_name)
|
20
16
|
klass.send(:new, underscored_hash)
|
21
17
|
end
|
22
18
|
|
23
|
-
private
|
24
|
-
|
25
19
|
def self.pomsify_class_name(class_name)
|
26
|
-
class_name =
|
20
|
+
class_name = class_name.blank? ? 'Typeless' : class_name.capitalize
|
21
|
+
class_name =
|
22
|
+
'Poms' + class_name unless SUPPORTED_CLASSES.include? class_name
|
27
23
|
class_name
|
28
24
|
end
|
29
25
|
|
30
|
-
|
26
|
+
def self.poms_class(class_name)
|
27
|
+
Poms.const_get class_name
|
28
|
+
rescue NameError
|
29
|
+
Poms.const_set class_name, Class.new(Poms::Builder::NestedOpenStruct)
|
30
|
+
end
|
31
31
|
|
32
|
+
# An OpenStruct subclass that allows nesting to simulate a hash.
|
33
|
+
class NestedOpenStruct < OpenStruct
|
32
34
|
include Poms::Base
|
33
35
|
|
34
36
|
def initialize(hash)
|
35
37
|
@hash = hash
|
36
|
-
@hash.each do |k,v|
|
37
|
-
process_key_value(k,v)
|
38
|
+
@hash.each do |k, v|
|
39
|
+
process_key_value(k, v)
|
38
40
|
end
|
39
41
|
super hash
|
40
42
|
end
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
+
# rubocop:disable Metrics/MethodLength
|
44
45
|
def process_key_value(k, v)
|
45
46
|
case v
|
46
47
|
when Array
|
47
|
-
|
48
|
-
process_element(element)
|
49
|
-
end
|
50
|
-
@hash.send("[]=", k, struct_array)
|
48
|
+
process_array(k, v)
|
51
49
|
when Hash
|
52
|
-
@hash.send(
|
50
|
+
@hash.send('[]=', k, Poms::Builder.process_hash(v))
|
53
51
|
when String, Integer
|
54
|
-
|
55
52
|
case k
|
56
|
-
when
|
57
|
-
@hash.send(
|
53
|
+
when 'start', 'end', 'sort_date'
|
54
|
+
@hash.send('[]=', k, Time.at(v / 1000))
|
58
55
|
end
|
59
56
|
when NilClass, FalseClass, TrueClass, Time, Poms::Typeless
|
60
57
|
# do nothing
|
61
58
|
else
|
62
|
-
|
59
|
+
fail Poms::Exceptions::UnkownStructure,
|
60
|
+
"Error processing #{v.class}: #{v}, which was expected to be " \
|
61
|
+
'a String or Array'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
# rubocop:enable Metrics/MethodLength
|
65
|
+
|
66
|
+
def process_array(key, value)
|
67
|
+
struct_array = value.map do |element|
|
68
|
+
process_element(element)
|
63
69
|
end
|
70
|
+
@hash.send('[]=', key, struct_array)
|
64
71
|
end
|
65
72
|
|
66
73
|
def process_element(element)
|
@@ -70,16 +77,16 @@ module Poms
|
|
70
77
|
when Hash
|
71
78
|
Poms::Builder.process_hash element
|
72
79
|
else
|
73
|
-
|
80
|
+
fail Poms::Exceptions::UnkownStructure,
|
81
|
+
"Error processing #{element}: which was expected to be a " \
|
82
|
+
'String nor a Hash'
|
74
83
|
end
|
75
84
|
end
|
76
85
|
end
|
77
86
|
end
|
78
87
|
|
79
|
-
|
80
88
|
module Exceptions
|
81
89
|
class UnkownStructure < StandardError
|
82
90
|
end
|
83
91
|
end
|
84
|
-
|
85
92
|
end
|
@@ -2,7 +2,7 @@ require 'poms/fields'
|
|
2
2
|
|
3
3
|
module Poms
|
4
4
|
module Builderless
|
5
|
-
# A single broadcast fetched from Poms
|
5
|
+
# A single broadcast (episode) fetched from Poms
|
6
6
|
class Broadcast
|
7
7
|
def initialize(hash)
|
8
8
|
@hash = hash
|
@@ -23,6 +23,7 @@ module Poms
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
# A single event of a broadcast.
|
26
27
|
class Event
|
27
28
|
def initialize(hash)
|
28
29
|
@hash = hash
|