yt 0.23.0 → 0.23.1

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