yt 0.23.0 → 0.23.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 684b3fcaa4ab0f5f3ad32ec7296601f71e549e4a
4
- data.tar.gz: f6026fcc1c013dd12ef05c53fe1e4ff2964fb4a8
3
+ metadata.gz: 004e3876d58c7c369d0e2a215d41234ad37f7b57
4
+ data.tar.gz: c4cc02ed5cf02d23858e7de931d5bc1bea63c932
5
5
  SHA512:
6
- metadata.gz: c050616344cebcb10223924565f11d1c00f6d06900afb7c955e8a5ed6f999c96c3af6860402007b433769a1d5ddcdbae221ad4f93de8e35f18e2b0924d7dc62b
7
- data.tar.gz: e3d73c055a6cd8a2ffba67fc90066b0e412e7aa2a2c968fbf349892e18ade346b1758d73bf96d33b73033cfacef87b7846bffc94bd26e9e863020ed75390d807
6
+ metadata.gz: 691d6757cb7112eb8993d6c81b98cc44bd15a31a50e73c1294761563ba15117adde788c04d89003f23eb23f24bead8ca0aa5d4d0b7856da4287969c5836ab9fd
7
+ data.tar.gz: 3f488e8e0c4bbffe17c9b78177f61a4ee7ed535ba483217d7f71980bcd11f9939ddf52588a5f2dd0e244fae15023af9449b8539de930c7ed2bba43f15d8953c7
@@ -6,6 +6,11 @@ For more information about changelogs, check
6
6
  [Keep a Changelog](http://keepachangelog.com) and
7
7
  [Vandamme](http://tech-angels.github.io/vandamme).
8
8
 
9
+ ## 0.23.1 - 2015-05-19
10
+
11
+ * [FEATURE] New `by: :month` option for reports.
12
+ * [FEATURE] New `.reports` method to fetch multiple metrics at once.
13
+
9
14
  ## 0.23.0 - 2015-05-18
10
15
 
11
16
  **How to upgrade**
data/README.md CHANGED
@@ -41,7 +41,7 @@ To install on your system, run
41
41
 
42
42
  To use inside a bundled Ruby project, add this line to the Gemfile:
43
43
 
44
- gem 'yt', '~> 0.23.0'
44
+ gem 'yt', '~> 0.23.1'
45
45
 
46
46
  Since the gem follows [Semantic Versioning](http://semver.org),
47
47
  indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
@@ -3,6 +3,23 @@ module Yt
3
3
  # @private
4
4
  # Provides methods to access the analytics reports of a resource.
5
5
  module HasReports
6
+ # @!macro [new] reports
7
+ # Returns the reports for the given metrics grouped by the given dimension.
8
+ # @!method reports(options = {})
9
+ # @param [Hash] options the metrics, time-range and dimensions for the reports.
10
+ # @option options [Array<Symbol>] :only The metrics to generate reports
11
+ # for.
12
+ # @option options [Symbol] :by (:day) The dimension to collect metrics
13
+ # by. Accepted values are: +:day+, +:month+.
14
+ # @option options [#to_date] :since The first day of the time-range.
15
+ # Also aliased as +:from+.
16
+ # @option options [#to_date] :until The last day of the time-range.
17
+ # Also aliased as +:to+.
18
+ # @return [Hash<Symbol, Hash>] the reports for each metric specified.
19
+ # @example Get the views and estimated minutes watched by day for last week:
20
+ # resource.reports only: [:views, :estimated_minutes_watched] since: 1.week.ago, by: :day
21
+ # # => {views: {Wed, 8 May 2014 => 12, Thu, 9 May 2014 => 34, …}, estimated_minutes_watched: {Wed, 8 May 2014 => 9.0, Thu, 9 May 2014 => 6.0, …}}
22
+
6
23
  # @!macro [new] report
7
24
  # Returns the $1 grouped by the given dimension.
8
25
  # @!method $1(options = {})
@@ -18,6 +35,11 @@ module Yt
18
35
  # @example Get the $1 for each day of last week:
19
36
  # resource.$1 since: 2.weeks.ago, until: 1.week.ago, by: :day
20
37
  # # => {Wed, 8 May 2014 => 12.0, Thu, 9 May 2014 => 34.0, …}
38
+ # @return [Hash<Range<Date, Date>, $2>] if grouped by month, the $1
39
+ # for each month in the time-range.
40
+ # @example Get the $1 for this and last month:
41
+ # resource.$1 since: 1.month.ago, by: :month
42
+ # # => {Wed, 01 Apr 2014..Thu, 30 Apr 2014 => 12.0, Fri, 01 May 2014..Sun, 31 May 2014 => 34.0, …}
21
43
  # @macro report
22
44
 
23
45
  # @!macro [new] report_with_range
@@ -48,19 +70,19 @@ module Yt
48
70
 
49
71
  # @!macro [new] report_by_day
50
72
  # @option options [Symbol] :by (:day) The dimension to collect $1 by.
51
- # Accepted values are: +:day+.
73
+ # Accepted values are: +:day+, +:month+.
52
74
  # @macro report_with_day
53
75
 
54
76
  # @!macro [new] report_by_day_and_country
55
77
  # @option options [Symbol] :by (:day) The dimension to collect $1 by.
56
- # Accepted values are: +:day+, :+range+.
78
+ # Accepted values are: +:day+, +:month+, :+range+.
57
79
  # @macro report_with_day
58
80
  # @macro report_with_range
59
81
  # @macro report_with_country
60
82
 
61
83
  # @!macro [new] report_by_day_and_state
62
84
  # @option options [Symbol] :by (:day) The dimension to collect $1 by.
63
- # Accepted values are: +:day+, :+range+.
85
+ # Accepted values are: +:day+, +:month+, :+range+.
64
86
  # @macro report_with_day
65
87
  # @macro report_with_range
66
88
  # @macro report_with_country_and_state
@@ -96,7 +118,7 @@ module Yt
96
118
 
97
119
  # @!macro [new] report_by_video_dimensions
98
120
  # @option options [Symbol] :by (:day) The dimension to collect $1 by.
99
- # Accepted values are: +:day+, +:range+, +:traffic_source+,
121
+ # Accepted values are: +:day+, +:month+, +:range+, +:traffic_source+,
100
122
  # +:search_term+, +:playback_location+, +:related_video+,
101
123
  # +:embedded_player_location+.
102
124
  # @return [Hash<Symbol, $2>] if grouped by embedded player location,
@@ -122,7 +144,7 @@ module Yt
122
144
 
123
145
  # @!macro [new] report_by_channel_dimensions
124
146
  # @option options [Symbol] :by (:day) The dimension to collect $1 by.
125
- # Accepted values are: +:day+, +:range+, +:traffic_source+,
147
+ # Accepted values are: +:day+, +:month+, +:range+, +:traffic_source+,
126
148
  # +:search_term+, +:playback_location+, +:related_video+, +:video+,
127
149
  # +:playlist+, +:embedded_player_location+.
128
150
  # @return [Hash<Symbol, $2>] if grouped by embedded player location,
@@ -135,7 +157,7 @@ module Yt
135
157
 
136
158
  # @!macro [new] report_by_playlist_dimensions
137
159
  # @option options [Symbol] :by (:day) The dimension to collect $1 by.
138
- # Accepted values are: +:day+, +:range+, +:traffic_source+,
160
+ # Accepted values are: +:day+, +:month+, +:range+, +:traffic_source+,
139
161
  # +:playback_location+, +:related_video+, +:video+,
140
162
  # +:playlist+.
141
163
  # @macro report_with_channel_dimensions
@@ -179,8 +201,9 @@ module Yt
179
201
 
180
202
  define_metric_on_method metric
181
203
  define_metric_method metric
182
- define_range_metric_method metric, type
183
- define_all_metric_method metric
204
+ define_reports_method metric, type
205
+ define_range_metric_method metric
206
+ define_all_metric_method metric, type
184
207
  end
185
208
 
186
209
  private
@@ -191,20 +214,45 @@ module Yt
191
214
  end
192
215
  end
193
216
 
217
+ def define_reports_method(metric, type)
218
+ (@metrics ||= {})[metric] = type
219
+ define_method :reports do |options = {}|
220
+ from = options[:since] || options[:from] || (options[:by].in?([:day, :month]) ? 5.days.ago : '2005-02-01')
221
+ to = options[:until] || options[:to] || Date.today
222
+ location = options[:in]
223
+ country = location.is_a?(Hash) ? location[:country] : location
224
+ state = location[:state] if location.is_a?(Hash)
225
+ dimension = options[:by] || (metric == :viewer_percentage ? :gender_age_group : :range)
226
+ if dimension == :month
227
+ from = from.to_date.beginning_of_month
228
+ to = to.to_date.beginning_of_month
229
+ end
230
+ date_range = Range.new *[from, to].map(&:to_date)
231
+
232
+ only = options.fetch :only, []
233
+ reports = Collections::Reports.of(self).tap do |reports|
234
+ reports.metrics = self.class.instance_variable_get(:@metrics).select{|k, v| k.in? only}
235
+ end
236
+ reports.within date_range, country, state, dimension
237
+ end unless defined?(reports)
238
+ end
239
+
194
240
  def define_metric_method(metric)
195
241
  define_method metric do |options = {}|
196
- from = options[:since] || options[:from] || (options[:by] == :day ? 5.days.ago : '2005-02-01')
242
+ from = options[:since] || options[:from] || (options[:by].in?([:day, :month]) ? 5.days.ago : '2005-02-01')
197
243
  to = options[:until] || options[:to] || Date.today
198
244
  location = options[:in]
199
245
  country = location.is_a?(Hash) ? location[:country] : location
200
246
  state = location[:state] if location.is_a?(Hash)
201
-
202
- range = Range.new *[from, to].map(&:to_date)
203
247
  dimension = options[:by] || (metric == :viewer_percentage ? :gender_age_group : :range)
248
+ if dimension == :month
249
+ from = from.to_date.beginning_of_month
250
+ to = to.to_date.beginning_of_month
251
+ end
252
+ range = Range.new *[from, to].map(&:to_date)
204
253
 
205
254
  ivar = instance_variable_get "@#{metric}_#{dimension}_#{country}_#{state}"
206
255
  instance_variable_set "@#{metric}_#{dimension}_#{country}_#{state}", ivar || {}
207
-
208
256
  case dimension
209
257
  when :day
210
258
  Hash[*range.flat_map do |date|
@@ -216,23 +264,23 @@ module Yt
216
264
  end
217
265
  end
218
266
 
219
- def define_range_metric_method(metric, type)
267
+ def define_range_metric_method(metric)
220
268
  define_method "range_#{metric}" do |date_range, dimension, country, state|
221
269
  ivar = instance_variable_get "@range_#{metric}_#{dimension}_#{country}_#{state}"
222
270
  instance_variable_set "@range_#{metric}_#{dimension}_#{country}_#{state}", ivar || {}
223
- instance_variable_get("@range_#{metric}_#{dimension}_#{country}_#{state}")[date_range] ||= send("all_#{metric}").within date_range, country, state, dimension, type
271
+ instance_variable_get("@range_#{metric}_#{dimension}_#{country}_#{state}")[date_range] ||= send("all_#{metric}").within date_range, country, state, dimension
224
272
  end
225
273
  private "range_#{metric}"
226
274
  end
227
275
 
228
- def define_all_metric_method(metric)
276
+ def define_all_metric_method(metric, type)
229
277
  define_method "all_#{metric}" do
230
278
  # @note Asking for the "earnings" metric of a day in which a channel
231
279
  # made 0 USD returns the wrong "nil". But adding to the request the
232
280
  # "estimatedMinutesWatched" metric returns the correct value 0.
233
- query = metric
234
- query = "estimatedMinutesWatched,#{metric}" if metric == :earnings
235
- Collections::Reports.of(self).tap{|reports| reports.metric = query}
281
+ metrics = {metric => type}
282
+ metrics[:estimated_minutes_watched] = Integer if metric == :earnings
283
+ Collections::Reports.of(self).tap{|reports| reports.metrics = metrics}
236
284
  end
237
285
  private "all_#{metric}"
238
286
  end
@@ -4,21 +4,22 @@ module Yt
4
4
  module Collections
5
5
  # @private
6
6
  class Reports < Base
7
- DIMENSIONS = Hash.new({name: 'day', parse: ->(day, *values) {[Date.iso8601(day), values.last]} }).tap do |hash|
8
- hash[:range] = {parse: ->(*values) { [:total, values.last]} }
9
- hash[:traffic_source] = {name: 'insightTrafficSourceType', parse: ->(source, value) {[TRAFFIC_SOURCES.key(source), value]} }
10
- hash[:playback_location] = {name: 'insightPlaybackLocationType', parse: ->(location, value) {[PLAYBACK_LOCATIONS.key(location), value]} }
11
- hash[:embedded_player_location] = {name: 'insightPlaybackLocationDetail', parse: ->(url, value) {[url, value]} }
12
- hash[:related_video] = {name: 'insightTrafficSourceDetail', parse: ->(video_id, value) { [Yt::Video.new(id: video_id, auth: @auth), value] } }
13
- hash[:search_term] = {name: 'insightTrafficSourceDetail', parse: ->(search_term, value) { [search_term, value] } }
14
- hash[:video] = {name: 'video', parse: ->(video_id, value) { [Yt::Video.new(id: video_id, auth: @auth), value] } }
15
- hash[:playlist] = {name: 'playlist', parse: ->(playlist_id, value) { [Yt::Playlist.new(id: playlist_id, auth: @auth), value] } }
16
- hash[:device_type] = {name: 'deviceType', parse: ->(type, value) { [type.downcase.to_sym, value] } }
17
- hash[:country] = {name: 'country', parse: ->(country_code, *values) { [country_code, values.last] } }
18
- hash[:state] = {name: 'province', parse: ->(country_and_state_code, *values) { [country_and_state_code[3..-1], values.last] } }
7
+ DIMENSIONS = Hash.new({name: 'day', parse: ->(day, *values) { @metrics.keys.zip(values.map{|v| {Date.iso8601(day) => v}}).to_h} }).tap do |hash|
8
+ hash[:month] = {name: 'month', parse: ->(month, *values) { @metrics.keys.zip(values.map{|v| {Range.new(Date.strptime(month, '%Y-%m').beginning_of_month, Date.strptime(month, '%Y-%m').end_of_month) => v} }).to_h} }
9
+ hash[:range] = {parse: ->(*values) { @metrics.keys.zip(values.map{|v| {total: v}}).to_h } }
10
+ hash[:traffic_source] = {name: 'insightTrafficSourceType', parse: ->(source, *values) { @metrics.keys.zip(values.map{|v| {TRAFFIC_SOURCES.key(source) => v}}).to_h} }
11
+ hash[:playback_location] = {name: 'insightPlaybackLocationType', parse: ->(location, *values) { @metrics.keys.zip(values.map{|v| {PLAYBACK_LOCATIONS.key(location) => v}}).to_h} }
12
+ hash[:embedded_player_location] = {name: 'insightPlaybackLocationDetail', parse: ->(url, *values) {@metrics.keys.zip(values.map{|v| {url => v}}).to_h} }
13
+ hash[:related_video] = {name: 'insightTrafficSourceDetail', parse: ->(video_id, *values) { @metrics.keys.zip(values.map{|v| {Yt::Video.new(id: video_id, auth: @auth) => v}}).to_h} }
14
+ hash[:search_term] = {name: 'insightTrafficSourceDetail', parse: ->(search_term, *values) {@metrics.keys.zip(values.map{|v| {search_term => v}}).to_h} }
15
+ hash[:video] = {name: 'video', parse: ->(video_id, *values) { @metrics.keys.zip(values.map{|v| {Yt::Video.new(id: video_id, auth: @auth) => v}}).to_h} }
16
+ hash[:playlist] = {name: 'playlist', parse: ->(playlist_id, *values) { @metrics.keys.zip(values.map{|v| {Yt::Playlist.new(id: playlist_id, auth: @auth) => v}}).to_h} }
17
+ hash[:device_type] = {name: 'deviceType', parse: ->(type, *values) {@metrics.keys.zip(values.map{|v| {type.downcase.to_sym => v}}).to_h} }
18
+ hash[:country] = {name: 'country', parse: ->(country_code, *values) { @metrics.keys.zip(values.map{|v| {country_code => v}}).to_h} }
19
+ hash[:state] = {name: 'province', parse: ->(country_and_state_code, *values) { @metrics.keys.zip(values.map{|v| {country_and_state_code[3..-1] => v}}).to_h} }
19
20
  hash[:gender_age_group] = {name: 'gender,ageGroup', parse: ->(gender, *values) { [gender.downcase.to_sym, *values] }}
20
- hash[:gender] = {name: 'gender', parse: ->(gender, value) { [gender.downcase.to_sym, value] } }
21
- hash[:age_group] = {name: 'ageGroup', parse: ->(age_group, value) { [age_group[3..-1], value] } }
21
+ hash[:gender] = {name: 'gender', parse: ->(gender, *values) {@metrics.keys.zip(values.map{|v| {gender.downcase.to_sym => v}}).to_h} }
22
+ hash[:age_group] = {name: 'ageGroup', parse: ->(age_group, *values) {@metrics.keys.zip(values.map{|v| {age_group[3..-1] => v}}).to_h} }
22
23
  end
23
24
 
24
25
  # @see https://developers.google.com/youtube/analytics/v1/dimsmets/dims#Traffic_Source_Dimensions
@@ -49,9 +50,9 @@ module Yt
49
50
  mobile: 'MOBILE' # only present for data < September 10, 2013
50
51
  }
51
52
 
52
- attr_writer :metric
53
+ attr_writer :metrics
53
54
 
54
- def within(days_range, country, state, dimension, type, try_again = true)
55
+ def within(days_range, country, state, dimension, try_again = true)
55
56
  @days_range = days_range
56
57
  @dimension = dimension
57
58
  @country = country
@@ -61,7 +62,18 @@ module Yt
61
62
  each{|gender, age_group, value| hash[gender][age_group[3..-1]] = value}
62
63
  end
63
64
  else
64
- Hash[*flat_map{|value| [value.first, type_cast(value.last, type)]}]
65
+ hash = flat_map do |hashes|
66
+ hashes.map do |metric, values|
67
+ [metric, values.transform_values{|v| type_cast(v, @metrics[metric])}]
68
+ end.to_h
69
+ end
70
+ hash = hash.inject(@metrics.transform_values{|v| {}}) do |result, hash|
71
+ result.deep_merge hash
72
+ end
73
+ if dimension == :month
74
+ hash = hash.transform_values{|h| h.sort_by{|range, v| range.first}.to_h}
75
+ end
76
+ (@metrics.one? || @metrics.keys == [:earnings, :estimated_minutes_watched]) ? hash[@metrics.keys.first] : hash
65
77
  end
66
78
  # NOTE: Once in a while, YouTube responds with 400 Error and the message
67
79
  # "Invalid query. Query did not conform to the expectations."; in this
@@ -70,7 +82,7 @@ module Yt
70
82
  # same query is a workaround that works and can hardly cause any damage.
71
83
  # Similarly, once in while YouTube responds with a random 503 error.
72
84
  rescue Yt::Error => e
73
- try_again && rescue?(e) ? sleep(3) && within(days_range, country, state, dimension, type, false) : raise
85
+ try_again && rescue?(e) ? sleep(3) && within(days_range, country, state, dimension, false) : raise
74
86
  end
75
87
 
76
88
  private
@@ -99,12 +111,12 @@ module Yt
99
111
  @parent.reports_params.tap do |params|
100
112
  params['start-date'] = @days_range.begin
101
113
  params['end-date'] = @days_range.end
102
- params['metrics'] = @metric.to_s.camelize(:lower)
114
+ params['metrics'] = @metrics.keys.join(',').to_s.camelize(:lower)
103
115
  params['dimensions'] = DIMENSIONS[@dimension][:name] unless @dimension == :range
104
116
  params['max-results'] = 10 if @dimension == :video
105
117
  params['max-results'] = 200 if @dimension == :playlist
106
118
  params['max-results'] = 25 if @dimension.in? [:embedded_player_location, :related_video, :search_term]
107
- params['sort'] = "-#{@metric.to_s.camelize(:lower)}" if @dimension.in? [:video, :playlist, :embedded_player_location, :related_video, :search_term]
119
+ params['sort'] = "-#{@metrics.keys.join(',').to_s.camelize(:lower)}" if @dimension.in? [:video, :playlist, :embedded_player_location, :related_video, :search_term]
108
120
  params[:filters] = ((params[:filters] || '').split(';') + ["country==US"]).compact.uniq.join(';') if @dimension == :state && !@state
109
121
  params[:filters] = ((params[:filters] || '').split(';') + ["country==#{@country}"]).compact.uniq.join(';') if @country && !@state
110
122
  params[:filters] = ((params[:filters] || '').split(';') + ["province==US-#{@state}"]).compact.uniq.join(';') if @state
@@ -103,6 +103,8 @@ module Yt
103
103
 
104
104
  ### ANALYTICS ###
105
105
 
106
+ # @macro reports
107
+
106
108
  # @macro report_by_channel_dimensions
107
109
  has_report :views, Integer
108
110
 
@@ -151,6 +151,8 @@ module Yt
151
151
 
152
152
  ### ANALYTICS ###
153
153
 
154
+ # @macro reports
155
+
154
156
  # @macro report_by_playlist_dimensions
155
157
  has_report :views, Integer
156
158
 
@@ -372,6 +372,8 @@ module Yt
372
372
 
373
373
  ### ANALYTICS ###
374
374
 
375
+ # @macro reports
376
+
375
377
  # @macro report_by_video_dimensions
376
378
  has_report :views, Integer
377
379
 
@@ -1,3 +1,3 @@
1
1
  module Yt
2
- VERSION = '0.23.0'
2
+ VERSION = '0.23.1'
3
3
  end
@@ -3,13 +3,13 @@ require 'yt/collections/reports'
3
3
  require 'yt/models/content_owner'
4
4
 
5
5
  describe Yt::Collections::Reports do
6
- subject(:reports) { Yt::Collections::Reports.new parent: content_owner }
6
+ subject(:reports) { Yt::Collections::Reports.new(parent: content_owner).tap{|reports| reports.metrics = {views: Integer}} }
7
7
  let(:content_owner) { Yt::ContentOwner.new owner_name: 'any-name' }
8
8
  let(:error){ {reason: reason, message: message} }
9
9
  let(:msg) { {response_body: {error: {errors: [error]}}}.to_json }
10
10
 
11
11
  describe '#within' do
12
- let(:result) { reports.within Range.new(5.days.ago, 4.days.ago), nil, nil, :day, Float }
12
+ let(:result) { reports.within Range.new(5.days.ago, 4.days.ago), nil, nil, :day }
13
13
  context 'given the request raises error 400 with "Invalid Query" message' do
14
14
  let(:reason) { 'badRequest' }
15
15
  let(:message) { 'Invalid query. Query did not conform to the expectations' }
@@ -22,7 +22,7 @@ describe Yt::Collections::Reports do
22
22
  end
23
23
 
24
24
  context 'but returns a success code 2XX the second time' do
25
- before { try_again.and_return [[1,2]] }
25
+ before { try_again.and_return [views: {total: 20}] }
26
26
  it { expect{result}.not_to fail }
27
27
  end
28
28
  end
@@ -10,6 +10,39 @@ describe Yt::Channel, :partner do
10
10
  context 'managed by the authenticated Content Owner' do
11
11
  let(:id) { ENV['YT_TEST_PARTNER_CHANNEL_ID'] }
12
12
 
13
+ describe 'multiple reports can be retrieved at once' do
14
+ metrics = {views: Integer, uniques: Integer,
15
+ estimated_minutes_watched: Float, comments: Integer, likes: Integer,
16
+ dislikes: Integer, shares: Integer, subscribers_gained: Integer,
17
+ subscribers_lost: Integer, favorites_added: Integer,
18
+ favorites_removed: Integer, average_view_duration: Float,
19
+ average_view_percentage: Float, annotation_clicks: Integer,
20
+ annotation_click_through_rate: Float,
21
+ annotation_close_rate: Float, earnings: Float, impressions: Integer,
22
+ monetized_playbacks: Integer}
23
+
24
+ specify 'by day' do
25
+ range = {since: 5.days.ago.to_date, until: 3.days.ago.to_date}
26
+ result = channel.reports range.merge(only: metrics, by: :day)
27
+ metrics.each do |metric, type|
28
+ expect(result[metric].keys).to all(be_a Date)
29
+ expect(result[metric].values).to all(be_a type)
30
+ end
31
+ end
32
+
33
+ specify 'by month' do
34
+ result = channel.reports only: metrics, by: :month, since: 1.month.ago
35
+ metrics.each do |metric, type|
36
+ expect(result[metric].keys).to all(be_a Range)
37
+ expect(result[metric].keys.map &:first).to all(be_a Date)
38
+ expect(result[metric].keys.map &:first).to eq result[metric].keys.map(&:first).map(&:beginning_of_month)
39
+ expect(result[metric].keys.map &:last).to all(be_a Date)
40
+ expect(result[metric].keys.map &:last).to eq result[metric].keys.map(&:last).map(&:end_of_month)
41
+ expect(result[metric].values).to all(be_a type)
42
+ end
43
+ end
44
+ end
45
+
13
46
  [:views, :uniques, :comments, :likes, :dislikes, :shares,
14
47
  :subscribers_gained, :subscribers_lost, :favorites_added,
15
48
  :favorites_removed, :estimated_minutes_watched, :average_view_duration,
@@ -24,14 +57,32 @@ describe Yt::Channel, :partner do
24
57
 
25
58
  context 'with a given start and end (:since/:until option)' do
26
59
  let(:options) { {by: :day, since: date_in, until: date_out} }
27
- it { expect(result.keys.min).to eq date_in.to_date }
28
- it { expect(result.keys.max).to eq date_out.to_date }
60
+ specify do
61
+ expect(result.keys.min).to eq date_in.to_date
62
+ expect(result.keys.max).to eq date_out.to_date
63
+ end
29
64
  end
30
65
 
31
66
  context 'with a given start and end (:from/:to option)' do
32
67
  let(:options) { {by: :day, from: date_in, to: date_out} }
33
- it { expect(result.keys.min).to eq date_in.to_date }
34
- it { expect(result.keys.max).to eq date_out.to_date }
68
+ specify do
69
+ expect(result.keys.min).to eq date_in.to_date
70
+ expect(result.keys.max).to eq date_out.to_date
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "#{metric} can be grouped by month" do
76
+ let(:metric) { metric }
77
+
78
+ let(:result) { channel.public_send metric, by: :month, since: 3.months.ago }
79
+ specify do
80
+ expect(result.keys).to eq(result.keys.sort_by{|range| range.first})
81
+ expect(result.keys).to all(be_a Range)
82
+ expect(result.keys.map &:first).to all(be_a Date)
83
+ expect(result.keys.map &:first).to eq result.keys.map(&:first).map(&:beginning_of_month)
84
+ expect(result.keys.map &:last).to all(be_a Date)
85
+ expect(result.keys.map &:last).to eq result.keys.map(&:last).map(&:end_of_month)
35
86
  end
36
87
  end
37
88
  end
@@ -59,29 +110,24 @@ describe Yt::Channel, :partner do
59
110
  it { expect(result).to be_nil }
60
111
  end
61
112
  end
62
- end
63
113
 
64
- {views: Integer, comments: Integer, likes: Integer, dislikes: Integer,
65
- shares: Integer, subscribers_gained: Integer, subscribers_lost: Integer,
66
- favorites_added: Integer, favorites_removed: Integer,
67
- estimated_minutes_watched: Float, average_view_duration: Float,
68
- average_view_percentage: Float, impressions: Integer,
69
- monetized_playbacks: Integer, annotation_clicks: Integer,
70
- annotation_click_through_rate: Float, annotation_close_rate: Float,
71
- earnings: Float}.each do |metric, type|
72
114
  describe "#{metric} can be grouped by range" do
73
115
  let(:metric) { metric }
74
116
 
75
117
  context 'without a :by option (default)' do
76
118
  let(:result) { channel.public_send metric }
77
- it { expect(result.size).to be 1 }
78
- it { expect(result[:total]).to be_a type }
119
+ specify do
120
+ expect(result.size).to be 1
121
+ expect(result[:total]).to be_a type
122
+ end
79
123
  end
80
124
 
81
125
  context 'with the :by option set to :range' do
82
126
  let(:result) { channel.public_send metric, by: :range }
83
- it { expect(result.size).to be 1 }
84
- it { expect(result[:total]).to be_a type }
127
+ specify do
128
+ expect(result.size).to be 1
129
+ expect(result[:total]).to be_a type
130
+ end
85
131
  end
86
132
  end
87
133
  end
@@ -1398,7 +1444,7 @@ describe Yt::Channel, :partner do
1398
1444
  end
1399
1445
 
1400
1446
  describe 'annotation clicks can be grouped by country' do
1401
- let(:range) { {since: 4.days.ago, until: 3.days.ago} }
1447
+ let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
1402
1448
 
1403
1449
  specify 'with the :by option set to :country' do
1404
1450
  clicks = channel.annotation_clicks range.merge by: :country
@@ -1409,7 +1455,7 @@ describe Yt::Channel, :partner do
1409
1455
  end
1410
1456
 
1411
1457
  describe 'annotation clicks can be grouped by state' do
1412
- let(:range) { {since: 4.days.ago, until: 3.days.ago} }
1458
+ let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
1413
1459
 
1414
1460
  specify 'with the :by option set to :state' do
1415
1461
  clicks = channel.annotation_clicks range.merge by: :state
@@ -1508,7 +1554,7 @@ describe Yt::Channel, :partner do
1508
1554
  end
1509
1555
 
1510
1556
  describe 'annotation click-through rate can be grouped by state' do
1511
- let(:range) { {since: 4.days.ago, until: 3.days.ago} }
1557
+ let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
1512
1558
 
1513
1559
  specify 'with the :by option set to :state' do
1514
1560
  rate = channel.annotation_click_through_rate range.merge by: :state
@@ -10,8 +10,36 @@ describe Yt::Playlist, :partner do
10
10
  context 'managed by the authenticated Content Owner' do
11
11
  let(:id) { ENV['YT_TEST_PARTNER_PLAYLIST_ID'] }
12
12
 
13
- [:views, :estimated_minutes_watched, :average_view_duration,
14
- :playlist_starts, :average_time_in_playlist, :views_per_playlist_start].each do |metric|
13
+ describe 'multiple reports can be retrieved at once' do
14
+ metrics = {views: Integer, estimated_minutes_watched: Float,
15
+ average_view_duration: Float, playlist_starts: Integer,
16
+ average_time_in_playlist: Float, views_per_playlist_start: Float}
17
+
18
+ specify 'by day' do
19
+ range = {since: 5.days.ago.to_date, until: 3.days.ago.to_date}
20
+ result = playlist.reports range.merge(only: metrics, by: :day)
21
+ metrics.each do |metric, type|
22
+ expect(result[metric].keys).to all(be_a Date)
23
+ expect(result[metric].values).to all(be_a type)
24
+ end
25
+ end
26
+
27
+ specify 'by month' do
28
+ result = playlist.reports only: metrics, by: :month, since: 1.month.ago
29
+ metrics.each do |metric, type|
30
+ expect(result[metric].keys).to all(be_a Range)
31
+ expect(result[metric].keys.map &:first).to all(be_a Date)
32
+ expect(result[metric].keys.map &:first).to eq result[metric].keys.map(&:first).map(&:beginning_of_month)
33
+ expect(result[metric].keys.map &:last).to all(be_a Date)
34
+ expect(result[metric].keys.map &:last).to eq result[metric].keys.map(&:last).map(&:end_of_month)
35
+ expect(result[metric].values).to all(be_a type)
36
+ end
37
+ end
38
+ end
39
+
40
+ {views: Integer, estimated_minutes_watched: Float, average_view_duration: Float,
41
+ playlist_starts: Integer, average_time_in_playlist: Float,
42
+ views_per_playlist_start: Float}.each do |metric, type|
15
43
  describe "#{metric} can be retrieved for a range of days" do
16
44
  let(:date_in) { ENV['YT_TEST_PARTNER_VIDEO_DATE'] }
17
45
  let(:date_out) { Date.parse(ENV['YT_TEST_PARTNER_VIDEO_DATE']) + 5 }
@@ -20,21 +48,33 @@ describe Yt::Playlist, :partner do
20
48
 
21
49
  context 'with a given start and end (:since/:until option)' do
22
50
  let(:options) { {by: :day, since: date_in, until: date_out} }
23
- it { expect(result.keys.min).to eq date_in.to_date }
24
- it { expect(result.keys.max).to eq date_out.to_date }
51
+ specify do
52
+ expect(result.keys.min).to eq date_in.to_date
53
+ expect(result.keys.max).to eq date_out.to_date
54
+ end
25
55
  end
26
56
 
27
57
  context 'with a given start and end (:from/:to option)' do
28
58
  let(:options) { {by: :day, from: date_in, to: date_out} }
29
- it { expect(result.keys.min).to eq date_in.to_date }
30
- it { expect(result.keys.max).to eq date_out.to_date }
59
+ specify do
60
+ expect(result.keys.min).to eq date_in.to_date
61
+ expect(result.keys.max).to eq date_out.to_date
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "#{metric} can be grouped by month" do
67
+ let(:metric) { metric }
68
+ let(:result) { playlist.public_send metric, by: :month, since: 1.month.ago }
69
+ specify do
70
+ expect(result.keys).to all(be_a Range)
71
+ expect(result.keys.map &:first).to all(be_a Date)
72
+ expect(result.keys.map &:first).to eq result.keys.map(&:first).map(&:beginning_of_month)
73
+ expect(result.keys.map &:last).to all(be_a Date)
74
+ expect(result.keys.map &:last).to eq result.keys.map(&:last).map(&:end_of_month)
31
75
  end
32
76
  end
33
- end
34
77
 
35
- {views: Integer, estimated_minutes_watched: Float, average_view_duration: Float,
36
- playlist_starts: Integer, average_time_in_playlist: Float,
37
- views_per_playlist_start: Float}.each do |metric, type|
38
78
  describe "#{metric} can be retrieved for a specific day" do
39
79
  let(:metric) { metric }
40
80
  let(:result) { playlist.public_send "#{metric}_on", date }
@@ -55,14 +95,18 @@ describe Yt::Playlist, :partner do
55
95
 
56
96
  context 'without a :by option (default)' do
57
97
  let(:result) { playlist.public_send metric }
58
- it { expect(result.size).to be 1 }
59
- it { expect(result[:total]).to be_a type }
98
+ specify do
99
+ expect(result.size).to be 1
100
+ expect(result[:total]).to be_a type
101
+ end
60
102
  end
61
103
 
62
104
  context 'with the :by option set to :range' do
63
105
  let(:result) { playlist.public_send metric, by: :range }
64
- it { expect(result.size).to be 1 }
65
- it { expect(result[:total]).to be_a type }
106
+ specify do
107
+ expect(result.size).to be 1
108
+ expect(result[:total]).to be_a type
109
+ end
66
110
  end
67
111
  end
68
112
 
@@ -27,14 +27,50 @@ describe Yt::Video, :partner do
27
27
 
28
28
  context 'with a given start and end (:since/:until option)' do
29
29
  let(:options) { {by: :day, since: date_in, until: date_out} }
30
- it { expect(result.keys.min).to eq date_in.to_date }
31
- it { expect(result.keys.max).to eq date_out.to_date }
30
+ specify do
31
+ expect(result.keys.min).to eq date_in.to_date
32
+ expect(result.keys.max).to eq date_out.to_date
33
+ end
32
34
  end
33
35
 
34
36
  context 'with a given start and end (:from/:to option)' do
35
37
  let(:options) { {by: :day, from: date_in, to: date_out} }
36
- it { expect(result.keys.min).to eq date_in.to_date }
37
- it { expect(result.keys.max).to eq date_out.to_date }
38
+ specify do
39
+ expect(result.keys.min).to eq date_in.to_date
40
+ expect(result.keys.max).to eq date_out.to_date
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "#{metric} can be grouped by month" do
46
+ let(:metric) { metric }
47
+
48
+ let(:result) { video.public_send metric, by: :month, since: 1.month.ago }
49
+ specify do
50
+ expect(result.keys).to all(be_a Range)
51
+ expect(result.keys.map &:first).to all(be_a Date)
52
+ expect(result.keys.map &:first).to eq result.keys.map(&:first).map(&:beginning_of_month)
53
+ expect(result.keys.map &:last).to all(be_a Date)
54
+ expect(result.keys.map &:last).to eq result.keys.map(&:last).map(&:end_of_month)
55
+ end
56
+ end
57
+
58
+ describe "#{metric} can be retrieved for a single country" do
59
+ let(:result) { video.public_send metric, options }
60
+
61
+ context 'and grouped by day' do
62
+ let(:date_in) { 5.days.ago }
63
+ let(:options) { {by: :day, since: date_in, in: location} }
64
+
65
+ context 'with the :in option set to the country code' do
66
+ let(:location) { 'US' }
67
+ it { expect(result.keys.min).to eq date_in.to_date }
68
+ end
69
+
70
+ context 'with the :in option set to {country: country code}' do
71
+ let(:location) { {country: 'US'} }
72
+ it { expect(result.keys.min).to eq date_in.to_date }
73
+ end
38
74
  end
39
75
  end
40
76
  end
@@ -73,14 +109,18 @@ describe Yt::Video, :partner do
73
109
 
74
110
  context 'without a :by option (default)' do
75
111
  let(:result) { video.public_send metric }
76
- it { expect(result.size).to be 1 }
77
- it { expect(result[:total]).to be_a type }
112
+ specify do
113
+ expect(result.size).to be 1
114
+ expect(result[:total]).to be_a type
115
+ end
78
116
  end
79
117
 
80
118
  context 'with the :by option set to :range' do
81
119
  let(:result) { video.public_send metric, by: :range }
82
- it { expect(result.size).to be 1 }
83
- it { expect(result[:total]).to be_a type }
120
+ specify do
121
+ expect(result.size).to be 1
122
+ expect(result[:total]).to be_a type
123
+ end
84
124
  end
85
125
  end
86
126
  end
@@ -92,39 +132,17 @@ describe Yt::Video, :partner do
92
132
 
93
133
  context 'without a :by option (default)' do
94
134
  let(:result) { video.public_send metric }
95
- it { expect(result.size).to be 1 }
96
- it { expect(result[:total]).to be_a type }
135
+ specify do
136
+ expect(result.size).to be 1
137
+ expect(result[:total]).to be_a type
138
+ end
97
139
  end
98
140
 
99
141
  context 'with the :by option set to :range' do
100
142
  let(:result) { video.public_send metric, by: :range }
101
- it { expect(result.size).to be 1 }
102
- it { expect(result[:total]).to be_a type }
103
- end
104
- end
105
- end
106
-
107
- [:views, :uniques, :comments, :likes, :dislikes, :shares,
108
- :subscribers_gained, :subscribers_lost, :favorites_added,
109
- :favorites_removed, :estimated_minutes_watched, :average_view_duration,
110
- :average_view_percentage, :impressions, :monetized_playbacks,
111
- :annotation_clicks, :annotation_click_through_rate,
112
- :annotation_close_rate, :earnings].each do |metric|
113
- describe "#{metric} can be retrieved for a single country" do
114
- let(:result) { video.public_send metric, options }
115
-
116
- context 'and grouped by day' do
117
- let(:date_in) { 5.days.ago }
118
- let(:options) { {by: :day, since: date_in, in: location} }
119
-
120
- context 'with the :in option set to the country code' do
121
- let(:location) { 'US' }
122
- it { expect(result.keys.min).to eq date_in.to_date }
123
- end
124
-
125
- context 'with the :in option set to {country: country code}' do
126
- let(:location) { {country: 'US'} }
127
- it { expect(result.keys.min).to eq date_in.to_date }
143
+ specify do
144
+ expect(result.size).to be 1
145
+ expect(result[:total]).to be_a type
128
146
  end
129
147
  end
130
148
  end
@@ -176,6 +194,39 @@ describe Yt::Video, :partner do
176
194
  end
177
195
  end
178
196
 
197
+ describe 'multiple reports can be retrieved at once' do
198
+ metrics = {views: Integer, uniques: Integer,
199
+ estimated_minutes_watched: Float, comments: Integer, likes: Integer,
200
+ dislikes: Integer, shares: Integer, subscribers_gained: Integer,
201
+ subscribers_lost: Integer, favorites_added: Integer,
202
+ favorites_removed: Integer, average_view_duration: Float,
203
+ average_view_percentage: Float, annotation_clicks: Integer,
204
+ annotation_click_through_rate: Float,
205
+ annotation_close_rate: Float, earnings: Float, impressions: Integer,
206
+ monetized_playbacks: Integer}
207
+
208
+ specify 'by day' do
209
+ range = {since: 5.days.ago.to_date, until: 3.days.ago.to_date}
210
+ result = video.reports range.merge(only: metrics, by: :day)
211
+ metrics.each do |metric, type|
212
+ expect(result[metric].keys).to all(be_a Date)
213
+ expect(result[metric].values).to all(be_a type)
214
+ end
215
+ end
216
+
217
+ specify 'by month' do
218
+ result = video.reports only: metrics, by: :month, since: 1.month.ago
219
+ metrics.each do |metric, type|
220
+ expect(result[metric].keys).to all(be_a Range)
221
+ expect(result[metric].keys.map &:first).to all(be_a Date)
222
+ expect(result[metric].keys.map &:first).to eq result[metric].keys.map(&:first).map(&:beginning_of_month)
223
+ expect(result[metric].keys.map &:last).to all(be_a Date)
224
+ expect(result[metric].keys.map &:last).to eq result[metric].keys.map(&:last).map(&:end_of_month)
225
+ expect(result[metric].values).to all(be_a type)
226
+ end
227
+ end
228
+ end
229
+
179
230
  describe 'earnings can be grouped by day' do
180
231
  let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
181
232
  let(:keys) { range.values }
@@ -271,7 +322,7 @@ describe Yt::Video, :partner do
271
322
  end
272
323
 
273
324
  describe 'views can be grouped by related video' do
274
- let(:range) { {since: 4.days.ago, until: 3.days.ago} }
325
+ let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
275
326
 
276
327
  specify 'with the :by option set to :related_video' do
277
328
  views = video.views range.merge by: :related_video
@@ -280,7 +331,7 @@ describe Yt::Video, :partner do
280
331
  end
281
332
 
282
333
  describe 'views can be grouped by search term' do
283
- let(:range) { {since: 4.days.ago, until: 3.days.ago} }
334
+ let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
284
335
 
285
336
  specify 'with the :by option set to :search_term' do
286
337
  views = video.views range.merge by: :search_term
@@ -289,7 +340,7 @@ describe Yt::Video, :partner do
289
340
  end
290
341
 
291
342
  describe 'views can be grouped by device type' do
292
- let(:range) { {since: 4.days.ago, until: 3.days.ago} }
343
+ let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
293
344
 
294
345
  specify 'with the :by option set to :device_type' do
295
346
  views = video.views range.merge by: :device_type
@@ -299,7 +350,7 @@ describe Yt::Video, :partner do
299
350
  end
300
351
 
301
352
  describe 'views can be grouped by country' do
302
- let(:range) { {since: 4.days.ago, until: 3.days.ago} }
353
+ let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
303
354
 
304
355
  specify 'with the :by option set to :country' do
305
356
  views = video.views range.merge by: :country
@@ -310,7 +361,7 @@ describe Yt::Video, :partner do
310
361
  end
311
362
 
312
363
  describe 'views can be grouped by state' do
313
- let(:range) { {since: 4.days.ago, until: 3.days.ago} }
364
+ let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
314
365
 
315
366
  specify 'with the :by option set to :state' do
316
367
  views = video.views range.merge by: :state
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.0
4
+ version: 0.23.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claudio Baccigalupo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-18 00:00:00.000000000 Z
11
+ date: 2015-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport