adam 1.0.2

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.
@@ -0,0 +1,8 @@
1
+ module Adam
2
+ VERSION = '1.0.2'
3
+
4
+ autoload :Killmail, 'adam/killmail'
5
+ autoload :KillLog, 'adam/kill_log'
6
+ autoload :Kill, 'adam/kill'
7
+ autoload :Killboard, 'adam/killboard'
8
+ end
@@ -0,0 +1,137 @@
1
+ require 'digest'
2
+
3
+ module Adam
4
+
5
+ class Kill
6
+ attr_accessor :eve_id, :time, :solar_system, :victim, :involved_parties, :loot
7
+
8
+ def initialize
9
+ yield self if block_given?
10
+ end
11
+
12
+ def to_killmail
13
+
14
+ killmail = ""
15
+ killmail << time.strftime("%Y.%m.%d %H:%M")
16
+ killmail << "\n"
17
+ killmail << "Victim: #{victim.pilot}\n"
18
+ killmail << "Corp: #{victim.corporation}\n"
19
+ killmail << "Alliance: #{victim.alliance}\n" if victim.alliance
20
+ killmail << "Alliance: Unknown\n" unless victim.alliance
21
+ killmail << "Faction: #{victim.faction}\n" if victim.faction
22
+ killmail << "Faction: NONE\n" unless victim.faction
23
+ killmail << "Destroyed: #{victim.ship}\n"
24
+ killmail << "System: #{solar_system.name}\n"
25
+ killmail << "Security: #{solar_system.security_status.round(2)}\n"
26
+ killmail << "Damage Taken: #{victim.damage_taken}\n"
27
+ killmail << "\n"
28
+ killmail << "Involved parties:\n"
29
+ killmail << "\n"
30
+
31
+ involved_parties.each do |involved_party|
32
+
33
+ case involved_party.type
34
+
35
+ when "PC"
36
+ killmail << "Name: #{involved_party.pilot} (laid the final blow)\n" if involved_party.final_blow
37
+ killmail << "Name: #{involved_party.pilot}\n" unless involved_party.final_blow
38
+ killmail << "Security: #{involved_party.security_status.round(2)}\n"
39
+ killmail << "Corp: #{involved_party.corporation}\n"
40
+ killmail << "Alliance: #{involved_party.alliance}\n" if involved_party.alliance
41
+ killmail << "Alliance: NONE\n" unless involved_party.alliance
42
+ killmail << "Faction: #{involved_party.faction}\n" if involved_party.faction
43
+ killmail << "Faction: NONE\n" unless involved_party.faction
44
+ killmail << "Ship: #{involved_party.ship}\n"
45
+ killmail << "Weapon: #{involved_party.weapon}\n"
46
+ killmail << "Damage Done: #{involved_party.damage_done}\n"
47
+ killmail << "\n"
48
+
49
+ when "NPC"
50
+ killmail << "Name: #{involved_party.ship} / #{involved_party.corporation or involved_party.faction} (laid the final blow)\n" if involved_party.final_blow
51
+ killmail << "Name: #{involved_party.ship} / #{involved_party.corporation or involved_party.faction}\n" unless involved_party.final_blow
52
+ killmail << "Damage Done: #{involved_party.damage_done}\n"
53
+ killmail << "\n"
54
+
55
+ end
56
+
57
+ end
58
+
59
+ killmail << "\n"
60
+ killmail << "\n"
61
+
62
+ destroyed_items = loot.select { |l| l.dropped == false }
63
+ unless destroyed_items.empty?
64
+ killmail << "Destroyed items:\n"
65
+ killmail << "\n"
66
+ destroyed_items.each do |loot|
67
+ killmail << "#{loot.name}"
68
+ killmail << ", Qty: #{loot.quantity}" if loot.quantity > 1
69
+ killmail << " (Cargo)" if loot.cargo
70
+ killmail << " (Drone Bay)" if loot.drone_bay
71
+ killmail << "\n"
72
+ end
73
+ end
74
+
75
+ dropped_items = loot.select { |l| l.dropped == true }
76
+ unless dropped_items.empty?
77
+ killmail << "Dropped items:\n"
78
+ killmail << "\n"
79
+ dropped_items.each do |loot|
80
+ killmail << "#{loot.name}"
81
+ killmail << ", Qty: #{loot.quantity}" if loot.quantity > 1
82
+ killmail << " (Cargo)" if loot.cargo
83
+ killmail << " (Drone Bay)" if loot.drone_bay
84
+ killmail << "\n"
85
+ end
86
+ end
87
+
88
+ killmail
89
+ end
90
+
91
+ alias_method :to_s, :to_killmail
92
+
93
+ def digest
94
+ string = time.to_s + victim.pilot.to_s + victim.ship.to_s + solar_system.to_s + victim.damage_taken.to_s
95
+ involved_parties.sort! { |x, y| x.damage_done <=> y.damage_done }
96
+ involved_parties.each { |p| string += p.pilot.to_s + p.damage_done.to_s }
97
+ Digest::MD5.hexdigest(string)
98
+ end
99
+
100
+ end
101
+
102
+ class Kill::SolarSystem
103
+ attr_accessor :name, :security_status
104
+
105
+ def initialize
106
+ yield self if block_given?
107
+ end
108
+
109
+ end
110
+
111
+ class Kill::Victim
112
+ attr_accessor :pilot, :corporation, :alliance, :faction, :ship, :damage_taken
113
+
114
+ def initialize
115
+ yield self if block_given?
116
+ end
117
+
118
+ end
119
+
120
+ class Kill::InvolvedParty
121
+ attr_accessor :type, :pilot, :security_status, :corporation, :alliance, :faction, :ship, :weapon, :damage_done, :final_blow
122
+
123
+ def initialize
124
+ yield self if block_given?
125
+ end
126
+
127
+ end
128
+
129
+ class Kill::Loot
130
+ attr_accessor :name, :quantity, :cargo, :drone_bay, :dropped
131
+
132
+ def initialize
133
+ yield self if block_given?
134
+ end
135
+ end
136
+
137
+ end
@@ -0,0 +1,109 @@
1
+ require 'adam/kill_log/validation_error'
2
+ require 'models' unless defined?(SolarSystem) and defined?(Item)
3
+
4
+ require 'hpricot'
5
+ require 'time'
6
+
7
+ module Adam
8
+
9
+ module KillLog
10
+
11
+ extend self
12
+
13
+ def parse(source)
14
+ document = Hpricot(source)
15
+
16
+ kill_logs = []
17
+ document.search("//rowset[@name=kills]/row").each do |kill_log|
18
+ begin
19
+ kill_logs << parse_single(kill_log)
20
+ rescue ValidationError
21
+ next
22
+ end
23
+ end
24
+
25
+ kill_logs
26
+ end
27
+
28
+ private
29
+
30
+ def parse_single(kill_element)
31
+
32
+ kill = Adam::Kill.new do |kill|
33
+
34
+ kill.eve_id = kill_element['killid'].to_i
35
+ kill.time = Time.parse(kill_element['killtime']).utc
36
+
37
+ kill.solar_system = Adam::Kill::SolarSystem.new do |ss|
38
+ ss.name = SolarSystem.find(kill_element['solarsystemid']).name
39
+ ss.security_status = SolarSystem.find(kill_element['solarsystemid']).security_status
40
+ end
41
+
42
+ kill.victim = Adam::Kill::Victim.new do |v|
43
+ victim_element = kill_element.at('/victim')
44
+
45
+ raise ValidationError, "Victim pilot no longer exists" if victim_element['characterid'] != '0' and victim_element['charactername'].empty?
46
+ raise ValidationError, "Victim corporation no longer exists" if victim_element['corporationid'] != '0' and victim_element['corporationname'].empty?
47
+ raise ValidationError, "Victim alliance no longer exists" if victim_element['allianceid'] != '0' and victim_element['alliancename'].empty?
48
+
49
+ v.pilot = victim_element['charactername']
50
+ v.corporation = victim_element['corporationname']
51
+ v.alliance = victim_element['alliancename'] == '' ? false : victim_element['alliancename']
52
+ v.faction = victim_element['factionname'] == '' ? false: victim_element['factionname']
53
+ v.ship = Item.find(victim_element['shiptypeid']).name
54
+ v.damage_taken = victim_element['damagetaken'].to_i
55
+ end
56
+
57
+ kill.involved_parties = []
58
+ kill_element.search('/rowset[@name=attackers]/row').each do |involved_party_element|
59
+
60
+ kill.involved_parties << Adam::Kill::InvolvedParty.new do |ip|
61
+ raise ValidationError, "Involved party pilot no longer exists" if involved_party_element['characterid'] != '0' and involved_party_element['charactername'].empty?
62
+ raise ValidationError, "Involved party corporation no longer exists" if involved_party_element['corporationid'] != '0' and involved_party_element['corporationname'].empty?
63
+ raise ValidationError, "Involved party alliance no longer exists" if involved_party_element['allianceid'] != '0' and involved_party_element['alliancename'].empty?
64
+
65
+ ip.type = involved_party_element['charactername'].empty? ? 'NPC' : 'PC'
66
+ ip.pilot = involved_party_element['charactername'] unless involved_party_element['charactername'].empty?
67
+ ip.corporation = involved_party_element['corporationname']
68
+ ip.alliance = involved_party_element['alliancename'] == '' ? false : involved_party_element['alliancename']
69
+ ip.faction = involved_party_element['factionname'] == '' ? false : involved_party_element['factionname']
70
+ ip.security_status = involved_party_element['securitystatus'].to_f
71
+ ip.ship = Item.find(involved_party_element['shiptypeid']).name
72
+ ip.weapon = Item.find(involved_party_element['weapontypeid']).name
73
+ ip.damage_done = involved_party_element['damagedone'].to_i
74
+ ip.final_blow = involved_party_element['finalblow'] == '1' ? true : false
75
+ end
76
+
77
+ end
78
+
79
+ kill.loot = []
80
+ kill_element.search('/rowset[@name=items]/row').each do |loot_element|
81
+ if loot_element['qtydropped'].to_i > 0
82
+ kill.loot << Adam::Kill::Loot.new do |l|
83
+ l.name = Item.find(loot_element['typeid']).name
84
+ l.quantity = loot_element['qtydropped'].to_i
85
+ l.cargo = loot_element['flag'] == '5' ? true : false
86
+ l.drone_bay = loot_element['flag'] == '87' ? true : false
87
+ l.dropped = true
88
+ end
89
+ end
90
+
91
+ if loot_element['qtydestroyed'].to_i > 0
92
+ kill.loot << Adam::Kill::Loot.new do |l|
93
+ l.name = Item.find(loot_element['typeid']).name
94
+ l.quantity = loot_element['qtydropped'].to_i
95
+ l.cargo = loot_element['flag'] == '5' ? true : false
96
+ l.drone_bay = loot_element['flag'] == '87' ? true : false
97
+ l.dropped = false
98
+ end
99
+ end
100
+ end
101
+
102
+ end
103
+
104
+ return kill
105
+ end
106
+
107
+ end
108
+
109
+ end
@@ -0,0 +1,5 @@
1
+ module Adam
2
+ module KillLog
3
+ class ValidationError < RuntimeError; end
4
+ end
5
+ end
@@ -0,0 +1,52 @@
1
+ require 'adam/killboard/feed_error'
2
+
3
+ require 'date'
4
+ require 'net/http'
5
+ require 'uri'
6
+ require 'cgi'
7
+ require 'hpricot'
8
+
9
+ module Adam
10
+
11
+ class Killboard
12
+ attr_reader :uri, :feed_uri
13
+
14
+ def initialize(options = {})
15
+ @uri, @feed_uri = options[:uri], options[:feed_uri]
16
+ end
17
+
18
+ # Loads an array of killmails from an EDK-compatible feed.
19
+ #
20
+ # +options+ is a hash with these keys:
21
+ # * +week+ - An integer determining which week to import. Defaults to current week.
22
+ # * +year+ - An integer determining which year to import the week from. Defaults to current year.
23
+ def killmails(options = {})
24
+ options = { :week => Date.today.cweek, :year => Date.today.year }.merge!(options)
25
+
26
+ uri = URI.parse(@feed_uri)
27
+
28
+ query_string = { 'week' => options[:week], 'year' => options[:year], 'nocache' => Time.now.to_i }.map{ |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&")
29
+
30
+ response = nil
31
+ connection = Net::HTTP.new(uri.host, uri.port)
32
+ connection.start do |http|
33
+ tries = 0
34
+ begin
35
+ response = http.get(uri.path + '?' + uri.query + '&' + query_string)
36
+ rescue Timeout::Error
37
+ tries += 1
38
+ sleep 10
39
+ retry if tries < 3
40
+ end
41
+ end
42
+
43
+ xml = Hpricot.XML(response.body)
44
+
45
+ raise FeedError.new(response.body), "Feed malformed" unless xml.at('/rss')
46
+
47
+ killmails = xml.search("//item/description").collect { |element| element.inner_text }
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,15 @@
1
+ module Adam
2
+
3
+ class Killboard
4
+
5
+ class FeedError < RuntimeError
6
+ attr_reader :source
7
+
8
+ def initialize(source)
9
+ @source = source
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,130 @@
1
+ require "adam/killmail/validation_error"
2
+
3
+ require "time"
4
+
5
+ module Adam
6
+
7
+ module Killmail
8
+
9
+ extend self
10
+
11
+ def parse(source)
12
+
13
+ # Normalize line endings
14
+ source.encode! :universal_newline => true
15
+
16
+ kill = Adam::Kill.new do |kill|
17
+
18
+ time = source[/([0-9]{4}\.[0-9]{2}\.[0-9]{2} [0-9]{2}:[0-9]{2})/, 1] or raise ValidationError.new(source), "Time malformed"
19
+ time = Time.parse(time + " UTC")
20
+
21
+ kill.time = time
22
+
23
+ kill.solar_system = Adam::Kill::SolarSystem.new do |ss|
24
+ ss.name = source[/System: (.+)/, 1] or raise ValidationError.new(source), "Solar system malformed"
25
+ ss.security_status = source[/Security: ([\.0-9]+)/, 1].to_f or raise ValidationError.new(source), "Solar system security malformed"
26
+ end
27
+
28
+ kill.victim = Adam::Kill::Victim.new do |v|
29
+ v.pilot = source[/Victim: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Victim pilot malformed"
30
+ v.corporation = source[/Corp: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Victim corporation malformed"
31
+ v.alliance = source[/Alliance: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Victim alliance malformed"
32
+ v.faction = source[/Faction: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Victim faction malformed"
33
+ v.ship = source[/Destroyed: (.+)/, 1] or raise ValidationError.new(source), "Victim ship malformed"
34
+ v.damage_taken = source[/Damage Taken: ([0-9]+)/, 1].to_i or raise ValidationError.new(source), "Victim damage taken malformed"
35
+
36
+ # Set pilot to nil if it's a moon
37
+ v.pilot = nil if v.pilot =~ /[a-zA-Z0-9\- ]+ - Moon [0-9]+/
38
+
39
+ # Convert alliance/faction from "unknown" or "none" to false
40
+ v.alliance = false if v.alliance =~ /unknown|none/i
41
+ v.faction = false if v.faction =~ /unknown|none/i
42
+ end
43
+
44
+ kill.involved_parties = []
45
+
46
+ involved_parties = source[/Involved parties:\n\n(((.+\n){8}\n|(.+\n){2}\n)*)/, 1] or raise ValidationError.new(source), "Involved parties malformed"
47
+ involved_parties.split("\n\n").each_with_index do |snippet, i|
48
+
49
+ lines = 0 and snippet.each_line { |line| lines += 1 }
50
+
51
+ case lines
52
+
53
+ when 8
54
+ kill.involved_parties << Adam::Kill::InvolvedParty.new do |ip|
55
+ ip.type = "PC"
56
+ ip.pilot = snippet[/Name: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Involved party #{i+1} pilot malformed"
57
+ ip.security_status = snippet[/Security: ([\-\.0-9]+)/, 1].to_f or raise ValidationError.new(source), "Involved party #{i+1} security malformed"
58
+ ip.corporation = snippet[/Corp: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Involved party #{i+1} corporation malformed"
59
+ ip.alliance = snippet[/Alliance: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Involved party #{i+1} alliance malformed"
60
+ ip.faction = snippet[/Faction: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Involved party #{i+1} faction malformed"
61
+ ip.ship = snippet[/Ship: (.+)/, 1] or raise ValidationError.new(source), "Involved party #{i+1} ship malformed"
62
+ ip.weapon = snippet[/Weapon: (.+)/, 1] or raise ValidationError.new(source), "Involved party #{i+1} weapon malformed"
63
+ ip.damage_done = (snippet[/Damage Done: ([0-9]+)/, 1] or raise ValidationError.new(source), "Involved party #{i+1} damage malformed").to_i
64
+ ip.final_blow = snippet =~ /\(laid the final blow\)/ ? true : false
65
+
66
+ # Convert alliance/faction from "unknown" or "none" to false
67
+ ip.alliance = false if ip.alliance =~ /unknown|none/i
68
+ ip.faction = false if ip.faction =~ /unknown|none/i
69
+ end
70
+
71
+ when 2
72
+ kill.involved_parties << Adam::Kill::InvolvedParty.new do |ip|
73
+ ip.type = "NPC"
74
+ ip.ship = snippet[/Name: ([^\/]+)/, 1] or raise ValidationError.new(source), "Involved party #{i+1} ship malformed"
75
+ ip.damage_done = (snippet[/Damage Done: ([0-9]+)/, 1] or raise ValidationError.new(source), "Involved party #{i+1} damage malformed").to_i
76
+ ip.final_blow = snippet =~ /\(laid the final blow\)/ ? true : false
77
+
78
+ # Determine whether allegiance is a faction or a corporation
79
+ allegiance = snippet[/Name: [^\/]+ \/ ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Involved party #{i+1} allegiance malformed"
80
+ if allegiance =~ /^(Caldari State|Minmatar Republic|Amarr Empire|Gallente Federation|Jove Empire|CONCORD Assembly|Ammatar Mandate|Khanid Kingdom|The Syndicate|Guristas Pirates|Angel Cartel|The Blood Raider Covenant|The InterBus|ORE|Thukker Tribe|The Servant Sisters of EVE|The Society|Mordu's Legion Command|Sansha's Nation|Serpentis)$/
81
+ ip.faction = allegiance
82
+ elsif allegiance == 'Unknown'
83
+ ip.corporation = false
84
+ else
85
+ ip.corporation = allegiance
86
+ end
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+
93
+ kill.loot = []
94
+
95
+ if source =~ /Destroyed items:/
96
+ source[/Destroyed items:\n\n(((.+)\n)*)/, 1].split("\n").each_with_index do |snippet, i|
97
+ loot = Adam::Kill::Loot.new do |l|
98
+ l.name = snippet[/([^,\(\)]+)/, 1] or raise ValidationError.new(source), "Destroyed item #{i+1} name malformed"
99
+ l.quantity = snippet =~ /Qty: ([0-9]+)/ ? snippet[/Qty: ([0-9]+)/, 1].to_i : 1
100
+ l.cargo = snippet[/(Cargo)/] ? true : false
101
+ l.drone_bay = snippet[/(Drone Bay)/] ? true : false
102
+ l.dropped = false
103
+ end
104
+ existing_loot = kill.loot.select { |el| el.name.eql?(loot.name) and el.cargo.eql?(loot.cargo) and el.drone_bay.eql?(loot.drone_bay) and el.dropped.eql?(loot.dropped) }[0]
105
+ existing_loot ? existing_loot.quantity += loot.quantity : kill.loot << loot
106
+ end
107
+ end
108
+
109
+ if source =~ /Dropped items:/
110
+ source[/Dropped items:\n\n(((.+)\n)*)/, 1].split("\n").each_with_index do |snippet, i|
111
+ loot = Adam::Kill::Loot.new do |l|
112
+ l.name = snippet[/([^,\(\)]+)/, 1] or raise ValidationError.new(source), "Dropped item #{i+1} name malformed"
113
+ l.quantity = snippet =~ /Qty: ([0-9]+)/ ? snippet[/Qty: ([0-9]+)/, 1].to_i : 1
114
+ l.cargo = snippet[/(Cargo)/] ? true : false
115
+ l.drone_bay = snippet[/(Drone Bay)/] ? true : false
116
+ l.dropped = true
117
+ end
118
+ existing_loot = kill.loot.select { |el| el.name.eql?(loot.name) and el.cargo.eql?(loot.cargo) and el.drone_bay.eql?(loot.drone_bay) and el.dropped.eql?(loot.dropped) }[0]
119
+ existing_loot ? existing_loot.quantity += loot.quantity : kill.loot << loot
120
+ end
121
+ end
122
+
123
+ end
124
+
125
+ return kill
126
+ end
127
+
128
+ end
129
+
130
+ end