page_view_parser 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: dc62810f4d5cdcc46810bf3cb009e2173e086f40289103c6de060ebef3916bed
|
4
|
+
data.tar.gz: 4f5c6a7d74a12615f98c5a8439c26bfcba6c8d04509033322792f8b2d154b7b5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c361c7e10da596db6600f87b500d3a50dff9646d162f6a59dacf14493d9a72e8dbdbc9db672a87197afb9e307df66fe689894a089450bee05a0684ce2c5d9e1b
|
7
|
+
data.tar.gz: c196b8b6fa9e18ed3784d4c04cdb22fbba05a4d740d12245627c9a3cd08ef9f97c2fda524bb91b1c5e1a8decddb55894dedba7e025d7e5b47469405e45dad5ca
|
data/lib/log_parser.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'page.rb'
|
4
|
+
|
5
|
+
# Takes a log file where each line has the format of:
|
6
|
+
# PAGE_NAME VISITOR_IP
|
7
|
+
# eg.
|
8
|
+
# /about 123.456.789.123
|
9
|
+
# and turns it into a list of 'page' objects.
|
10
|
+
# The target object to turn each line in the log into is
|
11
|
+
# expected to be able to receive page: and visitor: keyword arguments.
|
12
|
+
class LogParser
|
13
|
+
class MalformedLog < StandardError; end
|
14
|
+
|
15
|
+
def initialize(page_class: Page)
|
16
|
+
@page_class = page_class
|
17
|
+
end
|
18
|
+
|
19
|
+
# arranging by path in a hash first instead of straight into an Array to avoid
|
20
|
+
# an iteration of the whole list so far on each check for existence. Instead,
|
21
|
+
# using the quicker lookup by key to then later just extract the values into
|
22
|
+
# the list.
|
23
|
+
def parse_from_file(file_path:)
|
24
|
+
page_views = {}.tap do |pages|
|
25
|
+
File.open(file_path).each do |line|
|
26
|
+
build_page line, pages
|
27
|
+
end
|
28
|
+
end
|
29
|
+
[].push(*page_views.values)
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse_from_string(string:)
|
33
|
+
page_views = {}.tap do |pages|
|
34
|
+
string.split("\n").each do |line|
|
35
|
+
build_page line, pages
|
36
|
+
end
|
37
|
+
end
|
38
|
+
[].push(*page_views.values)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
attr_reader :file_path, :page_class
|
44
|
+
|
45
|
+
def build_page(line, pages)
|
46
|
+
path, visitor = line.split(' ')
|
47
|
+
raise MalformedLog, 'Log malformed' if
|
48
|
+
path.nil? || visitor.nil?
|
49
|
+
|
50
|
+
if pages[path].nil? # The current path hasn't been seen before
|
51
|
+
pages[path] = page_class.new(path: path, visitors: [visitor])
|
52
|
+
else
|
53
|
+
pages[path].visitors << visitor
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/page.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Represents a record of a page that can be visited, holding a record of the
|
4
|
+
# visitors via their ip address
|
5
|
+
class Page
|
6
|
+
attr_reader :path, :visitors
|
7
|
+
|
8
|
+
def initialize(path:, visitors: [])
|
9
|
+
@path = path
|
10
|
+
@visitors = visitors
|
11
|
+
end
|
12
|
+
|
13
|
+
def <<(visitor)
|
14
|
+
visitors << visitor
|
15
|
+
end
|
16
|
+
|
17
|
+
def view_count
|
18
|
+
visitors.count
|
19
|
+
end
|
20
|
+
|
21
|
+
def unique_view_count
|
22
|
+
visitors.uniq.count
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s(strategy: DEFAULT_PAGE_PRESENTATION_STRATEGY)
|
26
|
+
strategy.call(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
DEFAULT_PAGE_PRESENTATION_STRATEGY = proc do |page|
|
30
|
+
"#{page.path} visited by #{page.visitors.uniq}"
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PageListFormatStrategies
|
4
|
+
# Base class that represents the interface all pages format strategy
|
5
|
+
# classes must implement.
|
6
|
+
class Base
|
7
|
+
def initialize(pages:)
|
8
|
+
@pages = pages
|
9
|
+
end
|
10
|
+
|
11
|
+
# It is expected that all sub class strategies will override this method and
|
12
|
+
# provide it's own formatting algorithm / behaviour. The result however is
|
13
|
+
# always an array of the new format the Pages have taken.
|
14
|
+
def call
|
15
|
+
pages
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :pages
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../page_list_format_strategies/base.rb'
|
4
|
+
|
5
|
+
module PageListFormatStrategies
|
6
|
+
# A presentation strategy that presents a list of pages in descending order
|
7
|
+
# by the number of unique views with its unique view count.
|
8
|
+
class WithUniqueViewCount < Base
|
9
|
+
def call
|
10
|
+
presentation_strategy = proc do |page|
|
11
|
+
str = ''
|
12
|
+
str += "#{page.path} #{page.unique_view_count} "
|
13
|
+
str += "unique visit#{page.unique_view_count > 1 ? 's' : ''}"
|
14
|
+
str
|
15
|
+
end
|
16
|
+
|
17
|
+
pages.sort_by { |page| -page.unique_view_count }
|
18
|
+
.map { |page| page.to_s(strategy: presentation_strategy) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../page_list_format_strategies/base.rb'
|
4
|
+
|
5
|
+
module PageListFormatStrategies
|
6
|
+
# A presentation strategy that presents a list of page paths in descending
|
7
|
+
# order (highest number of views at the top) with their total view count.
|
8
|
+
class WithViewCount < Base
|
9
|
+
def call
|
10
|
+
presentation_strategy = proc do |page|
|
11
|
+
"#{page.path} #{page.view_count} visit#{page.view_count > 1 ? 's' : ''}"
|
12
|
+
end
|
13
|
+
|
14
|
+
pages.sort_by { |page| -page.view_count }
|
15
|
+
.map { |page| page.to_s(strategy: presentation_strategy) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: page_view_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Hayes-Reed
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-06-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: guard
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: guard-rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.9'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.9'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.85'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.85'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.18'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.18'
|
83
|
+
description: A simple webserver parser that outputs page count information
|
84
|
+
email: john.hayes.reed@gmail.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- lib/log_parser.rb
|
90
|
+
- lib/page.rb
|
91
|
+
- lib/page_list_format_strategies/base.rb
|
92
|
+
- lib/page_list_format_strategies/with_unique_view_count.rb
|
93
|
+
- lib/page_list_format_strategies/with_view_count.rb
|
94
|
+
homepage:
|
95
|
+
licenses: []
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubygems_version: 3.0.6
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: Page View Parser
|
116
|
+
test_files: []
|