play_asia 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +33 -0
- data/Rakefile +7 -0
- data/lib/play_asia/api.rb +35 -0
- data/lib/play_asia/api_listing.rb +347 -0
- data/lib/play_asia/http_client.rb +7 -0
- data/lib/play_asia/response.rb +70 -0
- data/lib/play_asia/version.rb +3 -0
- data/lib/play_asia.rb +8 -0
- data/play_asia.gemspec +20 -0
- data/test/stubs/stubbed_http_client.rb +25 -0
- data/test/test_api.rb +63 -0
- data/test/test_api_listing.rb +140 -0
- data/test/test_response.rb +120 -0
- metadata +98 -0
data/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
*.sublime-*
|
2
|
+
.idea
|
3
|
+
*.gem
|
4
|
+
*.rbc
|
5
|
+
.bundle
|
6
|
+
.config
|
7
|
+
coverage
|
8
|
+
InstalledFiles
|
9
|
+
Gemfile.lock
|
10
|
+
lib/bundler/man
|
11
|
+
pkg
|
12
|
+
rdoc
|
13
|
+
spec/reports
|
14
|
+
test/tmp
|
15
|
+
test/version_tmp
|
16
|
+
tmp
|
17
|
+
|
18
|
+
# YARD artifacts
|
19
|
+
.yardoc
|
20
|
+
_yardoc
|
21
|
+
doc/
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 On the Game
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# PlayAsia
|
2
|
+
|
3
|
+
A thin wrapper around the [Play Asia](http://www.play-asia.com) API.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'play_asia'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install play_asia
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
api = PlayAsia::Api.new
|
22
|
+
key: # your API key,
|
23
|
+
user: # your API user,
|
24
|
+
|
25
|
+
api.listing mask: [:price, :name], type: [:game]
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
class PlayAsia::Api
|
4
|
+
attr_accessor :endpoint
|
5
|
+
attr_accessor :headers
|
6
|
+
attr_accessor :http_client
|
7
|
+
|
8
|
+
def initialize(opts = {})
|
9
|
+
@opts = opts
|
10
|
+
@endpoint = 'http://www.play-asia.com/__api__.php'
|
11
|
+
@http_client = PlayAsia::HttpClient.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def query(opts = {})
|
15
|
+
opts = @opts.merge opts
|
16
|
+
url = build_url @endpoint, opts
|
17
|
+
headers = @headers || {}
|
18
|
+
|
19
|
+
PlayAsia::Response.new @http_client.request(url, headers).read
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def build_url(endpoint, opts)
|
24
|
+
ensure_required_parameters opts
|
25
|
+
|
26
|
+
params = opts.map { |k,v| "#{k}=#{v}" }.join '&'
|
27
|
+
"#{endpoint}?#{params}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def ensure_required_parameters opts
|
31
|
+
raise ArgumentError, 'Missing API key (expected :key)' unless opts[:key]
|
32
|
+
raise ArgumentError, 'Missing User ID (expected :user)' unless opts[:user]
|
33
|
+
raise ArgumentError, 'Missing Query type (expected :query)' unless opts[:query]
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,347 @@
|
|
1
|
+
class PlayAsia::Api
|
2
|
+
def listing(opts = {})
|
3
|
+
opts = process_friendly_keys opts.merge({ query: :listing })
|
4
|
+
response = query opts
|
5
|
+
|
6
|
+
raise "Query error: '#{response.error_message}'" if response.error?
|
7
|
+
|
8
|
+
response
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
MASK = {
|
13
|
+
price: 'p',
|
14
|
+
barcodes: 'j',
|
15
|
+
manufacturer_codes: 'm',
|
16
|
+
sale_info: 's',
|
17
|
+
release_date: 'r',
|
18
|
+
name: 'n',
|
19
|
+
image: 'i',
|
20
|
+
url: 'l',
|
21
|
+
affiliate_url: 'a',
|
22
|
+
genre: 'g',
|
23
|
+
version: 'v',
|
24
|
+
encoding: 'e',
|
25
|
+
compatible: 'c'
|
26
|
+
}
|
27
|
+
|
28
|
+
TYPES = {
|
29
|
+
accessory: 2,
|
30
|
+
cd: 3,
|
31
|
+
groceries: 7,
|
32
|
+
apparel: 8,
|
33
|
+
electronics: 9,
|
34
|
+
movie: 4,
|
35
|
+
book: 6,
|
36
|
+
game: 1,
|
37
|
+
toy: 5
|
38
|
+
}
|
39
|
+
|
40
|
+
GENRES = {
|
41
|
+
strategy_video_game: 10,
|
42
|
+
racing_video_game: 11,
|
43
|
+
simulation_video_game: 12,
|
44
|
+
tv_series_dvd_vcd: 122,
|
45
|
+
enka_dvd_vcd: 123,
|
46
|
+
puzzle_video_game: 13,
|
47
|
+
music_video_game: 14,
|
48
|
+
language_learning_software_video_games: 147,
|
49
|
+
slg_video_game: 15,
|
50
|
+
documentary_dvd_vcd: 159,
|
51
|
+
classics_video_game: 16,
|
52
|
+
fantasy_mystery_dvd_vcd: 160,
|
53
|
+
musical_dvd_vcd: 161,
|
54
|
+
rock_pop_dvd_vcd: 162,
|
55
|
+
rap_hip_hop_dvd_vcd: 163,
|
56
|
+
western_dvd_vcd: 164,
|
57
|
+
oldies_dvd_vcd: 165,
|
58
|
+
soul_r_and_b_dvd_vcd: 166,
|
59
|
+
family_dvd_vcd: 167,
|
60
|
+
opera_dvd_vcd: 168,
|
61
|
+
concert_dvd_vcd: 169,
|
62
|
+
misc_video_game: 17,
|
63
|
+
heavy_metal_dvd_vcd: 170,
|
64
|
+
jazz_dvd_vcd: 171,
|
65
|
+
classical_dvd_vcd: 172,
|
66
|
+
folk_dvd_vcd: 173,
|
67
|
+
ballet_dvd_vcd: 178,
|
68
|
+
sports_video_dvd_vcd: 179,
|
69
|
+
action_video_game: 18,
|
70
|
+
gambling_dvd_vcd: 185,
|
71
|
+
adventure_video_game: 19,
|
72
|
+
augmented_reality_video_game: 192,
|
73
|
+
fighting_video_game: 2,
|
74
|
+
board_video_game: 20,
|
75
|
+
party_video_game: 21,
|
76
|
+
comedy_dvd_vcd: 22,
|
77
|
+
action_dvd_vcd: 23,
|
78
|
+
adult_dvd_vcd: 24,
|
79
|
+
crime_dvd_vcd: 25,
|
80
|
+
drama_dvd_vcd: 26,
|
81
|
+
romance_dvd_vcd: 27,
|
82
|
+
martial_arts_dvd_vcd: 28,
|
83
|
+
horror_dvd_vcd: 29,
|
84
|
+
beat_em_up_video_game: 3,
|
85
|
+
thriller_dvd_vcd: 30,
|
86
|
+
sci_fi_dvd_vcd: 31,
|
87
|
+
gambling_video_game: 32,
|
88
|
+
pinball_video_game: 33,
|
89
|
+
animation_dvd_vcd: 34,
|
90
|
+
ghost_dvd_vcd: 35,
|
91
|
+
soundtrack_music_cd: 36,
|
92
|
+
j_pop_music_cd: 37,
|
93
|
+
cantopop_music_cd: 38,
|
94
|
+
j_pop_dvd_vcd: 39,
|
95
|
+
shooting_video_game: 4,
|
96
|
+
video_game_soundtrack_music_cd: 40,
|
97
|
+
video_game_movie_dvd_vcd: 41,
|
98
|
+
japanese_movie_dvd_vcd: 42,
|
99
|
+
non_japanese_movie_dvd_vcd: 43,
|
100
|
+
education_dvd_vcd: 44,
|
101
|
+
misc_movie_dvd_vcd: 45,
|
102
|
+
karaoke_dvd_vcd: 46,
|
103
|
+
k_pop_music_cd: 47,
|
104
|
+
electronic_music_cd: 48,
|
105
|
+
dance_music_cd: 49,
|
106
|
+
gun_shooting_video_game: 5,
|
107
|
+
pop_music_cd: 50,
|
108
|
+
idol_movie_dvd_vcd: 54,
|
109
|
+
enka_music_cd: 55,
|
110
|
+
hentai_dvd_vcd: 57,
|
111
|
+
platform_video_game: 6,
|
112
|
+
rpg_video_game: 7,
|
113
|
+
action_adventure_video_game: 8,
|
114
|
+
sports_video_game: 9
|
115
|
+
}
|
116
|
+
|
117
|
+
COMPATIBILITIES = {
|
118
|
+
am3_advance_media_player: 23,
|
119
|
+
atari_jaguar: 20,
|
120
|
+
blackberry_bold_9900_9930: 201,
|
121
|
+
blackberry_torch_2_9810: 203,
|
122
|
+
blackberry_torch_9850_9860: 205,
|
123
|
+
dreamcast: 9,
|
124
|
+
dsi_ll_xl_japanese_only: 116,
|
125
|
+
famicom_disk_system: 87,
|
126
|
+
famicom_nes: 18,
|
127
|
+
gamecube: 2,
|
128
|
+
game_boy: 59,
|
129
|
+
game_boy_advance: 8,
|
130
|
+
game_boy_advance_sp: 39,
|
131
|
+
game_boy_color: 14,
|
132
|
+
game_boy_micro: 60,
|
133
|
+
game_boy_pocket: 84,
|
134
|
+
game_gear: 30,
|
135
|
+
gp2x: 61,
|
136
|
+
gp2x_caanoo: 112,
|
137
|
+
gp2x_f_200: 97,
|
138
|
+
gp2x_wiz: 99,
|
139
|
+
gp32: 10,
|
140
|
+
htchd7: 137,
|
141
|
+
htc_7_trophy: 139,
|
142
|
+
htc_cha_cha_a810e: 147,
|
143
|
+
htc_desire_hd_a9191: 120,
|
144
|
+
htc_evo4g: 157,
|
145
|
+
htc_evo_3d_x515m: 149,
|
146
|
+
htc_g2: 141,
|
147
|
+
htc_increadible_s_s710e: 143,
|
148
|
+
htc_one_s_z520e: 135,
|
149
|
+
htc_radar_c110e: 155,
|
150
|
+
htc_raider_4g_x710e: 151,
|
151
|
+
htc_rhyme_s510b: 153,
|
152
|
+
htc_sensation_xe_z715e: 133,
|
153
|
+
htc_sensation_z710e: 145,
|
154
|
+
ipad: 111,
|
155
|
+
ipad_2: 119,
|
156
|
+
ipad_3: 127,
|
157
|
+
iphone_3g: 98,
|
158
|
+
iphone_3gs: 114,
|
159
|
+
iphone_4: 115,
|
160
|
+
iphone_4s: 124,
|
161
|
+
iphone_5: 125,
|
162
|
+
ipod_4g_20gb: 67,
|
163
|
+
ipod_4g_40gb: 68,
|
164
|
+
ipod_5g_30gb: 63,
|
165
|
+
ipod_5g_60gb: 64,
|
166
|
+
ipod_classic_160gb: 95,
|
167
|
+
ipod_classic_80gb: 94,
|
168
|
+
ipod_mini_4gb_6gb: 66,
|
169
|
+
ipod_nano: 62,
|
170
|
+
ipod_nano_2nd_gen: 86,
|
171
|
+
ipod_nano_3rd_gen: 96,
|
172
|
+
ipod_nano_5th_gen: 109,
|
173
|
+
ipod_nano_6g: 131,
|
174
|
+
ipod_photo_30gb: 69,
|
175
|
+
ipod_photo_60gb: 70,
|
176
|
+
ipod_series: 92,
|
177
|
+
ipod_shuffle: 65,
|
178
|
+
ipod_touch: 123,
|
179
|
+
ipod_touch_4g: 129,
|
180
|
+
kindle_fire: 237,
|
181
|
+
kinect: 113,
|
182
|
+
laseractive: 103,
|
183
|
+
laseractive_ld_rom: 105,
|
184
|
+
laseractive_mega_ld: 104,
|
185
|
+
lcd_game: 72,
|
186
|
+
macbook_pro_15_inch_retina: 233,
|
187
|
+
macintosh: 21,
|
188
|
+
mark_iii: 58,
|
189
|
+
mega_cd: 25,
|
190
|
+
msx: 90,
|
191
|
+
neo_geo: 22,
|
192
|
+
neo_geo_cd: 29,
|
193
|
+
neo_geo_pocket: 82,
|
194
|
+
neo_geo_pocket_color: 16,
|
195
|
+
nintendo64: 4,
|
196
|
+
nintendo64_dd: 88,
|
197
|
+
nintendo_3ds: 110,
|
198
|
+
nintendo_3ds_ll_xl: 231,
|
199
|
+
nintendo_ds: 32,
|
200
|
+
nintendo_dsi: 102,
|
201
|
+
nintendo_dsi_ll_xl: 108,
|
202
|
+
nintendo_ds_lite: 71,
|
203
|
+
nintendo_mini_classics: 75,
|
204
|
+
nintendo_wii: 73,
|
205
|
+
nokia_603: 221,
|
206
|
+
nokia_c7: 211,
|
207
|
+
nokia_e6_00: 215,
|
208
|
+
nokia_e7_00: 213,
|
209
|
+
nokia_lumia_710: 207,
|
210
|
+
nokia_lumia_800: 209,
|
211
|
+
nokia_n9: 219,
|
212
|
+
nokia_x7_00: 217,
|
213
|
+
panasonic_q: 12,
|
214
|
+
pc_and_mac: 117,
|
215
|
+
pc_cd_rom: 74,
|
216
|
+
pc_engine_arcade_cd_rom: 79,
|
217
|
+
pc_engine_cd_rom: 78,
|
218
|
+
pc_engine_hucard: 76,
|
219
|
+
pc_engine_supergrafx: 83,
|
220
|
+
pc_engine_super_cd_rom: 77,
|
221
|
+
pc_engine_turbo_grafx_16: 19,
|
222
|
+
pc_fx: 34,
|
223
|
+
pico: 100,
|
224
|
+
pippin: 89,
|
225
|
+
playdia: 101,
|
226
|
+
playstation2: 1,
|
227
|
+
playstation3: 37,
|
228
|
+
playstation3_slim: 107,
|
229
|
+
playstation: 3,
|
230
|
+
playstation_vita: 121,
|
231
|
+
pocket_dream_console: 85,
|
232
|
+
pokemon_mini: 26,
|
233
|
+
samsung_galaxy_a_advance_i9070: 159,
|
234
|
+
samsung_galaxy_mini_2_gt_s6500: 229,
|
235
|
+
samsung_galaxy_note_gt_n7000: 179,
|
236
|
+
samsung_galaxy_r_gt_i9103: 171,
|
237
|
+
samsung_galaxy_sii_lte_sgh_i727: 173,
|
238
|
+
samsung_galaxy_sl_i9003: 167,
|
239
|
+
samsung_galaxy_s_captivate: 177,
|
240
|
+
samsung_galaxy_s_gt_i9000: 225,
|
241
|
+
samsung_galaxy_s_iii_gt_i9300: 227,
|
242
|
+
samsung_galaxy_s_ii_gt_i9100: 169,
|
243
|
+
samsung_galaxy_tab: 118,
|
244
|
+
samsung_galaxy_w_i8150: 175,
|
245
|
+
samsung_google_nexuss: 163,
|
246
|
+
samsung_gt_i9220: 181,
|
247
|
+
samsung_gt_i9228: 183,
|
248
|
+
samsung_sgh_i717: 185,
|
249
|
+
samsung_shv_e160k: 223,
|
250
|
+
samsung_shv_e160l: 191,
|
251
|
+
samsung_shv_e160s: 189,
|
252
|
+
samsung_shv_e169k: 187,
|
253
|
+
samsung_wave_iii_s8600: 161,
|
254
|
+
samsung_wave_ii_s8530: 165,
|
255
|
+
sega_mega_drive_sega_genesis: 24,
|
256
|
+
sega_saturn: 11,
|
257
|
+
sony_ericsson_xperia_arc: 197,
|
258
|
+
sony_ericsson_xperia_arc_s: 199,
|
259
|
+
sony_ericsson_xperia_neo: 193,
|
260
|
+
sony_ericsson_xperia_play: 195,
|
261
|
+
sony_psp: 33,
|
262
|
+
sony_psp_go: 106,
|
263
|
+
sony_psp_slim_and_lite: 93,
|
264
|
+
super_32x: 35,
|
265
|
+
super_famicom_snes: 7,
|
266
|
+
three_d_o: 36,
|
267
|
+
tomy_evio: 27,
|
268
|
+
virtual_boy: 31,
|
269
|
+
wii_u: 122,
|
270
|
+
windows_pc: 13,
|
271
|
+
wonderswan: 15,
|
272
|
+
wonderswan_color: 80,
|
273
|
+
wonderswan_crystal: 81,
|
274
|
+
x68000: 91,
|
275
|
+
xbox360: 38,
|
276
|
+
xbox: 6
|
277
|
+
}
|
278
|
+
|
279
|
+
ENCODINGS = {
|
280
|
+
aac: 31,
|
281
|
+
audio_cd: 14,
|
282
|
+
blu_ray_region_a: 27,
|
283
|
+
blu_ray_region_b: 28,
|
284
|
+
blu_ray_region_free: 29,
|
285
|
+
dvd_region_1: 6,
|
286
|
+
dvd_region_2: 7,
|
287
|
+
dvd_region_3: 8,
|
288
|
+
dvd_region_4: 9,
|
289
|
+
dvd_region_5: 10,
|
290
|
+
dvd_region_6: 11,
|
291
|
+
dvd_region_free: 5,
|
292
|
+
hd_dvd_region_2: 24,
|
293
|
+
hd_dvd_region_3: 25,
|
294
|
+
hd_dvd_region_free: 26,
|
295
|
+
no_region_protection: 13,
|
296
|
+
ntsc_j: 2,
|
297
|
+
ntsc_uc: 3,
|
298
|
+
pal: 4,
|
299
|
+
record: 30,
|
300
|
+
umd_music_region_2: 17,
|
301
|
+
umd_music_region_3: 23,
|
302
|
+
umd_music_region_free: 22,
|
303
|
+
umd_video_region_1: 20,
|
304
|
+
umd_video_region_2: 16,
|
305
|
+
umd_video_region_2_6: 21,
|
306
|
+
umd_video_region_3: 19,
|
307
|
+
umd_video_region_free: 18,
|
308
|
+
vcd_region_free: 12,
|
309
|
+
vhs_region_free: 15
|
310
|
+
}
|
311
|
+
|
312
|
+
VERSIONS = {
|
313
|
+
asia: 6,
|
314
|
+
european: 5,
|
315
|
+
hong_kong: 19,
|
316
|
+
japanese: 2,
|
317
|
+
korean: 3,
|
318
|
+
us: 4
|
319
|
+
}
|
320
|
+
|
321
|
+
def process_friendly_keys opts
|
322
|
+
opts[:mask] = map_array_to_string opts[:mask], MASK if opts[:mask]
|
323
|
+
opts[:type] = map_array_to_string opts[:type], TYPES, ',' if opts[:type]
|
324
|
+
opts[:genre] = map_array_to_string opts[:genre], GENRES, ',' if opts[:genre]
|
325
|
+
opts[:compatible] = map_array_to_string opts[:compatible], COMPATIBILITIES, ',' if opts[:compatible]
|
326
|
+
opts[:encoding] = map_array_to_string opts[:encoding], ENCODINGS, ',' if opts[:encoding]
|
327
|
+
opts[:version] = map_array_to_string opts[:version], VERSIONS, ',' if opts[:version]
|
328
|
+
|
329
|
+
# map true/false literals to 1/0
|
330
|
+
opts.each do |key, value|
|
331
|
+
if value == true
|
332
|
+
opts[key] = '1'
|
333
|
+
elsif value == false
|
334
|
+
opts[key] = '0'
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
opts
|
339
|
+
end
|
340
|
+
|
341
|
+
def map_array_to_string(values, map, join_string = nil)
|
342
|
+
if values && values.is_a?(Array)
|
343
|
+
return values.flatten.map { |k| map[k] || k }.join join_string
|
344
|
+
end
|
345
|
+
values
|
346
|
+
end
|
347
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class PlayAsia::ResponseError < RuntimeError
|
2
|
+
end
|
3
|
+
|
4
|
+
class PlayAsia::Response
|
5
|
+
attr_reader :raw_text, :status, :items, :content
|
6
|
+
|
7
|
+
def initialize(text)
|
8
|
+
@raw_text = text
|
9
|
+
@parsed = Nokogiri::XML.parse text
|
10
|
+
|
11
|
+
parse_content
|
12
|
+
end
|
13
|
+
|
14
|
+
def error?
|
15
|
+
status[:error] != '0'
|
16
|
+
end
|
17
|
+
|
18
|
+
def error_message
|
19
|
+
status[:errorstring]
|
20
|
+
end
|
21
|
+
|
22
|
+
def start
|
23
|
+
status[:start] ? status[:start].to_i : 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def total_items
|
27
|
+
status[:total_items] ? status[:total_items].to_i : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def items_count
|
31
|
+
status[:items] ? status[:items].to_i : nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def has_more?
|
35
|
+
raise "Unknown total number of items" if total_items.nil?
|
36
|
+
start + items.size < total_items
|
37
|
+
end
|
38
|
+
|
39
|
+
def complete?
|
40
|
+
!has_more?
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def parse_content
|
45
|
+
@status = parse_status
|
46
|
+
@content = @parsed.at 'content'
|
47
|
+
@items = parse_items
|
48
|
+
|
49
|
+
raise PlayAsia::ResponseError, "status/items not found.\n#{status}" unless items_count || error?
|
50
|
+
raise PlayAsia::ResponseError, "Unexpected number of items #{@items.size} instead of #{items_count}" if !error? && @items.size < items_count
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_status
|
54
|
+
dumb_xml_to_hash @parsed.at('status')
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_items
|
58
|
+
content.search('item').map do |xml|
|
59
|
+
dumb_xml_to_hash xml
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def dumb_xml_to_hash(xml)
|
64
|
+
hash = {}
|
65
|
+
xml.search('*').each do |node|
|
66
|
+
hash[node.name.downcase.to_sym] = node.text
|
67
|
+
end
|
68
|
+
hash
|
69
|
+
end
|
70
|
+
end
|
data/lib/play_asia.rb
ADDED
data/play_asia.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/play_asia/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ['James Gregory', 'On the Game']
|
6
|
+
gem.email = ['james@onthegame.com.au']
|
7
|
+
gem.description = 'A thin wrapper around the Play Asia API'
|
8
|
+
gem.summary = 'Play Asia API'
|
9
|
+
gem.homepage = 'http://www.onthegame.com.au/about/opensource'
|
10
|
+
|
11
|
+
gem.add_runtime_dependency 'nokogiri'
|
12
|
+
gem.add_development_dependency 'minitest-reporters'
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($\)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.name = 'play_asia'
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.version = PlayAsia::VERSION
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class StubbedHttpClient
|
2
|
+
attr_reader :last_url, :last_options
|
3
|
+
|
4
|
+
def initialize response
|
5
|
+
@response = response
|
6
|
+
end
|
7
|
+
|
8
|
+
def request url, options
|
9
|
+
@last_url = url
|
10
|
+
@last_options = options
|
11
|
+
|
12
|
+
StubFileResponse.new @response
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
class StubFileResponse
|
17
|
+
def initialize content
|
18
|
+
@content = content
|
19
|
+
end
|
20
|
+
|
21
|
+
def read
|
22
|
+
@content
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/test/test_api.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'play_asia'
|
3
|
+
require_relative 'stubs/stubbed_http_client'
|
4
|
+
|
5
|
+
class ApiTest < MiniTest::Unit::TestCase
|
6
|
+
STUBBED_RESPONSE = '<message><status><query>test</query><error>0</error><errorstring /><items>1</items></status><content><item>1</item></content></message>'
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@api = PlayAsia::Api.new
|
10
|
+
@http_client = StubbedHttpClient.new STUBBED_RESPONSE
|
11
|
+
@api.http_client = @http_client
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_query_defaults_to_using_play_asia_domain
|
15
|
+
@api.query key: 'api_key', user: 1, query: 'test'
|
16
|
+
|
17
|
+
assert @http_client.last_url.start_with? 'http://www.play-asia.com/__api__.php'
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_query_uses_arguments_as_query_string
|
21
|
+
@api.query key: 'api_key', user: 1, query: 'test', a: 1, b: 2, c: 3
|
22
|
+
url = @http_client.last_url
|
23
|
+
query_string = parse_hash_from_query_string url.split('?').last
|
24
|
+
|
25
|
+
assert_equal query_string['key'], 'api_key'
|
26
|
+
assert_equal query_string['user'], '1'
|
27
|
+
assert_equal query_string['query'], 'test'
|
28
|
+
assert_equal query_string['a'], '1'
|
29
|
+
assert_equal query_string['b'], '2'
|
30
|
+
assert_equal query_string['c'], '3'
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_query_raises_if_no_key_given
|
34
|
+
ex = assert_raises ArgumentError do
|
35
|
+
@api.query user: 1, query: 'test'
|
36
|
+
end
|
37
|
+
assert_equal ex.message, 'Missing API key (expected :key)'
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_query_raises_if_no_user_given
|
41
|
+
ex = assert_raises ArgumentError do
|
42
|
+
@api.query key: 'api_key', query: 'test'
|
43
|
+
end
|
44
|
+
assert_equal ex.message, 'Missing User ID (expected :user)'
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_query_raises_if_no_query_name_given
|
48
|
+
ex = assert_raises ArgumentError do
|
49
|
+
@api.query key: 'api_key', user: 1
|
50
|
+
end
|
51
|
+
assert_equal ex.message, 'Missing Query type (expected :query)'
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def parse_hash_from_query_string query_string
|
56
|
+
hash = {}
|
57
|
+
query_string.split('&').each do |pair|
|
58
|
+
key,value = pair.split '='
|
59
|
+
hash[key] = value
|
60
|
+
end
|
61
|
+
hash
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'play_asia'
|
3
|
+
require 'minitest/mock'
|
4
|
+
require_relative 'stubs/stubbed_http_client'
|
5
|
+
|
6
|
+
class ApiListingTest < MiniTest::Unit::TestCase
|
7
|
+
OK_RESPONSE = PlayAsia::Response.new '<message><status><query>test</query><error>0</error><errorstring /><items>1</items></status><content><item>1</item></content></message>'
|
8
|
+
|
9
|
+
def test_should_map_mask_array_to_string
|
10
|
+
api = api_with_stubbed_query
|
11
|
+
api.listing mask: [:price, :barcodes, :manufacturer_codes, :sale_info, :release_date, :name, :image,
|
12
|
+
:url, :affiliate_url, :genre, :version, :encoding, :compatible]
|
13
|
+
|
14
|
+
assert_equal 'pjmsrnilagvec', api.queried_options[:mask]
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_should_use_string_for_mask_if_given
|
18
|
+
api = api_with_stubbed_query
|
19
|
+
api.listing mask: 'string'
|
20
|
+
|
21
|
+
assert_equal 'string', api.queried_options[:mask]
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_map_type_array_to_csv_of_integers
|
25
|
+
api = api_with_stubbed_query
|
26
|
+
api.listing type: [:accessory, :cd, :groceries, :apparel, :electronics, :movie, :book, :game, :toy]
|
27
|
+
|
28
|
+
assert_equal '2,3,7,8,9,4,6,1,5', api.queried_options[:type]
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_should_use_string_for_type_if_given
|
32
|
+
api = api_with_stubbed_query
|
33
|
+
api.listing type: 'string'
|
34
|
+
|
35
|
+
assert_equal 'string', api.queried_options[:type]
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_should_map_genre_array_to_csv_of_integers
|
39
|
+
api = api_with_stubbed_query
|
40
|
+
api.listing genre: [:strategy_video_game, :racing_video_game, :simulation_video_game, :tv_series_dvd_vcd]
|
41
|
+
|
42
|
+
assert_equal '10,11,12,122', api.queried_options[:genre]
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_should_use_string_for_genre_if_given
|
46
|
+
api = api_with_stubbed_query
|
47
|
+
api.listing genre: 'string'
|
48
|
+
|
49
|
+
assert_equal 'string', api.queried_options[:genre]
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_should_map_compatible_array_to_csv_of_integers
|
53
|
+
api = api_with_stubbed_query
|
54
|
+
api.listing compatible: [:dreamcast, :ipad]
|
55
|
+
|
56
|
+
assert_equal '9,111', api.queried_options[:compatible]
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_should_use_string_for_compatible_if_given
|
60
|
+
api = api_with_stubbed_query
|
61
|
+
api.listing compatibility: 'string'
|
62
|
+
|
63
|
+
assert_equal 'string', api.queried_options[:compatibility]
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_should_map_encoding_array_to_csv_of_integers
|
67
|
+
api = api_with_stubbed_query
|
68
|
+
api.listing encoding: [:pal, :aac]
|
69
|
+
|
70
|
+
assert_equal '4,31', api.queried_options[:encoding]
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_should_use_string_for_encoding_if_given
|
74
|
+
api = api_with_stubbed_query
|
75
|
+
api.listing encoding: 'string'
|
76
|
+
|
77
|
+
assert_equal 'string', api.queried_options[:encoding]
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_should_map_version_array_to_csv_of_integers
|
81
|
+
api = api_with_stubbed_query
|
82
|
+
api.listing version: [:asia, :hong_kong]
|
83
|
+
|
84
|
+
assert_equal '6,19', api.queried_options[:version]
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_should_use_version_for_encoding_if_given
|
88
|
+
api = api_with_stubbed_query
|
89
|
+
api.listing version: 'string'
|
90
|
+
|
91
|
+
assert_equal 'string', api.queried_options[:version]
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_should_map_skip_preowned_boolean_true_to_1
|
95
|
+
api = api_with_stubbed_query
|
96
|
+
api.listing skip_preowned: true
|
97
|
+
|
98
|
+
assert_equal '1', api.queried_options[:skip_preowned]
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_should_map_skip_preowned_boolean_false_to_0
|
102
|
+
api = api_with_stubbed_query
|
103
|
+
api.listing skip_preowned: false
|
104
|
+
|
105
|
+
assert_equal '0', api.queried_options[:skip_preowned]
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_should_allow_string_for_skip_preowned
|
109
|
+
api = api_with_stubbed_query
|
110
|
+
api.listing skip_preowned: 'yes'
|
111
|
+
|
112
|
+
assert_equal 'yes', api.queried_options[:skip_preowned]
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_should_only_use_supplied_parameters_and_query
|
116
|
+
api = api_with_stubbed_query
|
117
|
+
api.listing type: [:game], mask: [:name]
|
118
|
+
|
119
|
+
refute_nil api.queried_options[:type]
|
120
|
+
refute_nil api.queried_options[:mask]
|
121
|
+
assert_equal [:type, :mask, :query], api.queried_options.keys
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
def api_with_stubbed_query
|
126
|
+
api = PlayAsia::Api.new
|
127
|
+
|
128
|
+
# overwrite the query method so we can grab the options passed to it
|
129
|
+
class << api
|
130
|
+
attr_reader :queried_options
|
131
|
+
|
132
|
+
def query(opts = {})
|
133
|
+
@queried_options = opts
|
134
|
+
OK_RESPONSE
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
api
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'play_asia'
|
3
|
+
|
4
|
+
class ResponseTest < MiniTest::Unit::TestCase
|
5
|
+
def test_should_have_error_when_error_in_status
|
6
|
+
assert error_response.error?
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_should_have_error_message_when_errorstring_in_status
|
10
|
+
error_message = 'I am an error!'
|
11
|
+
|
12
|
+
assert_equal error_message, error_response_with_errorstring(error_message).error_message
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_have_more_should_be_true_if_number_of_items_is_less_than_total_items
|
16
|
+
assert ok_response_with_paged_items.has_more?
|
17
|
+
refute ok_response_with_paged_items.complete?
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_have_more_should_be_false_if_number_of_items_is_greater_or_equal_to_total_items
|
21
|
+
refute ok_response_with_all_items.has_more?
|
22
|
+
assert ok_response_with_all_items.complete?
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_have_more_should_be_true_if_number_of_items_is_less_than_total_items_with_start_offset
|
26
|
+
assert ok_response_with_paged_items_page_two.has_more?
|
27
|
+
refute ok_response_with_paged_items_page_two.complete?
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_have_more_should_be_false_if_number_of_items_is_greater_or_equal_to_total_items_with_start_offset
|
31
|
+
refute ok_response_with_paged_items_page_three.has_more?
|
32
|
+
assert ok_response_with_paged_items_page_three.complete?
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def error_response
|
37
|
+
PlayAsia::Response.new '<message><status><error>1</error></status><content /></message>'
|
38
|
+
end
|
39
|
+
|
40
|
+
def error_response_with_errorstring(error_string)
|
41
|
+
PlayAsia::Response.new "<message><status><error>1</error><errorstring>#{error_string}</errorstring></status><content /></message>"
|
42
|
+
end
|
43
|
+
|
44
|
+
def ok_response_with_paged_items
|
45
|
+
PlayAsia::Response.new <<RESPONSE
|
46
|
+
<message>
|
47
|
+
<status>
|
48
|
+
<error>0</error>
|
49
|
+
<errorstring />
|
50
|
+
<total_items>3</total_items>
|
51
|
+
<items>1</items>
|
52
|
+
</status>
|
53
|
+
<content>
|
54
|
+
<item>
|
55
|
+
<name>one</name>
|
56
|
+
</item>
|
57
|
+
</content>
|
58
|
+
</message>
|
59
|
+
RESPONSE
|
60
|
+
end
|
61
|
+
|
62
|
+
def ok_response_with_paged_items_page_two
|
63
|
+
PlayAsia::Response.new <<RESPONSE
|
64
|
+
<message>
|
65
|
+
<status>
|
66
|
+
<error>0</error>
|
67
|
+
<errorstring />
|
68
|
+
<start>1</start>
|
69
|
+
<total_items>3</total_items>
|
70
|
+
<items>1</items>
|
71
|
+
</status>
|
72
|
+
<content>
|
73
|
+
<item>
|
74
|
+
<name>two</name>
|
75
|
+
</item>
|
76
|
+
</content>
|
77
|
+
</message>
|
78
|
+
RESPONSE
|
79
|
+
end
|
80
|
+
|
81
|
+
def ok_response_with_paged_items_page_three
|
82
|
+
PlayAsia::Response.new <<RESPONSE
|
83
|
+
<message>
|
84
|
+
<status>
|
85
|
+
<error>0</error>
|
86
|
+
<errorstring />
|
87
|
+
<start>2</start>
|
88
|
+
<total_items>3</total_items>
|
89
|
+
<items>1</items>
|
90
|
+
</status>
|
91
|
+
<content>
|
92
|
+
<item>
|
93
|
+
<name>three</name>
|
94
|
+
</item>
|
95
|
+
</content>
|
96
|
+
</message>
|
97
|
+
RESPONSE
|
98
|
+
end
|
99
|
+
|
100
|
+
def ok_response_with_all_items
|
101
|
+
PlayAsia::Response.new <<RESPONSE
|
102
|
+
<message>
|
103
|
+
<status>
|
104
|
+
<error>0</error>
|
105
|
+
<errorstring />
|
106
|
+
<total_items>2</total_items>
|
107
|
+
<items>2</items>
|
108
|
+
</status>
|
109
|
+
<content>
|
110
|
+
<item>
|
111
|
+
<name>one</name>
|
112
|
+
</item>
|
113
|
+
<item>
|
114
|
+
<name>two</name>
|
115
|
+
</item>
|
116
|
+
</content>
|
117
|
+
</message>
|
118
|
+
RESPONSE
|
119
|
+
end
|
120
|
+
end
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: play_asia
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- James Gregory
|
9
|
+
- On the Game
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-02-21 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: nokogiri
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: minitest-reporters
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
description: A thin wrapper around the Play Asia API
|
48
|
+
email:
|
49
|
+
- james@onthegame.com.au
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- .gitignore
|
55
|
+
- Gemfile
|
56
|
+
- LICENSE
|
57
|
+
- README.md
|
58
|
+
- Rakefile
|
59
|
+
- lib/play_asia.rb
|
60
|
+
- lib/play_asia/api.rb
|
61
|
+
- lib/play_asia/api_listing.rb
|
62
|
+
- lib/play_asia/http_client.rb
|
63
|
+
- lib/play_asia/response.rb
|
64
|
+
- lib/play_asia/version.rb
|
65
|
+
- play_asia.gemspec
|
66
|
+
- test/stubs/stubbed_http_client.rb
|
67
|
+
- test/test_api.rb
|
68
|
+
- test/test_api_listing.rb
|
69
|
+
- test/test_response.rb
|
70
|
+
homepage: http://www.onthegame.com.au/about/opensource
|
71
|
+
licenses: []
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 1.8.24
|
91
|
+
signing_key:
|
92
|
+
specification_version: 3
|
93
|
+
summary: Play Asia API
|
94
|
+
test_files:
|
95
|
+
- test/stubs/stubbed_http_client.rb
|
96
|
+
- test/test_api.rb
|
97
|
+
- test/test_api_listing.rb
|
98
|
+
- test/test_response.rb
|