leaderboard 3.10.0 → 3.11.0

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: 0e2258ac4147cfe36d76299662c67d8ac5f360de
4
- data.tar.gz: 50896b7f86ae70b0339551f8b0afd5ce32383353
3
+ metadata.gz: 3f0aeb0cd68034cf6d268f8f1d8d4e8a39c0df66
4
+ data.tar.gz: 4576a03574ab9f93200d11ab861b9b3203a179dc
5
5
  SHA512:
6
- metadata.gz: dba84526f444d7494f2ea0a21ec8e8fd90b408f7477c1a9abe06cc6f9ff688f90e17935bebbdb71ca2261593608e61b610d8441cda7d161dda74306294308bed
7
- data.tar.gz: 5c25f504a4ba53fcdc109692a82b09b50fef8711ab3521b9a2a9d303c3dd9a83caa305297df510974029c5d4ba98bf696d515a6411025b82c5bc7c9f34950093
6
+ metadata.gz: ac3cc4247ea3c1ca634375112b2614dbe18a1d1a8ab818f08c2f27fe1c1167dea897b95eb7014704a81c0a9303ed03865537837f0eb7efed8bd1b34e8990de1e
7
+ data.tar.gz: 68128561ee0b7d89d929c251d19b5463ca836325d15a1a163a48e370dba1a39e8475106c7575d9ddbc0ea04dcdbeb8c544e88512879ca25805d124f023ae2b6a
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 3.11.0 (2016-09-16)
4
+
5
+ * More pipelining [#58](https://github.com/agoragames/leaderboard/pull/58).
6
+ Also adds `members_data_for(...) and `members_data_for_in(...)` methods.
7
+ * Guard against an out of bounds index in `member_at`
8
+
3
9
  ## 3.10.0 (2015-03-20)
4
10
 
5
11
  * Fixes TieRankingLeaderboard doesn't rank if the score is 0 [#53](https://github.com/agoragames/leaderboard/issues/53).
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011-2014 David Czarnecki
1
+ Copyright (c) 2011-2016 David Czarnecki
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -21,7 +21,9 @@ check out the [Redis documentation](http://redis.io/documentation).
21
21
 
22
22
  ## Compatibility
23
23
 
24
- The gem has been built and tested under Ruby 1.9.3 and Ruby 2.1.2.
24
+ The gem has been built and tested under 2.2.1.
25
+
26
+ NOTE: The gem should work fine in earlier versions of Ruby such as 1.8.7 or 1.9.3. There are no specific aspects of Ruby 2.x that we utilize at this time.
25
27
 
26
28
  ## Usage
27
29
 
@@ -184,6 +186,7 @@ You can pass various options to the calls `leaders`, `all_leaders`, `around_me`,
184
186
  * `:page_size` - An integer value to change the page size for that call.
185
187
  * `:members_only` - `true` or `false` (default) to return only the members without their score and rank.
186
188
  * `:sort_by` - Valid values for `:sort_by` are `:none` (default), `:score` and `:rank`.
189
+ * `:include_missing` - `true` (default) or `false` to return members that are not ranked.
187
190
 
188
191
  You can also use the `members` and `members_in` methods as aliases for the `leaders` and `leaders_in` methods.
189
192
 
@@ -340,6 +343,7 @@ Competition ranking: The `CompetitionRankingLeaderboard` subclass of `Leaderboar
340
343
  ```
341
344
  delete_leaderboard: Delete the current leaderboard
342
345
  member_data_for(member): Retrieve the optional member data for a given member in the leaderboard
346
+ members_data_for(members): Retrieve the optional member data for a given list of members in the leaderboard
343
347
  update_member_data(member, member_data): Update the optional member data for a given member in the leaderboard
344
348
  remove_member_data(member): Remove the optional member data for a given member in the leaderboard
345
349
  remove_member(member): Remove a member from the leaderboard
@@ -482,5 +486,5 @@ Unofficially supported (they need some feature parity love):
482
486
 
483
487
  ## Copyright
484
488
 
485
- Copyright (c) 2011-2014 David Czarnecki. See LICENSE.txt for further details.
489
+ Copyright (c) 2011-2016 David Czarnecki. See LICENSE.txt for further details.
486
490
 
@@ -67,29 +67,36 @@ class CompetitionRankingLeaderboard < Leaderboard
67
67
  end
68
68
  end unless leaderboard_options[:members_only]
69
69
 
70
+ included_members = []
71
+ scores = []
72
+
70
73
  members.each_with_index do |member, index|
71
74
  data = {}
72
75
  data[@member_key] = member
73
76
  unless leaderboard_options[:members_only]
74
77
  data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1]
78
+
75
79
  if data[@score_key] == nil
76
80
  next unless leaderboard_options[:include_missing]
77
81
  end
78
-
79
- if @reverse
80
- data[@rank_key] = @redis_connection.zcount(leaderboard_name, '-inf', "(#{data[@score_key]}") + 1 rescue nil
81
- else
82
- data[@rank_key] = @redis_connection.zcount(leaderboard_name, "(#{data[@score_key]}", '+inf') + 1 rescue nil
83
- end
84
82
  end
85
83
 
86
- if leaderboard_options[:with_member_data]
87
- data[@member_data_key] = member_data_for_in(leaderboard_name, member)
88
- end
84
+ included_members << member
85
+ scores << data[@score_key]
89
86
 
90
87
  ranks_for_members << data
91
88
  end
92
89
 
90
+ if leaderboard_options[:with_member_data]
91
+ members_data_for_in(leaderboard_name, included_members).each_with_index do |member_data, index|
92
+ ranks_for_members[index][@member_data_key] = member_data
93
+ end
94
+ end
95
+
96
+ rankings_for_members_having_scores_in(leaderboard_name, included_members, scores).each_with_index do |rank, index|
97
+ ranks_for_members[index][@rank_key] = rank
98
+ end
99
+
93
100
  case leaderboard_options[:sort_by]
94
101
  when :rank
95
102
  ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] }
@@ -99,4 +106,26 @@ class CompetitionRankingLeaderboard < Leaderboard
99
106
 
100
107
  ranks_for_members
101
108
  end
102
- end
109
+
110
+ protected
111
+
112
+ # Retrieve a list of the rankings of leaders given their member names and scores
113
+ #
114
+ # @param leaderboard_name [String] Name of the leaderboard.
115
+ # @param members [Array] Member names.
116
+ # @param scores [Array] a list of scores for the members, aligned with the member names
117
+ #
118
+ # @return a list of the rankings for the passed in members and scores
119
+ def rankings_for_members_having_scores_in(leaderboard_name, members, scores)
120
+ @redis_connection.multi do |transaction|
121
+ members.each_with_index do |member, index|
122
+ if @reverse
123
+ transaction.zcount(leaderboard_name, '-inf', "(#{scores[index]}")
124
+ else
125
+ transaction.zcount(leaderboard_name, "(#{scores[index]}", '+inf')
126
+ end
127
+ end
128
+ end.map{|rank| rank ? rank + 1 : rank}
129
+ end
130
+
131
+ end
@@ -219,6 +219,26 @@ class Leaderboard
219
219
  @redis_connection.hget(member_data_key(leaderboard_name), member)
220
220
  end
221
221
 
222
+ # Retrieve the optional member data for a given member in the named leaderboard.
223
+ #
224
+ # @param leaderboard_name [String] Name of the leaderboard.
225
+ # @param members [Array] Member names.
226
+ #
227
+ # @return array of strings of optional member data.
228
+ def members_data_for_in(leaderboard_name, members)
229
+ return [] unless members.size > 0
230
+ @redis_connection.hmget(member_data_key(leaderboard_name), *members)
231
+ end
232
+
233
+ # Retrieve the optional member data for the given members in the leaderboard.
234
+ #
235
+ # @param members [Array] Member names.
236
+ #
237
+ # @return array of strings of optional member data.
238
+ def members_data_for(members)
239
+ members_data_for_in(@leaderboard_name, members)
240
+ end
241
+
222
242
  # Update the optional member data for a given member in the leaderboard.
223
243
  #
224
244
  # @param member [String] Member name.
@@ -860,7 +880,7 @@ class Leaderboard
860
880
  #
861
881
  # @return a page of leaders from the named leaderboard.
862
882
  def member_at_in(leaderboard_name, position, options = {})
863
- if position <= total_members_in(leaderboard_name)
883
+ if position > 0 && position <= total_members_in(leaderboard_name)
864
884
  leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
865
885
  leaderboard_options.merge!(options)
866
886
  page_size = validate_page_size(leaderboard_options[:page_size]) || @page_size
@@ -964,13 +984,15 @@ class Leaderboard
964
984
  data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1]
965
985
  end
966
986
 
967
- if leaderboard_options[:with_member_data]
968
- data[@member_data_key] = member_data_for_in(leaderboard_name, member)
969
- end
970
-
971
987
  ranks_for_members << data
972
988
  end
973
989
 
990
+ if leaderboard_options[:with_member_data]
991
+ members_data_for_in(leaderboard_name, members).each_with_index do |member_data, index|
992
+ ranks_for_members[index][@member_data_key] = member_data
993
+ end
994
+ end
995
+
974
996
  case leaderboard_options[:sort_by]
975
997
  when :rank
976
998
  ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] }
@@ -1,3 +1,3 @@
1
1
  class Leaderboard
2
- VERSION = '3.10.0'.freeze
2
+ VERSION = '3.11.0'.freeze
3
3
  end
@@ -249,13 +249,15 @@ class TieRankingLeaderboard < Leaderboard
249
249
  end
250
250
  end
251
251
 
252
- if leaderboard_options[:with_member_data]
253
- data[@member_data_key] = member_data_for_in(leaderboard_name, member)
254
- end
255
-
256
252
  ranks_for_members << data
257
253
  end
258
254
 
255
+ if leaderboard_options[:with_member_data]
256
+ members_data_for_in(leaderboard_name, members).each_with_index do |member_data, index|
257
+ ranks_for_members[index][@member_data_key] = member_data
258
+ end
259
+ end
260
+
259
261
  case leaderboard_options[:sort_by]
260
262
  when :rank
261
263
  ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] }
@@ -199,6 +199,14 @@ describe 'Leaderboard' do
199
199
  expect(@leaderboard.member_data_for('member_id')).to eq({'username' => 'member_name', 'other_data_key' => 'other_data_value'}.to_s)
200
200
  end
201
201
 
202
+ it 'should allow you to retrieve optional member data for multiple members' do
203
+ rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE)
204
+
205
+ members_data = @leaderboard.members_data_for(['member_1', 'member_3'])
206
+ expect(members_data[0]).to eq({:member_name => 'Leaderboard member 1'}.to_s)
207
+ expect(members_data[1]).to eq({:member_name => 'Leaderboard member 3'}.to_s)
208
+ end
209
+
202
210
  it 'should allow you to update optional member data' do
203
211
  @leaderboard.rank_member('member_id', 1, {'username' => 'member_name'})
204
212
 
@@ -234,6 +242,12 @@ describe 'Leaderboard' do
234
242
  expect(@leaderboard.member_at(1, :with_member_data => true)[:member_data]).to eq({:member_name => 'Leaderboard member 50'}.to_s)
235
243
  end
236
244
 
245
+ it 'should not return a single member when calling member_at with a position < 0' do
246
+ rank_members_in_leaderboard(5)
247
+ expect(@leaderboard.member_at(1)[:rank]).to eql(1)
248
+ expect(@leaderboard.member_at(-5)).to be nil
249
+ end
250
+
237
251
  it 'should return the correct information when calling around_me' do
238
252
  rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1)
239
253
 
@@ -2,6 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  describe 'Leaderboard::VERSION' do
4
4
  it 'should be the correct version' do
5
- expect(Leaderboard::VERSION).to eq('3.10.0')
5
+ expect(Leaderboard::VERSION).to eq('3.11.0')
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leaderboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.10.0
4
+ version: 3.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Czarnecki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-20 00:00:00.000000000 Z
11
+ date: 2016-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis