scrap_cbf_record 0.1.0

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