rslog 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8772ce859d1a57c687b9c4cb7b8cd55bbddcce5467b4eff8715dc1e734bf77f1
4
+ data.tar.gz: fad32cd0d5a00e854680959383ba962776ee95b243c13b85134ac74227cb651c
5
+ SHA512:
6
+ metadata.gz: ea4482e67eb1709cb5d344ecda30086d508dfb0680777e690f7d598ecb34d504692454cd876ef34f604c85a1fae07705a2dbb49852d71eae307c9eb9b3046254
7
+ data.tar.gz: 40370482e148847bd6135070bbe37383e81d120fd7f2e6a464c2b839435cefc5a4545e5daf7a60797759e249091f3ad7ec41f438099a0906a6d809086556d9ec
data/bin/rslog ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/rslog'
5
+ RSlog.run
data/lib/rslog.rb ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'rslog/container'
5
+ require_relative 'rslog/input_parser'
6
+ require_relative 'rslog/extractor'
7
+ require_relative 'rslog/validator'
8
+ require_relative 'rslog/data_parser'
9
+ require_relative 'rslog/presenter'
10
+
11
+ # For development
12
+ # require 'pry'
13
+
14
+ class RSlog
15
+ VERSION = '0.0.1'
16
+
17
+ def self.run
18
+ Container.new.process_all
19
+ end
20
+ end
21
+
22
+ # For development
23
+ # RSlog.run.talk
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Container
4
+ attr_accessor(*%i[
5
+ argv file_name messages errors data options validator types result
6
+ ])
7
+
8
+ def initialize
9
+ @errors = []
10
+ @messages = []
11
+ @validator = :ip
12
+ @types = %i[all uniq]
13
+ end
14
+
15
+ def file_name?
16
+ !file_name.empty? && no_errors?
17
+ end
18
+
19
+ def data?
20
+ messages.include?('Data in place') && no_errors?
21
+ end
22
+
23
+ def no_errors?
24
+ errors.empty?
25
+ end
26
+
27
+ def talk
28
+ puts messages.join("\n")
29
+ puts errors.join("\n")
30
+ self
31
+ end
32
+
33
+ def process_all
34
+ InputParser.new(self).execute
35
+ Extractor.new(self).execute if file_name?
36
+ validate_parse_present if data?
37
+ talk
38
+ self
39
+ end
40
+
41
+ def validate_parse_present
42
+ Validator.new(self).execute
43
+ types.each do |type|
44
+ DataParser.new(self).execute(type)
45
+ Presenter.new(self).execute(type, :text)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'tools/array'
4
+ require_relative 'tools/hash'
5
+ require_relative 'validator'
6
+
7
+ require 'pry'
8
+
9
+ class DataParser
10
+ # type = :count (default) -> just count in groups
11
+ # type = :uniq -> uniq entries in groups
12
+ def initialize(container)
13
+ @container = container
14
+ end
15
+
16
+ def execute(type)
17
+ @container.result =
18
+ @container.data
19
+ .group_by_index(0)
20
+ .count_by_groups(type)
21
+ .to_a
22
+ .sort_by { |item| item[1] }
23
+ .reverse
24
+ .map { |i| i.map(&:to_s).join(' ') }
25
+ self
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'container'
4
+
5
+ class Extractor
6
+ def initialize(container)
7
+ @container = container
8
+ end
9
+
10
+ def execute
11
+ check
12
+ self
13
+ end
14
+
15
+ private
16
+
17
+ def check
18
+ if File.zero?(@container.file_name)
19
+ @container.messages << 'Empty file'
20
+ else
21
+ @container.data = File.open(@container.file_name, 'r').to_a
22
+ @container.messages << 'Data in place'
23
+ end
24
+ rescue StandardError => e
25
+ @container.errors << e
26
+ end
27
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+
5
+ class InputParser
6
+ OPTS = {
7
+ version: {
8
+ descr: ['-v', '--version', 'Show version and exit'],
9
+ action: proc do
10
+ puts "#{File.basename($PROGRAM_NAME)}: #{RSlog::VERSION}"
11
+ exit
12
+ end
13
+ },
14
+ help: {
15
+ descr: ['-h', '--help', 'Prints this message and exit'],
16
+ action: proc do |opts|
17
+ puts opts
18
+ exit
19
+ end
20
+ }
21
+ }.freeze
22
+
23
+ def initialize(container)
24
+ @container = container
25
+ @argv = container.argv
26
+ @file_name = container.file_name
27
+ @options = container.options
28
+ @errors = container.errors
29
+ end
30
+
31
+ def execute
32
+ create_opts
33
+ handle_opts
34
+ handle_args
35
+ self
36
+ end
37
+
38
+ private
39
+
40
+ attr_accessor :opts
41
+
42
+ def create_opts
43
+ @opts = OptionParser.new do |opts|
44
+ opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} FILENAME"
45
+ opts.on(*OPTS[:version][:descr]) do
46
+ OPTS[:version][:action].call
47
+ end
48
+ opts.on(*OPTS[:help][:descr]) do
49
+ OPTS[:help][:action].call(opts)
50
+ end
51
+ end
52
+ end
53
+
54
+ def handle_opts
55
+ @opts.parse!(into: @container.options)
56
+ rescue OptionParser::InvalidOption => e
57
+ @container.errors << e
58
+ end
59
+
60
+ def handle_args
61
+ @container.file_name = ARGV.select { |str| str =~ /.\.log|.\.txt/ }[0] || ''
62
+ @container.errors << 'No file_name provided' if @container.file_name.empty?
63
+ end
64
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'tools/hash'
4
+ require_relative 'tools/array'
5
+
6
+ class Presenter
7
+ DECORATORS = {
8
+ all: {
9
+ title:
10
+ 'List of webpages with most page views ordered from most views to less',
11
+ suffix: 'visits'
12
+ },
13
+ uniq: {
14
+ title: 'List list of webpages with most unique page views also ordered',
15
+ suffix: 'unique views'
16
+ }
17
+ }.freeze
18
+
19
+ def initialize(container)
20
+ @container = container
21
+ end
22
+
23
+ def execute(type, formatter)
24
+ @container.messages << format_as(type, formatter)
25
+ self
26
+ end
27
+
28
+ private
29
+
30
+ def format_as(type, formatter)
31
+ case formatter
32
+ when :text
33
+ [
34
+ DECORATORS[type][:title],
35
+ @container.result.to_multiline_string(DECORATORS[type][:suffix]),
36
+ separator
37
+ ].join("\n")
38
+ end
39
+ end
40
+
41
+ def separator
42
+ '-----------------------------'
43
+ end
44
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ def group_by_index(index = 0)
5
+ group_by { |str| str.split(' ')[index] }
6
+ end
7
+
8
+ def to_multiline_string(suffix = '')
9
+ arr = []
10
+ each do |item|
11
+ arr << "#{item} #{suffix}"
12
+ end
13
+ arr.join("\n")
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ class Hash
6
+ def count_by_groups(type = :all)
7
+ res = {}
8
+ each do |group_key, arr|
9
+ res[group_key] = arr.size if type == :all
10
+ res[group_key] = Set.new(arr).size if type == :uniq
11
+ end
12
+ res
13
+ end
14
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'tools/array'
4
+
5
+ class Validator
6
+ TEMPLATES = {
7
+ # IP address regex, source https://regexr.com/38odc
8
+ ip: /\b(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9])\.){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))\b/
9
+ }.freeze
10
+
11
+ MESSAGES = {
12
+ valid: proc { |validator| "All #{validator.upcase}s are valid" },
13
+ invalid: proc { |validator| "Some #{validator.upcase}s are NOT valid" }
14
+ }.freeze
15
+
16
+ def initialize(container)
17
+ @container = container
18
+ end
19
+
20
+ def execute
21
+ @container.messages << MESSAGES[validate].call(@container.validator)
22
+ self
23
+ end
24
+
25
+ private
26
+
27
+ def validate
28
+ return :valid if @container.data.all? TEMPLATES[@container.validator]
29
+
30
+ :invalid
31
+ end
32
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rslog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andrey Eremeev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-03-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby script to get overall Statistic for weblog logs!
14
+ email: a.eremeev@outlook.com
15
+ executables:
16
+ - rslog
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/rslog
21
+ - lib/rslog.rb
22
+ - lib/rslog/container.rb
23
+ - lib/rslog/data_parser.rb
24
+ - lib/rslog/extractor.rb
25
+ - lib/rslog/input_parser.rb
26
+ - lib/rslog/presenter.rb
27
+ - lib/rslog/tools/array.rb
28
+ - lib/rslog/tools/hash.rb
29
+ - lib/rslog/validator.rb
30
+ homepage: https://rubygems.org/gems/rslog
31
+ licenses:
32
+ - MIT
33
+ metadata: {}
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: 2.6.0
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubygems_version: 3.0.3
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: R(uby)S(tatistic)log
53
+ test_files: []