scrap_cbf_record 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/scrap_cbf_record.rb +72 -0
- data/lib/scrap_cbf_record/active_record.rb +105 -0
- data/lib/scrap_cbf_record/active_records/base.rb +196 -0
- data/lib/scrap_cbf_record/active_records/matches.rb +80 -0
- data/lib/scrap_cbf_record/active_records/rankings.rb +70 -0
- data/lib/scrap_cbf_record/active_records/rounds.rb +60 -0
- data/lib/scrap_cbf_record/active_records/teams.rb +42 -0
- data/lib/scrap_cbf_record/config.rb +217 -0
- data/lib/scrap_cbf_record/configs/base.rb +258 -0
- data/lib/scrap_cbf_record/configs/championship.rb +97 -0
- data/lib/scrap_cbf_record/configs/match.rb +164 -0
- data/lib/scrap_cbf_record/configs/ranking.rb +152 -0
- data/lib/scrap_cbf_record/configs/round.rb +113 -0
- data/lib/scrap_cbf_record/configs/team.rb +99 -0
- data/lib/scrap_cbf_record/errors.rb +83 -0
- data/lib/scrap_cbf_record/logger.rb +20 -0
- data/lib/scrap_cbf_record/models/base.rb +16 -0
- data/lib/scrap_cbf_record/models/championship.rb +28 -0
- data/lib/scrap_cbf_record/models/concerns/active_record_relation.rb +37 -0
- data/lib/scrap_cbf_record/models/match.rb +71 -0
- data/lib/scrap_cbf_record/models/ranking.rb +58 -0
- data/lib/scrap_cbf_record/models/round.rb +54 -0
- data/lib/scrap_cbf_record/models/team.rb +22 -0
- data/lib/scrap_cbf_record/version.rb +5 -0
- metadata +170 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ScrapCbfRecord
|
4
|
+
class Config
|
5
|
+
# Team settings
|
6
|
+
class Team < Base
|
7
|
+
class << self
|
8
|
+
# Default settings
|
9
|
+
#
|
10
|
+
# @return [Hash]
|
11
|
+
def default
|
12
|
+
{
|
13
|
+
class_name: 'Team',
|
14
|
+
rename_attrs: {},
|
15
|
+
exclude_attrs_on_create: %i[],
|
16
|
+
exclude_attrs_on_update: %i[],
|
17
|
+
associations: {}
|
18
|
+
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Settings use by the system
|
23
|
+
# Not configurable
|
24
|
+
#
|
25
|
+
# @return [Hash]
|
26
|
+
def required
|
27
|
+
{ must_exclude_attrs: %i[] }
|
28
|
+
end
|
29
|
+
|
30
|
+
# Record Attributes
|
31
|
+
# It must match with ScrapCbf
|
32
|
+
#
|
33
|
+
# @return [Array]
|
34
|
+
def record_attrs
|
35
|
+
%i[
|
36
|
+
name
|
37
|
+
state
|
38
|
+
avatar_url
|
39
|
+
]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
attr_reader :class_name,
|
44
|
+
:rename_attrs,
|
45
|
+
:exclude_attrs_on_create,
|
46
|
+
:exclude_attrs_on_update,
|
47
|
+
:associations
|
48
|
+
|
49
|
+
# Starts the settings with default
|
50
|
+
#
|
51
|
+
# @return [nil]
|
52
|
+
def initialize
|
53
|
+
@class_name = default_class_name
|
54
|
+
@rename_attrs = default_rename_attrs
|
55
|
+
@exclude_attrs_on_create = default_exclude_attrs_on_create
|
56
|
+
@exclude_attrs_on_update = default_exclude_attrs_on_update
|
57
|
+
@associations = default_associations
|
58
|
+
|
59
|
+
ScrapCbfRecord::Team.config = self
|
60
|
+
|
61
|
+
super(*configs)
|
62
|
+
end
|
63
|
+
|
64
|
+
# These method receives the users settings
|
65
|
+
# Missing settings are left as default
|
66
|
+
#
|
67
|
+
# @param [config] Hash contaning the settings
|
68
|
+
# @return [nil]
|
69
|
+
def config=(config)
|
70
|
+
raise ::ArgumentError, 'config must be a Hash' unless config.is_a?(Hash)
|
71
|
+
|
72
|
+
@class_name = config[:class_name] if config[:class_name]
|
73
|
+
@rename_attrs = config[:rename_attrs] if config[:rename_attrs]
|
74
|
+
if config[:exclude_attrs_on_create]
|
75
|
+
@exclude_attrs_on_create = config[:exclude_attrs_on_create]
|
76
|
+
end
|
77
|
+
if config[:exclude_attrs_on_update]
|
78
|
+
@exclude_attrs_on_update = config[:exclude_attrs_on_update]
|
79
|
+
end
|
80
|
+
@associations = config[:associations] if config[:associations]
|
81
|
+
|
82
|
+
super(*configs)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Return the configurable settings
|
86
|
+
#
|
87
|
+
# @return [Array]
|
88
|
+
def configs
|
89
|
+
[
|
90
|
+
@class_name,
|
91
|
+
@rename_attrs,
|
92
|
+
@exclude_attrs_on_create,
|
93
|
+
@exclude_attrs_on_update,
|
94
|
+
@associations
|
95
|
+
]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ScrapCbfRecord
|
4
|
+
# Base error for all ScrapCbf errors.
|
5
|
+
class BaseError < ::StandardError; end
|
6
|
+
|
7
|
+
# Raise when error occurs while decoding
|
8
|
+
class JsonDecodeError < BaseError
|
9
|
+
def initialize(argument)
|
10
|
+
super(argument)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Raise when missing a Hash key
|
15
|
+
class MissingKeyError < BaseError
|
16
|
+
def initialize(arg)
|
17
|
+
message = "Hash missing required key: #{arg}"
|
18
|
+
super(message)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Raise when a validation error is found
|
23
|
+
class ActiveRecordValidationError < BaseError
|
24
|
+
def initialize
|
25
|
+
message = 'An error raised while saving records.' \
|
26
|
+
' Check the log for more details'
|
27
|
+
super(message)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Raise when the championship instance is not found on database
|
32
|
+
class ChampionshipInstanceNotFoundError < BaseError
|
33
|
+
def initialize(year)
|
34
|
+
message = "The Championship instance for year #{year}" \
|
35
|
+
' was not found on database. Check if the values are right' \
|
36
|
+
' or the instance exist on database, before saving records'
|
37
|
+
|
38
|
+
super(message)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class RecordClassNotDefinedError < BaseError
|
43
|
+
def initialize(record)
|
44
|
+
message = "The record class #{record.class_name}" \
|
45
|
+
' was not defined. Check if the class exist or is being loaded'
|
46
|
+
|
47
|
+
super(message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class RecordAssociationAttributeNotDefinedError < BaseError
|
52
|
+
def initialize(record, attribute)
|
53
|
+
message = "The record class #{record.class_name}" \
|
54
|
+
" has not defined the attribute #{attribute}." \
|
55
|
+
" If you don't want define this attribute," \
|
56
|
+
' remove it from the config associations.'
|
57
|
+
|
58
|
+
super(message)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class RecordAttributeNotDefinedError < BaseError
|
63
|
+
def initialize(record, attribute)
|
64
|
+
message = "The record class #{record.class}" \
|
65
|
+
" has not defined the attribute #{attribute}." \
|
66
|
+
" If you don't want define this attribute," \
|
67
|
+
' add it to the config lists of excludes on create and update.'
|
68
|
+
|
69
|
+
super(message)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class RecordRenameAttributeNotDefinedError < BaseError
|
74
|
+
def initialize(record, attribute)
|
75
|
+
message = "The record class #{record.class}" \
|
76
|
+
" has not defined the renamed attribute #{attribute}." \
|
77
|
+
' Check if you write the attribute name correct, or' \
|
78
|
+
' if you don\'t want rename, remove it from the config list rename attrs.'
|
79
|
+
|
80
|
+
super(message)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/logger'
|
4
|
+
require 'active_support/tagged_logging'
|
5
|
+
|
6
|
+
class ScrapCbfRecord
|
7
|
+
class TagLogger
|
8
|
+
class << self
|
9
|
+
attr_writer :logger
|
10
|
+
|
11
|
+
def logger
|
12
|
+
@logger ||= ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_context(tags, message)
|
16
|
+
logger.tagged(*tags) { logger.info message }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ScrapCbfRecord
|
4
|
+
# Base class for the models abstractions
|
5
|
+
class Base
|
6
|
+
class << self
|
7
|
+
# Create a instance for the real model, the one used by the user
|
8
|
+
#
|
9
|
+
# @param [args] arguments passed to new instance
|
10
|
+
# @return [Object] the instance model
|
11
|
+
def new(args)
|
12
|
+
@config.klass.new(args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ScrapCbfRecord
|
4
|
+
# Abstraction for the class Championship
|
5
|
+
class Championship < Base
|
6
|
+
class << self
|
7
|
+
attr_accessor :config
|
8
|
+
|
9
|
+
def find_by!(attributes)
|
10
|
+
year = attributes[:year]
|
11
|
+
associate = attributes[:associate]
|
12
|
+
|
13
|
+
# if associate is nil, that means self is calling this method
|
14
|
+
instance = if associate.nil? || associate
|
15
|
+
@config.klass.find_by(
|
16
|
+
"#{@config.searchable_attr(:year)}": year
|
17
|
+
)
|
18
|
+
else
|
19
|
+
year
|
20
|
+
end
|
21
|
+
|
22
|
+
raise ChampionshipInstanceNotFoundError, year unless instance
|
23
|
+
|
24
|
+
instance
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ScrapCbfRecord
|
4
|
+
# This class helps with the communication between models association
|
5
|
+
class ActiveRecordRelation
|
6
|
+
# @param [association_class] the class associated that will be searched
|
7
|
+
# @param [associate] boolean true if associate, false if it's not
|
8
|
+
# @return [ActiveRecordRelation]
|
9
|
+
def initialize(association_class, associate)
|
10
|
+
@association_class = association_class
|
11
|
+
@associate = associate
|
12
|
+
end
|
13
|
+
|
14
|
+
# Searchs on the association. Dependes on the associate value,
|
15
|
+
# the search on db will be made if more or less arguments, or none.
|
16
|
+
# be made on database level. If it's not, it may be using
|
17
|
+
#
|
18
|
+
# @param [attributes] hash contaning the attributes use to search
|
19
|
+
# @return [Object] return the obj found on db or their identifier
|
20
|
+
def find_by(attributes)
|
21
|
+
attributes[:associate] = @associate
|
22
|
+
@association_class.send __method__, attributes
|
23
|
+
end
|
24
|
+
|
25
|
+
# Searchs on the association. Dependes on the associate value,
|
26
|
+
# the search on db will be made if more or less arguments, or none.
|
27
|
+
# be made on database level. If it's not, it may be using
|
28
|
+
#
|
29
|
+
# @note Raises a exception if not found
|
30
|
+
# @param [attributes] hash contaning the attributes use to search
|
31
|
+
# @return [Object] return the obj found on db or their identifier
|
32
|
+
def find_by!(attributes)
|
33
|
+
attributes[:associate] = @associate
|
34
|
+
@association_class.send __method__, attributes
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ScrapCbfRecord
|
4
|
+
# Abstraction for the class Match
|
5
|
+
class Match < Base
|
6
|
+
class << self
|
7
|
+
attr_accessor :config
|
8
|
+
|
9
|
+
def championship
|
10
|
+
ActiveRecordRelation.new(
|
11
|
+
Championship,
|
12
|
+
@config.championship_associate?
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def round
|
17
|
+
ActiveRecordRelation.new(
|
18
|
+
Round,
|
19
|
+
@config.round_associate?
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def team
|
24
|
+
ActiveRecordRelation.new(
|
25
|
+
Team,
|
26
|
+
@config.team_associate?
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def opponent
|
31
|
+
ActiveRecordRelation.new(
|
32
|
+
Team,
|
33
|
+
@config.opponent_associate?
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Find the current model on db. If current model is associate
|
38
|
+
# to championship, the attribute serie is not need, as the
|
39
|
+
# association can be used as a unique identifer for the model.
|
40
|
+
#
|
41
|
+
# @param attributes [Hash] the attrs used to find on db
|
42
|
+
# @return [Object, nil] returns Object if find, else nil
|
43
|
+
def find_by(attributes)
|
44
|
+
id_match = attributes[:id_match]
|
45
|
+
championship = attributes[:championship]
|
46
|
+
serie = attributes[:serie]
|
47
|
+
|
48
|
+
if @config.championship_associate?
|
49
|
+
find_match_associated(id_match, championship)
|
50
|
+
else
|
51
|
+
find_match(id_match, championship, serie)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def find_match(id_match, championship, serie)
|
56
|
+
@config.klass.find_by(
|
57
|
+
"#{@config.searchable_attr(:id_match)}": id_match,
|
58
|
+
"#{@config.searchable_attr(:championship)}": championship,
|
59
|
+
"#{@config.searchable_attr(:serie)}": serie
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
def find_match_associated(id_match, championship)
|
64
|
+
@config.klass.find_by(
|
65
|
+
"#{@config.searchable_attr(:id_match)}": id_match,
|
66
|
+
"#{@config.searchable_attr(:championship_id)}": championship.id
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ScrapCbfRecord
|
4
|
+
# Abstraction for the class Ranking
|
5
|
+
class Ranking < Base
|
6
|
+
class << self
|
7
|
+
attr_accessor :config
|
8
|
+
|
9
|
+
def championship
|
10
|
+
ActiveRecordRelation.new(
|
11
|
+
Championship,
|
12
|
+
@config.championship_associate?
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def team
|
17
|
+
ActiveRecordRelation.new(
|
18
|
+
Team,
|
19
|
+
@config.team_associate?
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def next_opponent
|
24
|
+
ActiveRecordRelation.new(
|
25
|
+
Team,
|
26
|
+
@config.next_opponent_associate?
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_by(attributes)
|
31
|
+
position = attributes[:position]
|
32
|
+
championship = attributes[:championship]
|
33
|
+
serie = attributes[:serie]
|
34
|
+
|
35
|
+
if @config.championship_associate?
|
36
|
+
find_ranking_associated(position, championship)
|
37
|
+
else
|
38
|
+
find_ranking(position, championship, serie)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_ranking(position, championship, serie)
|
43
|
+
@config.klass.find_by(
|
44
|
+
"#{@config.searchable_attr(:position)}": position,
|
45
|
+
"#{@config.searchable_attr(:championship)}": championship,
|
46
|
+
"#{@config.searchable_attr(:serie)}": serie
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def find_ranking_associated(position, championship)
|
51
|
+
@config.klass.find_by(
|
52
|
+
"#{@config.searchable_attr(:position)}": position,
|
53
|
+
"#{@config.searchable_attr(:championship_id)}": championship.id
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ScrapCbfRecord
|
4
|
+
# Abstraction for the class Round
|
5
|
+
class Round < Base
|
6
|
+
class << self
|
7
|
+
attr_accessor :config
|
8
|
+
|
9
|
+
def championship
|
10
|
+
ActiveRecordRelation.new(
|
11
|
+
Championship,
|
12
|
+
@config.championship_associate?
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_by(attributes)
|
17
|
+
number = attributes[:number]
|
18
|
+
championship = attributes[:championship]
|
19
|
+
serie = attributes[:serie]
|
20
|
+
associate = attributes[:associate]
|
21
|
+
|
22
|
+
# if associate is nil, that means self is calling this method
|
23
|
+
if associate.nil? || associate
|
24
|
+
find_round_on_database(number, championship, serie)
|
25
|
+
else
|
26
|
+
number
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_round_on_database(number, championship, serie)
|
31
|
+
if @config.championship_associate?
|
32
|
+
find_round_associated(number, championship)
|
33
|
+
else
|
34
|
+
find_round(number, championship, serie)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_round(number, championship, serie)
|
39
|
+
@config.klass.find_by(
|
40
|
+
"#{@config.searchable_attr(:number)}": number,
|
41
|
+
"#{@config.searchable_attr(:championship)}": championship,
|
42
|
+
"#{@config.searchable_attr(:serie)}": serie
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_round_associated(number, championship)
|
47
|
+
@config.klass.find_by(
|
48
|
+
"#{@config.searchable_attr(:number)}": number,
|
49
|
+
"#{@config.searchable_attr(:championship_id)}": championship.id
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|