scrap_cbf_record 0.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.
@@ -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