leagues 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,195 @@
1
+ ####
2
+ ### check - nest CET class inside UTC e.g. UTC::CET - why? why not?
3
+ ## make UTC and CET into a module (not class) - why? why not?
4
+
5
+ module CET ## central european time helpers
6
+ def self.now() zone.now; end
7
+ def self.today() now.to_date; end
8
+ def self.strptime( str, format )
9
+
10
+ ### fix - change to Time.strptime - why? why not?
11
+ ## (simply) ignore offset; double check that hours, minutes
12
+ ## get parsed as is (without applying offset)
13
+
14
+ d = DateTime.strptime( str, format )
15
+ ## remove assert check - why? why not?
16
+ if d.zone != '+00:00' ### use d.offset != Ration(0,1) - why? why not?
17
+ puts "!! ASSERT - CET parse date; DateTime returns offset != +0:00"
18
+ pp d.zone
19
+ pp d
20
+ exit 1
21
+ end
22
+
23
+ ### 2006-03-26 02:00:00
24
+ ## raise exception
25
+ ## is an invalid local time. (TZInfo::PeriodNotFound)
26
+ ## quick fix add +1
27
+ ## 2012-03-25 02:00:00
28
+ ## is an invalid local time. (TZInfo::PeriodNotFound)
29
+
30
+ if ['2018-03-25 02:00',
31
+ '2012-03-25 02:00',
32
+ '2006-03-26 02:00',
33
+ ].include?( d.strftime( '%Y-%m-%d %H:%M' ))
34
+ puts "!! hack - fix CET date #{d} - add +1 hour"
35
+ pp d
36
+ zone.local_time( d.year, d.month, d.day, d.hour+1, d.min, d.sec )
37
+ else
38
+ zone.local_time( d.year, d.month, d.day, d.hour, d.min, d.sec )
39
+ end
40
+ end
41
+ def self.zone() @zone ||= UTC.find_zone( 'Europe/Vienna' ); end
42
+ end # class CET
43
+
44
+
45
+
46
+ module UTC
47
+ def self.now() Time.now.utc; end
48
+ def self.today() now.to_date; end
49
+
50
+ ## -- todo - make sure / assert it's always utc - how???
51
+ ## utc = ## tz_utc.strptime( m['utcDate'], '%Y-%m-%dT%H:%M:%SZ' )
52
+ ## note: DateTime.strptime is supposed to be unaware of timezones!!!
53
+ ## use to parse utc
54
+ ## quick hack -
55
+ ## use to_time.getutc instead of utc ???
56
+ def self.strptime( str, format )
57
+ d = DateTime.strptime( str, format )
58
+ ## remove assert check - why? why not?
59
+ if d.zone != '+00:00' ### use d.offset != Ration(0,1) - why? why not?
60
+ puts "!! ASSERT - UTC parse date; DateTime returns offset != +0:00"
61
+ pp d.zone
62
+ pp d
63
+ exit 1
64
+ end
65
+ ## note - ignores offset if any !!!!
66
+ ## todo/check - report warn if offset different from 0:00 (0/1) - why? why not?
67
+ Time.utc( d.year, d.month, d.day, d.hour, d.min, d.sec )
68
+ end
69
+
70
+ def self.find_zone( name )
71
+ zone = TZInfo::Timezone.get( name )
72
+ ## wrap tzinfo timezone in our own - for adding more (auto)checks etc.
73
+ zone ? Timezone.new( zone ) : nil
74
+ end
75
+
76
+ class Timezone ## nested inside UTC
77
+ ## todo/fix
78
+ ## cache timezone - why? why not?
79
+ def initialize( zone )
80
+ @zone = zone
81
+ end
82
+
83
+ def name() @zone.name; end
84
+ def dst?() @zone.dst?; end
85
+
86
+
87
+ def to_local( time )
88
+ ## assert time is Time (not Date or DateTIme)
89
+ ## and assert utc!!!
90
+ assert( time.is_a?( Time ), "time #{time} is NOT of class Time; got #{time.class.name}" )
91
+ assert( time.utc?, "time #{time} is NOT utc; utc? returns #{time.utc?}" )
92
+ local = @zone.to_local( time )
93
+ local
94
+ end
95
+
96
+ def local_time( year, month=1, mday=1, hour=0, min=0, sec=0 )
97
+ ## add auto-fix for ambigious time (dst vs non-dst)
98
+ ## always select first for now (that is, dst)
99
+ @zone.local_time( year, month, mday, hour, min, sec ) {|time| time.first }
100
+ end
101
+
102
+ def now() @zone.now; end
103
+
104
+
105
+
106
+
107
+ def assert( cond, msg )
108
+ if cond
109
+ # do nothing
110
+ else
111
+ puts "!!! assert failed - #{msg}"
112
+ exit 1
113
+ end
114
+ end
115
+ end # class Timezone
116
+ end # module UTC
117
+
118
+
119
+
120
+
121
+ module TimezoneHelper
122
+
123
+ def find_zone!( league:, season: )
124
+ zone = find_zone( league: league, season: season )
125
+ if zone.nil? ## still not found; report error
126
+ puts "!! ERROR: no timezone found for #{league} #{season}"
127
+ exit 1
128
+ end
129
+ zone
130
+ end
131
+
132
+
133
+ def find_zone( league:, season: )
134
+ ## note: do NOT pass in league struct! pass in key (string)
135
+ raise ArgumentError, "league code as string|symbol expected" unless league.is_a?(String) || league.is_a?(Symbol)
136
+
137
+ @zones ||= begin
138
+ zones = {}
139
+ ['timezones_africa',
140
+ 'timezones_america',
141
+ 'timezones_asia',
142
+ 'timezones_europe',
143
+ 'timezones_middle_east',
144
+ 'timezones_pacific',
145
+ 'timezones_world',].each do |name|
146
+ recs = read_csv( "#{SportDb::Module::Leagues.root}/config/#{name}.csv" )
147
+ recs.each do |rec|
148
+ zone = UTC.find_zone( rec['zone'] )
149
+ if zone.nil?
150
+ ## raise ArgumentError - invalid zone
151
+ puts "!! ERROR - cannot find timezone in timezone db:"
152
+ pp rec
153
+ exit 1
154
+ end
155
+ ## todo/fix - rename key to (league) code
156
+ zones[ rec['key']] = zone
157
+ end
158
+ end
159
+ zones
160
+ end
161
+
162
+
163
+ ###
164
+ ## map code here - why? why not?
165
+ ## or (always) require canoncial code???
166
+ season = Season( season )
167
+ league_info = LeagueCodes.find_by( code: league, season: season )
168
+
169
+ league_code = if league_info
170
+ ## lookup first try by league+season
171
+ league_info['code'] ## use canonical name
172
+ else
173
+ ## fallback; no league found
174
+ ## or report error in the future - why? why not?
175
+ league.to_s.downcase
176
+ end
177
+
178
+
179
+ ## e.g. world+2022, etc.
180
+ key = "#{league_code}+#{season}"
181
+ zone = @zones[key]
182
+
183
+ ## try league e.g. eng.1 etc.
184
+ zone = @zones[league_code] if zone.nil?
185
+
186
+ ## try first code only (country code )
187
+ if zone.nil?
188
+ code, _ = league_code.split( '.', 2 )
189
+ zone = @zones[code]
190
+ end
191
+
192
+ zone
193
+ end
194
+ end # module TimezoneHelper
195
+
@@ -0,0 +1,24 @@
1
+
2
+ module SportDb
3
+ module Module
4
+ module Leagues
5
+ MAJOR = 0 ## todo: namespace inside version or something - why? why not??
6
+ MINOR = 1
7
+ PATCH = 0
8
+ VERSION = [MAJOR,MINOR,PATCH].join('.')
9
+
10
+ def self.version
11
+ VERSION
12
+ end
13
+
14
+ def self.banner
15
+ "leagues/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in (#{root})"
16
+ end
17
+
18
+ def self.root
19
+ File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
20
+ end
21
+
22
+ end # module Leagues
23
+ end # module Module
24
+ end # module SportDb
data/lib/leagues.rb ADDED
@@ -0,0 +1,63 @@
1
+ require 'cocos'
2
+ require 'season/formats' ## add season support
3
+
4
+
5
+ require 'tzinfo'
6
+
7
+
8
+
9
+
10
+ ## our own code
11
+ require_relative 'leagues/version'
12
+ require_relative 'leagues/league_codes'
13
+
14
+ require_relative 'leagues/leagueset'
15
+
16
+ require_relative 'leagues/timezones'
17
+
18
+
19
+ ###
20
+ ## note - make LeagueCodes "global" by default for now - why? why not?
21
+ LeagueCodes = SportDb::LeagueCodes
22
+ Leagueset = SportDb::Leagueset
23
+ #### add alias - why? why not?
24
+ LeagueSet = Leagueset
25
+
26
+
27
+
28
+ module LeaguesetHelper
29
+ ###
30
+ ### note - make read_leagueset & friends public/global by default - why? why not?
31
+ def read_leagueset( path ) Leagueset.read( path ); end
32
+ def parse_leagueset( txt ) Leagueset.parse( txt ); end
33
+ def parse_leagueset_args( args ) Leagueset.parse_args( args ); end
34
+ end
35
+
36
+
37
+
38
+ module FileHelper
39
+ def find_file( filename, path: )
40
+ path.each do |src_dir|
41
+ path = "#{src_dir}/#{filename}"
42
+ return path if File.exist?( path )
43
+ end
44
+
45
+ ## fix - raise file not found error!!!
46
+ nil ## not found - raise filenot found error - why? why not?
47
+ end
48
+ end
49
+
50
+
51
+
52
+ ####
53
+ ### note - make find_zone! public/global by default - why? why not?
54
+ module Kernel
55
+ include FileHelper
56
+ include LeaguesetHelper
57
+ include TimezoneHelper
58
+ end
59
+
60
+
61
+
62
+
63
+ puts SportDb::Module::Leagues.banner ## say hello
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: leagues
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gerald Bauer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-04-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tzinfo
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
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: season-formats
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cocos
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdoc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '4.0'
62
+ - - "<"
63
+ - !ruby/object:Gem::Version
64
+ version: '7'
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '4.0'
72
+ - - "<"
73
+ - !ruby/object:Gem::Version
74
+ version: '7'
75
+ - !ruby/object:Gem::Dependency
76
+ name: hoe
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '4.2'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '4.2'
89
+ description: leagues - football leagues & timezone helpers
90
+ email: gerald.bauer@gmail.com
91
+ executables: []
92
+ extensions: []
93
+ extra_rdoc_files:
94
+ - CHANGELOG.md
95
+ - Manifest.txt
96
+ - README.md
97
+ files:
98
+ - CHANGELOG.md
99
+ - Manifest.txt
100
+ - README.md
101
+ - Rakefile
102
+ - config/codes_alt.csv
103
+ - config/leagues.csv
104
+ - config/leagues_more.csv
105
+ - config/timezones_africa.csv
106
+ - config/timezones_america.csv
107
+ - config/timezones_asia.csv
108
+ - config/timezones_europe.csv
109
+ - config/timezones_middle_east.csv
110
+ - config/timezones_pacific.csv
111
+ - config/timezones_world.csv
112
+ - lib/leagues.rb
113
+ - lib/leagues/league_codes.rb
114
+ - lib/leagues/leagueset.rb
115
+ - lib/leagues/timezones.rb
116
+ - lib/leagues/version.rb
117
+ homepage: https://github.com/sportdb/sport.db
118
+ licenses:
119
+ - Public Domain
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options:
123
+ - "--main"
124
+ - README.md
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 3.1.0
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubygems_version: 3.5.22
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: leagues - football leagues & timezone helpers
142
+ test_files: []