dsander-reve 0.0.116

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/ChangeLog +155 -0
  2. data/LICENSE +22 -0
  3. data/Rakefile +79 -0
  4. data/init.rb +1 -0
  5. data/lib/reve/classes.rb +1341 -0
  6. data/lib/reve/exceptions.rb +353 -0
  7. data/lib/reve/extensions.rb +108 -0
  8. data/lib/reve.rb +1001 -0
  9. data/reve.rb +1 -0
  10. data/test/test_reve.rb +1191 -0
  11. data/test/xml/alliances.xml +171 -0
  12. data/test/xml/assets.xml +32 -0
  13. data/test/xml/badxml.xml +6 -0
  14. data/test/xml/certificate_tree.xml +231 -0
  15. data/test/xml/char_facwarstats.xml +18 -0
  16. data/test/xml/char_medals.xml +12 -0
  17. data/test/xml/character_sheet.xml +288 -0
  18. data/test/xml/characterid.xml +11 -0
  19. data/test/xml/charactername.xml +11 -0
  20. data/test/xml/characters.xml +13 -0
  21. data/test/xml/conqurable_stations.xml +12 -0
  22. data/test/xml/corp_facwarstats.xml +17 -0
  23. data/test/xml/corp_medals.xml +23 -0
  24. data/test/xml/corp_member_medals.xml +20 -0
  25. data/test/xml/corp_membersecurity.xml +49 -0
  26. data/test/xml/corporate_assets_list.xml +16 -0
  27. data/test/xml/corporate_market_orders.xml +10 -0
  28. data/test/xml/corporate_wallet_balance.xml +16 -0
  29. data/test/xml/corporate_wallet_journal.xml +11 -0
  30. data/test/xml/corporate_wallet_transactions.xml +10 -0
  31. data/test/xml/corporation_sheet.xml +52 -0
  32. data/test/xml/errors/error_100.xml +5 -0
  33. data/test/xml/errors/error_101.xml +5 -0
  34. data/test/xml/errors/error_102.xml +5 -0
  35. data/test/xml/errors/error_103.xml +5 -0
  36. data/test/xml/errors/error_104.xml +5 -0
  37. data/test/xml/errors/error_105.xml +5 -0
  38. data/test/xml/errors/error_106.xml +5 -0
  39. data/test/xml/errors/error_107.xml +5 -0
  40. data/test/xml/errors/error_108.xml +5 -0
  41. data/test/xml/errors/error_109.xml +5 -0
  42. data/test/xml/errors/error_110.xml +5 -0
  43. data/test/xml/errors/error_111.xml +5 -0
  44. data/test/xml/errors/error_112.xml +5 -0
  45. data/test/xml/errors/error_113.xml +5 -0
  46. data/test/xml/errors/error_114.xml +5 -0
  47. data/test/xml/errors/error_115.xml +5 -0
  48. data/test/xml/errors/error_116.xml +5 -0
  49. data/test/xml/errors/error_117.xml +5 -0
  50. data/test/xml/errors/error_118.xml +5 -0
  51. data/test/xml/errors/error_119.xml +5 -0
  52. data/test/xml/errors/error_120.xml +5 -0
  53. data/test/xml/errors/error_121.xml +5 -0
  54. data/test/xml/errors/error_122.xml +5 -0
  55. data/test/xml/errors/error_123.xml +5 -0
  56. data/test/xml/errors/error_124.xml +5 -0
  57. data/test/xml/errors/error_125.xml +5 -0
  58. data/test/xml/errors/error_200.xml +5 -0
  59. data/test/xml/errors/error_201.xml +5 -0
  60. data/test/xml/errors/error_202.xml +5 -0
  61. data/test/xml/errors/error_203.xml +5 -0
  62. data/test/xml/errors/error_204.xml +5 -0
  63. data/test/xml/errors/error_205.xml +5 -0
  64. data/test/xml/errors/error_206.xml +5 -0
  65. data/test/xml/errors/error_207.xml +5 -0
  66. data/test/xml/errors/error_208.xml +5 -0
  67. data/test/xml/errors/error_209.xml +5 -0
  68. data/test/xml/errors/error_210.xml +5 -0
  69. data/test/xml/errors/error_211.xml +5 -0
  70. data/test/xml/errors/error_212.xml +5 -0
  71. data/test/xml/errors/error_213.xml +5 -0
  72. data/test/xml/errors/error_214.xml +5 -0
  73. data/test/xml/errors/error_500.xml +5 -0
  74. data/test/xml/errors/error_501.xml +5 -0
  75. data/test/xml/errors/error_502.xml +5 -0
  76. data/test/xml/errors/error_503.xml +5 -0
  77. data/test/xml/errors/error_504.xml +5 -0
  78. data/test/xml/errors/error_505.xml +5 -0
  79. data/test/xml/errors/error_506.xml +5 -0
  80. data/test/xml/errors/error_507.xml +5 -0
  81. data/test/xml/errors/error_508.xml +5 -0
  82. data/test/xml/errors/error_509.xml +5 -0
  83. data/test/xml/errors/error_510.xml +5 -0
  84. data/test/xml/errors/error_511.xml +5 -0
  85. data/test/xml/errors/error_512.xml +5 -0
  86. data/test/xml/errors/error_513.xml +5 -0
  87. data/test/xml/errors/error_514.xml +5 -0
  88. data/test/xml/errors/error_515.xml +5 -0
  89. data/test/xml/errors/error_516.xml +5 -0
  90. data/test/xml/errors/error_517.xml +5 -0
  91. data/test/xml/errors/error_518.xml +5 -0
  92. data/test/xml/errors/error_519.xml +5 -0
  93. data/test/xml/errors/error_520.xml +5 -0
  94. data/test/xml/errors/error_521.xml +5 -0
  95. data/test/xml/errors/error_522.xml +5 -0
  96. data/test/xml/errors/error_523.xml +5 -0
  97. data/test/xml/errors/error_524.xml +5 -0
  98. data/test/xml/errors/error_525.xml +5 -0
  99. data/test/xml/errors/error_900.xml +5 -0
  100. data/test/xml/errors/error_901.xml +5 -0
  101. data/test/xml/errors/error_902.xml +5 -0
  102. data/test/xml/errors/error_903.xml +5 -0
  103. data/test/xml/errors/error_999.xml +5 -0
  104. data/test/xml/errors.xml +70 -0
  105. data/test/xml/eve_facwarstats.xml +35 -0
  106. data/test/xml/eve_facwartopstats.xml +178 -0
  107. data/test/xml/industryjobs.xml +11 -0
  108. data/test/xml/kills.xml +569 -0
  109. data/test/xml/map_facwarsystems.xml +13 -0
  110. data/test/xml/mapjumps.xml +15 -0
  111. data/test/xml/mapkills.xml +16 -0
  112. data/test/xml/market_transactions.xml +79 -0
  113. data/test/xml/marketorders.xml +43 -0
  114. data/test/xml/member_tracking.xml +22 -0
  115. data/test/xml/nonmember_corpsheet.xml +30 -0
  116. data/test/xml/reftypes.xml +14 -0
  117. data/test/xml/server_status.xml +9 -0
  118. data/test/xml/skill_in_training-amarr-titan.xml +15 -0
  119. data/test/xml/skill_in_training-none.xml +7 -0
  120. data/test/xml/skill_queue.xml +18 -0
  121. data/test/xml/skilltree.xml +41 -0
  122. data/test/xml/sovereignty.xml +29 -0
  123. data/test/xml/starbase_fuel.xml +23 -0
  124. data/test/xml/starbases.xml +12 -0
  125. data/test/xml/wallet_balance.xml +17 -0
  126. data/test/xml/wallet_journal.xml +48 -0
  127. data/tester.rb +17 -0
  128. metadata +187 -0
data/lib/reve.rb ADDED
@@ -0,0 +1,1001 @@
1
+ #--
2
+ # Code copyright Lisa Seelye, 2007-2008. www.crudvision.com
3
+ # This library is licensed under the terms of the MIT license. For full text
4
+ # see the LICENSE file distributed with this package.
5
+ # (Also, send Raquel Smith some ISK if you would like to show appreciation ;-)
6
+ #++
7
+
8
+ begin
9
+ require 'hpricot'
10
+ rescue LoadError
11
+ require 'rubygems'
12
+ require 'hpricot'
13
+ end
14
+ require 'net/http'
15
+ require 'uri'
16
+ require 'cgi'
17
+ require 'fileutils'
18
+
19
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
20
+
21
+ require 'reve/exceptions'
22
+ require 'reve/extensions'
23
+ require 'reve/classes'
24
+
25
+
26
+ module Reve
27
+ # API Class.
28
+ # Basic Usage:
29
+ # api = Reve::API.new('my_UserID', 'my_apiKey')
30
+ # alliances = api.alliances # Returns an array of Reve::Classes::Alliance
31
+ #
32
+ # api.personal_wallet_blanace(:characterid => 892008733) # Returns an array of
33
+ # Reve::Classes::WalletBalance. Note that the CharacterID Number is required
34
+ # here.
35
+ #
36
+ # api.sovereignty :just_hash => true # Returns the hash for this call with no
37
+ # Alliance data with it.
38
+ #
39
+ # As of Revision 22 (28 August 2007) all API calls take a parameter,
40
+ # :just_hash, to just get the hash that represents that particular API call;
41
+ # No data related to the call is returned if :just_hash is present
42
+ #
43
+ # All API methods have the functionality to read XML from an arbitrary location. This could be another webserver, or a XML file on disk.
44
+ # 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.
45
+ class API
46
+
47
+ @@alliances_url = 'http://api.eve-online.com/eve/AllianceList.xml.aspx'
48
+ @@sovereignty_url = 'http://api.eve-online.com/map/Sovereignty.xml.aspx'
49
+ @@reftypes_url = 'http://api.eve-online.com/eve/RefTypes.xml.aspx'
50
+ @@skill_tree_url = 'http://api.eve-online.com/eve/SkillTree.xml.aspx'
51
+ @@member_tracking_url = 'http://api.eve-online.com/corp/MemberTracking.xml.aspx'
52
+ @@corporate_wallet_balance_url = 'http://api.eve-online.com/corp/AccountBalance.xml.aspx'
53
+ @@personal_wallet_balance_url = 'http://api.eve-online.com/char/AccountBalance.xml.aspx'
54
+ @@corporate_wallet_trans_url = 'http://api.eve-online.com/corp/WalletTransactions.xml.aspx'
55
+ @@personal_wallet_trans_url = 'http://api.eve-online.com/char/WalletTransactions.xml.aspx'
56
+ @@corporate_wallet_journal_url = 'http://api.eve-online.com/corp/WalletJournal.xml.aspx'
57
+ @@personal_wallet_journal_url = 'http://api.eve-online.com/char/WalletJournal.xml.aspx'
58
+ @@characters_url = 'http://api.eve-online.com/account/Characters.xml.aspx'
59
+ @@training_skill_url = 'http://api.eve-online.com/char/SkillInTraining.xml.aspx'
60
+ @@skill_queue_url = 'http://api.eve-online.com/char/SkillQueue.xml.aspx'
61
+ @@character_sheet_url = 'http://api.eve-online.com/char/CharacterSheet.xml.aspx'
62
+ @@starbases_url = 'http://api.eve-online.com/corp/StarbaseList.xml.aspx'
63
+ @@starbasedetail_url = 'http://api.eve-online.com/corp/StarbaseDetail.xml.aspx'
64
+ @@conqurable_outposts_url = 'http://api.eve-online.com/eve/ConquerableStationList.xml.aspx'
65
+ @@corporation_sheet_url = 'http://api.eve-online.com/corp/CorporationSheet.xml.aspx'
66
+ @@errors_url = 'http://api.eve-online.com/eve/ErrorList.xml.aspx'
67
+ @@map_jumps_url = 'http://api.eve-online.com/map/Jumps.xml.aspx'
68
+ @@map_kills_url = 'http://api.eve-online.com/map/Kills.xml.aspx'
69
+ @@personal_market_orders_url = 'http://api.eve-online.com/char/MarketOrders.xml.aspx'
70
+ @@corporate_market_orders_url = 'http://api.eve-online.com/corp/MarketOrders.xml.aspx'
71
+ @@personal_industry_jobs_url = 'http://api.eve-online.com/char/IndustryJobs.xml.aspx'
72
+ @@corporate_industry_jobs_url = 'http://api.eve-online.com/corp/IndustryJobs.xml.aspx'
73
+ @@personal_assets_url = 'http://api.eve-online.com/char/AssetList.xml.aspx'
74
+ @@corporate_assets_url = 'http://api.eve-online.com/corp/AssetList.xml.aspx'
75
+ @@personal_kills_url = 'http://api.eve-online.com/char/KillLog.xml.aspx'
76
+ @@corporate_kills_url = 'http://api.eve-online.com/corp/KillLog.xml.aspx'
77
+ @@character_id_url = 'http://api.eve-online.com/eve/CharacterID.xml.aspx' # ?names=CCP%20Garthagk,Raquel%20Smith
78
+ @@character_name_url = 'http://api.eve-online.com/eve/CharacterName.xml.aspx' # ?ids=797400947,892008733
79
+ @@personal_faction_war_stats_url= 'http://api.eve-online.com/char/FacWarStats.xml.aspx'
80
+ @@corporate_faction_war_stats_url= 'http://api.eve-online.com/corp/FacWarStats.xml.aspx'
81
+ @@general_faction_war_stats_url= 'http://api.eve-online.com/eve/FacWarStats.xml.aspx'
82
+ @@top_faction_war_stats_url = 'http://api.eve-online.com/eve/FacWarTopStats.xml.aspx'
83
+ @@faction_war_occupancy_url = 'http://api.eve-online.com/map/FacWarSystems.xml.aspx'
84
+ @@certificate_tree_url = 'http://api.eve-online.com/eve/CertificateTree.xml.aspx'
85
+ @@character_medals_url = 'http://api.eve-online.com/char/Medals.xml.aspx'
86
+ @@corporate_medals_url = 'http://api.eve-online.com/corp/Medals.xml.aspx'
87
+ @@corp_member_medals_url = 'http://api.eve-online.com/corp/MemberMedals.xml.aspx'
88
+ @@server_status_url = 'http://api.eve-online.com/Server/ServerStatus.xml.aspx'
89
+
90
+ cattr_accessor :character_sheet_url, :training_skill_url, :characters_url, :personal_wallet_journal_url,
91
+ :corporate_wallet_journal_url, :personal_wallet_trans_url, :corporate_wallet_trans_url,
92
+ :personal_wallet_balance_url, :corporate_wallet_balance_url, :member_tracking_url,
93
+ :skill_tree_url, :reftypes_url, :sovereignty_url, :alliances_url, :starbases_url,
94
+ :starbasedetail_url, :conqurable_outposts_url, :corporation_sheet_url, :map_jumps_url,
95
+ :map_kills_url, :personal_market_orders_url, :corporate_market_orders_url,
96
+ :personal_industry_jobs_url, :corporate_industry_jobs_url, :personal_assets_url,
97
+ :corporate_assets_url, :personal_kills_url, :corporate_kills_url,
98
+ :personal_faction_war_stats_url, :corporate_faction_war_stats_url,
99
+ :general_faction_war_stats_url, :top_faction_war_stats_url, :faction_war_occupancy_url,
100
+ :certificate_tree_url, :character_medals_url, :corporate_medals_url,
101
+ :corp_member_medals_url, :server_status_url, :skill_queue_url
102
+
103
+
104
+ attr_accessor :key, :userid, :charid
105
+ attr_accessor :http_user_agent, :save_path
106
+ attr_reader :current_time, :cached_until, :last_hash
107
+
108
+ # Create a new API instance.
109
+ # current_time and cached_until are meaningful only for the LAST call made.
110
+ # Expects:
111
+ # * userid ( Integer | String ) - Your API userID
112
+ # * key ( String ) - Your API key (Full key or restricted key)
113
+ # * charid ( Integer | String ) - Default characterID for calls requiring it.
114
+ # NOTE: All values passed to the constructor are typecasted to a String for safety.
115
+ def initialize(userid = "", key = "", charid = "")
116
+ @userid = (userid || "").to_s
117
+ @key = (key || "").to_s
118
+ @charid = (charid || "").to_s
119
+
120
+ @save_path = nil
121
+
122
+ @http_user_agent = "Reve"
123
+ @max_tries = 3
124
+
125
+ @current_time = nil
126
+ @cached_until = nil
127
+ @last_hash = nil
128
+ end
129
+ # Save XML to this directory with the format:
130
+ # :save_path/:userid/:method/:expires_at_in_unixtime.xml
131
+ # eg: ./xml/12345/characters/1200228878.xml
132
+ # or: ./xml/alliances/1200228878.xml
133
+ # If @save_path is nil then XML is not saved.
134
+ def save_path=(p)
135
+ @save_path = p
136
+ end
137
+
138
+ # Get the server status of Tranquility as a Reve::Classes::ServerStatus
139
+ # object.
140
+ # See Also: Reve::Classes::ServerStatus
141
+ def server_status(opts = {})
142
+ args = postfields(opts)
143
+ h = compute_hash( opts.merge(:url => @@server_status_url) )
144
+ return h if h
145
+ xml = process_query(nil,opts[:url] || @@server_status_url,true,opts)
146
+ Reve::Classes::ServerStatus.new(
147
+ xml.search("/eveapi/result/serverOpen/").first.to_s,
148
+ xml.search("/eveapi/result/onlinePlayers/").first.to_s
149
+ )
150
+ end
151
+
152
+ # Convert a list of names to their ids.
153
+ # Expects a Hash as a parameter with these keys:
154
+ # * names ( Array ) - An Array of Names to fetch the IDs of.
155
+ # See Also: character_name, Reve::Classes::Character, character_sheet
156
+ def names_to_ids(opts = {} )
157
+ names = opts[:names] || []
158
+ return [] if names.empty? # No names were passed.
159
+ opts[:names] = names.join(',')
160
+ args = postfields(opts)
161
+ h = compute_hash( opts.merge(:url => @@character_id_url) )
162
+ return h if h
163
+ xml = process_query(nil,opts[:url] || @@character_id_url, true,opts)
164
+ ret = []
165
+ xml.search("//rowset/row").each do |elem|
166
+ ret << Reve::Classes::Character.new(elem)
167
+ end
168
+ ret
169
+ end
170
+
171
+ alias_method :character_id, :names_to_ids
172
+
173
+ # Convert ids to Character names.
174
+ # Expects a Hash as a parameter with these keys:
175
+ # * ids ( Array ) - An Array of Character IDs to fetch the names of.
176
+ # See Also: character_name, Reve::Classes::Character, character_sheet
177
+ def character_name(opts = {})
178
+ ids = opts[:ids] || []
179
+ return [] if ids.empty?
180
+ opts[:ids] = ids.join(',')
181
+ compute_hash( opts.merge(:url => @@character_name_url) ) ||
182
+ process_query(Reve::Classes::Character,opts[:url] || @@character_name_url,false,opts)
183
+ end
184
+
185
+ # Return a list of Alliances and member Corporations from
186
+ # http://api.eve-online.com/eve/AllianceList.xml.aspx
187
+ # Use the corporation_sheet method to get information for each member
188
+ # Corporation
189
+ # See also: Reve::Classes::Alliance, Reve::Classes::Corporation and
190
+ # corporation_sheet
191
+ def alliances(opts = {})
192
+ args = postfields(opts)
193
+ h = compute_hash(args.merge(:url => @@alliances_url))
194
+ return h if h
195
+ xml = process_query(nil,opts[:url] || @@alliances_url,true,args)
196
+ alliances = []
197
+ xml.search("/eveapi/result/rowset[@name='alliances']/row").each do |alliance|
198
+ alliance_obj = Reve::Classes::Alliance.new(alliance)
199
+ alliance.search("rowset[@name='memberCorporations']/row").each do |corporation|
200
+ alliance_obj.member_corporations << Reve::Classes::Corporation.new(corporation)
201
+ end
202
+ alliances << alliance_obj
203
+ end
204
+ alliances
205
+ end
206
+
207
+ # Returns a list of the number of jumps for each system. If there are no
208
+ # jumps for a system it will not be included. See also Reve::Classes::MapJump
209
+ def map_jumps(opts = {})
210
+ compute_hash( opts.merge(:url => @@map_jumps_url) ) ||
211
+ process_query(Reve::Classes::MapJump,opts[:url] || @@map_jumps_url,false)
212
+ end
213
+
214
+ # Returns a list of the number of kills for each system. If there are no
215
+ # kills for a system it will not be included. See also Reve::Classes::MapKill
216
+ def map_kills(opts = {})
217
+ compute_hash( opts.merge(:url => @@map_kills_url) ) ||
218
+ process_query(Reve::Classes::MapKill,opts[:url] || @@map_kills_url,false)
219
+ end
220
+
221
+ # Returns a list of API Errors
222
+ def errors(opts = {})
223
+ compute_hash( opts.merge(:url => @@errors_url) ) ||
224
+ process_query(Reve::Classes::APIError,opts[:url] || @@errors_url,false)
225
+ end
226
+
227
+ # Returns the Sovereignty list from
228
+ # http://api.eve-online.com/map/Sovereignty.xml.aspx
229
+ # See also: Reve::Classes::Sovereignty
230
+ def sovereignty(opts = {})
231
+ compute_hash( opts.merge(:url => @@sovereignty_url) ) ||
232
+ process_query(Reve::Classes::Sovereignty,opts[:url] || @@sovereignty_url,false)
233
+ end
234
+
235
+ # Returns a RefType list (whatever they are) from
236
+ # http://api.eve-online.com/eve/RefTypes.xml.aspx
237
+ # See also: Reve::Classes::RefType
238
+ def ref_types(opts = {})
239
+ compute_hash( opts.merge(:url => @@reftypes_url) ) ||
240
+ process_query(Reve::Classes::RefType,opts[:url] || @@reftypes_url,false)
241
+ end
242
+
243
+ # Returns a list of ConqurableStations and outposts from
244
+ # http://api.eve-online.com/eve/ConquerableStationList.xml.aspx
245
+ # See also: Reve::Classes::ConqurableStation
246
+ def conquerable_stations(opts = {})
247
+ compute_hash( opts.merge(:url => @@conqurable_outposts_url) ) ||
248
+ process_query(Reve::Classes::ConquerableStation, opts[:url] || @@conqurable_outposts_url, false)
249
+ end
250
+
251
+ alias_method :conqurable_stations, :conquerable_stations
252
+
253
+ # Returns a list of Reve::Classes::MarketOrder objects for market orders that are up
254
+ # Pass the characterid of the Character to check for
255
+ def personal_market_orders(opts = {:characterid => nil})
256
+ args = postfields(opts)
257
+ h = compute_hash(args.merge(:url => @@personal_market_orders_url))
258
+ return h if h
259
+ process_query(Reve::Classes::PersonalMarketOrder, opts[:url] || @@personal_market_orders_url, false, args)
260
+ end
261
+
262
+ # Returns a list of Reve::Classes::MarketOrder objects for market orders that are up on behalf of a Corporation
263
+ # Pass the characterid of the Character of whose corporation to check for
264
+ def corporate_market_orders(opts = {:characterid => nil})
265
+ args = postfields(opts)
266
+ h = compute_hash(args.merge(:url => @@corporate_market_orders_url))
267
+ return h if h
268
+ process_query(Reve::Classes::CorporateMarketOrder, opts[:url] || @@corporate_market_orders_url, false, args)
269
+ end
270
+
271
+ # Returns a list of Reve::Classes::PersonalIndustryJob objects.
272
+ def personal_industry_jobs(opts = {:characterid => nil})
273
+ args = postfields(opts)
274
+ h = compute_hash(args.merge(:url => @@personal_industry_jobs_url))
275
+ return h if h
276
+ process_query(Reve::Classes::PersonalIndustryJob, opts[:url] || @@personal_industry_jobs_url,false,args)
277
+ end
278
+
279
+ # Returns a list of Reve::Classes::CorporateIndustryJob objects.
280
+ def corporate_industry_jobs(opts = {:characterid => nil})
281
+ args = postfields(opts)
282
+ h = compute_hash(args.merge(:url => @@corporate_industry_jobs_url))
283
+ return h if h
284
+ process_query(Reve::Classes::CorporateIndustryJob, opts[:url] || @@corporate_industry_jobs_url,false,args)
285
+ end
286
+
287
+ # Returns the SkillTree from
288
+ # http://api.eve-online.com/eve/SkillTree.xml.aspx
289
+ # See also: Reve::Classes::SkillTree
290
+ # NOTE: This doesn't actually return a 'tree' yet.
291
+ def skill_tree(opts = {})
292
+ h = compute_hash(opts.merge(:url => @@skill_tree_url) )
293
+ return h if h
294
+ doc = process_query(nil,opts[:url] || @@skill_tree_url,true)
295
+ skills = []
296
+ (doc/'rowset[@name=skills]/row').each do |skill|
297
+ name = skill['typeName']
298
+ type_id = skill['typeID']
299
+ group_id = skill['groupID']
300
+ rank = (skill/:rank).inner_html
301
+ desc = (skill/:description).inner_html
302
+ required_skills = []
303
+ reqs = (skill/'rowset@name=[requiredskills]/row')
304
+ reqs.each do |required|
305
+ 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?
306
+ required_skills << Reve::Classes::SkillRequirement.new(required) if required['typeID'] && required['skillLevel']
307
+ end
308
+ required_attribs = []
309
+ (skill/'requiredAttributes').each do |req|
310
+ pri = doc.at(req.xpath + "/primaryAttribute")
311
+ sec = doc.at(req.xpath + "/secondaryAttribute")
312
+ required_attribs << Reve::Classes::PrimaryAttribute.new(pri.inner_html)
313
+ required_attribs << Reve::Classes::SecondaryAttribute.new(sec.inner_html)
314
+ end
315
+ bonuses = []
316
+ res = (skill/'rowset@name=[skillBonusCollection]/row')
317
+ res.each do |bonus|
318
+ next if bonus.kind_of? Hpricot::Text
319
+ bonuses << Reve::Classes::SkillBonus.new(bonus) if bonus['bonusType'] && bonus['bonusValue']
320
+ end
321
+ skills << Reve::Classes::SkillTree.new(name,type_id,group_id,desc,rank,required_attribs,required_skills,bonuses)
322
+ end
323
+ skills
324
+ end
325
+
326
+ # Does big brother tracking from
327
+ # http://api.eve-online.com/corp/MemberTracking.xml.aspx
328
+ # Expects:
329
+ # * characterid ( Integer | String ) - Look at players in this Character's Corporation
330
+ # See also: Reve::Classes::MemberTracking
331
+ def member_tracking(opts = {:characterid => nil})
332
+ args = postfields(opts)
333
+ h = compute_hash(args.merge(:url => @@member_tracking_url))
334
+ return h if h
335
+ process_query(Reve::Classes::MemberTracking,opts[:url] || @@member_tracking_url,false,args)
336
+ end
337
+
338
+ # Gets one's own personal WalletBalance from
339
+ # http://api.eve-online.com/char/AccountBalance.xml.aspx
340
+ # Expects:
341
+ # * characterid ( Integer | String ) - Look at this player's WalletBalance
342
+ # See also: Reve::Classes::WalletBalance and corporate_wallet_balance
343
+ def personal_wallet_balance(opts = { :characterid => nil })
344
+ args = postfields(opts)
345
+ h = compute_hash(args.merge(:url => @@personal_wallet_balance_url))
346
+ return h if h
347
+ process_query(Reve::Classes::WalletBalance,opts[:url] || @@personal_wallet_balance_url,false,args)
348
+ end
349
+
350
+ # Gets one's corporate WalletBalance from
351
+ # http://api.eve-online.com/corp/AccountBalance.xml.aspx
352
+ # Expects:
353
+ # * characterid ( Integer | String ) - Look at WalletBalance objects from this Character's Corporation
354
+ # See also: Reve::Classes::WalletBalance and personal_wallet_balance
355
+ def corporate_wallet_balance(opts = { :characterd => nil })
356
+ args = postfields(opts)
357
+ h = compute_hash(args.merge(:url => @@corporate_wallet_balance_url))
358
+ return h if h
359
+ process_query(Reve::Classes::WalletBalance,opts[:url] || @@corporate_wallet_balance_url,false,args)
360
+ end
361
+
362
+ # Gets one's own personal WalletTransaction list from
363
+ # http://api.eve-online.com/char/WalletTransactions.xml.aspx
364
+ # Expects:
365
+ # * characterid ( Integer | String ) - Look at this player's WalletTransaction list
366
+ # * beforetransid ( Integer | String ) - Gets a list of WalletTransaction objects from before this Transaction ID.
367
+ # See also: Reve::Classes::WalletTransaction and
368
+ # corporate_wallet_transactions
369
+ def personal_wallet_transactions(opts = { :characterid => nil, :beforetransid => nil })
370
+ args = postfields(opts)
371
+ h = compute_hash(args.merge(:url => @@personal_wallet_trans_url) )
372
+ return h if h
373
+ process_query(Reve::Classes::PersonalWalletTransaction,opts[:url] || @@personal_wallet_trans_url,false,args)
374
+ end
375
+
376
+ # Gets one's corporate WalletTransaction list from
377
+ # http://api.eve-online.com/corp/WalletTransactions.xml.aspx
378
+ # Expects:
379
+ # * account_key ( Integer | String ) - Account key (1000-1006) to look at.
380
+ # * characterid ( Integer | String ) - Look at WalletTransaction objects from this Character's Corporation
381
+ # * beforetransid ( Integer | String ) - Gets a list of WalletTransaction objects from before this Transaction ID.
382
+ # See also: Reve::Classes::WalletTransaction and
383
+ # personal_wallet_transactions
384
+ def corporate_wallet_transactions(opts = {:accountkey => nil, :characterid => nil, :beforerefid => nil})
385
+ args = postfields(opts)
386
+ h = compute_hash(args.merge(:url => @@corporate_wallet_trans_url))
387
+ return h if h
388
+ process_query(Reve::Classes::CorporateWalletTransaction,opts[:url] || @@corporate_wallet_trans_url,false,args)
389
+ end
390
+
391
+ # Gets one's own corporate WalletJournal list from
392
+ # http://api.eve-online.com/corp/WalletJournal.xml.aspx
393
+ # Expects:
394
+ # * account_key ( Integer | String ) - Account key (1000-1006) to look at.
395
+ # * characterid ( Integer | String ) - Look at WalletJournal objects from this Character's Corporation
396
+ # * beforerefid ( Integer | String ) - Gets a list of WalletTransaction objects from before this RefID.
397
+ # See also: Reve::Classes::WalletJournal and personal_wallet_journal
398
+ def corporate_wallet_journal(opts = {:accountkey => nil, :characterid => nil, :beforerefid => nil})
399
+ args = postfields(opts)
400
+ h = compute_hash(args.merge(:url => @@corporate_wallet_journal_url))
401
+ return h if h
402
+ process_query(Reve::Classes::WalletJournal,opts[:url] || @@corporate_wallet_journal_url,false,args)
403
+ end
404
+
405
+ # Gets one's own personal WalletJournal list from
406
+ # http://api.eve-online.com/char/WalletJournal.xml.aspx
407
+ # Expects:
408
+ # * characterid ( Integer | String ) - Look at this player's WalletJournal list
409
+ # * beforerefid ( Integer | String ) - Gets a list of WalletJournal objects from before this RefID.
410
+ # See also: Reve::Classes::WalletJournal and corporate_wallet_journal
411
+ def personal_wallet_journal(opts = { :characterid => nil, :beforerefid => nil} )
412
+ args = postfields(opts)
413
+ h = compute_hash(args.merge(:url => @@personal_wallet_journal_url))
414
+ return h if h
415
+ process_query(Reve::Classes::WalletJournal,opts[:url] || @@personal_wallet_journal_url,false,args)
416
+ end
417
+
418
+ # Get the medals a Corporation can give out. Returns a list of
419
+ # Reve::Classes::CorporateMedal objects.
420
+ # Expects:
421
+ # * characterid ( Integer | String ) - Get this Medals this Character's Corporation can give out
422
+ # See also: Reve::Classes::CorporateMedal, Reve::Classes::Medal
423
+ def corporate_medals(opts = { :characterid => nil })
424
+ args = postfields(opts)
425
+ h = compute_hash(args.merge(:url => @@corporate_medals_url))
426
+ return h if h
427
+ process_query(Reve::Classes::CorporateMedal, opts[:url] || @@corporate_medals_url,false,args)
428
+ end
429
+
430
+
431
+ # Gets the medals the Corporation has given out. Returns a list of
432
+ # Reve::Classes::CorporateMemberMedal
433
+ # Expects:
434
+ # * characterid ( Integer | String ) - Get this Medals this Character's Corporation has given out
435
+ # See also: Reve::Classes::CorporateMedal, Reve::Classes::Medal
436
+ def corporate_member_medals(opts = { :characterid => nil })
437
+ args = postfields(opts)
438
+ h = compute_hash(args.merge(:url => @@corp_member_medals_url))
439
+ return h if h
440
+ process_query(Reve::Classes::CorporateMemberMedal, opts[:url] || @@corp_member_medals_url,false,args)
441
+ end
442
+
443
+
444
+ # Gets the list of Medals awarded to a Character. Returns a
445
+ # Reve::Classes::CharacterMedals object.
446
+ def character_medals(opts = { :characterid => nil })
447
+ args = postfields(opts)
448
+ h = compute_hash(args.merge(:url => @@character_medals_url))
449
+ return h if h
450
+ xml = process_query(nil,opts[:url] || @@character_medals_url,true,args)
451
+ current = xml.search("/eveapi/result/rowset[@name=currentCorporation]/row").inject([]) do |cur,elem|
452
+ cur << Reve::Classes::CharacterMedal.new(elem)
453
+ end
454
+ other = xml.search("/eveapi/result/rowset[@name=otherCorporations]/row").inject([]) do |cur,elem|
455
+ cur << Reve::Classes::CharacterMedal.new(elem)
456
+ end
457
+ Reve::Classes::CharacterMedals.new(current,other)
458
+ end
459
+
460
+ # Gets the Reve::Classes::PersonalFactionWarStat for a character.
461
+ # Expects:
462
+ # * characterid ( Integer | String ) - Get this character's PersonalFactionWarStat.
463
+ # See Also Reve::Classes::PersonalFactionWarStat and corporate_faction_war_stats
464
+ def personal_faction_war_stats(opts = { :characterid => nil })
465
+ args = postfields(opts)
466
+ h = compute_hash(args.merge(:url => @@personal_faction_war_stats_url))
467
+ return h if h
468
+ xml = process_query(nil,opts[:url] || @@personal_faction_war_stats_url,true,args)
469
+ elems = {}
470
+ [ :factionID, :factionName, :enlisted, :currentRank, :highestRank,
471
+ :killsYesterday, :killsLastWeek, :killsTotal, :victoryPointsYesterday,
472
+ :victoryPointsLastWeek, :victoryPointsTotal ].each do |elem|
473
+ elems[elem.to_s] = xml.search("/eveapi/result/" + elem.to_s).first.inner_html
474
+ end
475
+ Reve::Classes::PersonalFactionWarParticpant.new(elems)
476
+ end
477
+
478
+ # Gets the CorporateFactionWarStat for the Corporation a Character belongs to.
479
+ # Expects:
480
+ # * characterid ( Integer | String ) - Get this character's corp's CorporateFactionWarStat.
481
+ # See Also Reve::Classes::CorporateFactionWarStat and personal_faction_war_stats
482
+ def corporate_faction_war_stats(opts = { :characterid => nil })
483
+ args = postfields(opts)
484
+ h = compute_hash(args.merge(:url => @@corporate_faction_war_stats_url))
485
+ return h if h
486
+ xml = process_query(nil,opts[:url] || @@corporate_faction_war_stats_url,true,args)
487
+ elems = {}
488
+ [ :factionID, :factionName, :enlisted, :pilots,
489
+ :killsYesterday, :killsLastWeek, :killsTotal, :victoryPointsYesterday,
490
+ :victoryPointsLastWeek, :victoryPointsTotal ].each do |elem|
491
+ elems[elem.to_s] = xml.search("/eveapi/result/" + elem.to_s).first.inner_html
492
+ end
493
+ Reve::Classes::CorporateFactionWarParticpant.new(elems)
494
+ end
495
+
496
+ # Gets Faction-wide war stats.
497
+ # See also: Reve::Classes::EveFactionWarStat, Reve::Classes::FactionwideFactionWarParticpant,
498
+ # Reve::Classes::FactionWar
499
+ def faction_war_stats(opts = {} )
500
+ args = postfields(opts)
501
+ h = compute_hash(args.merge(:url => @@general_faction_war_stats_url))
502
+ return h if h
503
+ xml = process_query(nil,opts[:url] || @@general_faction_war_stats_url,true,args)
504
+ participants = xml.search("/eveapi/result/rowset[@name='factions']/row").collect do |faction|
505
+ Reve::Classes::FactionwideFactionWarParticpant.new(faction)
506
+ end
507
+ wars = xml.search("/eveapi/result/rowset[@name='factionWars']/row").collect do |faction_war|
508
+ Reve::Classes::FactionWar.new(faction_war)
509
+ end
510
+ totals = {}
511
+ [ :killsYesterday, :killsLastWeek, :killsTotal, :victoryPointsYesterday,
512
+ :victoryPointsLastWeek, :victoryPointsTotal ].each do |elem|
513
+ totals[elem.to_s] = xml.search("/eveapi/result/totals/" + elem.to_s).first.inner_html
514
+ end
515
+ Reve::Classes::EveFactionWarStat.new(totals, wars, participants)
516
+ end
517
+
518
+ # Returns the occupancy data for each System.
519
+ # See also: Reve::Classes::FactionWarSystemStatus
520
+ def faction_war_system_stats(opts = {})
521
+ args = postfields(opts)
522
+ h = compute_hash(args.merge(:url => @@faction_war_occupancy_url))
523
+ return h if h
524
+ process_query(Reve::Classes::FactionWarSystemStatus,opts[:url] || @@faction_war_occupancy_url,false,args)
525
+ end
526
+ alias_method :faction_war_occupancy, :faction_war_system_stats
527
+
528
+ # Gets a list of the top 10 statistics for Characters, Corporations and
529
+ # Factions in factional warfare. Read the notes on Reve::Classes::FactionWarTopStats.
530
+ def faction_war_top_stats(opts = {})
531
+ args = postfields(opts)
532
+ h = compute_hash(args.merge(:url => @@top_faction_war_stats_url))
533
+ return h if h
534
+ xml = process_query(nil,opts[:url] || @@top_faction_war_stats_url,true,args)
535
+ template = { :yesterday_kills => "KillsYesterday", :last_week_kills => "KillsLastWeek", :total_kills => "KillsTotal",
536
+ :yesterday_victory_points => 'VictoryPointsYesterday', :last_week_victory_points => 'VictoryPointsLastWeek', :total_victory_points => 'VictoryPointsTotal' }
537
+ # Inject here to save 60 lines.
538
+ characters = template.inject({}) do |h,(key,val)|
539
+ klass = key.to_s =~ /kills/ ? Reve::Classes::CharacterFactionKills : Reve::Classes::CharacterFactionVictoryPoints
540
+ h[key] = pull_out_top_10_data(xml,klass,'characters',val)
541
+ h
542
+ end
543
+ corporations = template.inject({}) do |h,(key,val)|
544
+ klass = key.to_s =~ /kills/ ? Reve::Classes::CorporationFactionKills : Reve::Classes::CorporationFactionVictoryPoints
545
+ h[key] = pull_out_top_10_data(xml,klass,'corporations',val)
546
+ h
547
+ end
548
+ factions = template.inject({}) do |h,(key,val)|
549
+ klass = key.to_s =~ /kills/ ? Reve::Classes::FactionKills : Reve::Classes::FactionVictoryPoints
550
+ h[key] = pull_out_top_10_data(xml,klass,'factions',val)
551
+ h
552
+ end
553
+ Reve::Classes::FactionWarTopStats.new(characters,corporations,factions)
554
+ end
555
+
556
+ # Get a list of personal assets for the characterid.
557
+ # See the Reve::Classes::Asset and Reve::Classes::AssetContainer classes
558
+ # for attributes available.
559
+ def personal_assets_list(opts = { :characterid => nil })
560
+ args = postfields(opts)
561
+ h = compute_hash(args.merge(:url => @@personal_assets_url))
562
+ return h if h
563
+ xml = process_query(nil,opts[:url] || @@personal_assets_url,true,args)
564
+ assets = []
565
+ xml.search("/eveapi/result/rowset[@name='assets']/row").each do |container|
566
+ asset_container = Reve::Classes::AssetContainer.new(container)
567
+ container.search("rowset[@name='contents']/row").each do |asset|
568
+ asset_container.assets << Reve::Classes::Asset.new(asset)
569
+ end
570
+ assets << asset_container
571
+ end
572
+ assets
573
+ end
574
+
575
+ # Get a list of the Corporate Assets. Pass the characterid of the Corporate member See also assets_list method
576
+ def corporate_assets_list(opts = { :characterid => nil})
577
+ args = postfields(opts)
578
+ h = compute_hash(args.merge(:url => @@corporate_assets_url))
579
+ return h if h
580
+ xml = process_query(nil,opts[:url] || @@corporate_assets_url,true,args)
581
+ assets = []
582
+ xml.search("/eveapi/result/rowset/row").each do |container|
583
+ asset_container = Reve::Classes::AssetContainer.new(container)
584
+ container.search("rowset[@name='contents']/row").each do |asset|
585
+ asset_container.assets << Reve::Classes::Asset.new(asset)
586
+ end
587
+ assets << asset_container
588
+ end
589
+ assets
590
+ end
591
+
592
+ # Returns a Character list for the associated key and userid from
593
+ # http://api.eve-online.com/account/Characters.xml.aspx
594
+ # See also: Reve::Classes::Character
595
+ def characters(opts = {})
596
+ args = postfields(opts)
597
+ h = compute_hash(args.merge(:url => @@characters_url))
598
+ return h if h
599
+ process_query(Reve::Classes::Character,opts[:url] || @@characters_url,false,args)
600
+ end
601
+
602
+ # Gets the SkillInTraining from
603
+ # http://api.eve-online.com/char/SkillInTraining.xml.aspx
604
+ # Expects:
605
+ # * characterid ( Integer | String ) - Get the SkillInTraining for this Character
606
+ # See also: Reve::Classes::SkillInTraining
607
+ def skill_in_training(opts = {:characterid => nil})
608
+ args = postfields(opts)
609
+ ch = compute_hash(args.merge(:url => @@training_skill_url))
610
+ return ch if ch
611
+ h = {}
612
+ xml = process_query(nil,opts[:url] || @@training_skill_url,true,args)
613
+ xml.search("//result").each do |elem|
614
+ for field in [ 'currentTQTime', 'trainingEndTime','trainingStartTime','trainingTypeID','trainingStartSP','trainingDestinationSP','trainingToLevel','skillInTraining' ]
615
+ h[field] = (elem/field.intern).inner_html
616
+ end
617
+ end
618
+ Reve::Classes::SkillInTraining.new(h)
619
+ end
620
+
621
+ # Returns a list of Reve::Classes::QueuedSkill for characterid
622
+ # http://api.eve-online.com/char/SkillQueue.xml.aspx
623
+ # Expects:
624
+ # * characterid ( Integer | String ) - Get the QueuedSkill list for this character
625
+ # See also Reve::Classes::QueuedSkill
626
+ def skill_queue(opts = {:characterid => nil})
627
+ args = postfields(opts)
628
+ ch = compute_hash(args.merge(:url => @@skill_queue_url))
629
+ return ch if ch
630
+ process_query(Reve::Classes::QueuedSkill,opts[:url] || @@skill_queue_url,false,args)
631
+ end
632
+
633
+ # Returns a list of Reve::Classes::Starbase for characterid's Corporation.
634
+ # http://api.eve-online.com/corp/StarbaseList.xml.aspx
635
+ # Expects:
636
+ # * characterid ( Integer | String ) - Get the Starbase list for this character's Corporation
637
+ # See also Reve::Classes::Starbase
638
+ def starbases(opts = { :characterid => nil})
639
+ args = postfields(opts)
640
+ h = compute_hash(args.merge(:url => @@starbases_url))
641
+ return h if h
642
+ process_query(Reve::Classes::Starbase,opts[:url] || @@starbases_url,false,args)
643
+ end
644
+
645
+ # Returns the fuel status for the Starbase whose item id is starbase_id
646
+ # http://api.eve-online.com/corp/StarbaseDetail.xml.aspx
647
+ # Expects:
648
+ # * characterid ( Integer | String ) - Get the Starbase associated wih this character's Corporation
649
+ # * starbase_id ( Integer ) - Get the fuel for this Starbase. This is the Starbase's itemid.
650
+ # See also Reve::Classes::StarbaseFuel
651
+ def starbase_fuel(opts = { :characterid => nil, :starbaseid => nil })
652
+ args = postfields(opts)
653
+ h = compute_hash(args.merge(:url => @@starbasedetail_url))
654
+ return h if h
655
+ ret = process_query(Reve::Classes::StarbaseFuel,opts[:url] || @@starbasedetail_url, false, args)
656
+ ret.each { |r| r.starbase_id = opts[:starbaseid] }
657
+ ret
658
+ end
659
+
660
+
661
+ # Get the last kills for the characterid passed.
662
+ # Expects:
663
+ # * Hash of arguments
664
+ # * * characterid ( Integer ) - The Character whose Kills to retrieve
665
+ # * * beforekillid ( Integer ) - (Optional) - Return the most recent kills before this killid.
666
+ def personal_kills(opts = { :characterid => nil })
667
+ args = postfields(opts)
668
+ h = compute_hash(args.merge(:url => @@personal_kills_url))
669
+ return h if h
670
+ xml = process_query(nil,opts[:url] || @@personal_kills_url,true,args)
671
+ kills = []
672
+ xml.search("/eveapi/result/rowset/row").each do |e|
673
+ victim = Reve::Classes::KillVictim.new(e.search("victim").first) rescue next # cant find victim
674
+ attackers = []
675
+ losses = []
676
+ e.search("rowset[@name='attackers']/row").each do |attacker|
677
+ attackers << Reve::Classes::KillAttacker.new(attacker)
678
+ end
679
+ e.search("rowset[@name='items']/row").each do |lost_item|
680
+ lost = Reve::Classes::KillLoss.new(lost_item)
681
+ lost_item.search("rowset[@name='items']/row").each do |contained|
682
+ lost.contained_losses << Reve::Classes::KillLoss.new(contained)
683
+ end
684
+ losses << lost
685
+ end
686
+ kills << Reve::Classes::Kill.new(e, victim, attackers, losses)
687
+ end
688
+ kills
689
+ end
690
+
691
+ # See the options for personal_kills
692
+ def corporate_kills(opts = { :characterid => nil })
693
+ args = postfields(opts)
694
+ h = compute_hash(args.merge(:url => @@corporate_kills_url))
695
+ return h if h
696
+ xml = process_query(nil,opts[:url] || @@corporate_kills_url,true,args)
697
+ kills = []
698
+ xml.search("/eveapi/result/rowset/row").each do |e|
699
+ victim = Reve::Classes::KillVictim.new(e.search("victim").first) rescue next # cant find victim
700
+ attackers = []
701
+ losses = []
702
+ e.search("rowset[@name='attackers']/row").each do |attacker|
703
+ attackers << Reve::Classes::KillAttacker.new(attacker)
704
+ end
705
+ e.search("rowset[@name='items']/row").each do |lost_item|
706
+ lost = Reve::Classes::KillLoss.new(lost_item)
707
+ lost_item.search("rowset[@name='items']/row").each do |contained|
708
+ lost.contained_losses << Reve::Classes::KillLoss.new(contained)
709
+ end
710
+ losses << lost
711
+ end
712
+ kills << Reve::Classes::Kill.new(e, victim, attackers, losses)
713
+ end
714
+ kills
715
+ end
716
+
717
+ # Gets the CorporationSheet from http://api.eve-online.com/corp/CorporationSheet.xml.aspx
718
+ # Expects:
719
+ # * Hash of arguments:
720
+ # * * characterid ( Integer | String ) - Gets the CorporationSheet for this Character
721
+ # * * corporationid ( Integer ) - If the characterid isn't passed then send the corporation's id
722
+ # (See the alliances method for a list) to get the details of a Corporation that belongs to an Alliance.
723
+ # See also: Reve::Classes::CorporationSheet
724
+ def corporation_sheet(opts = { :characterid => nil })
725
+ args = postfields(opts)
726
+ h = compute_hash(args.merge(:url => @@corporation_sheet_url))
727
+ return h if h
728
+ xml = process_query(nil,opts[:url] || @@corporation_sheet_url,true,args)
729
+
730
+ h = { 'graphicid' => 0, 'shape1' => 0, 'shape2' => 0, 'shape3' => 0, 'color1' => 0, 'color2' => 0, 'color3' => 0, }
731
+ h.keys.each { |k| h[k] = xml.search("//result/logo/" + k + "/").to_s.to_i }
732
+ corporate_logo = Reve::Classes::CorporateLogo.new h
733
+
734
+ wallet_divisions = xml.search("//result/rowset[@name='walletDivisions']/").collect { |k| k if k.kind_of? Hpricot::Elem } - [ nil ]
735
+ divisions = xml.search("//result/rowset[@name='divisions']/").collect { |k| k if k.kind_of? Hpricot::Elem } - [ nil ]
736
+ divisions.collect! { |d| Reve::Classes::CorporateDivision.new(d) }
737
+ wallet_divisions.collect! { |w| Reve::Classes::WalletDivision.new(w) }
738
+
739
+ # Map the XML names to our own names and assign them to the temporary
740
+ # hash +res+ to pass to Reve::Classes::CorporationSheet#new
741
+ res = Hash.new
742
+ { :corporationid => :id, :corporationname => :name, :ticker => :ticker, :ceoid => :ceo_id,
743
+ :ceoname => :ceo_name, :stationid => :station_id, :stationname => :station_name,
744
+ :description => :description, :url => :url, :allianceid => :alliance_id,
745
+ :alliancename => :alliance_name, :taxrate => :tax_rate, :membercount => :member_count,
746
+ :memberlimit => :member_limit, :shares => :shares }.each do |k,v|
747
+ res[v] = xml.search("//result/#{k.to_s}/").first.to_s.strip
748
+ end
749
+
750
+ Reve::Classes::CorporationSheet.new res, divisions, wallet_divisions, corporate_logo
751
+ end
752
+
753
+
754
+ # Returns a Reve::Classes::CertificateTree object that contains the
755
+ # Certificate tree structure. See the rdoc for Reve::Classes::CertificateTree
756
+ # for details.
757
+ # See also: Reve::Classes::CertificateTree
758
+ def certificate_tree(opts = {})
759
+ args = postfields(opts)
760
+ h = compute_hash(args.merge(:url => @@certificate_tree_url))
761
+ return h if h
762
+ xml = process_query(nil,opts[:url] || @@certificate_tree_url,true,args)
763
+
764
+ tree = Reve::Classes::CertificateTree.new
765
+ xml.search("/eveapi/result/rowset[@name=categories]/row").each do |category|
766
+ cat = Reve::Classes::CertificateCategory.new(category)
767
+ category.search("rowset[@name=classes]/row").each do |klass|
768
+ kl = Reve::Classes::CertificateClass.new(klass)
769
+ klass.search("rowset[@name=certificates]/row").each do |certificate|
770
+ cert = Reve::Classes::Certificate.new(certificate)
771
+ certificate.search("rowset[@name=requiredSkills]/row").each do |skill|
772
+ cert.required_skills << Reve::Classes::CertificateRequiredSkill.new(skill)
773
+ end
774
+ certificate.search("rowset[@name=requiredCertificates]/row").each do |requiredcert|
775
+ cert.required_certificates << Reve::Classes::CertificateRequiredCertificate.new(requiredcert)
776
+ end
777
+ kl.certificates << cert
778
+ end
779
+ cat.classes << kl
780
+ end
781
+ tree.categories << cat
782
+ end
783
+ tree
784
+ end
785
+
786
+ # Gets the CharacterSheet from
787
+ # http://api.eve-online.com/char/CharacterSheet.xml.aspx
788
+ # Expects:
789
+ # * characterid ( Fixnum ) - Get the CharacterSheet for this Character
790
+ # See also: Reve::Classes::CharacterSheet
791
+ def character_sheet(opts = { :characterid => nil })
792
+ args = postfields(opts)
793
+ h = compute_hash(args.merge(:url => @@character_sheet_url))
794
+ return h if h
795
+
796
+ xml = process_query(nil,opts[:url] || @@character_sheet_url,true,args)
797
+ cs = Reve::Classes::CharacterSheet.new
798
+
799
+ [ Reve::Classes::IntelligenceEnhancer, Reve::Classes::MemoryEnhancer, Reve::Classes::CharismaEnhancer,
800
+ Reve::Classes::PerceptionEnhancer, Reve::Classes::WillpowerEnhancer
801
+ ].each do |klass|
802
+ xml_attr = klass.to_s.split("::").last.sub("Enhancer",'').downcase + "Bonus"
803
+ i = klass.new(xml.search("/eveapi/result/attributeEnhancers/#{xml_attr}").search("augmentatorName/").first.to_s,
804
+ xml.search("/eveapi/result/attributeEnhancers/#{xml_attr}").search("augmentatorValue/").first.to_s.to_i)
805
+ cs.enhancers << i
806
+ end
807
+
808
+ [ 'characterID', 'name', 'race', 'bloodLine', 'gender','corporationName',
809
+ 'corporationID','balance', 'cloneName', 'cloneSkillPoints'
810
+ ].each do |field|
811
+ cs.send("#{field.downcase}=",xml.search("/eveapi/result/#{field}/").first.to_s)
812
+ end
813
+
814
+ [ 'intelligence','memory','charisma','perception','willpower' ].each do |attrib|
815
+ cs.send("#{attrib}=",xml.search("/eveapi/result/attributes/#{attrib}/").first.to_s.to_i)
816
+ end
817
+ xml.search("rowset[@name=skills]/row").each do |elem|
818
+ cs.skills << Reve::Classes::Skill.new(elem)
819
+ end
820
+
821
+ xml.search("rowset[@name=certificates]/row").each do |elem|
822
+ cs.certificate_ids << elem['certificateID'].to_i
823
+ end
824
+ [ :corporationRolesAtHQ, :corporationRoles, :corporationRolesAtBase, :corporationRolesAtOther ].each do |role_kind|
825
+ xml.search("rowset[@name=#{role_kind.to_s}]/row").each do |elem|
826
+ arry = []
827
+ role = Reve::Classes::CorporateRole.new(elem)
828
+ arry << role
829
+ cs.send("#{role_kind}=".to_sym,arry)
830
+ end
831
+ end
832
+
833
+ xml.search("rowset[@name=corporationTitles]/row").each do |elem|
834
+ cs.corporate_titles << Reve::Classes::CorporateTitle.new(elem)
835
+ end
836
+
837
+ cs
838
+ end
839
+
840
+
841
+ protected
842
+ # Sets up the post fields for Net::HTTP::Get hash for process_query method.
843
+ # See also format_url_request
844
+ # TODO: Consider moving this whole thing into process_query to avoid
845
+ # calling this in every method!
846
+ def postfields(opts = {})
847
+ ret = { "userid" => @userid, "apikey" => @key, "characterid" => @charid }.merge(opts.stringify_keys)
848
+ ret.inject({}) do |n, (k,v)|
849
+ n[k.downcase] = v.to_s if v
850
+ n
851
+ end
852
+ end
853
+
854
+ # Creates a hash for some hash of postfields. For each API method pass
855
+ # :just_hash => to something to return a hash that can be matched to
856
+ # the last_hash instance method created in process_query.
857
+ # This method is called in each API method before process_query and if
858
+ # :just_hash was passed in args then a String will be returned, otherwise
859
+ # nil will be returned
860
+ # TODO: Consider moving this whole thing into process_query before the URI parsing
861
+ def compute_hash(args = {})
862
+ args.stringify_keys!
863
+ return nil unless args.include?('just_hash')
864
+ args.delete('just_hash')
865
+ url = args['url'].kind_of?(URI) ? args['url'].path : args['url']
866
+ args.delete('url')
867
+ spl = url.split '/'
868
+ ret = (spl[-2] + '/' + spl[-1]) + ':'
869
+ args.delete_if { |k,v| (v || "").to_s.length == 0 } # Delete keys if the value is nil
870
+ h = args.stringify_keys
871
+ ret += h.sort.flatten.collect{ |e| e.to_s }.join(':')
872
+ ret.gsub(/:$/,'')
873
+ end
874
+
875
+ # Processes a URL and for simple <rowset><row /><row /></rowset> results
876
+ # create an array of objects of type klass. Or just return the XML if
877
+ # just_xml is set true. args is from postfields
878
+ # This method will call check_exception to see if an Exception came from
879
+ # CCP.
880
+ # Expects:
881
+ # * klass ( Class ) - The class container for parsing. An array of these is returned in default behaviour.
882
+ # * url ( String ) - API URL
883
+ # * just_xml ( Boolean ) - Return only the XML and not attempt to parse //rowset/row. Useful if the XML is not in that form.
884
+ # * args ( Hash ) - Hash of arguments for the request. See postfields method.
885
+ def process_query(klass, url, just_xml = false, opts = {})
886
+
887
+ #args = postfields(opts)
888
+ #h = compute_hash(args.merge(:url => url))
889
+ #return h if h
890
+
891
+ @last_hash = compute_hash(opts.merge({:url => url, :just_hash => true })) # compute hash
892
+
893
+ xml = check_exception(get_xml(url,opts))
894
+ save_xml(xml) if @save_path
895
+
896
+ return xml if just_xml
897
+ return [] if xml.nil? # No XML document returned. We should panic.
898
+
899
+ # Create the array of klass objects to return, assume we start with an empty set from the XML search for rows
900
+ # and build from there.
901
+ xml.search("//rowset/row").inject([]) { |ret,elem| ret << klass.new(elem) }
902
+ end
903
+
904
+ # Turns a hash into ?var=baz&bam=boo
905
+ def format_url_request(opts)
906
+ req = "?"
907
+
908
+ opts.stringify_keys!
909
+ opts.keys.sort.each do |key|
910
+ req += "#{CGI.escape(key.to_s)}=#{CGI.escape(opts[key].to_s)}&" if opts[key]
911
+ end
912
+ req.chop # We are lazy and append a & to each pair even if it's the last one. FIXME: Don't do this.
913
+ end
914
+
915
+
916
+ # Gets the XML from a source.
917
+ # Expects:
918
+ # * 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.
919
+ # * opts ( Hash ) - Hash of parameters for the request, such as userid, apikey and such.
920
+ # NOTE: To override the lowercase http -> URI rule make the HTTP part uppercase.
921
+ def get_xml(source,opts)
922
+ xml = ""
923
+
924
+ # Let people still pass Strings starting with http.
925
+ if source =~ /^http/
926
+ source = URI.parse(source)
927
+ end
928
+
929
+ if source.kind_of?(URI)
930
+ opts.merge({ :version => 2, :url => nil }) #the uri bit will now ignored in format_url_request
931
+ req_args = format_url_request(opts)
932
+ req = Net::HTTP::Get.new(source.path + req_args)
933
+ req['User-Agent'] = @http_referer_agent || "Reve"
934
+
935
+ res = nil
936
+ response = nil
937
+ 1.upto(@max_tries) do |try|
938
+ begin
939
+ # ||= to prevent making a new Net::HTTP object, the res = nil above should reset this for the next request.
940
+ # the request needs to be here to rescue exceptions from it.
941
+ res ||= Net::HTTP.new(source.host, source.port).start {|http| http.request(req) }
942
+ case res
943
+ when Net::HTTPSuccess, Net::HTTPRedirection
944
+ response = res.body
945
+ end
946
+ rescue Exception
947
+ sleep 5
948
+ next
949
+ end
950
+ break if response
951
+ end
952
+ raise Reve::Exceptions::ReveNetworkStatusException.new( (res.body rescue "No Response Body!") ) unless response
953
+
954
+ xml = response
955
+
956
+ # here ends test for URI
957
+ elsif source.kind_of?(String)
958
+ xml = File.open(source).read
959
+ else
960
+ raise Reve::Exceptions::ReveNetworkStatusException.new("Don't know how to deal with a #{source.class} XML source. I expect a URI or String")
961
+ end
962
+ xml
963
+ end
964
+
965
+ # Raises the proper exception (if there is one), otherwise it returns the
966
+ # XML response.
967
+ def check_exception(xml)
968
+ x = Hpricot::XML(xml)
969
+ begin
970
+ out = x.search("//error") # If this fails then there are some big problems with Hpricot#search ?
971
+ rescue Exception => e
972
+ $stderr.puts "Fatal error ((#{e.to_s})): Couldn't search the XML document ((#{xml})) for any potential error messages! Is your Hpricot broken?"
973
+ exit 1
974
+ end
975
+ @current_time = (x/:currentTime).inner_html.to_time rescue Time.now.utc # Shouldn't need to rescue this but one never knows
976
+ @cached_until = (x/:cachedUntil).inner_html.to_time rescue nil # Errors aren't always cached
977
+ return x if out.size < 1
978
+ code = out.first['code'].to_i
979
+ str = out.first.inner_html
980
+ Reve::Exceptions.raise_it(code,str)
981
+ end
982
+
983
+ def save_xml(xml)
984
+ path = build_save_filename
985
+ FileUtils.mkdir_p(File.dirname(path))
986
+ File.open(path,'w') { |f| f.print xml.to_original_html }
987
+ end
988
+ def build_save_filename
989
+ method = caller(3).first.match(/\`(.+)'/)[1] # Get the API method that's being called. This is called from save_xml -> process_query -> :real_method
990
+ File.join(@save_path,@userid.to_s,method,( @cached_until || Time.now.utc).to_i.to_s + '.xml')
991
+ end
992
+
993
+ # Returns an array of +klass+
994
+ def pull_out_top_10_data(xml,klass,kind,field)
995
+ xml.search("/eveapi/result/#{kind}/rowset[@name='#{field}']/row").inject([]) do |all,row|
996
+ all << klass.new(row)
997
+ all
998
+ end
999
+ end
1000
+ end
1001
+ end