reve 0.0.74
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/ChangeLog +155 -0
- data/Rakefile +43 -0
- data/init.rb +1 -0
- data/lib/reve.rb +793 -0
- data/reve.rb +1 -0
- data/test/test_reve.rb +700 -0
- data/test/xml/alliances.xml +171 -0
- data/test/xml/assets.xml +32 -0
- data/test/xml/badxml.xml +6 -0
- data/test/xml/character_sheet.xml +37 -0
- data/test/xml/characterid.xml +11 -0
- data/test/xml/charactername.xml +11 -0
- data/test/xml/characters.xml +13 -0
- data/test/xml/conqurable_stations.xml +11 -0
- data/test/xml/corporation_sheet.xml +52 -0
- data/test/xml/errors/error_100.xml +5 -0
- data/test/xml/errors/error_101.xml +5 -0
- data/test/xml/errors/error_102.xml +5 -0
- data/test/xml/errors/error_103.xml +5 -0
- data/test/xml/errors/error_104.xml +5 -0
- data/test/xml/errors/error_105.xml +5 -0
- data/test/xml/errors/error_106.xml +5 -0
- data/test/xml/errors/error_107.xml +5 -0
- data/test/xml/errors/error_108.xml +5 -0
- data/test/xml/errors/error_109.xml +5 -0
- data/test/xml/errors/error_110.xml +5 -0
- data/test/xml/errors/error_111.xml +5 -0
- data/test/xml/errors/error_112.xml +5 -0
- data/test/xml/errors/error_113.xml +5 -0
- data/test/xml/errors/error_114.xml +5 -0
- data/test/xml/errors/error_115.xml +5 -0
- data/test/xml/errors/error_116.xml +5 -0
- data/test/xml/errors/error_117.xml +5 -0
- data/test/xml/errors/error_118.xml +5 -0
- data/test/xml/errors/error_119.xml +5 -0
- data/test/xml/errors/error_120.xml +5 -0
- data/test/xml/errors/error_121.xml +5 -0
- data/test/xml/errors/error_200.xml +5 -0
- data/test/xml/errors/error_201.xml +5 -0
- data/test/xml/errors/error_202.xml +5 -0
- data/test/xml/errors/error_203.xml +5 -0
- data/test/xml/errors/error_204.xml +5 -0
- data/test/xml/errors/error_205.xml +5 -0
- data/test/xml/errors/error_206.xml +5 -0
- data/test/xml/errors/error_207.xml +5 -0
- data/test/xml/errors/error_208.xml +5 -0
- data/test/xml/errors/error_209.xml +5 -0
- data/test/xml/errors/error_210.xml +5 -0
- data/test/xml/errors/error_211.xml +5 -0
- data/test/xml/errors/error_212.xml +5 -0
- data/test/xml/errors/error_213.xml +5 -0
- data/test/xml/errors/error_214.xml +5 -0
- data/test/xml/errors/error_500.xml +5 -0
- data/test/xml/errors/error_501.xml +5 -0
- data/test/xml/errors/error_502.xml +5 -0
- data/test/xml/errors/error_503.xml +5 -0
- data/test/xml/errors/error_504.xml +5 -0
- data/test/xml/errors/error_505.xml +5 -0
- data/test/xml/errors/error_506.xml +5 -0
- data/test/xml/errors/error_507.xml +5 -0
- data/test/xml/errors/error_508.xml +5 -0
- data/test/xml/errors/error_509.xml +5 -0
- data/test/xml/errors/error_510.xml +5 -0
- data/test/xml/errors/error_511.xml +5 -0
- data/test/xml/errors/error_512.xml +5 -0
- data/test/xml/errors/error_513.xml +5 -0
- data/test/xml/errors/error_514.xml +5 -0
- data/test/xml/errors/error_515.xml +5 -0
- data/test/xml/errors/error_516.xml +5 -0
- data/test/xml/errors/error_517.xml +5 -0
- data/test/xml/errors/error_518.xml +5 -0
- data/test/xml/errors/error_519.xml +5 -0
- data/test/xml/errors/error_520.xml +5 -0
- data/test/xml/errors/error_521.xml +5 -0
- data/test/xml/errors/error_522.xml +5 -0
- data/test/xml/errors/error_523.xml +5 -0
- data/test/xml/errors/error_900.xml +5 -0
- data/test/xml/errors/error_901.xml +5 -0
- data/test/xml/errors/error_902.xml +5 -0
- data/test/xml/errors/error_903.xml +5 -0
- data/test/xml/errors/error_999.xml +5 -0
- data/test/xml/industryjobs.xml +11 -0
- data/test/xml/kills.xml +163 -0
- data/test/xml/mapjumps.xml +15 -0
- data/test/xml/mapkills.xml +16 -0
- data/test/xml/market_transactions.xml +79 -0
- data/test/xml/marketorders.xml +37 -0
- data/test/xml/member_tracking.xml +22 -0
- data/test/xml/nonmember_corpsheet.xml +30 -0
- data/test/xml/reftypes.xml +14 -0
- data/test/xml/skill_in_training-amarr-titan.xml +13 -0
- data/test/xml/skill_in_training-none.xml +7 -0
- data/test/xml/skilltree.xml +40 -0
- data/test/xml/sovereignty.xml +29 -0
- data/test/xml/starbase_fuel.xml +23 -0
- data/test/xml/starbases.xml +12 -0
- data/test/xml/wallet_balance.xml +17 -0
- data/test/xml/wallet_journal.xml +48 -0
- data/tester.rb +17 -0
- metadata +151 -0
data/lib/reve.rb
ADDED
@@ -0,0 +1,793 @@
|
|
1
|
+
#--
|
2
|
+
# Code copyright Lisa Seelye, 2007-2008. www.crudvision.com
|
3
|
+
# Reve is not licensed for commercial use. For other uses there are no
|
4
|
+
# restrictions.
|
5
|
+
#
|
6
|
+
# The author is not adverse to tokens of appreciation in the form of Eve ISK,
|
7
|
+
# ships, and feedback. Please use
|
8
|
+
# http://www.crudvision.com/reve-ruby-eve-online-api-library/ to provide
|
9
|
+
# feedback or send ISK to Raquel Smith in Eve. :-)
|
10
|
+
#++
|
11
|
+
|
12
|
+
begin
|
13
|
+
require 'hpricot'
|
14
|
+
rescue LoadError
|
15
|
+
require 'rubygems'
|
16
|
+
require 'hpricot'
|
17
|
+
end
|
18
|
+
require 'net/http'
|
19
|
+
require 'uri'
|
20
|
+
require 'cgi'
|
21
|
+
require 'fileutils'
|
22
|
+
|
23
|
+
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
24
|
+
|
25
|
+
require 'lib/reve/exceptions'
|
26
|
+
require 'lib/reve/extensions'
|
27
|
+
require 'lib/reve/classes'
|
28
|
+
|
29
|
+
|
30
|
+
module Reve
|
31
|
+
# API Class.
|
32
|
+
# Basic Usage:
|
33
|
+
# api = Reve::API.new('my_UserID', 'my_apiKey')
|
34
|
+
# alliances = api.alliances # Returns an array of Reve::Classes::Alliance
|
35
|
+
#
|
36
|
+
# api.personal_wallet_blanace(:characterid => 892008733) # Returns an array of
|
37
|
+
# Reve::Classes::WalletBalance. Note that the CharacterID Number is required
|
38
|
+
# here.
|
39
|
+
#
|
40
|
+
# api.sovereignty :just_hash => true # Returns the hash for this call with no
|
41
|
+
# Alliance data with it.
|
42
|
+
#
|
43
|
+
# As of Revision 22 (28 August 2007) all API calls take a parameter,
|
44
|
+
# :just_hash, to just get the hash that represents that particular API call;
|
45
|
+
# No data related to the call is returned if :just_hash is present
|
46
|
+
#
|
47
|
+
# All API methods have the functionality to read XML from an arbitrary location. This could be another webserver, or a XML file on disk.
|
48
|
+
# To use this pass the hash option :url => +location+ where +location+ is a String or URI class. See format_url_request documentation for more details.
|
49
|
+
class API
|
50
|
+
|
51
|
+
@@alliances_url = 'http://api.eve-online.com/eve/AllianceList.xml.aspx'
|
52
|
+
@@sovereignty_url = 'http://api.eve-online.com/map/Sovereignty.xml.aspx'
|
53
|
+
@@reftypes_url = 'http://api.eve-online.com/eve/RefTypes.xml.aspx'
|
54
|
+
@@skill_tree_url = 'http://api.eve-online.com/eve/SkillTree.xml.aspx'
|
55
|
+
@@member_tracking_url = 'http://api.eve-online.com/corp/MemberTracking.xml.aspx'
|
56
|
+
@@corporate_wallet_balance_url = 'http://api.eve-online.com/corp/AccountBalance.xml.aspx'
|
57
|
+
@@personal_wallet_balance_url = 'http://api.eve-online.com/char/AccountBalance.xml.aspx'
|
58
|
+
@@corporate_wallet_trans_url = 'http://api.eve-online.com/corp/WalletTransactions.xml.aspx'
|
59
|
+
@@personal_wallet_trans_url = 'http://api.eve-online.com/char/WalletTransactions.xml.aspx'
|
60
|
+
@@corporate_wallet_journal_url = 'http://api.eve-online.com/corp/WalletJournal.xml.aspx'
|
61
|
+
@@personal_wallet_journal_url = 'http://api.eve-online.com/char/WalletJournal.xml.aspx'
|
62
|
+
@@characters_url = 'http://api.eve-online.com/account/Characters.xml.aspx'
|
63
|
+
@@training_skill_url = 'http://api.eve-online.com/char/SkillInTraining.xml.aspx'
|
64
|
+
@@character_sheet_url = 'http://api.eve-online.com/char/CharacterSheet.xml.aspx'
|
65
|
+
@@starbases_url = 'http://api.eve-online.com/corp/StarbaseList.xml.aspx'
|
66
|
+
@@starbasedetail_url = 'http://api.eve-online.com/corp/StarbaseDetail.xml.aspx'
|
67
|
+
@@conqurable_outposts_url = 'http://api.eve-online.com/eve/ConquerableStationList.xml.aspx'
|
68
|
+
@@corporation_sheet_url = 'http://api.eve-online.com/corp/CorporationSheet.xml.aspx'
|
69
|
+
@@errors_url = 'http://api.eve-online.com/eve/ErrorList.xml.aspx'
|
70
|
+
@@map_jumps_url = 'http://api.eve-online.com/map/Jumps.xml.aspx'
|
71
|
+
@@map_kills_url = 'http://api.eve-online.com/map/Kills.xml.aspx'
|
72
|
+
@@personal_market_orders_url = 'http://api.eve-online.com/char/MarketOrders.xml.aspx'
|
73
|
+
@@corporate_market_orders_url = 'http://api.eve-online.com/corp/MarketOrders.xml.aspx'
|
74
|
+
@@personal_industry_jobs_url = 'http://api.eve-online.com/char/IndustryJobs.xml.aspx'
|
75
|
+
@@corporate_industry_jobs_url = 'http://api.eve-online.com/corp/IndustryJobs.xml.aspx'
|
76
|
+
@@personal_assets_url = 'http://api.eve-online.com/char/AssetList.xml.aspx'
|
77
|
+
@@corporate_assets_url = 'http://api.eve-online.com/corp/AssetList.xml.aspx'
|
78
|
+
@@personal_kills_url = 'http://api.eve-online.com/char/KillLog.xml.aspx'
|
79
|
+
@@corporate_kills_url = 'http://api.eve-online.com/corp/KillLog.xml.aspx'
|
80
|
+
@@character_id_url = 'http://api.eve-online.com/eve/CharacterID.xml.aspx' # ?names=CCP%20Garthagk,Raquel%20Smith
|
81
|
+
@@character_name_url = 'http://api.eve-online.com/eve/CharacterName.xml.aspx' # ?ids=797400947,892008733
|
82
|
+
|
83
|
+
cattr_accessor :character_sheet_url, :training_skill_url, :characters_url, :personal_wallet_journal_url,
|
84
|
+
:corporate_wallet_journal_url, :personal_wallet_trans_url, :corporate_wallet_trans_url,
|
85
|
+
:personal_wallet_balance_url, :corporate_wallet_balance_url, :member_tracking_url,
|
86
|
+
:skill_tree_url, :reftypes_url, :sovereignty_url, :alliances_url, :starbases_url,
|
87
|
+
:starbasedetail_url, :conqurable_outposts_url, :corporation_sheet_url, :map_jumps_url,
|
88
|
+
:map_kills_url, :personal_market_orders_url, :corporate_market_orders_url,
|
89
|
+
:personal_industry_jobs_url, :corporate_industry_jobs_url, :personal_assets_url,
|
90
|
+
:corporate_assets_url, :personal_kills_url, :corporate_kills_url
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
attr_accessor :key, :userid, :charid
|
95
|
+
attr_accessor :http_user_agent, :save_path
|
96
|
+
attr_reader :current_time, :cached_until, :last_hash
|
97
|
+
|
98
|
+
# Create a new API instance.
|
99
|
+
# current_time and cached_until are meaningful only for the LAST call made.
|
100
|
+
# Expects:
|
101
|
+
# * userid ( Integer | String ) - Your API userID
|
102
|
+
# * key ( String ) - Your API key (Full key or restricted key)
|
103
|
+
# * charid ( Integer | String ) - Default characterID for calls requiring it.
|
104
|
+
# NOTE: All values passed to the constructor are typecasted to a String for safety.
|
105
|
+
def initialize(userid = "", key = "", charid = "")
|
106
|
+
@userid = (userid || "").to_s
|
107
|
+
@key = (key || "").to_s
|
108
|
+
@charid = (charid || "").to_s
|
109
|
+
|
110
|
+
@save_path = nil
|
111
|
+
|
112
|
+
@http_user_agent = "Reve"
|
113
|
+
@max_tries = 3
|
114
|
+
|
115
|
+
@current_time = nil
|
116
|
+
@cached_until = nil
|
117
|
+
@last_hash = nil
|
118
|
+
end
|
119
|
+
# Save XML to this directory with the format:
|
120
|
+
# :save_path/:userid/:method/:expires_at_in_unixtime.xml
|
121
|
+
# eg: ./xml/12345/characters/1200228878.xml
|
122
|
+
# or: ./xml/alliances/1200228878.xml
|
123
|
+
# If @save_path is nil then XML is not saved.
|
124
|
+
def save_path=(p)
|
125
|
+
@save_path = p
|
126
|
+
end
|
127
|
+
|
128
|
+
# Convert Character names to Character ids.
|
129
|
+
# Expects a Hash as a parameter with these keys:
|
130
|
+
# * names ( Array ) - An Array of Character names to fetch the IDs of.
|
131
|
+
# See Also: character_name, Reve::Classes::Character, character_sheet
|
132
|
+
#--
|
133
|
+
# This is an odd method because the XML from this looks like:
|
134
|
+
# <rowset ...>
|
135
|
+
# <row:name name="CCP Garthagk" characterID="797400947" xmlns:row="characterID" />
|
136
|
+
# </rowset>
|
137
|
+
# I have to hack the Hpricot::Doc document coming from process_query to
|
138
|
+
# gsub out the row:name -> row to make the XPath work. Hope it doesn't
|
139
|
+
# perform too slowly! (We don't, of course, care about the xmlns:row bit)
|
140
|
+
#++
|
141
|
+
def character_id(opts = {} )
|
142
|
+
names = opts[:names] || []
|
143
|
+
return [] if names.empty? # No names were passed.
|
144
|
+
opts[:names] = names.join(',')
|
145
|
+
args = postfields(opts)
|
146
|
+
h = compute_hash( opts.merge(:url => @@character_id_url) )
|
147
|
+
return h if h
|
148
|
+
xml = process_query(nil,opts[:url] || @@character_id_url, true,opts)
|
149
|
+
xml = Hpricot(xml.to_s.gsub('row:name','row')) # Namespaces are evil!!
|
150
|
+
ret = []
|
151
|
+
xml.search("//rowset/row").each do |elem|
|
152
|
+
ret << Reve::Classes::Character.new(elem)
|
153
|
+
end
|
154
|
+
ret
|
155
|
+
end
|
156
|
+
|
157
|
+
# Convert Character names to Character names.
|
158
|
+
# Expects a Hash as a parameter with these keys:
|
159
|
+
# * ids ( Array ) - An Array of Character IDs to fetch the names of.
|
160
|
+
# See Also: character_name, Reve::Classes::Character, character_sheet
|
161
|
+
def character_name(opts = {})
|
162
|
+
ids = opts[:ids] || []
|
163
|
+
return [] if ids.empty?
|
164
|
+
opts[:ids] = ids.join(',')
|
165
|
+
compute_hash( opts.merge(:url => @@character_name_url) ) ||
|
166
|
+
process_query(Reve::Classes::Character,opts[:url] || @@character_name_url,false,opts)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Return a list of Alliances and member Corporations from
|
170
|
+
# http://api.eve-online.com/eve/AllianceList.xml.aspx
|
171
|
+
# Use the corporation_sheet method to get information for each member
|
172
|
+
# Corporation
|
173
|
+
# See also: Reve::Classes::Alliance, Reve::Classes::Corporation and
|
174
|
+
# corporation_sheet
|
175
|
+
def alliances(opts = {})
|
176
|
+
args = postfields(opts)
|
177
|
+
h = compute_hash(args.merge(:url => @@alliances_url))
|
178
|
+
return h if h
|
179
|
+
xml = process_query(nil,opts[:url] || @@alliances_url,true,args)
|
180
|
+
alliances = []
|
181
|
+
xml.search("/eveapi/result/rowset[@name='alliances']/row").each do |alliance|
|
182
|
+
alliance_obj = Reve::Classes::Alliance.new(alliance)
|
183
|
+
alliance.search("rowset[@name='memberCorporations']/row").each do |corporation|
|
184
|
+
alliance_obj.member_corporations << Reve::Classes::Corporation.new(corporation)
|
185
|
+
end
|
186
|
+
alliances << alliance_obj
|
187
|
+
end
|
188
|
+
alliances
|
189
|
+
end
|
190
|
+
|
191
|
+
# Returns a list of the number of jumps for each system. If there are no
|
192
|
+
# jumps for a system it will not be included. See also Reve::Classes::MapJump
|
193
|
+
def map_jumps(opts = {})
|
194
|
+
compute_hash( opts.merge(:url => @@map_jumps_url) ) ||
|
195
|
+
process_query(Reve::Classes::MapJump,opts[:url] || @@map_jumps_url,false)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Returns a list of the number of kills for each system. If there are no
|
199
|
+
# kills for a system it will not be included. See also Reve::Classes::MapKill
|
200
|
+
def map_kills(opts = {})
|
201
|
+
compute_hash( opts.merge(:url => @@map_kills_url) ) ||
|
202
|
+
process_query(Reve::Classes::MapKill,opts[:url] || @@map_kills_url,false)
|
203
|
+
end
|
204
|
+
|
205
|
+
# Returns a list of API Errors
|
206
|
+
def errors(opts = {})
|
207
|
+
compute_hash( opts.merge(:url => @@errors_url) ) ||
|
208
|
+
process_query(Reve::Classes::APIError,opts[:url] || @@errors_url,false)
|
209
|
+
end
|
210
|
+
|
211
|
+
# Returns the Sovereignty list from
|
212
|
+
# http://api.eve-online.com/map/Sovereignty.xml.aspx
|
213
|
+
# See also: Reve::Classes::Sovereignty
|
214
|
+
def sovereignty(opts = {})
|
215
|
+
compute_hash( opts.merge(:url => @@sovereignty_url) ) ||
|
216
|
+
process_query(Reve::Classes::Sovereignty,opts[:url] || @@sovereignty_url,false)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Returns a RefType list (whatever they are) from
|
220
|
+
# http://api.eve-online.com/eve/RefTypes.xml.aspx
|
221
|
+
# See also: Reve::Classes::RefType
|
222
|
+
def ref_types(opts = {})
|
223
|
+
compute_hash( opts.merge(:url => @@reftypes_url) ) ||
|
224
|
+
process_query(Reve::Classes::RefType,opts[:url] || @@reftypes_url,false)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Returns a list of ConqurableStations and outposts from
|
228
|
+
# http://api.eve-online.com/eve/ConquerableStationList.xml.aspx
|
229
|
+
# See also: Reve::Classes::ConqurableStation
|
230
|
+
def conqurable_stations(opts = {})
|
231
|
+
compute_hash( opts.merge(:url => @@conqurable_outposts_url) ) ||
|
232
|
+
process_query(Reve::Classes::ConqurableStation, opts[:url] || @@conqurable_outposts_url, false)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Returns a list of Reve::Classes::MarketOrder objects for market orders that are up
|
236
|
+
# Pass the characterid of the Character to check for
|
237
|
+
def personal_market_orders(opts = {:characterid => nil})
|
238
|
+
args = postfields(opts)
|
239
|
+
h = compute_hash(args.merge(:url => @@personal_market_orders_url))
|
240
|
+
return h if h
|
241
|
+
process_query(Reve::Classes::PersonalMarketOrder, opts[:url] || @@personal_market_orders_url, false, args)
|
242
|
+
end
|
243
|
+
|
244
|
+
# Returns a list of Reve::Classes::MarketOrder objects for market orders that are up on behalf of a Corporation
|
245
|
+
# Pass the characterid of the Character of whose corporation to check for
|
246
|
+
def corporate_market_orders(opts = {:characterid => nil})
|
247
|
+
args = postfields(opts)
|
248
|
+
h = compute_hash(args.merge(:url => @@corporate_market_orders_url))
|
249
|
+
return h if h
|
250
|
+
process_query(Reve::Classes::PersonalMarketOrder, opts[:url] || @@corporate_market_orders_url, false, args)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Returns a list of Reve::Classes::PersonalIndustryJob objects.
|
254
|
+
def personal_industry_jobs(opts = {:characterid => nil})
|
255
|
+
args = postfields(opts)
|
256
|
+
h = compute_hash(args.merge(:url => @@personal_industry_jobs_url))
|
257
|
+
return h if h
|
258
|
+
process_query(Reve::Classes::PersonalIndustryJob, opts[:url] || @@personal_industry_jobs_url,false,args)
|
259
|
+
end
|
260
|
+
|
261
|
+
# Returns a list of Reve::Classes::CorporateIndustryJob objects.
|
262
|
+
def corporate_industry_jobs(opts = {:characterid => nil})
|
263
|
+
args = postfields(opts)
|
264
|
+
h = compute_hash(args.merge(:url => @@corporate_industry_jobs_url))
|
265
|
+
return h if h
|
266
|
+
process_query(Reve::Classes::CorporateIndustryJob, opts[:url] || @@corporate_industry_jobs_url,false,args)
|
267
|
+
end
|
268
|
+
|
269
|
+
# Returns the SkillTree from
|
270
|
+
# http://api.eve-online.com/eve/SkillTree.xml.aspx
|
271
|
+
# See also: Reve::Classes::SkillTree
|
272
|
+
# NOTE: This doesn't actually return a 'tree' yet.
|
273
|
+
def skill_tree(opts = {})
|
274
|
+
h = compute_hash(opts.merge(:url => @@skill_tree_url) )
|
275
|
+
return h if h
|
276
|
+
doc = process_query(nil,opts[:url] || @@skill_tree_url,true)
|
277
|
+
skills = []
|
278
|
+
(doc/'rowset[@name=skills]/row').each do |skill|
|
279
|
+
name = skill['typename']
|
280
|
+
type_id = skill['typeid']
|
281
|
+
group_id = skill['groupid']
|
282
|
+
rank = (skill/:rank).inner_html
|
283
|
+
desc = (skill/:description).inner_html
|
284
|
+
required_skills = []
|
285
|
+
reqs = (skill/'rowset@name=[requiredskills]/row')
|
286
|
+
reqs.each do |required|
|
287
|
+
next if required.kind_of? Hpricot::Text # why is this needed? Why is this returned? How can I only get stuff with typeid and skilllevel?
|
288
|
+
required_skills << Reve::Classes::SkillRequirement.new(required) if required['typeid'] && required['skilllevel']
|
289
|
+
end
|
290
|
+
required_attribs = []
|
291
|
+
(skill/'requiredattributes').each do |req|
|
292
|
+
pri = doc.at(req.xpath + "/primaryattribute")
|
293
|
+
sec = doc.at(req.xpath + "/secondaryattribute")
|
294
|
+
required_attribs << Reve::Classes::PrimaryAttribute.new(pri.inner_html)
|
295
|
+
required_attribs << Reve::Classes::SecondaryAttribute.new(sec.inner_html)
|
296
|
+
end
|
297
|
+
bonuses = []
|
298
|
+
res = (skill/'rowset@name=[skillbonuscollection]/row')
|
299
|
+
res.each do |bonus|
|
300
|
+
next if bonus.kind_of? Hpricot::Text
|
301
|
+
bonuses << Reve::Classes::SkillBonus.new(bonus) if bonus['bonustype'] && bonus['bonusvalue']
|
302
|
+
end
|
303
|
+
skills << Reve::Classes::SkillTree.new(name,type_id,group_id,desc,rank,required_attribs,required_skills,bonuses)
|
304
|
+
end
|
305
|
+
skills
|
306
|
+
end
|
307
|
+
|
308
|
+
# Does big brother tracking from
|
309
|
+
# http://api.eve-online.com/corp/MemberTracking.xml.aspx
|
310
|
+
# Expects:
|
311
|
+
# * charid ( Integer | String ) - Look at players in this Character's Corporation
|
312
|
+
# See also: Reve::Classes::MemberTracking
|
313
|
+
def member_tracking(opts = {:characterid => nil})
|
314
|
+
args = postfields(opts)
|
315
|
+
h = compute_hash(args.merge(:url => @@member_tracking_url))
|
316
|
+
return h if h
|
317
|
+
process_query(Reve::Classes::MemberTracking,opts[:url] || @@member_tracking_url,false,args)
|
318
|
+
end
|
319
|
+
|
320
|
+
# Gets one's own personal WalletBalance from
|
321
|
+
# http://api.eve-online.com/char/AccountBalance.xml.aspx
|
322
|
+
# Expects:
|
323
|
+
# * charid ( Integer | String ) - Look at this player's WalletBalance
|
324
|
+
# See also: Reve::Classes::WalletBalance and corporate_wallet_balance
|
325
|
+
def personal_wallet_balance(opts = { :characterid => nil })
|
326
|
+
args = postfields(opts)
|
327
|
+
h = compute_hash(args.merge(:url => @@personal_wallet_balance_url))
|
328
|
+
return h if h
|
329
|
+
process_query(Reve::Classes::WalletBalance,opts[:url] || @@personal_wallet_balance_url,false,args)
|
330
|
+
end
|
331
|
+
|
332
|
+
# Gets one's corporate WalletBalance from
|
333
|
+
# http://api.eve-online.com/corp/AccountBalance.xml.aspx
|
334
|
+
# Expects:
|
335
|
+
# * charid ( Integer | String ) - Look at WalletBalance objects from this Character's Corporation
|
336
|
+
# See also: Reve::Classes::WalletBalance and personal_wallet_balance
|
337
|
+
def corporate_wallet_balance(opts = { :characterd => nil })
|
338
|
+
args = postfields(opts)
|
339
|
+
h = compute_hash(args.merge(:url => @@corporate_wallet_balance_url))
|
340
|
+
return h if h
|
341
|
+
process_query(Reve::Classes::WalletBalance,opts[:url] || @@corporate_wallet_balance_url,false,args)
|
342
|
+
end
|
343
|
+
|
344
|
+
# Gets one's own personal WalletTransaction list from
|
345
|
+
# http://api.eve-online.com/char/WalletTransactions.xml.aspx
|
346
|
+
# Expects:
|
347
|
+
# * characterid ( Integer | String ) - Look at this player's WalletTransaction list
|
348
|
+
# * before_trans_id ( Integer | String ) - Gets a list of WalletTransaction objects from before this Transaction ID.
|
349
|
+
# See also: Reve::Classes::WalletTransaction and
|
350
|
+
# corporate_wallet_transactions
|
351
|
+
def personal_wallet_transactions(opts = { :characterid => nil, :before_trans_id => nil })
|
352
|
+
args = postfields(opts)
|
353
|
+
h = compute_hash(args.merge(:url => @@personal_wallet_trans_url) )
|
354
|
+
return h if h
|
355
|
+
process_query(Reve::Classes::PersonalWalletTransaction,opts[:url] || @@personal_wallet_trans_url,false,opts)
|
356
|
+
end
|
357
|
+
|
358
|
+
# Gets one's corporate WalletTransaction list from
|
359
|
+
# http://api.eve-online.com/corp/WalletTransactions.xml.aspx
|
360
|
+
# Expects:
|
361
|
+
# * account_key ( Integer | String ) - Account key (1000-1006) to look at.
|
362
|
+
# * charid ( Integer | String ) - Look at WalletTransaction objects from this Character's Corporation
|
363
|
+
# * before_trans_id ( Integer | String ) - Gets a list of WalletTransaction objects from before this Transaction ID.
|
364
|
+
# See also: Reve::Classes::WalletTransaction and
|
365
|
+
# personal_wallet_transactions
|
366
|
+
def corporate_wallet_transactions(opts = {:accountkey => nil, :characterid => nil, :beforerefid => nil})
|
367
|
+
args = postfields(opts)
|
368
|
+
h = compute_hash(args.merge(:url => @@corporate_wallet_trans_url))
|
369
|
+
return h if h
|
370
|
+
process_query(Reve::Classes::CorporateWalletTransaction,opts[:url] || @@corporate_wallet_trans_url,false,args)
|
371
|
+
end
|
372
|
+
|
373
|
+
# Gets one's own corporate WalletJournal list from
|
374
|
+
# http://api.eve-online.com/corp/WalletJournal.xml.aspx
|
375
|
+
# Expects:
|
376
|
+
# * account_key ( Integer | String ) - Account key (1000-1006) to look at.
|
377
|
+
# * charid ( Integer | String ) - Look at WalletJournal objects from this Character's Corporation
|
378
|
+
# * before_ref_id ( Integer | String ) - Gets a list of WalletTransaction objects from before this RefID.
|
379
|
+
# See also: Reve::Classes::WalletJournal and personal_wallet_journal
|
380
|
+
def corporate_wallet_journal(opts = {:accountkey => nil, :characterid => nil, :beforerefid => nil})
|
381
|
+
args = postfields(opts)
|
382
|
+
h = compute_hash(args.merge(:url => @@corporate_wallet_journal_url))
|
383
|
+
return h if h
|
384
|
+
process_query(Reve::Classes::WalletJournal,opts[:url] || @@corporate_wallet_journal_url,false,args)
|
385
|
+
end
|
386
|
+
|
387
|
+
# Gets one's own personal WalletJournal list from
|
388
|
+
# http://api.eve-online.com/char/WalletJournal.xml.aspx
|
389
|
+
# Expects:
|
390
|
+
# * charid ( Integer | String ) - Look at this player's WalletJournal list
|
391
|
+
# * before_ref_id ( Integer | String ) - Gets a list of WalletJournal objects from before this RefID.
|
392
|
+
# See also: Reve::Classes::WalletJournal and corporate_wallet_journal
|
393
|
+
def personal_wallet_journal(opts = { :characterid => nil, :beforerefid => nil} )
|
394
|
+
args = postfields(opts)
|
395
|
+
h = compute_hash(args.merge(:url => @@personal_wallet_journal_url))
|
396
|
+
return h if h
|
397
|
+
process_query(Reve::Classes::WalletJournal,opts[:url] || @@personal_wallet_journal_url,false,args)
|
398
|
+
end
|
399
|
+
|
400
|
+
# Get a list of personal assets for the characterid.
|
401
|
+
# See the Reve::Classes::Asset and Reve::Classes::AssetContainer classes
|
402
|
+
# for attributes available.
|
403
|
+
def personal_assets_list(opts = { :characterid => nil })
|
404
|
+
args = postfields(opts)
|
405
|
+
h = compute_hash(args.merge(:url => @@personal_assets_url))
|
406
|
+
return h if h
|
407
|
+
xml = process_query(nil,opts[:url] || @@personal_assets_url,true,args)
|
408
|
+
assets = []
|
409
|
+
xml.search("/eveapi/result/rowset[@name='assets']/row").each do |container|
|
410
|
+
asset_container = Reve::Classes::AssetContainer.new(container)
|
411
|
+
container.search("rowset[@name='contents']/row").each do |asset|
|
412
|
+
asset_container.assets << Reve::Classes::Asset.new(asset)
|
413
|
+
end
|
414
|
+
assets << asset_container
|
415
|
+
end
|
416
|
+
assets
|
417
|
+
end
|
418
|
+
|
419
|
+
# Get a list of the Corporate Assets. Pass the characterid of the Corporate member See also assets_list method
|
420
|
+
def corporate_assets_list(opts = { :characterid => nil})
|
421
|
+
args = postfields(opts)
|
422
|
+
h = compute_hash(args.merge(:url => @@corporate_assets_url))
|
423
|
+
return h if h
|
424
|
+
xml = process_query(nil,opts[:url] || @@corporate_assets_url,true,args)
|
425
|
+
assets = []
|
426
|
+
xml.search("/eveapi/result/rowset/row").each do |container|
|
427
|
+
asset_container = Reve::Classes::AssetContainer.new(container)
|
428
|
+
container.search("rowset[@name='contents']/row").each do |asset|
|
429
|
+
asset_container.assets << Reve::Classes::Asset.new(asset)
|
430
|
+
end
|
431
|
+
assets << asset_container
|
432
|
+
end
|
433
|
+
assets
|
434
|
+
end
|
435
|
+
|
436
|
+
# Returns a Character list for the associated key and userid from
|
437
|
+
# http://api.eve-online.com/account/Characters.xml.aspx
|
438
|
+
# See also: Reve::Classes::Character
|
439
|
+
def characters(opts = {})
|
440
|
+
args = postfields(opts)
|
441
|
+
h = compute_hash(args.merge(:url => @@characters_url))
|
442
|
+
return h if h
|
443
|
+
process_query(Reve::Classes::Character,opts[:url] || @@characters_url,false,args)
|
444
|
+
end
|
445
|
+
|
446
|
+
# Gets the SkillInTraining from
|
447
|
+
# http://api.eve-online.com/char/SkillInTraining.xml.aspx
|
448
|
+
# Expects:
|
449
|
+
# * charid ( Integer | String ) - Get the SkillInTraining for this Character
|
450
|
+
# See also: Reve::Classes::SkillInTraining
|
451
|
+
def skill_in_training(opts = {:characterid => nil})
|
452
|
+
args = postfields(opts)
|
453
|
+
ch = compute_hash(args.merge(:url => @@training_skill_url))
|
454
|
+
return ch if ch
|
455
|
+
h = {}
|
456
|
+
xml = process_query(nil,opts[:url] || @@training_skill_url,true,args)
|
457
|
+
xml.search("//result").each do |elem|
|
458
|
+
for field in [ 'currentTQTime', 'trainingEndTime','trainingStartTime','trainingTypeID','trainingStartSP','trainingDestinationSP','trainingToLevel','skillInTraining' ]
|
459
|
+
field.downcase!
|
460
|
+
h[field] = (elem/field.intern).inner_html
|
461
|
+
end
|
462
|
+
end
|
463
|
+
Reve::Classes::SkillInTraining.new(h)
|
464
|
+
end
|
465
|
+
|
466
|
+
# Returns a list of Reve::Classes::Starbase for charid's Corporation.
|
467
|
+
# http://api.eve-online.com/corp/StarbaseList.xml.aspx
|
468
|
+
# Expects:
|
469
|
+
# * charid ( Integer | String ) - Get the Starbase list for this character's Corporation
|
470
|
+
# See also Reve::Classes::Starbase
|
471
|
+
def starbases(opts = { :characterid => nil})
|
472
|
+
args = postfields(opts)
|
473
|
+
h = compute_hash(args.merge(:url => @@starbases_url))
|
474
|
+
return h if h
|
475
|
+
process_query(Reve::Classes::Starbase,opts[:url] || @@starbases_url,false,args)
|
476
|
+
end
|
477
|
+
|
478
|
+
# Returns the fuel status for the Starbase whose item id is starbase_id
|
479
|
+
# http://api.eve-online.com/corp/StarbaseDetail.xml.aspx
|
480
|
+
# Expects:
|
481
|
+
# * charid ( Integer | String ) - Get the Starbase associated wih this character's Corporation
|
482
|
+
# * starbase_id ( Integer ) - Get the fuel for this Starbase. This is the Starbase's itemid.
|
483
|
+
# See also Reve::Classes::StarbaseFuel
|
484
|
+
def starbase_fuel(opts = { :characterid => nil, :starbaseid => nil })
|
485
|
+
args = postfields(opts)
|
486
|
+
h = compute_hash(args.merge(:url => @@starbasedetail_url))
|
487
|
+
return h if h
|
488
|
+
ret = process_query(Reve::Classes::StarbaseFuel,opts[:url] || @@starbasedetail_url, false, args)
|
489
|
+
ret.each { |r| r.starbase_id = opts[:starbaseid] }
|
490
|
+
ret
|
491
|
+
end
|
492
|
+
|
493
|
+
|
494
|
+
# Get the last kills for the characterid passed.
|
495
|
+
# Expects:
|
496
|
+
# * Hash of arguments
|
497
|
+
# * * characterid ( Integer ) - The Character whose Kills to retrieve
|
498
|
+
# * * beforekillid ( Integer ) - (Optional) - Return the most recent kills before this killid.
|
499
|
+
def personal_kills(opts = { :characterid => nil })
|
500
|
+
args = postfields(opts)
|
501
|
+
h = compute_hash(args.merge(:url => @@personal_kills_url))
|
502
|
+
return h if h
|
503
|
+
xml = process_query(nil,opts[:url] || @@personal_kills_url,true,args)
|
504
|
+
kills = []
|
505
|
+
xml.search("/eveapi/result/rowset/row").each do |e|
|
506
|
+
victim = Reve::Classes::KillVictim.new(e.search("victim").first) rescue next # cant find victim
|
507
|
+
attackers = []
|
508
|
+
losses = []
|
509
|
+
e.search("rowset[@name='attackers']/row").each do |attacker|
|
510
|
+
attackers << Reve::Classes::KillAttacker.new(attacker)
|
511
|
+
end
|
512
|
+
e.search("rowset[@name='items']/row").each do |lost_item|
|
513
|
+
lost = Reve::Classes::KillLoss.new(lost_item)
|
514
|
+
lost_item.search("rowset[@name='items']/row").each do |contained|
|
515
|
+
lost.contained_losses << Reve::Classes::KillLoss.new(contained)
|
516
|
+
end
|
517
|
+
losses << lost
|
518
|
+
end
|
519
|
+
kills << Reve::Classes::Kill.new(e, victim, attackers, losses)
|
520
|
+
end
|
521
|
+
kills
|
522
|
+
end
|
523
|
+
|
524
|
+
# See the options for personal_kills
|
525
|
+
def corporate_kills(opts = { :characterid => nil })
|
526
|
+
args = postfields(opts)
|
527
|
+
h = compute_hash(args.merge(:url => @@corporate_kills_url))
|
528
|
+
return h if h
|
529
|
+
xml = process_query(nil,opts[:url] || @@corporate_kills_url,true,args)
|
530
|
+
kills = []
|
531
|
+
xml.search("/eveapi/result/rowset/row").each do |e|
|
532
|
+
victim = Reve::Classes::KillVictim.new(e.search("victim").first) rescue next # cant find victim
|
533
|
+
attackers = []
|
534
|
+
losses = []
|
535
|
+
e.search("rowset[@name='attackers']/row").each do |attacker|
|
536
|
+
attackers << Reve::Classes::KillAttacker.new(attacker)
|
537
|
+
end
|
538
|
+
e.search("rowset[@name='items']/row").each do |lost_item|
|
539
|
+
lost = Reve::Classes::KillLoss.new(lost_item)
|
540
|
+
lost_item.search("rowset[@name='items']/row").each do |contained|
|
541
|
+
lost.contained_losses << Reve::Classes::KillLoss.new(contained)
|
542
|
+
end
|
543
|
+
losses << lost
|
544
|
+
end
|
545
|
+
kills << Reve::Classes::Kill.new(e, victim, attackers, losses)
|
546
|
+
end
|
547
|
+
kills
|
548
|
+
end
|
549
|
+
|
550
|
+
# Gets the CorporationSheet from http://api.eve-online.com/corp/CorporationSheet.xml.aspx
|
551
|
+
# Expects:
|
552
|
+
# * Hash of arguments:
|
553
|
+
# * * characterid ( Integer | String ) - Gets the CorporationSheet for this Character
|
554
|
+
# * * corporationid ( Integer ) - If the characterid isn't passed then send the corporation's id
|
555
|
+
# (See the alliances method for a list) to get the details of a Corporation that belongs to an Alliance.
|
556
|
+
# See also: Reve::Classes::CorporationSheet
|
557
|
+
def corporation_sheet(opts = { :characterid => nil })
|
558
|
+
args = postfields(opts)
|
559
|
+
h = compute_hash(args.merge(:url => @@corporation_sheet_url))
|
560
|
+
return h if h
|
561
|
+
xml = process_query(nil,opts[:url] || @@corporation_sheet_url,true,args)
|
562
|
+
|
563
|
+
h = { 'graphicid' => 0, 'shape1' => 0, 'shape2' => 0, 'shape3' => 0, 'color1' => 0, 'color2' => 0, 'color3' => 0, }
|
564
|
+
h.keys.each { |k| h[k] = xml.search("//result/logo/" + k + "/").to_s.to_i }
|
565
|
+
corporate_logo = Reve::Classes::CorporateLogo.new h
|
566
|
+
|
567
|
+
wallet_divisions = xml.search("//result/rowset[@name='walletDivisions']/").collect { |k| k if k.kind_of? Hpricot::Elem } - [ nil ]
|
568
|
+
divisions = xml.search("//result/rowset[@name='divisions']/").collect { |k| k if k.kind_of? Hpricot::Elem } - [ nil ]
|
569
|
+
divisions.collect! { |d| Reve::Classes::CorporateDivision.new(d) }
|
570
|
+
wallet_divisions.collect! { |w| Reve::Classes::WalletDivision.new(w) }
|
571
|
+
|
572
|
+
# Map the XML names to our own names and assign them to the temporary
|
573
|
+
# hash +res+ to pass to Reve::Classes::CorporationSheet#new
|
574
|
+
res = Hash.new
|
575
|
+
{ :corporationid => :id, :corporationname => :name, :ticker => :ticker, :ceoid => :ceo_id,
|
576
|
+
:ceoname => :ceo_name, :stationid => :station_id, :stationname => :station_name,
|
577
|
+
:description => :description, :url => :url, :allianceid => :alliance_id,
|
578
|
+
:alliancename => :alliance_name, :taxrate => :tax_rate, :membercount => :member_count,
|
579
|
+
:memberlimit => :member_limit }.each do |k,v|
|
580
|
+
res[v] = xml.search("//result/#{k.to_s}/").first.to_s.strip
|
581
|
+
end
|
582
|
+
|
583
|
+
Reve::Classes::CorporationSheet.new res, divisions, wallet_divisions, corporate_logo
|
584
|
+
end
|
585
|
+
|
586
|
+
# Gets the CharacterSheet from
|
587
|
+
# http://api.eve-online.com/char/CharacterSheet.xml.aspx
|
588
|
+
# Expects:
|
589
|
+
# * characterid ( Fixnum ) - Get the CharacterSheet for this Character
|
590
|
+
# See also: Reve::Classes::CharacterSheet
|
591
|
+
def character_sheet(opts = { :characterid => nil })
|
592
|
+
args = postfields(opts)
|
593
|
+
h = compute_hash(args.merge(:url => @@character_sheet_url))
|
594
|
+
return h if h
|
595
|
+
|
596
|
+
xml = process_query(nil,opts[:url] || @@character_sheet_url,true,args)
|
597
|
+
cs = Reve::Classes::CharacterSheet.new
|
598
|
+
|
599
|
+
(xml/:result/:attributeenhancers).each do |enh|
|
600
|
+
for kind in ['intelligenceBonus', 'memoryBonus', 'charismaBonus', 'perceptionBonus','willpowerBonus']
|
601
|
+
thing = nil
|
602
|
+
case kind
|
603
|
+
when 'intelligenceBonus'
|
604
|
+
thing = Reve::Classes::IntelligenceEnhancer
|
605
|
+
when 'memoryBonus'
|
606
|
+
thing = Reve::Classes::MemoryEnhancer
|
607
|
+
when 'charismaBonus'
|
608
|
+
thing = Reve::Classes::CharismaEnhancer
|
609
|
+
when 'perceptionBonus'
|
610
|
+
thing = Reve::Classes::PerceptionEnhancer
|
611
|
+
when 'willpowerBonus'
|
612
|
+
thing = Reve::Classes::WillpowerEnhancer
|
613
|
+
else
|
614
|
+
thing = Reve::Classes::AttributeEnhancer
|
615
|
+
end
|
616
|
+
(enh/kind.downcase.intern).each do |b|
|
617
|
+
name = (b/:augmentatorname).inner_html
|
618
|
+
value = (b/:augmentatorvalue).inner_html
|
619
|
+
cs.enhancers << thing.new(name,value)
|
620
|
+
end
|
621
|
+
end
|
622
|
+
end
|
623
|
+
|
624
|
+
(xml/:result).each do |elem|
|
625
|
+
for field in [ 'characterid', 'name', 'race', 'bloodline', 'gender','corporationname','corporationid','balance' ]
|
626
|
+
cs.send("#{field}=",(elem/field.intern).first.inner_html)
|
627
|
+
end
|
628
|
+
end
|
629
|
+
(xml/:result/:attributes).each do |elem|
|
630
|
+
for attrib in [ 'intelligence','memory','charisma','perception','willpower' ]
|
631
|
+
cs.send("#{attrib}=",(elem/attrib.intern).first.inner_html)
|
632
|
+
end
|
633
|
+
end
|
634
|
+
(xml/:result/:rowset/:row).each do |elem|
|
635
|
+
cs.skills << Reve::Classes::Skill.new(elem)
|
636
|
+
end
|
637
|
+
cs
|
638
|
+
end
|
639
|
+
|
640
|
+
|
641
|
+
protected
|
642
|
+
# Sets up the post fields for Net::HTTP::Get hash for process_query method.
|
643
|
+
# See also format_url_request
|
644
|
+
# TODO: Consider moving this whole thing into process_query to avoid
|
645
|
+
# calling this in every method!
|
646
|
+
def postfields(opts = {})
|
647
|
+
ret = { "userID" => @userid, "apiKey" => @key }.merge(opts)
|
648
|
+
ret.inject({}) do |n, (k,v)|
|
649
|
+
n[k] = v.to_s if v
|
650
|
+
n
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
# Creates a hash for some hash of postfields. For each API method pass
|
655
|
+
# :just_hash => to something to return a hash that can be matched to
|
656
|
+
# the last_hash instance method created in process_query.
|
657
|
+
# This method is called in each API method before process_query and if
|
658
|
+
# :just_hash was passed in args then a String will be returned, otherwise
|
659
|
+
# nil will be returned
|
660
|
+
# TODO: Consider moving this whole thing into process_query before the URI parsing
|
661
|
+
def compute_hash(args = {})
|
662
|
+
return nil unless args.include?(:just_hash)
|
663
|
+
args.delete(:just_hash)
|
664
|
+
url = args[:url].kind_of?(URI) ? args[:url].path : args[:url]
|
665
|
+
args.delete(:url)
|
666
|
+
spl = url.split '/'
|
667
|
+
ret = (spl[-2] + '/' + spl[-1]) + ':'
|
668
|
+
args.delete_if { |k,v| (v || "").to_s.length == 0 } # Delete keys if the value is nil
|
669
|
+
h = args.stringify_keys
|
670
|
+
ret += h.sort.flatten.collect{ |e| e.to_s }.join(':')
|
671
|
+
ret.gsub(/:$/,'')
|
672
|
+
end
|
673
|
+
|
674
|
+
# Processes a URL and for simple <rowset><row /><row /></rowset> results
|
675
|
+
# create an array of objects of type klass. Or just return the XML if
|
676
|
+
# just_xml is set true. args is from postfields
|
677
|
+
# This method will call check_exception to see if an Exception came from
|
678
|
+
# CCP.
|
679
|
+
# Expects:
|
680
|
+
# * klass ( Class ) - The class container for parsing. An array of these is returned in default behaviour.
|
681
|
+
# * url ( String ) - API URL
|
682
|
+
# * just_xml ( Boolean ) - Return only the XML and not attempt to parse //rowset/row. Useful if the XML is not in that form.
|
683
|
+
# * args ( Hash ) - Hash of arguments for the request. See postfields method.
|
684
|
+
def process_query(klass, url, just_xml = false, opts = {})
|
685
|
+
|
686
|
+
#args = postfields(opts)
|
687
|
+
#h = compute_hash(args.merge(:url => url))
|
688
|
+
#return h if h
|
689
|
+
|
690
|
+
@last_hash = compute_hash(opts.merge({:url => url, :just_hash => true })) # compute hash
|
691
|
+
|
692
|
+
xml = check_exception(get_xml(url,opts))
|
693
|
+
save_xml(xml) if @save_path
|
694
|
+
|
695
|
+
return xml if just_xml
|
696
|
+
return [] if xml.nil? # No XML document returned. We should panic.
|
697
|
+
ret = []
|
698
|
+
xml.search("//rowset/row").each do |elem|
|
699
|
+
ret << klass.new(elem)
|
700
|
+
end
|
701
|
+
ret
|
702
|
+
end
|
703
|
+
|
704
|
+
# Turns a hash into ?var=baz&bam=boo
|
705
|
+
def format_url_request(opts)
|
706
|
+
req = "?"
|
707
|
+
|
708
|
+
opts.stringify_keys!
|
709
|
+
opts.keys.sort.each do |key|
|
710
|
+
req += "#{CGI.escape(key.to_s)}=#{CGI.escape(opts[key].to_s)}&" if opts[key]
|
711
|
+
end
|
712
|
+
req.chop # We are lazy and append a & to each pair even if it's the last one. FIXME: Don't do this.
|
713
|
+
end
|
714
|
+
|
715
|
+
|
716
|
+
# Gets the XML from a source.
|
717
|
+
# Expects:
|
718
|
+
# * source ( String | URI ) - If the +source+ is a String Reve will attempt to load the XML file from the local filesystem by the path specified as +source+. If the +source+ is a URI or is a String starting with http (lowercase) Reve will fetch it from that URI on the web.
|
719
|
+
# * opts ( Hash ) - Hash of parameters for the request, such as userid, apikey and such.
|
720
|
+
# NOTE: To override the lowercase http -> URI rule make the HTTP part uppercase.
|
721
|
+
def get_xml(source,opts)
|
722
|
+
xml = ""
|
723
|
+
|
724
|
+
# Let people still pass Strings starting with http.
|
725
|
+
if source =~ /^http/
|
726
|
+
source = URI.parse(source)
|
727
|
+
end
|
728
|
+
|
729
|
+
if source.kind_of?(URI)
|
730
|
+
opts.merge({ :version => 2, :url => nil }) #the uri bit will now ignored in format_url_request
|
731
|
+
req_args = format_url_request(opts)
|
732
|
+
req = Net::HTTP::Get.new(source.path + req_args)
|
733
|
+
req['User-Agent'] = @http_referer_agent || "Reve"
|
734
|
+
|
735
|
+
res = nil
|
736
|
+
response = nil
|
737
|
+
1.upto(@max_tries) do |try|
|
738
|
+
begin
|
739
|
+
# ||= to prevent making a new Net::HTTP object, the res = nil above should reset this for the next request.
|
740
|
+
# the request needs to be here to rescue exceptions from it.
|
741
|
+
res ||= Net::HTTP.new(source.host, source.port).start {|http| http.request(req) }
|
742
|
+
case res
|
743
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
744
|
+
response = res.body
|
745
|
+
end
|
746
|
+
rescue Exception
|
747
|
+
sleep 5
|
748
|
+
next
|
749
|
+
end
|
750
|
+
break if response
|
751
|
+
end
|
752
|
+
raise Reve::Exceptions::ReveNetworkStatusException.new( (res.body rescue "No Response Body!") ) unless response
|
753
|
+
|
754
|
+
xml = response
|
755
|
+
|
756
|
+
# here ends test for URI
|
757
|
+
elsif source.kind_of?(String)
|
758
|
+
xml = File.open(source).read
|
759
|
+
else
|
760
|
+
raise Reve::Exceptions::ReveNetworkStatusException.new("Don't know how to deal with a #{source.class} XML source. I expect a URI or String")
|
761
|
+
end
|
762
|
+
xml
|
763
|
+
end
|
764
|
+
|
765
|
+
# Raises the proper exception (if there is one), otherwise it returns the
|
766
|
+
# XML response.
|
767
|
+
def check_exception(xml)
|
768
|
+
x = Hpricot(xml)
|
769
|
+
begin
|
770
|
+
out = x.search("//error") # If this fails then there are some big problems with Hpricot#search ?
|
771
|
+
rescue Exception => e
|
772
|
+
$stderr.puts "Fatal error ((#{e.to_s})): Couldn't search the XML document ((#{xml})) for any potential error messages! Is your Hpricot broken?"
|
773
|
+
exit 1
|
774
|
+
end
|
775
|
+
@current_time = (x/:currenttime).inner_html.to_time rescue Time.now.utc # Shouldn't need to rescue this but one never knows
|
776
|
+
@cached_until = (x/:cacheduntil).inner_html.to_time rescue nil # Errors aren't always cached
|
777
|
+
return x if out.size < 1
|
778
|
+
code = out.first['code'].to_i
|
779
|
+
str = out.first.inner_html
|
780
|
+
Reve::Exceptions.raise_it(code,str)
|
781
|
+
end
|
782
|
+
|
783
|
+
def save_xml(xml)
|
784
|
+
path = build_save_filename
|
785
|
+
FileUtils.mkdir_p(File.dirname(path))
|
786
|
+
File.open(path,'w') { |f| f.print xml.to_s }
|
787
|
+
end
|
788
|
+
def build_save_filename
|
789
|
+
method = caller(3).first.match(/\`(.+)'/)[1] # Get the API method that's being called. This is called from save_xml -> process_query -> :real_method
|
790
|
+
File.join(@save_path,@userid.to_s,method,( @cached_until || Time.now.utc).to_i.to_s + '.xml')
|
791
|
+
end
|
792
|
+
end
|
793
|
+
end
|