greeve 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +4 -0
- data/LICENSE +8 -0
- data/README.md +3 -0
- data/doc/Greeve.html +169 -0
- data/doc/Greeve/API.html +118 -0
- data/doc/Greeve/API/BaseItem.html +621 -0
- data/doc/Greeve/API/CharacterInfo.html +156 -0
- data/doc/Greeve/BaseItem.html +1416 -0
- data/doc/Greeve/Character.html +118 -0
- data/doc/Greeve/Corporation.html +118 -0
- data/doc/Greeve/Eve.html +130 -0
- data/doc/Greeve/Eve/CharacterInfo.html +251 -0
- data/doc/Greeve/Map.html +118 -0
- data/doc/Greeve/Request.html +225 -0
- data/doc/Greeve/Row.html +583 -0
- data/doc/Greeve/Rowset.html +613 -0
- data/doc/Greeve/Server.html +118 -0
- data/doc/_index.html +244 -0
- data/doc/class_list.html +51 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +58 -0
- data/doc/css/style.css +481 -0
- data/doc/file.CONTRIBUTING.html +76 -0
- data/doc/file.LICENSE.html +92 -0
- data/doc/file.README.html +75 -0
- data/doc/file_list.html +66 -0
- data/doc/frames.html +17 -0
- data/doc/index.html +75 -0
- data/doc/js/app.js +243 -0
- data/doc/js/full_list.js +216 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +211 -0
- data/doc/top-level-namespace.html +112 -0
- data/lib/greeve.rb +29 -0
- data/lib/greeve/base_item.rb +237 -0
- data/lib/greeve/eve/character_info.rb +45 -0
- data/lib/greeve/row.rb +72 -0
- data/lib/greeve/rowset.rb +71 -0
- data/lib/greeve/version.rb +4 -0
- metadata +215 -0
data/lib/greeve.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "bigdecimal"
|
2
|
+
require "ox"
|
3
|
+
require "typhoeus"
|
4
|
+
|
5
|
+
require_relative "greeve/version"
|
6
|
+
|
7
|
+
require_relative "greeve/base_item"
|
8
|
+
require_relative "greeve/row"
|
9
|
+
require_relative "greeve/rowset"
|
10
|
+
require_relative "greeve/eve/character_info"
|
11
|
+
|
12
|
+
# A Ruby wrapper for the EVE Online XML API.
|
13
|
+
module Greeve
|
14
|
+
# Base URL of the EVE XML API.
|
15
|
+
EVE_API_BASE_URL = "https://api.eveonline.com".freeze
|
16
|
+
|
17
|
+
# API resources.
|
18
|
+
module API; end
|
19
|
+
# Character resources.
|
20
|
+
module Character; end
|
21
|
+
# Corporation resources.
|
22
|
+
module Corporation; end
|
23
|
+
# Eve resources.
|
24
|
+
module Eve; end
|
25
|
+
# Map resources.
|
26
|
+
module Map; end
|
27
|
+
# Server resources.
|
28
|
+
module Server; end
|
29
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
require "bigdecimal"
|
2
|
+
require "time"
|
3
|
+
|
4
|
+
require_relative "rowset"
|
5
|
+
|
6
|
+
module Greeve
|
7
|
+
# An abstract class used to map XML responses from the EVE XML API into Ruby
|
8
|
+
# objects. This class is designed to be subclassed by classes representing
|
9
|
+
# the specific EVE API resources.
|
10
|
+
class BaseItem
|
11
|
+
# A DSL method to map an XML attribute to a Ruby object.
|
12
|
+
#
|
13
|
+
# @param name [Symbol] the Ruby name for this attribute
|
14
|
+
#
|
15
|
+
# @option opts [Symbol] :xpath the xpath string used to locate the attribute
|
16
|
+
# in the XML element
|
17
|
+
# @option opts [:integer, :numeric, :string] :type method used to coerce the
|
18
|
+
# XML value
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# attribute :character_id, xpath: "characterID/?[0]", type: :integer
|
22
|
+
def self.attribute(name, opts = {})
|
23
|
+
name = name.to_sym
|
24
|
+
@attributes ||= {}
|
25
|
+
|
26
|
+
raise "Attribute `#{name}` defined more than once" if @attributes[name]
|
27
|
+
raise "`:xpath` not specified for `#{name}`" unless opts[:xpath]
|
28
|
+
|
29
|
+
@attributes[name] = {
|
30
|
+
xpath: opts[:xpath],
|
31
|
+
type: opts[:type],
|
32
|
+
}
|
33
|
+
|
34
|
+
define_method(name) do
|
35
|
+
ivar = instance_variable_get(:"@#{name}")
|
36
|
+
return ivar unless ivar.nil?
|
37
|
+
|
38
|
+
value = @xml_element.locate(opts[:xpath]).first
|
39
|
+
|
40
|
+
unless value.nil?
|
41
|
+
value =
|
42
|
+
case opts[:type]
|
43
|
+
when :integer
|
44
|
+
value.to_i
|
45
|
+
when :numeric
|
46
|
+
BigDecimal.new(value)
|
47
|
+
when :string
|
48
|
+
value.to_s
|
49
|
+
when :datetime
|
50
|
+
Time.parse(value + " UTC")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
instance_variable_set(:"@#{name}", value)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# A DSL method to map an XML rowset to a Ruby object.
|
59
|
+
#
|
60
|
+
# @param name [Symbol] the Ruby name for this attribute
|
61
|
+
#
|
62
|
+
# @option opts [Symbol] :xpath the xpath string used to locate the attribute
|
63
|
+
# in the XML element
|
64
|
+
#
|
65
|
+
# @example
|
66
|
+
# rowset :employment_history, xpath: "eveapi/result/rowset[@name='employmentHistory']" do
|
67
|
+
# attribute :record_id, xpath: "@recordID", type: :integer
|
68
|
+
# attribute :corporation_id, xpath: "@corporationID", type: :integer
|
69
|
+
# attribute :corporation_name, xpath: "@corporationName", type: :string
|
70
|
+
# attribute :start_date, xpath: "@startDate", type: :datetime
|
71
|
+
# end
|
72
|
+
def self.rowset(name, opts = {}, &block)
|
73
|
+
name = name.to_sym
|
74
|
+
@attributes ||= {}
|
75
|
+
|
76
|
+
raise "Attribute `#{name}` defined more than once" if @attributes[name]
|
77
|
+
raise "`:xpath` not specified for `#{name}`" unless opts[:xpath]
|
78
|
+
|
79
|
+
@attributes[name] = {
|
80
|
+
xpath: opts[:xpath],
|
81
|
+
type: :rowset,
|
82
|
+
}
|
83
|
+
|
84
|
+
define_method(name) do
|
85
|
+
ivar = instance_variable_get(:"@#{name}")
|
86
|
+
return ivar unless ivar.nil?
|
87
|
+
|
88
|
+
# Since Ox doesn't support the xpath [@k='v'] syntax, parse it out
|
89
|
+
# with a regex (captures :path, :attr, :attr_value).
|
90
|
+
attr_regex = %r{\A(?<path>.*?)\[@(?<attr>\w+)=['"](?<attr_value>\w+)['"]\]\z}
|
91
|
+
match = opts[:xpath].match(attr_regex)
|
92
|
+
|
93
|
+
rowset_element =
|
94
|
+
@xml_element
|
95
|
+
.locate(match[:path])
|
96
|
+
.find { |e| e.attributes[match[:attr].to_sym] == match[:attr_value] }
|
97
|
+
|
98
|
+
rowset = Rowset.new(name, rowset_element, &block)
|
99
|
+
|
100
|
+
instance_variable_set(:"@#{name}", rowset)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# A DSL method to specify the API endpoint.
|
105
|
+
#
|
106
|
+
# @param path [String] path of the API endpoint. Doesn't need to include the
|
107
|
+
# leading slash `/`, or the extension `.xml.aspx`
|
108
|
+
#
|
109
|
+
# @example
|
110
|
+
# endpoint "eve/CharacterInfo"
|
111
|
+
def self.endpoint(path)
|
112
|
+
# Remove leading slash and file extension.
|
113
|
+
@endpoint = path.gsub(/\A\/*(.*?)(?:\.xml)?(?:\.aspx)?\z/, '\1')
|
114
|
+
end
|
115
|
+
|
116
|
+
# @abstract Subclass and use the DSL methods to map API endpoints to objects
|
117
|
+
#
|
118
|
+
# @option opts [String, Fixnum] :key API key
|
119
|
+
# @option opts [String] :vcode API vCode
|
120
|
+
# @option opts [Hash<String, String>] :query_params a hash of HTTP query
|
121
|
+
# params that specify how a value maps to the API request
|
122
|
+
#
|
123
|
+
# @example
|
124
|
+
# super(query_params: {
|
125
|
+
# "characterID" => character_id,
|
126
|
+
# })
|
127
|
+
def initialize(opts = {})
|
128
|
+
raise TypeError, "Cannot instantiate an abstract class" \
|
129
|
+
if self.class.superclass != Greeve::BaseItem
|
130
|
+
|
131
|
+
@api_key = opts[:key]
|
132
|
+
@api_vcode = opts[:vcode]
|
133
|
+
@query_params = opts[:query_params] || {}
|
134
|
+
|
135
|
+
if @api_key && @api_vcode
|
136
|
+
@query_params.merge!({
|
137
|
+
"keyID" => @api_key,
|
138
|
+
"vCode" => @api_vcode,
|
139
|
+
})
|
140
|
+
end
|
141
|
+
|
142
|
+
refresh
|
143
|
+
end
|
144
|
+
|
145
|
+
# Query the API, refreshing this object's data.
|
146
|
+
#
|
147
|
+
# @return true if the endpoint was fetched (HTTP request sent), false if
|
148
|
+
# the cache hasn't expired
|
149
|
+
def refresh
|
150
|
+
return false unless cache_expired?
|
151
|
+
|
152
|
+
fetch
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
156
|
+
# @return true if the API cache timer has expired and this object can
|
157
|
+
# be refreshed
|
158
|
+
def cache_expired?
|
159
|
+
!(cached_until && cached_until > Time.now)
|
160
|
+
end
|
161
|
+
|
162
|
+
# @return [Time, nil] time when the cache expires and the resource can be
|
163
|
+
# refreshed (sends an HTTP request)
|
164
|
+
def cached_until
|
165
|
+
return unless @xml_element
|
166
|
+
|
167
|
+
_cached_until = @xml_element.locate("eveapi/cachedUntil/?[0]").first
|
168
|
+
_cached_until ? Time.parse(_cached_until + " UTC") : nil
|
169
|
+
end
|
170
|
+
|
171
|
+
# :nodoc:
|
172
|
+
def inspect
|
173
|
+
attrs = to_s
|
174
|
+
|
175
|
+
unless attrs.empty?
|
176
|
+
attrs = attrs.split("\n").map { |l| " #{l}" }.join("\n")
|
177
|
+
attrs = "\n#{attrs}\n"
|
178
|
+
end
|
179
|
+
|
180
|
+
"#<#{self.class.name}:#{object_id}#{attrs}>"
|
181
|
+
end
|
182
|
+
|
183
|
+
# @return [String] a string representation of the non-nil attributes
|
184
|
+
def to_s
|
185
|
+
to_h
|
186
|
+
.map { |k, v|
|
187
|
+
v = v.to_s("F") if v.is_a?(BigDecimal)
|
188
|
+
"#{k}: #{v}"
|
189
|
+
}
|
190
|
+
.join("\n")
|
191
|
+
end
|
192
|
+
|
193
|
+
# @return [Hash] a hash of non-nil attributes
|
194
|
+
def to_h
|
195
|
+
attributes
|
196
|
+
.keys
|
197
|
+
.map { |name|
|
198
|
+
value = __send__(name)
|
199
|
+
value = value.to_a if value.is_a?(Rowset)
|
200
|
+
|
201
|
+
[name, value]
|
202
|
+
}
|
203
|
+
.to_h
|
204
|
+
.reject { |k, v| v.nil? }
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
# @return [Hash] the hash of attributes for this object
|
210
|
+
def attributes
|
211
|
+
self.class.instance_variable_get(:@attributes) || {}
|
212
|
+
end
|
213
|
+
|
214
|
+
# @return [String] the class's endpoint path
|
215
|
+
def endpoint
|
216
|
+
self.class.instance_variable_get(:@endpoint)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Fetch data from the API HTTP endpoint.
|
220
|
+
def fetch
|
221
|
+
url = "#{Greeve::EVE_API_BASE_URL}/#{endpoint}.xml.aspx"
|
222
|
+
response = Typhoeus.get(url, params: @query_params)
|
223
|
+
|
224
|
+
# TODO: Use a better error class.
|
225
|
+
raise TypeError, "HTTP error #{response.code}" \
|
226
|
+
unless (200..299).include?(response.code.to_i)
|
227
|
+
|
228
|
+
@xml_element = Ox.parse(response.body)
|
229
|
+
|
230
|
+
attributes.keys.each do |name|
|
231
|
+
instance_variable_set(:"@#{name}", nil)
|
232
|
+
end
|
233
|
+
|
234
|
+
@xml_element
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative "../base_item"
|
2
|
+
|
3
|
+
module Greeve
|
4
|
+
module Eve
|
5
|
+
# Public character info.
|
6
|
+
class CharacterInfo < Greeve::BaseItem
|
7
|
+
endpoint "eve/CharacterInfo"
|
8
|
+
|
9
|
+
attribute :character_id, xpath: "eveapi/result/characterID/?[0]", type: :integer
|
10
|
+
attribute :character_name, xpath: "eveapi/result/characterName/?[0]", type: :string
|
11
|
+
attribute :race, xpath: "eveapi/result/race/?[0]", type: :string
|
12
|
+
attribute :bloodline_id, xpath: "eveapi/result/bloodlineID/?[0]", type: :integer
|
13
|
+
attribute :bloodline, xpath: "eveapi/result/bloodline/?[0]", type: :string
|
14
|
+
attribute :ancestry_id, xpath: "eveapi/result/ancestryID/?[0]", type: :integer
|
15
|
+
attribute :ancestry, xpath: "eveapi/result/ancestry/?[0]", type: :string
|
16
|
+
attribute :account_balance, xpath: "eveapi/result/accountBalance/?[0]", type: :numeric
|
17
|
+
attribute :skill_points, xpath: "eveapi/result/skillPoints/?[0]", type: :integer
|
18
|
+
attribute :next_training_ends, xpath: "eveapi/result/nextTrainingEnds/?[0]", type: :datetime
|
19
|
+
attribute :ship_name, xpath: "eveapi/result/shipName/?[0]", type: :string
|
20
|
+
attribute :ship_type_id, xpath: "eveapi/result/shipTypeID/?[0]", type: :integer
|
21
|
+
attribute :ship_type_name, xpath: "eveapi/result/shipTypeName/?[0]", type: :string
|
22
|
+
attribute :corporation_id, xpath: "eveapi/result/corporationID/?[0]", type: :integer
|
23
|
+
attribute :corporation, xpath: "eveapi/result/corporation/?[0]", type: :string
|
24
|
+
attribute :corporation_date, xpath: "eveapi/result/corporationDate/?[0]", type: :datetime
|
25
|
+
attribute :alliance_id, xpath: "eveapi/result/allianceID/?[0]", type: :integer
|
26
|
+
attribute :alliance, xpath: "eveapi/result/alliance/?[0]", type: :string
|
27
|
+
attribute :alliance_date, xpath: "eveapi/result/allianceDate/?[0]", type: :datetime
|
28
|
+
attribute :last_known_location, xpath: "eveapi/result/lastKnownLocation/?[0]", type: :string
|
29
|
+
attribute :security_status, xpath: "eveapi/result/securityStatus/?[0]", type: :numeric
|
30
|
+
|
31
|
+
rowset :employment_history, xpath: "eveapi/result/rowset[@name='employmentHistory']" do
|
32
|
+
attribute :record_id, xpath: "@recordID", type: :integer
|
33
|
+
attribute :corporation_id, xpath: "@corporationID", type: :integer
|
34
|
+
attribute :corporation_name, xpath: "@corporationName", type: :string
|
35
|
+
attribute :start_date, xpath: "@startDate", type: :datetime
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param character_id [Integer] EVE character ID
|
39
|
+
def initialize(character_id, opts = {})
|
40
|
+
opts[:query_params] = { "characterID" => character_id }
|
41
|
+
super(opts)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/greeve/row.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
module Greeve
|
2
|
+
# Represents an XML `row` element, contained in a {Rowset}.
|
3
|
+
class Row
|
4
|
+
# @param xml_element [Ox::Element] the xml row element for this item
|
5
|
+
# @param attributes [Hash] the hash of attribute definitions for this row
|
6
|
+
def initialize(xml_element, attributes)
|
7
|
+
@xml_element = xml_element
|
8
|
+
@attributes = attributes
|
9
|
+
|
10
|
+
attributes.each do |name, opts|
|
11
|
+
define_singleton_method(name) do
|
12
|
+
ivar = instance_variable_get(:"@#{name}")
|
13
|
+
return ivar unless ivar.nil?
|
14
|
+
|
15
|
+
value = @xml_element.locate(opts[:xpath]).first
|
16
|
+
|
17
|
+
unless value.nil?
|
18
|
+
value =
|
19
|
+
case opts[:type]
|
20
|
+
when :integer
|
21
|
+
value.to_i
|
22
|
+
when :numeric
|
23
|
+
BigDecimal.new(value)
|
24
|
+
when :string
|
25
|
+
value.to_s
|
26
|
+
when :datetime
|
27
|
+
Time.parse(value + " UTC")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
instance_variable_set(:"@#{name}", value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# :nodoc:
|
37
|
+
def inspect
|
38
|
+
attrs = to_s
|
39
|
+
|
40
|
+
unless attrs.empty?
|
41
|
+
attrs = attrs.split("\n").map { |l| " #{l}" }.join("\n")
|
42
|
+
attrs = "\n#{attrs}\n"
|
43
|
+
end
|
44
|
+
|
45
|
+
"#<#{self.class.name}:#{object_id}#{attrs}>"
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [String] a string representation of the non-nil attributes
|
49
|
+
def to_s
|
50
|
+
to_h
|
51
|
+
.map { |k, v|
|
52
|
+
v = v.to_s("F") if v.is_a?(BigDecimal)
|
53
|
+
"#{k}: #{v}"
|
54
|
+
}
|
55
|
+
.join("\n")
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [Hash] a hash of non-nil attributes
|
59
|
+
def to_h
|
60
|
+
@attributes
|
61
|
+
.keys
|
62
|
+
.map { |name|
|
63
|
+
value = __send__(name)
|
64
|
+
value = value.to_a if value.is_a?(Rowset)
|
65
|
+
|
66
|
+
[name, value]
|
67
|
+
}
|
68
|
+
.to_h
|
69
|
+
.reject { |k, v| v.nil? }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative "row"
|
2
|
+
|
3
|
+
module Greeve
|
4
|
+
# Represents an XML `rowset` element.
|
5
|
+
class Rowset
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
# @return [Symbol] name of the rowset
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
# @param name [Symbol] name of the rowset
|
12
|
+
# @param xml_element [Ox::Element] the xml rowset element for this item
|
13
|
+
# @yield a block containing the attribute definitions for {Row}
|
14
|
+
def initialize(name, xml_element, &block)
|
15
|
+
@name = name
|
16
|
+
@xml_element = xml_element
|
17
|
+
@attributes = {}
|
18
|
+
@rows = nil
|
19
|
+
|
20
|
+
# Load the attribute configuration in the rowset block.
|
21
|
+
instance_eval(&block)
|
22
|
+
|
23
|
+
# Disable the #attribute method since the attributes have been configured.
|
24
|
+
define_singleton_method(:attribute) { raise NoMethodError, "private method" }
|
25
|
+
end
|
26
|
+
|
27
|
+
# :nodoc:
|
28
|
+
def each(&block)
|
29
|
+
rows.each(&block)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Array] an array of rows and their non-nil attributes
|
33
|
+
def to_a
|
34
|
+
map(&:to_h)
|
35
|
+
end
|
36
|
+
|
37
|
+
# :nodoc:
|
38
|
+
def inspect
|
39
|
+
"#<#{self.class.name}:#{object_id} name: #{@name}>"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Map an XML attribute to a Ruby object.
|
43
|
+
#
|
44
|
+
# @!visibility private
|
45
|
+
# @see {Greeve::BaseItem.attribute}
|
46
|
+
def attribute(name, opts = {})
|
47
|
+
name = name.to_sym
|
48
|
+
|
49
|
+
raise "Attribute `#{name}` defined more than once" if @attributes[name]
|
50
|
+
raise "`:xpath` not specified for `#{name}`" unless opts[:xpath]
|
51
|
+
|
52
|
+
@attributes[name] = {
|
53
|
+
xpath: opts[:xpath],
|
54
|
+
type: opts[:type],
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# @return [Array<Row>] an array of rows in the rowset
|
61
|
+
def rows
|
62
|
+
return @rows unless @rows.nil?
|
63
|
+
|
64
|
+
rows = @xml_element.locate("row").map do |row_element|
|
65
|
+
Row.new(row_element, @attributes)
|
66
|
+
end
|
67
|
+
|
68
|
+
@rows = rows
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|