rest-gw2 0.4.0 → 0.5.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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES.md +30 -0
  3. data/README.md +7 -3
  4. data/Rakefile +1 -0
  5. data/TODO.md +26 -0
  6. data/config.ru +6 -0
  7. data/lib/rest-gw2.rb +1 -0
  8. data/lib/rest-gw2/client.rb +249 -110
  9. data/lib/rest-gw2/client/item_detail.rb +80 -0
  10. data/lib/rest-gw2/server.rb +5 -583
  11. data/lib/rest-gw2/server/action.rb +283 -0
  12. data/lib/rest-gw2/server/cache.rb +14 -4
  13. data/lib/rest-gw2/server/imp.rb +270 -0
  14. data/lib/rest-gw2/server/runner.rb +1 -0
  15. data/lib/rest-gw2/server/view.rb +309 -0
  16. data/lib/rest-gw2/{view → server/view}/characters.erb +10 -6
  17. data/lib/rest-gw2/server/view/check_list.erb +10 -0
  18. data/lib/rest-gw2/server/view/check_percentage.erb +9 -0
  19. data/lib/rest-gw2/server/view/commerce.erb +24 -0
  20. data/lib/rest-gw2/{view → server/view}/dyes.erb +7 -7
  21. data/lib/rest-gw2/server/view/error.erb +1 -0
  22. data/lib/rest-gw2/server/view/exchange.erb +29 -0
  23. data/lib/rest-gw2/server/view/guild_info.erb +37 -0
  24. data/lib/rest-gw2/{view → server/view}/index.erb +0 -0
  25. data/lib/rest-gw2/{view → server/view}/info.erb +1 -1
  26. data/lib/rest-gw2/{view → server/view}/item_list.erb +0 -0
  27. data/lib/rest-gw2/{view/items.erb → server/view/item_section.erb} +0 -0
  28. data/lib/rest-gw2/{view → server/view}/item_show.erb +7 -1
  29. data/lib/rest-gw2/server/view/items.erb +8 -0
  30. data/lib/rest-gw2/server/view/items_from.erb +35 -0
  31. data/lib/rest-gw2/{view → server/view}/layout.erb +14 -4
  32. data/lib/rest-gw2/server/view/members.erb +23 -0
  33. data/lib/rest-gw2/server/view/menu.erb +13 -0
  34. data/lib/rest-gw2/server/view/menu_armors.erb +17 -0
  35. data/lib/rest-gw2/server/view/menu_commerce.erb +7 -0
  36. data/lib/rest-gw2/server/view/menu_guild.erb +11 -0
  37. data/lib/rest-gw2/server/view/menu_unlocks.erb +11 -0
  38. data/lib/rest-gw2/{view → server/view}/menu_weapons.erb +2 -1
  39. data/lib/rest-gw2/{view → server/view}/pages.erb +2 -2
  40. data/lib/rest-gw2/{view → server/view}/profile.erb +7 -7
  41. data/lib/rest-gw2/server/view/skins.erb +15 -0
  42. data/lib/rest-gw2/server/view/stash.erb +10 -0
  43. data/lib/rest-gw2/server/view/titles.erb +5 -0
  44. data/lib/rest-gw2/server/view/unlock_percentage.erb +1 -0
  45. data/lib/rest-gw2/server/view/unlocks_items.erb +5 -0
  46. data/lib/rest-gw2/server/view/unlocks_list.erb +3 -0
  47. data/lib/rest-gw2/{view → server/view}/wallet.erb +1 -1
  48. data/lib/rest-gw2/server/view/wip.erb +1 -0
  49. data/lib/rest-gw2/version.rb +2 -1
  50. data/rest-gw2.gemspec +43 -25
  51. data/task/README.md +8 -8
  52. data/task/gemgem.rb +29 -7
  53. metadata +42 -25
  54. data/lib/rest-gw2/view/error.erb +0 -1
  55. data/lib/rest-gw2/view/guild.erb +0 -14
  56. data/lib/rest-gw2/view/items_from.erb +0 -30
  57. data/lib/rest-gw2/view/menu.erb +0 -16
  58. data/lib/rest-gw2/view/menu_armors.erb +0 -11
  59. data/lib/rest-gw2/view/skins.erb +0 -14
  60. data/lib/rest-gw2/view/transactions.erb +0 -28
  61. data/lib/rest-gw2/view/wip.erb +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8beaa0b13cd7d66c054200ad4f919a7751e66a1a
4
- data.tar.gz: f48944e1a65d49072bc5bfdab62f739164978670
2
+ SHA256:
3
+ metadata.gz: 6977db172be53997d7f1f299d5961fce2a384d98cd85be0c815adc470437c434
4
+ data.tar.gz: dc9698c8f4d7c93c02dc13425169aaf7b25e8fc871ca56900b7d9ccda707bd25
5
5
  SHA512:
6
- metadata.gz: 06507ee1885c0a5c2ebfe1d050f56541ae5a5168552a527c46d22f5d281fb70ee56a37cec353c10cd6609acca2bc942e808acb58a748283f5470a76d08d3b9f5
7
- data.tar.gz: 4e5346ef0280fba26f7b9ed461a8fc60b2041a147ee4aca8310c095b2b821f60850df728b882e6966ae22507753bcec39092717bc1e5991a4d3293ec16d63de8
6
+ metadata.gz: 3035ba2ffb29c14d572488a582cfc7c5dcc0c4c64474b95bd8bb418703aa559825dac1b71c3c188c671b6b3cf16e3844d3a59574b5ef0f8964297ac4ac8e5365
7
+ data.tar.gz: fb4a98cb8fd9b2c85883af86f001080cee169e9e04eb5d3c72e2c192ea23ae3d70bf34a9dcc0073368ad2b5ff8883b9cdcc15a82a6ea676fad0c39b18204de78
data/CHANGES.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # CHANGES
2
2
 
3
+ ## rest-gw2 0.5.0 -- 2018-12-26
4
+
5
+ * Bunch of performance improvement.
6
+ * Allow setting `ENV['GW2_POOL_SIZE']` to configure pool size.
7
+ * Added `RestGW2::Client#me`
8
+ * Added `RestGW2::Client#guild_members`
9
+ * Added `RestGW2::Client#outfits_with_detail`
10
+ * Added `RestGW2::Client#mailcarriers_with_detail`
11
+ * Added `RestGW2::Client#gliders_with_detail`
12
+ * Added `RestGW2::Client#all_outfits`
13
+ * Added `RestGW2::Client#all_mailcarriers`
14
+ * Added `RestGW2::Client#all_gliders`
15
+ * Added `RestGW2::Client#all_fininshers`
16
+ * Added `RestGW2::Client#all_cats`
17
+ * Added `RestGW2::Client#all_titles`
18
+ * Added `RestGW2::Client#finishers_with_detail`
19
+ * Added `RestGW2::Client#cats_with_detail`
20
+ * Added `RestGW2::Client#nodes_with_detail`
21
+ * Added `RestGW2::Client#titles_with_detail`
22
+ * Added `RestGW2::Client#delivery_with_detail`
23
+ * Added `RestGW2::Client#all_unlocks`
24
+ * Added `RestGW2::Client#unlocks_with_detail`
25
+ * Added `RestGW2::ItemDetail`
26
+ * Show guild_leader for account_with_detail
27
+ * Added a bunch of different unlocks pages
28
+ * Added exchange rate page
29
+ * Show favicon based on the access token
30
+ * Show rarity border for items
31
+ * Show total prices for a particular item
32
+
3
33
  ## rest-gw2 0.4.0 -- 2016-02-05
4
34
 
5
35
  * Added `RestGW2::Client#stash_with_detail`
data/README.md CHANGED
@@ -14,7 +14,7 @@ A very simple [Guild Wars 2 API](https://wiki.guildwars2.com/wiki/API:Main)
14
14
  client built with [rest-core](https://github.com/godfat/rest-core).
15
15
 
16
16
  There's also a bundled web application showing your items, serving as an
17
- example using the client.
17
+ example using the client. There's also a [demo site](https://gw2.godfat.org/)
18
18
 
19
19
  ## FEATURES:
20
20
 
@@ -23,7 +23,7 @@ example using the client.
23
23
 
24
24
  ## REQUIREMENTS:
25
25
 
26
- * Tested with MRI (official CRuby), Rubinius and JRuby.
26
+ * Tested with MRI (official CRuby) and JRuby.
27
27
  * rest-core
28
28
 
29
29
  ### REQUIREMENTS: (if you need the web application)
@@ -94,6 +94,10 @@ The format for the config file would be like:
94
94
  jruby -S rake server
95
95
  jruby -S rake console
96
96
 
97
+ ## Current production script:
98
+
99
+ jruby -Xcompile.invokedynamic=true -J-Xmx1536m -S rake server -- -p PORT -s trinidad
100
+
97
101
  ## CONTRIBUTORS:
98
102
 
99
103
  * Lin Jen-Shin (@godfat)
@@ -102,7 +106,7 @@ The format for the config file would be like:
102
106
 
103
107
  Apache License 2.0
104
108
 
105
- Copyright (c) 2015-2016, Lin Jen-Shin (godfat)
109
+ Copyright (c) 2015-2019, Lin Jen-Shin (godfat)
106
110
 
107
111
  Licensed under the Apache License, Version 2.0 (the "License");
108
112
  you may not use this file except in compliance with the License.
data/Rakefile CHANGED
@@ -21,6 +21,7 @@ desc 'Run server'
21
21
  task 'server' do
22
22
  ARGV.shift
23
23
  load 'bin/rest-gw2'
24
+ Rake.application.top_level_tasks.clear
24
25
  end
25
26
 
26
27
  Gemgem.init(dir) do |s|
data/TODO.md ADDED
@@ -0,0 +1,26 @@
1
+ # Test
2
+
3
+ * Write a Rack app crawler and visit all the pages, and save the responses
4
+ and the cache data from the client. We could have a test to restore the
5
+ cache data for the client, and then visit all the pages again, and compare
6
+ the saved responses and the new responses. They should be identical for
7
+ all (200 OK) pages, of course.
8
+
9
+ # View
10
+
11
+ * Put upgrades and infusions icons in a column, rather than a row.
12
+ * Show upgrades and infusions names and prices.
13
+
14
+ # Feature
15
+
16
+ * https://wiki.guildwars2.com/wiki/API:2/account/recipes
17
+ * https://wiki.guildwars2.com/wiki/API:2/account/masteries
18
+ * https://wiki.guildwars2.com/wiki/API:2/commerce/listings
19
+
20
+ # Code Clarity
21
+
22
+ * Use more classes and objects so that the types are more clear
23
+
24
+ # Performance
25
+
26
+ * Smart item details cache, basing on item id
data/config.ru CHANGED
@@ -1,8 +1,14 @@
1
1
 
2
2
  require 'rest-gw2'
3
+
3
4
  warmup do
4
5
  RestCore.eagerload
5
6
  RestCore.eagerload(RestGW2)
6
7
  RestGW2::Client.new
7
8
  end
9
+
10
+ if pool_size = ENV['GW2_POOL_SIZE']
11
+ RestGW2::Client.pool_size = Integer(pool_size)
12
+ end
13
+
8
14
  run RestGW2::Server
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module RestGW2
3
4
  autoload :Client, 'rest-gw2/client'
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  require 'rest-core'
4
+ require 'rest-gw2/client/item_detail'
5
+ require 'set'
3
6
 
4
7
  module RestGW2
5
8
  Client = RC::Builder.client do
@@ -55,14 +58,25 @@ module RestGW2
55
58
  end
56
59
 
57
60
  Client.include(Module.new{
61
+ def me opts={}
62
+ get('v2/account', {}, opts)
63
+ end
64
+
58
65
  # https://wiki.guildwars2.com/wiki/API:2/account
59
66
  # https://wiki.guildwars2.com/wiki/API:2/worlds
60
- # https://wiki.guildwars2.com/wiki/API:1/guild_details
67
+ # https://wiki.guildwars2.com/wiki/API:2/guild/:id
61
68
  def account_with_detail opts={}
62
- me = get('v2/account', {}, opts)
63
- worlds = get('v2/worlds', :ids => me['world'])
64
- guilds = guilds_detail(me['guilds'])
65
- me.merge('world' => world_detail(worlds.first), 'guilds' => guilds)
69
+ m = me(opts)
70
+ worlds = get('v2/worlds', :ids => m['world'])
71
+ guilds = guilds_detail(m['guilds'])
72
+ # m['guild_leader'] would be nil if there's no guild permission
73
+ guild_leader = (m['guild_leader'] || []).map do |gid|
74
+ guilds.find{ |g| g['id'] == gid }
75
+ end
76
+ me.merge(
77
+ 'world' => world_detail(worlds.first),
78
+ 'guilds' => guilds,
79
+ 'guild_leader' => guild_leader)
66
80
  end
67
81
 
68
82
  # https://wiki.guildwars2.com/wiki/API:2/guild/:id/stash
@@ -86,6 +100,11 @@ module RestGW2
86
100
  end
87
101
  end
88
102
 
103
+ # https://wiki.guildwars2.com/wiki/API:2/guild/:id/members
104
+ def guild_members gid, opts={}
105
+ get("v2/guild/#{gid}/members", {}, opts)
106
+ end
107
+
89
108
  # https://wiki.guildwars2.com/wiki/API:2/characters
90
109
  def get_character name, opts={}
91
110
  get("v2/characters/#{RC::Middleware.escape(name)}", {}, opts)
@@ -97,12 +116,18 @@ module RestGW2
97
116
  get_character(name, opts)
98
117
  end
99
118
 
100
- guilds = chars.map do |c|
101
- get_guild(c['guild']) if c['guild']
102
- end
119
+ guild_ids = chars.map{ |c| c['guild'] }.compact.uniq
120
+ guild_promises = guilds_detail(guild_ids)
121
+
122
+ title_ids = chars.map{ |c| c['title'] }.compact
123
+ titles = get('v2/titles', :ids => title_ids.join(',')).
124
+ group_by{ |t| t['id'] }
125
+
126
+ guilds = guild_promises.group_by{ |g| g['id'] }
103
127
 
104
- chars.zip(guilds).map do |(c, g)|
105
- c['guild'] = g
128
+ chars.map do |c|
129
+ c['guild'] = guilds.dig(c['guild'], 0)
130
+ c['title'] = titles.dig(c['title'], 0, 'name')
106
131
  c
107
132
  end.sort_by{ |c| -c['age'] }
108
133
  end
@@ -115,81 +140,195 @@ module RestGW2
115
140
  end
116
141
  end
117
142
 
143
+ # https://wiki.guildwars2.com/wiki/API:2/currencies
144
+ # https://wiki.guildwars2.com/wiki/API:2/account/wallet
145
+ def wallet_with_detail opts={}
146
+ wallet = get('v2/account/wallet', {}, opts)
147
+ ids = wallet.map{ |w| w['id'] }.join(',')
148
+ currencies = get('v2/currencies', :ids => ids).group_by{ |w| w['id'] }
149
+ wallet.map do |currency|
150
+ currency.merge(currencies[currency['id']].first)
151
+ end.sort_by{ |c| c['order'] }
152
+ end
153
+
154
+ # https://wiki.guildwars2.com/wiki/API:2/account/skins
155
+ def skins_with_detail opts={}
156
+ unlocks_with_detail(:all_skins, 'v2/account/skins', opts)
157
+ end
158
+
159
+ # https://wiki.guildwars2.com/wiki/API:2/account/outfits
160
+ def outfits_with_detail opts={}
161
+ unlocks_with_detail(:all_outfits, 'v2/account/outfits', opts)
162
+ end
163
+
164
+ # https://wiki.guildwars2.com/wiki/API:2/account/mailcarriers
165
+ def mailcarriers_with_detail opts={}
166
+ unlocks_with_detail(:all_mailcarriers, 'v2/account/mailcarriers', opts)
167
+ end
168
+
169
+ # https://wiki.guildwars2.com/wiki/API:2/account/gliders
170
+ def gliders_with_detail opts={}
171
+ unlocks_with_detail(:all_gliders, 'v2/account/gliders', opts)
172
+ end
173
+
174
+ # https://wiki.guildwars2.com/wiki/API:2/skins
175
+ def all_skins
176
+ all_unlocks('v2/skins')
177
+ end
178
+
179
+ # https://wiki.guildwars2.com/wiki/API:2/outfits
180
+ def all_outfits
181
+ all_unlocks('v2/outfits')
182
+ end
183
+
184
+ # https://wiki.guildwars2.com/wiki/API:2/mailcarriers
185
+ def all_mailcarriers
186
+ all_unlocks('v2/mailcarriers')
187
+ end
188
+
189
+ # https://wiki.guildwars2.com/wiki/API:2/gliders
190
+ def all_gliders
191
+ all_unlocks('v2/gliders')
192
+ end
193
+
194
+ # https://wiki.guildwars2.com/wiki/API:2/finishers
195
+ def all_fininshers
196
+ all_unlocks('v2/finishers')
197
+ end
198
+
199
+ # https://wiki.guildwars2.com/wiki/API:2/cats
200
+ def all_cats
201
+ all_unlocks('v2/cats')
202
+ end
203
+
204
+ # https://wiki.guildwars2.com/wiki/API:2/titles
205
+ def all_titles
206
+ all_unlocks('v2/titles')
207
+ end
208
+
118
209
  # https://wiki.guildwars2.com/wiki/API:2/colors
119
210
  # https://wiki.guildwars2.com/wiki/API:2/account/dyes
120
211
  def dyes_with_detail opts={}
121
212
  mine = get('v2/account/dyes', opts)
213
+
122
214
  get('v2/colors').each_slice(100).map do |slice|
123
- slice.join(',')
124
- end.map do |ids|
125
- with_item_detail('v2/colors', :ids => ids) do |colors|
215
+ with_item_detail('v2/colors', :ids => slice.join(',')) do |colors|
126
216
  colors.map{ |c| c.merge('id' => c['item'], 'color_id' => c['id']) }
127
217
  end
128
218
  end.flatten.map do |color|
129
- color['count'] = if mine.include?(color['color_id'])
130
- 1
131
- else
132
- 0
133
- end
219
+ color['count'] =
220
+ if mine.include?(color['color_id'])
221
+ 1
222
+ else
223
+ 0
224
+ end
134
225
  color
135
226
  end.sort_by{ |c| c['categories'] }
136
227
  end
137
228
 
138
- # https://wiki.guildwars2.com/wiki/API:2/account/skins
139
- def skins_with_detail opts={}
140
- mine = get('v2/account/skins', {}, opts)
141
- all_skins.flatten.map do |skin|
142
- skin['count'] = if mine.include?(skin['id'])
143
- 1
144
- else
145
- 0
146
- end
147
- skin['nolink'] = true
148
- skin
149
- end.sort_by{ |s| s['name'] || '' }
150
- end
151
-
152
- # https://wiki.guildwars2.com/wiki/API:2/skins
153
- def all_skins
154
- get('v2/skins').each_slice(100).map do |slice|
155
- get('v2/skins', :ids => slice.join(','))
156
- end
157
- end
158
-
159
229
  # https://wiki.guildwars2.com/wiki/API:2/minis
160
230
  # https://wiki.guildwars2.com/wiki/API:2/account/minis
161
231
  def minis_with_detail opts={}
162
232
  mine = get('v2/account/minis', {}, opts)
233
+
163
234
  get('v2/minis').each_slice(100).map do |slice|
164
- slice.join(',')
165
- end.map do |ids|
166
- with_item_detail('v2/minis', :ids => ids) do |minis|
235
+ with_item_detail('v2/minis', :ids => slice.join(',')) do |minis|
167
236
  minis.map{ |m| m.merge('id' => m['item_id'], 'mini_id' => m['id']) }
168
237
  end
169
238
  end.flatten.map do |mini|
170
- mini['count'] = if mine.include?(mini['mini_id'])
171
- 1
172
- else
173
- 0
174
- end
239
+ mini['count'] =
240
+ if mine.include?(mini['mini_id'])
241
+ 1
242
+ else
243
+ 0
244
+ end
245
+ mini['nolink'] = true
175
246
  mini
176
247
  end.sort_by{ |m| m['order'] }
177
248
  end
178
249
 
179
- # https://wiki.guildwars2.com/wiki/API:2/account/wallet
180
- # https://wiki.guildwars2.com/wiki/API:2/currencies
181
- def wallet_with_detail opts={}
182
- wallet = get('v2/account/wallet', {}, opts)
183
- ids = wallet.map{ |w| w['id'] }.join(',')
184
- currencies = get('v2/currencies', :ids => ids).group_by{ |w| w['id'] }
185
- wallet.map do |currency|
186
- currency.merge(currencies[currency['id']].first)
187
- end.sort_by{ |c| c['order'] }
250
+ # https://wiki.guildwars2.com/wiki/API:2/account/finishers
251
+ def finishers_with_detail opts={}
252
+ mine_promise = get('v2/account/finishers', {}, opts)
253
+
254
+ all = all_fininshers
255
+ mine = mine_promise.group_by{ |u| u['id'] }
256
+
257
+ all.flatten.map do |finisher|
258
+ finisher['count'] =
259
+ if mine.dig(finisher['id'], 0, 'permanent')
260
+ Float::INFINITY
261
+ else
262
+ mine.dig(finisher['id'], 0, 'quantity') || 0
263
+ end
264
+ finisher['nolink'] = true
265
+ finisher['description'] = finisher['unlock_details']
266
+ finisher
267
+ end.sort_by{ |m| m['order'] }
188
268
  end
189
269
 
190
- def with_item_detail path, query={}, opts={}, &block
191
- block ||= :itself.to_proc
192
- expand_item_detail(block.call(get(path, query, opts)), opts)
270
+ # https://wiki.guildwars2.com/wiki/API:2/account/home/cats
271
+ def cats_with_detail opts={}
272
+ mine_promise = get('v2/account/home/cats', opts)
273
+
274
+ all = all_cats
275
+ mine = Set.new(mine_promise.map{ |cat| cat['id'] })
276
+
277
+ all.flatten.map do |cat|
278
+ cat['count'] =
279
+ if mine.member?(cat['id'])
280
+ 1
281
+ else
282
+ 0
283
+ end
284
+ cat['name'] = cat['hint']
285
+ cat
286
+ end.sort_by{ |c| c['name'] }
287
+ end
288
+
289
+ # https://wiki.guildwars2.com/wiki/API:2/nodes
290
+ # https://wiki.guildwars2.com/wiki/API:2/account/home/nodes
291
+ def nodes_with_detail opts={}
292
+ all = get('v2/nodes')
293
+ mine = Set.new(get('v2/account/home/nodes', opts))
294
+
295
+ all.map do |name|
296
+ count =
297
+ if mine.member?(name)
298
+ 1
299
+ else
300
+ 0
301
+ end
302
+ {'name' => name, 'count' => count}
303
+ end.sort_by{ |n| n['name'] }
304
+ end
305
+
306
+ # https://wiki.guildwars2.com/wiki/API:2/account/titles
307
+ def titles_with_detail opts={}
308
+ all = all_titles
309
+ mine = get('v2/account/titles')
310
+
311
+ all.flatten.map do |title|
312
+ title['count'] =
313
+ if mine.member?(title['id'])
314
+ 1
315
+ else
316
+ 0
317
+ end
318
+ title
319
+ end.sort_by{ |t| t['name'] }
320
+ end
321
+
322
+ # https://wiki.guildwars2.com/wiki/API:2/commerce/delivery
323
+ def delivery_with_detail query={}, opts={}
324
+ items = with_item_detail('v2/commerce/delivery',
325
+ {:page_size => 200}.merge(query), opts) do |delivery|
326
+ ['price' => delivery['coins']] + delivery['items']
327
+ end
328
+
329
+ compact_items(items) do |last, current|
330
+ last['id'] == current['id']
331
+ end
193
332
  end
194
333
 
195
334
  # https://wiki.guildwars2.com/wiki/API:2/commerce/transactions
@@ -203,62 +342,26 @@ module RestGW2
203
342
  end
204
343
 
205
344
  def transactions_with_detail_compact path, query={}, opts={}
206
- transactions_with_detail(path, query, opts).inject([]) do |ret, trans|
207
- last = ret.last
208
- if last && last['item_id'] == trans['item_id'] &&
209
- last['price'] == trans['price']
210
- last['count'] += trans['count']
211
- else
212
- ret << trans
213
- end
214
- ret
345
+ items = transactions_with_detail(path, query, opts)
346
+
347
+ compact_items(items) do |last, current|
348
+ last['id'] == current['id'] && last['price'] == current['price']
215
349
  end
216
350
  end
217
351
 
218
- # https://wiki.guildwars2.com/wiki/API:2/items
219
- # https://wiki.guildwars2.com/wiki/API:2/commerce/prices
352
+ def with_item_detail path, query={}, opts={}, &block
353
+ block ||= :itself.to_proc
354
+ expand_item_detail(block.call(get(path, query, opts)), opts)
355
+ end
356
+
220
357
  def expand_item_detail items, opts={}
221
- skins = all_skins
222
- detail = item_detail_group_by_id(items, opts)
223
- upgrades = extract_items_in_slots(items, opts, 'upgrades', 'infusions')
224
-
225
- skins_detail = skins.flatten.group_by{ |s| s['id'] }
226
- items.map do |i|
227
- next i unless data = i && detail[i['id']]
228
- s = i['skin']
229
- u = i['upgrades']
230
- f = i['infusions']
231
- i.merge(data).merge(
232
- 'count' => i['count'] || 1,
233
- 'skin' => s && skins_detail[s].first,
234
- 'upgrades' => u && u.flat_map(&upgrades.method(:[])),
235
- 'infusions' => f && f.flat_map(&upgrades.method(:[])))
236
- end
358
+ detail = ItemDetail.new(self, items, opts)
359
+ detail.populate
360
+
361
+ items.map(&detail.method(:fill))
237
362
  end
238
363
 
239
364
  private
240
- def item_detail_group_by_id items, opts={}
241
- items.map{ |i| i && i['id'] }.compact.each_slice(100).map do |slice|
242
- q = {:ids => slice.join(',')}
243
- [get('v2/items', q),
244
- get('v2/commerce/prices', q, {:error_detector => false}.merge(opts))]
245
- end.flat_map(&:itself).map(&:to_a).flatten.group_by{ |i| i['id'] }.
246
- inject({}){ |r, (id, v)| r[id] = v.inject(&:merge); r }
247
- # this is probably a dirty way to workaround converting hashes to arrays
248
- end
249
-
250
- def extract_items_in_slots items, opts, *slots
251
- upgrades = items.flat_map do |i|
252
- if i
253
- i.values_at(*slots).flatten.compact.map do |id|
254
- {'id' => id}
255
- end
256
- else
257
- []
258
- end
259
- end
260
- item_detail_group_by_id(upgrades, opts)
261
- end
262
365
 
263
366
  # https://wiki.guildwars2.com/wiki/API:2/worlds
264
367
  def world_detail world
@@ -285,13 +388,49 @@ module RestGW2
285
388
  "#{world['name']} (#{world['population']}) / #{region} (#{lang})"
286
389
  end
287
390
 
288
- # https://wiki.guildwars2.com/wiki/API:1/guild_details
289
391
  def guilds_detail guilds
290
392
  guilds.map(&method(:get_guild))
291
393
  end
292
394
 
395
+ # https://wiki.guildwars2.com/wiki/API:2/guild/:id
293
396
  def get_guild gid
294
- get('v1/guild_details', :guild_id => gid)
397
+ get("v2/guild/#{gid}")
398
+ end
399
+
400
+ # Returns Array[Promise[Detail]]
401
+ def all_unlocks path
402
+ get(path).each_slice(100).map do |slice|
403
+ get(path, :ids => slice.join(','))
404
+ end
405
+ end
406
+
407
+ def unlocks_with_detail kind, path, opts
408
+ all = public_send(kind)
409
+ mine = Set.new(get(path, {}, opts))
410
+ all.flatten.map do |unlock|
411
+ unlock['count'] =
412
+ if mine.member?(unlock['id'])
413
+ 1
414
+ else
415
+ 0
416
+ end
417
+ unlock['nolink'] = true
418
+ unlock
419
+ end.sort_by{ |u| u['order'] || u['name'] || '' }
420
+ end
421
+
422
+ def compact_items items
423
+ items.inject([]) do |result, item|
424
+ last = result.last
425
+
426
+ if last && yield(last, item)
427
+ last['count'] += item['count']
428
+ else
429
+ result << item
430
+ end
431
+
432
+ result
433
+ end
295
434
  end
296
435
  })
297
436
  end