csstats 1.0.7 → 1.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c7c268ffc0f969fd2c385d3d3f5ffb54ea1acb17
4
- data.tar.gz: fcbe5fc8300570713f890c6c3f20084b5ca4b57f
3
+ metadata.gz: b6e7d60a406dbc4c07be6f28a230f6cd8609c509
4
+ data.tar.gz: f0a2a88fc14bd167cc7cc06400cbddaa316a9e56
5
5
  SHA512:
6
- metadata.gz: f96bea67867c16803c117a0604104a6783e7d48be899842bbf6d86b95995b541547cd9c2c24103c263f752bf5159fe6a6c10f63d2f01051315948fbd0193038e
7
- data.tar.gz: 2b0a039d59c8b378d90dfb97eccfa0d37195abe9fc2ffce97deec0375ecdb5f9ebb2ac7b2001ad97b3c8d6f480eca10379788fd6be0fa2ba2b30bde8c51b99c7
6
+ metadata.gz: 49e281f6effe3c0534b25f0e3f43430b399c726512a9eeb7105fa6f73425c99c220a68ae37260bb377e918833a853269e58507475f11ac860c90137226c910dd
7
+ data.tar.gz: 9453510b9dcb1b140243e4a0778b073e6339632a26fb12e7afad8d314190ccbb230b3720847e353a1ef236c6272b01428623194a9d0e763d7686bf0135396aed
data/.gitignore CHANGED
@@ -12,6 +12,8 @@ lib/bundler/man
12
12
  pkg
13
13
  rdoc
14
14
  spec/reports
15
+ spec/tmp
16
+ spec/fixtures/tmp
15
17
  test/tmp
16
18
  test/version_tmp
17
19
  tmp
data/.hound.yml ADDED
@@ -0,0 +1,4 @@
1
+ fail_on_violations: true
2
+
3
+ ruby:
4
+ config_file: .rubocop.yml
data/.travis.yml CHANGED
@@ -1,25 +1,20 @@
1
1
  sudo: false
2
+ language: ruby
2
3
 
3
4
  before_install:
4
5
  - gem install bundler
5
6
 
6
7
  bundler_args: --without development
7
8
 
8
- language: ruby
9
-
10
9
  rvm:
11
- - 1.9.3
12
10
  - 2.0.0
13
11
  - 2.1.0
14
12
  - 2.2.0
15
13
  - 2.3.0
16
14
  - ruby-head
17
- - jruby-19mode
18
15
  - jruby-head
19
- - rbx
20
16
 
21
17
  matrix:
22
18
  allow_failures:
23
19
  - rvm: ruby-head
24
20
  - rvm: jruby-head
25
- - rvm: rbx
data/Gemfile CHANGED
@@ -2,11 +2,19 @@ source 'https://rubygems.org'
2
2
 
3
3
  gem 'rake'
4
4
 
5
+ group :development do
6
+ gem 'rubocop', '~> 0.44.1'
7
+ end
8
+
9
+ group :development, :test do
10
+ gem 'pry'
11
+ end
12
+
5
13
  group :test do
6
- gem 'codeclimate-test-reporter', require: false
7
- gem 'coveralls', '~> 0.8.13', require: false
8
- gem 'rspec', '~> 3.4.0'
9
- gem 'simplecov', '~> 0.11.2', require: false
14
+ gem 'codeclimate-test-reporter', '~> 0.6.0', require: false
15
+ gem 'coveralls', '~> 0.8.15', require: false
16
+ gem 'rspec', '~> 3.5.0'
17
+ gem 'simplecov', '~> 0.12.0', require: false
10
18
  end
11
19
 
12
20
  gemspec
data/README.md CHANGED
@@ -54,7 +54,6 @@ puts player_stats.kills
54
54
  This library aims to support and is [tested against][travis] the following Ruby
55
55
  implementations:
56
56
 
57
- * Ruby 1.9.3
58
57
  * Ruby 2.0.0
59
58
  * Ruby 2.1.0
60
59
  * Ruby 2.2.0
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'csstats'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require "pry"
11
+ Pry.start
12
+
13
+ # require 'irb'
14
+ # IRB.start
data/lib/csstats.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'csstats/error'
2
+ require 'csstats/parser'
3
+ require 'csstats/writer'
2
4
  require 'csstats/handler'
3
5
 
4
6
  module CSstats
@@ -1,8 +1,6 @@
1
- require 'hashie/mash'
2
-
3
1
  module CSstats
4
2
  class Handler
5
- attr_reader :path, :players, :maxplayers
3
+ attr_reader :file_path, :max_players
6
4
 
7
5
  # Public: Initialize file.
8
6
  #
@@ -12,16 +10,10 @@ module CSstats
12
10
  #
13
11
  # Returns nothing.
14
12
  def initialize(options = {})
15
- @path = options[:path]
16
- @maxplayers = options[:maxplayers] || 0
17
-
18
- @players = []
19
- raise CSstats::FileNotExist unless File.exist?(path.to_s)
20
-
21
- @file = File.new(path, 'r')
22
- _file_version = read_short_data(@file)
13
+ @file_path = options[:path]
14
+ @max_players = options[:maxplayers] || 0
23
15
 
24
- read_players!
16
+ raise CSstats::FileNotExist unless File.exist?(file_path.to_s)
25
17
  end
26
18
 
27
19
  # Public: Get the player information of specified id.
@@ -49,118 +41,10 @@ module CSstats
49
41
  players.find { |player| player.nick == name }
50
42
  end
51
43
 
52
- private
53
-
54
- def read_players!
55
- i = 0
56
- while !@file.eof? && (maxplayers == 0 || i < maxplayers)
57
- player = read_player(@file)
58
-
59
- if player
60
- player['rank'] = i + 1
61
- players[i] = player
62
- end
63
-
64
- i += 1
65
- end
66
- end
67
-
68
- # Internal: Count player efficiency.
69
- #
70
- # kills - The Integer of player kills in game.
71
- # deaths - The Integer of player deaths in game.
72
- #
73
- # Returns The Float of player efficiency.
74
- def count_efficiency(kills, deaths)
75
- (kills.to_f / (kills.to_f + deaths.to_f) * 100).round(2)
76
- end
77
-
78
- # Internal: Count player accuracy.
79
- #
80
- # hits - The Integer of player hits in game.
81
- # shots - The Integer of player shots in game.
82
- #
83
- # Returns The Float of player accuracy.
84
- def count_accuracy(hits, shots)
85
- (hits.to_f / shots.to_f * 100).round(2)
86
- end
87
-
88
- # Internal: Read player information from file.
89
- #
90
- # handle - The File which was opened for reading data.
91
- #
92
- # Returns The Mash of player information.
93
- def read_player(handle)
94
- length = read_short_data(handle)
95
- return if length == 0
96
-
97
- player_data = Hashie::Mash.new
98
-
99
- player_data.nick = read_string_data(handle, length)
100
-
101
- add_player_uniq(player_data, handle)
102
- add_player_general_data(player_data, handle)
103
- add_player_calculations(player_data)
104
-
105
- player_data
106
- end
107
-
108
- def add_player_uniq(player_data, handle)
109
- length = read_short_data(handle)
110
- player_data.uniq = read_string_data(handle, length)
111
- end
112
-
113
- def add_player_general_data(player_data, handle)
114
- data_types = %w(teamkill damage deaths kills shots hits headshots
115
- defusions defused plants explosions - head chest stomach
116
- leftarm rightarm leftleg rightleg -)
117
-
118
- data_types.each { |type| player_data[type] = read_int_data(handle) }
119
-
120
- # Remove all 0x00000000
121
- player_data.tap { |x| x.delete('-') }
122
- end
123
-
124
- def add_player_calculations(player_data)
125
- player_data.acc = count_accuracy(player_data.hits, player_data.shots)
126
- player_data.eff = count_efficiency(player_data.kills, player_data.deaths)
127
- end
128
-
129
- # Internal: Get the 32bit integer from file.
130
- #
131
- # handle - The File which was opened for reading data.
132
- #
133
- # Returns the Integer.
134
- def read_int_data(handle)
135
- data = handle.read(4)
136
- raise CSstats::Error, 'Cannot read int data.' unless data
137
-
138
- data.unpack('V').first
139
- end
140
-
141
- # Internal: Get the 16bit integer from file.
142
- #
143
- # handle - The File which was opened for reading data.
144
- #
145
- # Returns the Integer.
146
- def read_short_data(handle)
147
- data = handle.read(2)
148
- raise CSstats::Error, 'Cannot read short data.' unless data
149
-
150
- data.unpack('v').first
151
- end
152
-
153
- # Internal: Get the String from file.
154
- #
155
- # handle - The File which was opened for reading data.
156
- # len - The Integer length of string to read.
157
- #
158
- # Returns the String.
159
- def read_string_data(handle, length)
160
- data = handle.read(length)
161
- raise CSstats::Error, 'Cannot read string data.' unless data
162
-
163
- data.strip
44
+ def players
45
+ @players ||= CSstats::Parser::Players.new(
46
+ file_path, max_players: max_players
47
+ ).parse
164
48
  end
165
49
  end
166
50
  end
@@ -0,0 +1,9 @@
1
+ require_relative 'parser/file_reader/handler'
2
+ require_relative 'parser/file_reader'
3
+ require_relative 'parser/player'
4
+ require_relative 'parser/players'
5
+
6
+ module CSstats
7
+ module Parser
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ require_relative 'file_reader/handler'
2
+
3
+ module CSstats
4
+ module Parser
5
+ class FileReader
6
+ attr_reader :file_path, :limit
7
+
8
+ def initialize(file_path, options = {})
9
+ @file_path = file_path
10
+ @limit = options[:limit] || 0
11
+
12
+ raise CSstats::FileNotExist unless File.exist?(file_path.to_s)
13
+ end
14
+
15
+ def read(&block)
16
+ return unless block_given?
17
+
18
+ file = File.new(file_path, 'r')
19
+
20
+ # Need to read first data, which means file version.
21
+ _file_version = Handler.new(file).read_short_data
22
+
23
+ read_data(file, &block)
24
+
25
+ file.close
26
+ end
27
+
28
+ private
29
+
30
+ def read_data(file, &_block)
31
+ index = 0
32
+ while !file.eof? && (limit.zero? || index < limit)
33
+ yield(Handler.new(file), index)
34
+ index += 1
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,45 @@
1
+ module CSstats
2
+ module Parser
3
+ class FileReader
4
+ class Handler
5
+ attr_reader :handle
6
+
7
+ def initialize(handle)
8
+ @handle = handle
9
+ end
10
+
11
+ # Internal: Get the 32bit integer from file.
12
+ #
13
+ # Returns the Integer.
14
+ def read_int_data
15
+ data = handle.read(4)
16
+ raise CSstats::Error, 'Cannot read int data.' unless data
17
+
18
+ data.unpack('V').first
19
+ end
20
+
21
+ # Internal: Get the 16bit integer from file.
22
+ #
23
+ # Returns the Integer.
24
+ def read_short_data
25
+ data = handle.read(2)
26
+ raise CSstats::Error, 'Cannot read short data.' unless data
27
+
28
+ data.unpack('v').first
29
+ end
30
+
31
+ # Internal: Get the String from file.
32
+ #
33
+ # length - The Integer length of string to read.
34
+ #
35
+ # Returns the String.
36
+ def read_string_data(length)
37
+ data = handle.read(length)
38
+ raise CSstats::Error, 'Cannot read string data.' unless data
39
+
40
+ data.strip
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,82 @@
1
+ require 'hashie/mash'
2
+
3
+ module CSstats
4
+ module Parser
5
+ class Player
6
+ DATA_COLUMNS = %w(
7
+ teamkill damage deaths kills shots hits headshots defusions defused
8
+ plants explosions - head chest stomach leftarm rightarm leftleg
9
+ rightleg -
10
+ ).freeze
11
+
12
+ # Internal: Parse player information from file.
13
+ #
14
+ # handler - The File which was opened for reading data.
15
+ #
16
+ # Returns The Mash of player information.
17
+ def parse(handler)
18
+ length = handler.read_short_data
19
+ return if length.zero?
20
+
21
+ player_data = Hashie::Mash.new
22
+ player_data.nick = handler.read_string_data(length)
23
+
24
+ add_data(player_data, handler)
25
+
26
+ player_data
27
+ end
28
+
29
+ private
30
+
31
+ def add_data(player_data, handler)
32
+ add_uniq(player_data, handler)
33
+ add_general_data(player_data, handler)
34
+ add_calculations(player_data)
35
+ end
36
+
37
+ def add_uniq(player_data, handler)
38
+ length = handler.read_short_data
39
+ player_data.uniq = handler.read_string_data(length)
40
+ end
41
+
42
+ def add_general_data(player_data, handler)
43
+ DATA_COLUMNS.each { |type| player_data[type] = handler.read_int_data }
44
+
45
+ # Remove all 0x00000000
46
+ player_data.tap { |x| x.delete('-') }
47
+ end
48
+
49
+ def add_calculations(player_data)
50
+ player_data.acc = count_accuracy(player_data.hits, player_data.shots)
51
+ player_data.eff = count_efficiency(
52
+ player_data.kills, player_data.deaths
53
+ )
54
+ end
55
+
56
+ # Internal: Count player efficiency.
57
+ #
58
+ # kills - The Integer of player kills in game.
59
+ # deaths - The Integer of player deaths in game.
60
+ #
61
+ # Returns The Float of player efficiency.
62
+ def count_efficiency(kills, deaths)
63
+ kills_and_deaths = kills.to_f + deaths.to_f
64
+ return 0.0 if kills_and_deaths.zero?
65
+
66
+ (kills.to_f / kills_and_deaths * 100).round(2)
67
+ end
68
+
69
+ # Internal: Count player accuracy.
70
+ #
71
+ # hits - The Integer of player hits in game.
72
+ # shots - The Integer of player shots in game.
73
+ #
74
+ # Returns The Float of player accuracy.
75
+ def count_accuracy(hits, shots)
76
+ return 0.0 if shots.to_f.zero?
77
+
78
+ (hits.to_f / shots.to_f * 100).round(2)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,42 @@
1
+ module CSstats
2
+ module Parser
3
+ class Players
4
+ attr_reader :file_path, :max_players
5
+
6
+ def initialize(file_path, options = {})
7
+ @file_path = file_path
8
+ @max_players = options[:max_players] || 0
9
+ end
10
+
11
+ def parse
12
+ players = []
13
+
14
+ file_reader.read do |handler, index|
15
+ parse_player(handler, index, players)
16
+ end
17
+
18
+ players
19
+ end
20
+
21
+ private
22
+
23
+ def parse_player(handler, index, players)
24
+ player = player_parser.parse(handler)
25
+ return unless player
26
+
27
+ player['rank'] = index + 1
28
+ players[index] = player
29
+ end
30
+
31
+ def player_parser
32
+ @player_parser ||= CSstats::Parser::Player.new
33
+ end
34
+
35
+ def file_reader
36
+ @file_reader ||= CSstats::Parser::FileReader.new(
37
+ file_path, limit: max_players
38
+ )
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,3 +1,3 @@
1
1
  module CSstats
2
- VERSION = '1.0.7'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
@@ -0,0 +1,8 @@
1
+ require_relative 'writer/file_writer/handler'
2
+ require_relative 'writer/player'
3
+ require_relative 'writer/players'
4
+
5
+ module CSstats
6
+ module Writer
7
+ end
8
+ end
@@ -0,0 +1,28 @@
1
+ module CSstats
2
+ module Writer
3
+ class FileWriter
4
+ class Handler
5
+ attr_reader :handle
6
+
7
+ def initialize(handle)
8
+ @handle = handle
9
+ end
10
+
11
+ def write_int_data(int)
12
+ data = [int].pack('V')
13
+ handle.write(data)
14
+ end
15
+
16
+ def write_short_data(int)
17
+ data = [int].pack('v')
18
+ handle.write(data)
19
+ end
20
+
21
+ def write_string_data(string)
22
+ data = "#{string}\x00"
23
+ handle.write(data)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ module CSstats
2
+ module Writer
3
+ class Player
4
+ attr_reader :player
5
+
6
+ def initialize(player)
7
+ @player = player
8
+ end
9
+
10
+ def write(handler)
11
+ write_nick(handler)
12
+ write_uniq(handler)
13
+ write_general_data(handler)
14
+ end
15
+
16
+ private
17
+
18
+ def write_nick(handler)
19
+ handler.write_short_data(player.nick.length + 1)
20
+ handler.write_string_data(player.nick)
21
+ end
22
+
23
+ def write_uniq(handler)
24
+ handler.write_short_data(player.uniq.length + 1)
25
+ handler.write_string_data(player.uniq)
26
+ end
27
+
28
+ def write_general_data(handler)
29
+ CSstats::Parser::Player::DATA_COLUMNS.each do |type|
30
+ if type == '-'
31
+ handler.write_int_data(0)
32
+ else
33
+ handler.write_int_data(player[type])
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ module CSstats
2
+ module Writer
3
+ class Players
4
+ attr_reader :players
5
+
6
+ def initialize(players)
7
+ @players = players
8
+ end
9
+
10
+ def write(file_path)
11
+ file = File.new(file_path, 'w')
12
+ handler = CSstats::Writer::FileWriter::Handler.new(file)
13
+
14
+ handler.write_short_data(11) # File version
15
+
16
+ players.each do |player|
17
+ CSstats::Writer::Player.new(player).write(handler)
18
+ end
19
+
20
+ file.close
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe CSstats::Parser::Player do
4
+ let(:file_stream) { File.new(csstats_file) }
5
+ let(:handler) { CSstats::Parser::FileReader::Handler.new(file_stream) }
6
+ subject { described_class.new }
7
+ let(:player_data) { subject.parse(handler) }
8
+
9
+ before do
10
+ # We need to read first bytes, because it's file version.
11
+ handler.read_short_data
12
+ end
13
+
14
+ it 'has correct acc' do
15
+ expect(player_data.acc).to eq(24.3)
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe CSstats::Writer::Players do
4
+ let(:old_players) { CSstats::Handler.new(path: csstats_file).players }
5
+ let(:file_path) { tmp_file('test.dat') }
6
+ let(:new_players) { CSstats::Handler.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
+ CSstats::Writer::Players.new(old_players).write(file_path)
15
+ end
16
+
17
+ it 'has correct players count' do
18
+ CSstats::Writer::Players.new(old_players).write(file_path)
19
+ expect(new_players.length).to eq(208)
20
+ end
21
+
22
+ it 'has same players data' do
23
+ expect(old_players).to eq(new_players)
24
+ end
25
+ end
26
+ end
data/spec/spec_helper.rb CHANGED
@@ -20,6 +20,15 @@ RSpec.configure do |config|
20
20
  end
21
21
 
22
22
  def csstats_file
23
+ fixture_file('csstats.dat')
24
+ end
25
+
26
+ def fixture_file(filename)
23
27
  fixtures = File.expand_path('../fixtures', __FILE__)
24
- File.new(fixtures + '/csstats.dat').path
28
+ File.join(fixtures, filename)
29
+ end
30
+
31
+ def tmp_file(filename)
32
+ tmps = File.expand_path('../tmp', __FILE__)
33
+ File.join(tmps, filename)
25
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csstats
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justas Palumickas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-16 00:00:00.000000000 Z
11
+ date: 2016-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
@@ -41,11 +41,13 @@ dependencies:
41
41
  description: Gem which handle csstats.dat file generated by CSX module in AMX Mod
42
42
  X (http://www.amxmodx.org/)
43
43
  email: jpalumickas@gmail.com
44
- executables: []
44
+ executables:
45
+ - console
45
46
  extensions: []
46
47
  extra_rdoc_files: []
47
48
  files:
48
49
  - ".gitignore"
50
+ - ".hound.yml"
49
51
  - ".rspec"
50
52
  - ".rubocop.yml"
51
53
  - ".travis.yml"
@@ -54,15 +56,28 @@ files:
54
56
  - LICENSE
55
57
  - README.md
56
58
  - Rakefile
59
+ - bin/console
57
60
  - csstats.gemspec
58
61
  - lib/csstats.rb
59
62
  - lib/csstats/error.rb
60
63
  - lib/csstats/handler.rb
64
+ - lib/csstats/parser.rb
65
+ - lib/csstats/parser/file_reader.rb
66
+ - lib/csstats/parser/file_reader/handler.rb
67
+ - lib/csstats/parser/player.rb
68
+ - lib/csstats/parser/players.rb
61
69
  - lib/csstats/version.rb
70
+ - lib/csstats/writer.rb
71
+ - lib/csstats/writer/file_writer/handler.rb
72
+ - lib/csstats/writer/player.rb
73
+ - lib/csstats/writer/players.rb
62
74
  - spec/csstats/handler_spec.rb
75
+ - spec/csstats/parser/player_spec.rb
76
+ - spec/csstats/writer/players_spec.rb
63
77
  - spec/csstats_spec.rb
64
78
  - spec/fixtures/csstats.dat
65
79
  - spec/spec_helper.rb
80
+ - spec/tmp/.keep
66
81
  homepage: https://github.com/jpalumickas/csstats/
67
82
  licenses:
68
83
  - MIT
@@ -89,6 +104,9 @@ specification_version: 4
89
104
  summary: ''
90
105
  test_files:
91
106
  - spec/csstats/handler_spec.rb
107
+ - spec/csstats/parser/player_spec.rb
108
+ - spec/csstats/writer/players_spec.rb
92
109
  - spec/csstats_spec.rb
93
110
  - spec/fixtures/csstats.dat
94
111
  - spec/spec_helper.rb
112
+ - spec/tmp/.keep