poms 0.0.10 → 1.0.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 +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
|