play_asia 1.0.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.
- 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
|