csstats 1.0.7 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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