lisa-reve 0.0.120

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