csstats 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +33 -0
  3. data/.travis.yml +23 -7
  4. data/Gemfile +3 -7
  5. data/LICENSE +1 -1
  6. data/README.md +12 -9
  7. data/bin/console +1 -1
  8. data/csstats.gemspec +3 -4
  9. data/lib/csstats.rb +5 -3
  10. data/lib/csstats/client.rb +23 -0
  11. data/lib/csstats/columns.rb +28 -0
  12. data/lib/csstats/parser.rb +13 -4
  13. data/lib/csstats/parser/reader.rb +11 -0
  14. data/lib/csstats/parser/reader/file_reader.rb +45 -0
  15. data/lib/csstats/parser/{file_reader/handler.rb → reader/file_streamer.rb} +8 -8
  16. data/lib/csstats/parser/reader/player.rb +41 -0
  17. data/lib/csstats/parser/reader/players.rb +41 -0
  18. data/lib/csstats/{writer.rb → parser/writer.rb} +4 -2
  19. data/lib/csstats/{writer/file_writer/handler.rb → parser/writer/file_streamer.rb} +9 -10
  20. data/lib/csstats/parser/writer/player.rb +34 -0
  21. data/lib/csstats/parser/writer/players.rb +29 -0
  22. data/lib/csstats/player.rb +34 -0
  23. data/lib/csstats/players.rb +52 -0
  24. data/lib/csstats/version.rb +1 -1
  25. data/spec/csstats/client_spec.rb +13 -0
  26. data/spec/csstats/parser/reader/player_spec.rb +17 -0
  27. data/spec/csstats/parser/writer/players_spec.rb +30 -0
  28. data/spec/csstats/player_spec.rb +109 -0
  29. data/spec/csstats/players_spec.rb +30 -0
  30. data/spec/csstats_spec.rb +2 -2
  31. data/spec/spec_helper.rb +3 -7
  32. metadata +29 -21
  33. data/lib/csstats/handler.rb +0 -50
  34. data/lib/csstats/parser/file_reader.rb +0 -39
  35. data/lib/csstats/parser/player.rb +0 -82
  36. data/lib/csstats/parser/players.rb +0 -42
  37. data/lib/csstats/writer/player.rb +0 -39
  38. data/lib/csstats/writer/players.rb +0 -24
  39. data/spec/csstats/handler_spec.rb +0 -113
  40. data/spec/csstats/parser/player_spec.rb +0 -17
  41. data/spec/csstats/writer/players_spec.rb +0 -26
@@ -0,0 +1,41 @@
1
+ module CSstats
2
+ module Parser
3
+ module Reader
4
+ class Players
5
+ attr_reader :file_path, :max_players
6
+
7
+ def initialize(file_path, options = {})
8
+ @file_path = file_path
9
+ @max_players = options[:max_players] || 0
10
+ end
11
+
12
+ def parse
13
+ players = []
14
+
15
+ file_reader.read do |streamer, index|
16
+ parse_player(streamer, index, players)
17
+ end
18
+
19
+ players
20
+ end
21
+
22
+ private
23
+
24
+ def parse_player(streamer, index, players)
25
+ player_parser = CSstats::Parser::Reader::Player.new(streamer)
26
+ player = player_parser.parse
27
+ return unless player
28
+
29
+ player.rank = index + 1
30
+ players[index] = player
31
+ end
32
+
33
+ def file_reader
34
+ @file_reader ||= CSstats::Parser::Reader::FileReader.new(
35
+ file_path, limit: max_players
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,8 +1,10 @@
1
- require_relative 'writer/file_writer/handler'
1
+ require_relative 'writer/file_streamer'
2
2
  require_relative 'writer/player'
3
3
  require_relative 'writer/players'
4
4
 
5
5
  module CSstats
6
- module Writer
6
+ module Parser
7
+ module Writer
8
+ end
7
9
  end
8
10
  end
@@ -1,26 +1,25 @@
1
1
  module CSstats
2
- module Writer
3
- class FileWriter
4
- class Handler
5
- attr_reader :handle
2
+ module Parser
3
+ module Writer
4
+ class FileStreamer
5
+ attr_reader :stream
6
6
 
7
- def initialize(handle)
8
- @handle = handle
7
+ def initialize(stream)
8
+ @stream = stream
9
9
  end
10
10
 
11
11
  def write_int_data(int)
12
12
  data = [int].pack('V')
13
- handle.write(data)
13
+ stream.write(data)
14
14
  end
15
15
 
16
16
  def write_short_data(int)
17
17
  data = [int].pack('v')
18
- handle.write(data)
18
+ stream.write(data)
19
19
  end
20
20
 
21
21
  def write_string_data(string)
22
- data = "#{string}\x00"
23
- handle.write(data)
22
+ stream.write(string)
24
23
  end
25
24
  end
26
25
  end
@@ -0,0 +1,34 @@
1
+ module CSstats
2
+ module Parser
3
+ module Writer
4
+ class Player
5
+ attr_reader :streamer, :player
6
+
7
+ def initialize(streamer, player)
8
+ @streamer = streamer
9
+ @player = player
10
+ end
11
+
12
+ def write
13
+ CSstats::COLUMNS.each do |column|
14
+ next streamer.write_int_data(0) if column.empty?
15
+
16
+ value = player.send(column[:name])
17
+ send("write_#{column[:type]}", value)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def write_string(value)
24
+ streamer.write_short_data(value.length + 1)
25
+ streamer.write_string_data("#{value}\x00")
26
+ end
27
+
28
+ def write_integer(value)
29
+ streamer.write_int_data(value)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ module CSstats
2
+ module Parser
3
+ module Writer
4
+ class Players
5
+ attr_reader :file_path
6
+
7
+ def initialize(file_path)
8
+ @file_path = file_path
9
+ end
10
+
11
+ def write(players)
12
+ file = File.new(file_path, 'w')
13
+
14
+ streamer(file).write_short_data(11) # File version
15
+
16
+ players.each do |player|
17
+ CSstats::Parser::Writer::Player.new(streamer(file), player).write
18
+ end
19
+
20
+ file.close
21
+ end
22
+
23
+ def streamer(file)
24
+ CSstats::Parser::Writer::FileStreamer.new(file)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ module CSstats
2
+ class Player
3
+ attr_accessor :rank
4
+
5
+ def initialize(attributes = {})
6
+ CSstats::COLUMN_KEYS.each do |column|
7
+ self.class.send(:attr_accessor, column)
8
+ end
9
+
10
+ attributes.each do |key, value|
11
+ instance_variable_set("@#{key}", value)
12
+ end
13
+ end
14
+
15
+ def efficiency
16
+ kills_and_deaths = kills.to_f + deaths.to_f
17
+ return 0.0 if kills_and_deaths.zero?
18
+
19
+ (kills.to_f / kills_and_deaths * 100).round(2)
20
+ end
21
+
22
+ def accuracy
23
+ return 0.0 if shots.to_f.zero?
24
+
25
+ (hits.to_f / shots.to_f * 100).round(2)
26
+ end
27
+
28
+ def as_json
29
+ CSstats::COLUMN_KEYS.each_with_object({}) do |column, object|
30
+ object[column] = send(column)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,52 @@
1
+ module CSstats
2
+ class Players
3
+ attr_reader :client
4
+
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ def all
10
+ players
11
+ end
12
+
13
+ def find(id)
14
+ players[id - 1]
15
+ end
16
+
17
+ def find_by(attributes = {})
18
+ players.find do |player|
19
+ attributes.all? do |column, value|
20
+ player.send(column) == value
21
+ end
22
+ end
23
+ end
24
+
25
+ def where(attributes = {})
26
+ players.select do |player|
27
+ attributes.all? do |column, value|
28
+ player.send(column) == value
29
+ end
30
+ end
31
+ end
32
+
33
+ # def save
34
+ # CSstats::Parser.write_players(client, players)
35
+ # end
36
+
37
+ def method_missing(method_name, *args, &block)
38
+ return super unless respond_to?(method_name)
39
+ players.send(method_name, *args, &block)
40
+ end
41
+
42
+ def respond_to_missing?(method_name, include_private = false)
43
+ players.respond_to?(method_name, include_private)
44
+ end
45
+
46
+ private
47
+
48
+ def players
49
+ @players ||= CSstats::Parser.get_players(client)
50
+ end
51
+ end
52
+ end
@@ -1,3 +1,3 @@
1
1
  module CSstats
2
- VERSION = '1.1.0'.freeze
2
+ VERSION = '1.2.0'.freeze
3
3
  end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe CSstats::Client do
4
+ let(:client) { CSstats::Client.new(path: csstats_file, max_players: 5) }
5
+
6
+ it 'has correct file path' do
7
+ expect(client.file_path).to eq(csstats_file)
8
+ end
9
+
10
+ it 'has correct max players value' do
11
+ expect(client.max_players).to eq(5)
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe CSstats::Parser::Reader::Player do
4
+ let(:file_stream) { File.new(csstats_file) }
5
+ let(:streamer) { CSstats::Parser::Reader::FileStreamer.new(file_stream) }
6
+ subject { described_class.new(streamer) }
7
+ let(:player_data) { subject.parse }
8
+
9
+ before do
10
+ # We need to read first bytes, because it's file version.
11
+ streamer.read_short_data
12
+ end
13
+
14
+ it 'has correct head' do
15
+ expect(player_data.head).to eq(402)
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe CSstats::Parser::Writer::Players do
4
+ let(:old_players) { CSstats.new(path: csstats_file).players }
5
+ let(:file_path) { tmp_file('test.dat') }
6
+ let(:new_players) { CSstats.new(path: file_path).players }
7
+
8
+ it 'has correct players count in main file' do
9
+ expect(old_players.length).to eq(208)
10
+ end
11
+
12
+ context 'new file' do
13
+ before do
14
+ described_class.new(file_path).write(old_players)
15
+ end
16
+
17
+ after do
18
+ FileUtils.rm(file_path)
19
+ end
20
+
21
+ it 'has correct players count' do
22
+ described_class.new(file_path).write(old_players)
23
+ expect(new_players.length).to eq(208)
24
+ end
25
+
26
+ it 'has same players data' do
27
+ expect(old_players.map(&:as_json)).to eq(new_players.map(&:as_json))
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+
3
+ describe CSstats::Player do
4
+ let(:client) { CSstats::Client.new(path: csstats_file, max_players: 10) }
5
+ let(:players) { client.players }
6
+
7
+ it 'sets attributes from options' do
8
+ player = CSstats::Player.new(nick: 'Test')
9
+ expect(player.nick).to eq('Test')
10
+ end
11
+
12
+ it 'has ability to rewrite attribute' do
13
+ player = CSstats::Player.new
14
+ player.nick = 'Test'
15
+ expect(player.nick).to eq('Test')
16
+ end
17
+
18
+ context 'data' do
19
+ let(:player) { players.find_by(nick: 'CHMARSON') }
20
+
21
+ it 'has correct nick' do
22
+ expect(player.nick).to eq 'CHMARSON'
23
+ end
24
+
25
+ it 'has correct rank' do
26
+ expect(player.rank).to eq 2
27
+ end
28
+
29
+ it 'has correct teamkill' do
30
+ expect(player.teamkill).to eq 7
31
+ end
32
+
33
+ it 'has correct damage' do
34
+ expect(player.damage).to eq 101_543
35
+ end
36
+
37
+ it 'has correct deaths' do
38
+ expect(player.deaths).to eq 511
39
+ end
40
+
41
+ it 'has correct kills' do
42
+ expect(player.kills).to eq 759
43
+ end
44
+
45
+ it 'has correct shots' do
46
+ expect(player.shots).to eq 9421
47
+ end
48
+
49
+ it 'has correct hits' do
50
+ expect(player.hits).to eq 2885
51
+ end
52
+
53
+ it 'has correct headshots' do
54
+ expect(player.headshots).to eq 225
55
+ end
56
+
57
+ it 'has correct defusions' do
58
+ expect(player.defusions).to eq 15
59
+ end
60
+
61
+ it 'has correct defused' do
62
+ expect(player.defused).to eq 9
63
+ end
64
+
65
+ it 'has correct plants' do
66
+ expect(player.plants).to eq 33
67
+ end
68
+
69
+ it 'has correct explosions' do
70
+ expect(player.explosions).to eq 7
71
+ end
72
+
73
+ it 'has correct head' do
74
+ expect(player.head).to eq 275
75
+ end
76
+
77
+ it 'has correct chest' do
78
+ expect(player.chest).to eq 407
79
+ end
80
+
81
+ it 'has correct stomach' do
82
+ expect(player.stomach).to eq 376
83
+ end
84
+
85
+ it 'has correct leftarm' do
86
+ expect(player.leftarm).to eq 1126
87
+ end
88
+
89
+ it 'has correct rightarm' do
90
+ expect(player.rightarm).to eq 283
91
+ end
92
+
93
+ it 'has correct leftleg' do
94
+ expect(player.leftleg).to eq 202
95
+ end
96
+
97
+ it 'has correct rightleg' do
98
+ expect(player.rightleg).to eq 214
99
+ end
100
+
101
+ it 'has correct accuracy' do
102
+ expect(player.accuracy).to eq 30.62
103
+ end
104
+
105
+ it 'has correct efficiency' do
106
+ expect(player.efficiency).to eq 59.76
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe CSstats::Players do
4
+ let(:client) { CSstats::Client.new(path: csstats_file, max_players: 30) }
5
+ let(:players) { client.players }
6
+
7
+ it 'has correct players count' do
8
+ expect(players.count).to eq(30)
9
+ end
10
+
11
+ it 'returns players with all' do
12
+ expect(players.all.length).to eq(30)
13
+ end
14
+
15
+ it 'has array of Player class' do
16
+ expect(players.first).to be_a(CSstats::Player)
17
+ end
18
+
19
+ it 'has correct player data' do
20
+ expect(players.find(2).nick).to eq('CHMARSON')
21
+ end
22
+
23
+ it 'has correct count with where' do
24
+ expect(players.where(head: 102).count).to eq(2)
25
+ end
26
+
27
+ it 'has correct count with find_by' do
28
+ expect(players.find_by(head: 102).nick).to eq('LBM')
29
+ end
30
+ end