footty 0.4.1 → 2024.8.28

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 879022e67b5a32b7c48593dbe546a6fc3ceeba3a14bc2e64ecc6e6cea6004b0a
4
- data.tar.gz: b9075358a339760d56d5ac282a71859d1154002100e20b142d4f1dab44562676
3
+ metadata.gz: 2866ba25c1b7a6d08787aaff2bff8821bbc92dada92bcc85ad084b65ceace8b9
4
+ data.tar.gz: bad3de36a89de81e96565aa3c5c245d5cc53b56ea2faddfae38a0e8810f565e2
5
5
  SHA512:
6
- metadata.gz: 12825097748d31665a168847c9aa0c017fbd21cc4353b7d9917ebaf0553ef1b0b7ab34995c7c8f5c8f0da2b7d740ce7c12ac3b7d113bdd85f58f07d480fa41d8
7
- data.tar.gz: 8c7719e5dc9403397c4feaa10886acf04f5d2bc329f81f4a9069948ec4c17f379cab1c836f573099b9968b673b5b152b7e977e9885bf31c348e384e891a114a7
6
+ metadata.gz: fabcae4fbe59527bfb4dc35555d0ffa87271240a8ee385a6ea26842d3d268d58b4d6109ebee9159c362b1327447e5d36fae63b2e51f07931d32e5578103d7a70
7
+ data.tar.gz: df46117a0ab611d90315a17525308f71bd82aac6b00c2a07388e115d92381efdf2f8d339e98311278a80b8b68e3f83283b2eaef3d9ee7ab2c01f753a252d90c5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,4 @@
1
- ### 1.0.0 / 2018-06-09
2
-
3
- * Everything is new (again). First release.
1
+ ### 2024.8.28
2
+ ### 1.0.0 / 2018-06-09
3
+
4
+ * Everything is new (again). First release.
data/Manifest.txt CHANGED
@@ -3,9 +3,7 @@ Manifest.txt
3
3
  README.md
4
4
  Rakefile
5
5
  bin/footty
6
+ bin/ftty
6
7
  lib/footty.rb
7
- lib/footty/client.rb
8
+ lib/footty/dataset.rb
8
9
  lib/footty/version.rb
9
- test/helper.rb
10
- test/test_client_euro.rb
11
- test/test_client_worldcup.rb
data/README.md CHANGED
@@ -1,86 +1,74 @@
1
- # footty - football.db command line client for european ("euro") championship 2020 (in 2021) and more
2
-
3
- * home :: [github.com/sportdb/footty](https://github.com/sportdb/footty)
4
- * bugs :: [github.com/sportdb/footty/issues](https://github.com/sportdb/footty/issues)
5
- * gem :: [rubygems.org/gems/footty](https://rubygems.org/gems/footty)
6
- * rdoc :: [rubydoc.info/gems/footty](http://rubydoc.info/gems/footty)
7
- * forum :: [opensport](http://groups.google.com/group/opensport)
8
-
9
-
10
-
11
-
12
-
13
- ## Usage - Who's playing today?
14
-
15
- The footty command line tool lets you query the online football.db HTTP JSON API services
16
- for upcoming or past matches. For example:
17
-
18
- $ footty # Defaults to today's euro 2020 (in 2021) matches
19
-
20
- prints on Jun/14 2021:
21
-
22
- #20 Mon Jun/14 Scotland (SCO) vs Czech Republic (CZE) Group D / Matchday 1
23
- #25 Mon Jun/14 Poland (POL) vs Slovakia (SVK) Group E / Matchday 1
24
- #26 Mon Jun/14 Spain (ESP) vs Sweden (SWE) Group E / Matchday 1
25
-
26
- and the next day with `footty yesterday`:
27
-
28
- #20 Mon Jun/14 Scotland (SCO) 0-2 (0-1) Czech Republic (CZE) Group D / Matchday 1
29
- #25 Mon Jun/14 Poland (POL) 1-2 (0-1) Slovakia (SVK) Group E / Matchday 1
30
- #26 Mon Jun/14 Spain (ESP) 0-0 Sweden (SWE) Group E / Matchday 1
31
-
32
- prints on Jun/15 2021:
33
-
34
- #31 Tue Jun/15 Hungary (HUN) vs Portugal (POR) Group F / Matchday 1
35
- #32 Tue Jun/15 France (FRA) vs Germany (GER) Group F / Matchday 1
36
-
37
- and so on.
38
- Use `tomorrow` or `t` or `+1` to print tomorrow's matches e.g.:
39
-
40
- $ footty tomorrow # -or-
41
- $ footty t
42
-
43
- Use `yesterday` or `y` or `-1` to print yesterday's matches e.g.:
44
-
45
- $ footty yesterday # -or-
46
- $ footty y
47
-
48
- Use `upcoming` or `up` or `u` to print all upcoming matches e.g.:
49
-
50
- $ footty upcoming # -or-
51
- $ footty up
52
-
53
- Use `past` or `p` to print all past matches e.g.:
54
-
55
- $ footty past # -or-
56
- $ footty p
57
-
58
-
59
- That's it. Enjoy the beautiful game.
60
-
61
-
62
-
63
-
64
- ## Trivia
65
-
66
- Why tty? tty stands for teletype (tty) writer and is the old traditional (short) name for the unix command line.
67
-
68
-
69
- ## Install
70
-
71
- Just install the gem:
72
-
73
- $ gem install footty
74
-
75
-
76
- ## License
77
-
78
- The `footty` scripts are dedicated to the public domain.
79
- Use it as you please with no restrictions whatsoever.
80
-
81
-
82
- ## Questions? Comments?
83
-
84
- Send them along to the
85
- [Open Sports & Friends Forum/Mailing List](http://groups.google.com/group/opensport).
86
- Thanks!
1
+ # footty - football.db command line client for european ("euro") championship 2024 and more
2
+
3
+ * home :: [github.com/sportdb/footty](https://github.com/sportdb/footty)
4
+ * bugs :: [github.com/sportdb/footty/issues](https://github.com/sportdb/footty/issues)
5
+ * gem :: [rubygems.org/gems/footty](https://rubygems.org/gems/footty)
6
+ * rdoc :: [rubydoc.info/gems/footty](http://rubydoc.info/gems/footty)
7
+
8
+
9
+
10
+
11
+
12
+ ## Usage - Who's playing today?
13
+
14
+ The footty command line tool lets you query the online football.db HTTP JSON API services
15
+ for upcoming or past matches. For example:
16
+
17
+ $ footty # Defaults to today's euro 2024 matches
18
+
19
+ prints on Jun/14 2024:
20
+
21
+ #1 Fri Jun/14 Germany (GER) vs Scotland (SCO) Group A / Matchday 1
22
+
23
+ Use `tomorrow` or `t` or `+1` to print tomorrow's matches e.g.:
24
+
25
+ $ footty tomorrow # -or-
26
+ $ footty t
27
+
28
+ Use `yesterday` or `y` or `-1` to print yesterday's matches e.g.:
29
+
30
+ $ footty yesterday # -or-
31
+ $ footty y
32
+
33
+ Use `upcoming` or `up` or `u` to print all upcoming matches e.g.:
34
+
35
+ $ footty upcoming # -or-
36
+ $ footty up
37
+
38
+ Use `past` or `p` to print all past matches e.g.:
39
+
40
+ $ footty past # -or-
41
+ $ footty p
42
+
43
+
44
+ That's it. Enjoy the beautiful game.
45
+
46
+
47
+
48
+
49
+ ## Trivia
50
+
51
+ Why tty? tty stands for teletype (tty) writer and is the old traditional (short) name for the unix command line.
52
+
53
+
54
+ ## Install
55
+
56
+ Just install the gem:
57
+
58
+ $ gem install footty
59
+
60
+
61
+ ## License
62
+
63
+ The `footty` scripts are dedicated to the public domain.
64
+ Use it as you please with no restrictions whatsoever.
65
+
66
+
67
+
68
+
69
+
70
+ ## Questions? Comments?
71
+
72
+ Yes, you can. More than welcome.
73
+ See [Help & Support »](https://github.com/openfootball/help)
74
+
data/Rakefile CHANGED
@@ -1,30 +1,29 @@
1
- require 'hoe'
2
- require './lib/footty/version.rb'
3
-
4
- Hoe.spec 'footty' do
5
-
6
- self.version = Footty::VERSION
7
-
8
- self.summary = 'footty - football.db command line client for european "euro" championship 2020 (in 2021) and more - who is playing today?'
9
- self.description = summary
10
-
11
- self.urls = { home: 'https://github.com/sportdb/footty' }
12
-
13
- self.author = 'Gerald Bauer'
14
- self.email = 'opensport@googlegroups.com'
15
-
16
- # switch extension to .markdown for gihub formatting
17
- self.readme_file = 'README.md'
18
- self.history_file = 'CHANGELOG.md'
19
-
20
- self.extra_deps = [
21
- ['logutils' ],
22
- ['fetcher']
23
- ]
24
-
25
- self.licenses = ['Public Domain']
26
-
27
- self.spec_extras = {
28
- required_ruby_version: '>= 2.3'
29
- }
30
- end
1
+ require 'hoe'
2
+ require './lib/footty/version.rb'
3
+
4
+ Hoe.spec 'footty' do
5
+
6
+ self.version = Footty::VERSION
7
+
8
+ self.summary = 'footty - football.db command line client for european "euro" championship 2024 and more - who is playing today?'
9
+ self.description = summary
10
+
11
+ self.urls = { home: 'https://github.com/sportdb/footty' }
12
+
13
+ self.author = 'Gerald Bauer'
14
+ self.email = 'gerald.bauer@gmail.com'
15
+
16
+ # switch extension to .markdown for gihub formatting
17
+ self.readme_file = 'README.md'
18
+ self.history_file = 'CHANGELOG.md'
19
+
20
+ self.extra_deps = [
21
+ ['sportdb-quick']
22
+ ]
23
+
24
+ self.licenses = ['Public Domain']
25
+
26
+ self.spec_extras = {
27
+ required_ruby_version: '>= 3.1.0'
28
+ }
29
+ end
data/bin/footty CHANGED
@@ -1,5 +1,8 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'footty'
4
-
5
- Footty.main
1
+ #!/usr/bin/env ruby
2
+
3
+ ## tip: to test run:
4
+ ## ruby -I ./lib bin/footty
5
+
6
+ require 'footty'
7
+
8
+ Footty.main
data/bin/ftty ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ## tip: to test run:
4
+ ## ruby -I ./lib bin/ftty
5
+
6
+ require 'footty'
7
+
8
+ Footty.main
@@ -0,0 +1,142 @@
1
+ module Footty
2
+
3
+
4
+
5
+ class Dataset
6
+
7
+ def initialize( league:, year: )
8
+ @league = league
9
+ @year = year
10
+ @season = Season( "#{year}/#{year+1}" )
11
+ end
12
+
13
+
14
+ APIS = {
15
+ world: 'https://raw.githubusercontent.com/openfootball/worldcup.json/master/$year$/worldcup.json',
16
+ euro: 'https://raw.githubusercontent.com/openfootball/euro.json/master/$year$/euro.json',
17
+ de: 'https://raw.githubusercontent.com/openfootball/deutschland/master/$season$/1-bundesliga.txt',
18
+ en: 'https://raw.githubusercontent.com/openfootball/england/master/$season$/1-premierleague.txt',
19
+ at: 'https://raw.githubusercontent.com/openfootball/austria/master/$season$/1-bundesliga-i.txt',
20
+ }
21
+
22
+ ### note:
23
+ ## cache ALL methods - only do one web request for match schedule & results
24
+ def matches
25
+ @data ||= begin
26
+ url = APIS[ @league.downcase.to_sym ]
27
+ url = url.gsub( '$year$', @year.to_s )
28
+ url = url.gsub( '$season$', @season.to_path )
29
+
30
+ res = get!( url ) ## use "memoized" / cached result
31
+ if url.end_with?( '.json' )
32
+ JSON.parse( res.text )
33
+ else ## assume football.txt format
34
+ matches = SportDb::QuickMatchReader.parse( res.text )
35
+ data = matches.map {|match| match.as_json } # convert to json
36
+ ## quick hack to get keys as strings not symbols!!
37
+ ## fix upstream
38
+ JSON.parse( JSON.generate( data ))
39
+ end
40
+ end
41
+ end
42
+
43
+ def end_date
44
+ @end_date ||= begin
45
+ end_date = nil
46
+ each do |match|
47
+ date = Date.strptime(match['date'], '%Y-%m-%d' )
48
+ end_date = date if end_date.nil? ||
49
+ date > end_date
50
+ end
51
+ end_date
52
+ end
53
+ end
54
+
55
+ def start_date
56
+ @start_date ||= begin
57
+ start_date = nil
58
+ each do |match|
59
+ date = Date.strptime(match['date'], '%Y-%m-%d' )
60
+ start_date = date if start_date.nil? ||
61
+ date < start_date
62
+ end
63
+ start_date
64
+ end
65
+ end
66
+
67
+ def todays_matches( date: Date.today ) matches_for( date ); end
68
+ def tomorrows_matches( date: Date.today ) matches_for( date+1 ); end
69
+ def yesterdays_matches( date: Date.today ) matches_for( date-1 ); end
70
+
71
+ def matches_for( date )
72
+ matches = select_matches { |match| date == Date.parse( match['date'] ) }
73
+ matches
74
+ end
75
+
76
+
77
+ def upcoming_matches( date: Date.today,
78
+ limit: nil )
79
+ ## note: includes todays matches for now
80
+ matches = select_matches { |match| date <= Date.parse( match['date'] ) }
81
+
82
+ if limit
83
+ matches[0, limit] ## cut-off
84
+ else
85
+ matches
86
+ end
87
+ end
88
+
89
+ def past_matches( date: Date.today )
90
+ matches = select_matches { |match| date > Date.parse( match['date'] ) }
91
+ ## note reveserve matches (chronological order/last first)
92
+ matches.reverse
93
+ end
94
+
95
+
96
+ private
97
+ def each
98
+ data = matches
99
+ if data.is_a?( Hash) && data.has_key?('rounds')
100
+ data['rounds'].each do |round|
101
+ round['matches'].each do |match|
102
+ ## hack: add (outer) round to match
103
+ match['round'] = round['name']
104
+ yield( match )
105
+ end
106
+ end
107
+ else ## assume flat matches in Array
108
+ data.each do |match|
109
+ yield( match )
110
+ end
111
+ end
112
+ end
113
+
114
+
115
+ def select_matches
116
+ matches = []
117
+ each do |match|
118
+ matches << match if yield( match )
119
+ end
120
+
121
+ ## todo/fix:
122
+ ## sort matches here; might not be chronologicial (by default)
123
+ matches
124
+ end # method select_matches
125
+
126
+
127
+ def get!( url )
128
+ response = Webclient.get( url )
129
+
130
+ if response.status.ok?
131
+ response
132
+ else
133
+ puts "!! HTTP ERROR - #{response.status.code} #{response.status.message}"
134
+ ## dump headers
135
+ response.headers.each do |key,value|
136
+ puts " #{key}: #{value}"
137
+ end
138
+ exit 1
139
+ end
140
+ end # method get!
141
+ end # class Client
142
+ end # module Footty
@@ -1,14 +1,14 @@
1
-
2
- module Footty
3
- VERSION = '0.4.1'
4
-
5
- def self.banner
6
- "footty/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in (#{root})"
7
- end
8
-
9
- def self.root
10
- File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
11
- end
12
- end
13
-
14
-
1
+
2
+ module Footty
3
+ VERSION = '2024.8.28'
4
+
5
+ def self.banner
6
+ "footty/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in (#{root})"
7
+ end
8
+
9
+ def self.root
10
+ File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
11
+ end
12
+ end
13
+
14
+
data/lib/footty.rb CHANGED
@@ -1,160 +1,187 @@
1
- ## stdlibs
2
-
3
- require 'net/http'
4
- require 'uri'
5
- require 'json'
6
- require 'pp'
7
-
8
-
9
- ## 3rd party gems/libs
10
- ## require 'props'
11
-
12
- require 'logutils'
13
- require 'fetcher'
14
-
15
-
16
- # our own code
17
- require 'footty/version' # let it always go first
18
- require 'footty/client'
19
-
20
-
21
- module Footty
22
-
23
- def self.client
24
- ## note: hard code tournament / league for now
25
- @client ||= Client.new( league: 'euro', year: 2020 ) ## use "singelton" / shared client
26
- end
27
-
28
-
29
-
30
- def self.main
31
- puts banner # say hello
32
-
33
- what = ARGV[0] || 'today'
34
- what = what.downcase
35
-
36
- ## in the future make today "configurable" as param - why? why not?
37
- today = Date.today
38
-
39
- if ['yesterday', 'y', '-1'].include?( what )
40
- matches = client.yesterdays_matches
41
- if matches.empty?
42
- puts "** No matches played yesterday.\n"
43
- end
44
- elsif ['tomorrow', 't', '+1', '1'].include?( what )
45
- matches = client.tomorrows_matches
46
- if matches.empty?
47
- puts "** No matches scheduled tomorrow.\n"
48
- end
49
- elsif ['past', 'p', 'prev'].include?( what )
50
- matches = client.past_matches
51
- if matches.empty?
52
- puts "** No matches played yet.\n"
53
- end
54
- elsif ['upcoming', 'up', 'u', 'next', 'n'].include?( what )
55
- matches = client.upcoming_matches
56
- if matches.empty?
57
- puts "** No more matches scheduled.\n"
58
- end
59
- else
60
- matches = client.todays_matches
61
-
62
- ## no matches today
63
- if matches.empty?
64
- puts "** No matches scheduled today.\n"
65
-
66
- ## note: was world cup 2018 - end date -- Date.new( 2018, 7, 11 )
67
- if Date.today > Date.new( 2021, 7, 11 ) ## tournament is over, look back
68
- puts "Past matches:"
69
- matches = client.past_matches
70
- else ## world cup is upcoming /in-progress,look forward
71
- puts "Upcoming matches:"
72
- matches = client.upcoming_matches
73
- end
74
- end
75
- end
76
-
77
-
78
-
79
- print_matches( matches )
80
- end
81
-
82
-
83
-
84
- def self.print_matches( matches )
85
- ## print games
86
-
87
- today = Date.today
88
-
89
- matches.each do |match|
90
- print " %5s" % "\##{match['num']} "
91
-
92
- date = Date.parse( match['date'] )
93
- print "#{date.strftime('%a %b/%d')} " ## e.g. Thu Jun/14
94
- if date > today
95
- diff = (date - today).to_i
96
- print "%10s" % "(in #{diff}d) "
97
- end
98
-
99
- print "%22s" % "#{match['team1']['name']} (#{match['team1']['code']})"
100
-
101
- ## todo/fix: add support for knockout scores
102
- ## with score1et/score1p (extra time and penalty)
103
- if match['score1'] && match['score2']
104
- print " #{match['score1']}-#{match['score2']} "
105
- print "(#{match['score1i']}-#{match['score2i']}) "
106
- else
107
- print " vs "
108
- end
109
-
110
- print "%-22s" % "#{match['team2']['name']} (#{match['team2']['code']})"
111
-
112
- if match['group']
113
- print " #{match['group']} /" ## group phase/stage
114
- end
115
-
116
- print " #{match['round']} " ## knock out (k.o.) phase/stage
117
-
118
- if match['stadium']
119
- print " @ #{match['stadium']['name']}, #{match['city']}"
120
- end
121
-
122
- print "\n"
123
-
124
-
125
- if match['goals1'] && match['goals2']
126
- print " ["
127
- match['goals1'].each_with_index do |goal,i|
128
- print " " if i > 0
129
- print "#{goal['name']}"
130
- print " #{goal['minute']}"
131
- print "+#{goal['offset']}" if goal['offset']
132
- print "'"
133
- print " (o.g.)" if goal['owngoal']
134
- print " (pen.)" if goal['penalty']
135
- end
136
- match['goals2'].each_with_index do |goal,i|
137
- if i == 0
138
- print "; "
139
- else
140
- print " "
141
- end
142
- print "#{goal['name']}"
143
- print " #{goal['minute']}"
144
- print "+#{goal['offset']}" if goal['offset']
145
- print "'"
146
- print " (o.g.)" if goal['owngoal']
147
- print " (pen.)" if goal['penalty']
148
- end
149
- print "]\n"
150
- end
151
-
152
-
153
- end
154
- end
155
-
156
- end # module Footty
157
-
158
-
159
-
160
- Footty.main if __FILE__ == $0
1
+ require 'sportdb/quick' ## note - pulls in cocos et al
2
+
3
+
4
+ # our own code
5
+ require_relative 'footty/version' # let it always go first
6
+ require_relative 'footty/dataset'
7
+
8
+
9
+ module Footty
10
+
11
+ def self.main
12
+ puts banner # say hello
13
+
14
+ league = 'en'
15
+ year = 2024
16
+
17
+ ## filter ARGV for league or year
18
+ args = ARGV.select do |arg|
19
+ if arg =~ /^\d{4}$/
20
+ year = arg.to_i(10)
21
+ false ## eat-up
22
+ elsif ['world',
23
+ 'euro',
24
+ 'de',
25
+ 'en',
26
+ 'at'].include?( arg )
27
+ league = arg
28
+ false
29
+ else
30
+ true
31
+ end
32
+ end
33
+
34
+
35
+ what = args[0] || 'today'
36
+ what = what.downcase
37
+
38
+
39
+ # Dataset.new( league: 'euro', year: 2024 )
40
+ dataset = Dataset.new( league: league, year: year )
41
+
42
+
43
+ ## in the future make today "configurable" as param - why? why not?
44
+ today = Date.today
45
+
46
+ if ['yesterday', 'y', '-1'].include?( what )
47
+ matches = dataset.yesterdays_matches
48
+ if matches.empty?
49
+ puts "** No matches played yesterday.\n"
50
+ end
51
+ elsif ['tomorrow', 't', '+1', '1'].include?( what )
52
+ matches = dataset.tomorrows_matches
53
+ if matches.empty?
54
+ puts "** No matches scheduled tomorrow.\n"
55
+ end
56
+ elsif ['past', 'p', 'prev'].include?( what )
57
+ matches = dataset.past_matches
58
+ if matches.empty?
59
+ puts "** No matches played yet.\n"
60
+ end
61
+ elsif ['upcoming', 'up', 'u', 'next', 'n'].include?( what )
62
+ matches = dataset.upcoming_matches
63
+ if matches.empty?
64
+ puts "** No more matches scheduled.\n"
65
+ end
66
+ else
67
+ matches = dataset.todays_matches
68
+
69
+ ## no matches today
70
+ if matches.empty?
71
+ puts "** No matches scheduled today.\n"
72
+
73
+ ## note: was world cup 2018 - end date -- Date.new( 2018, 7, 11 )
74
+ ## note: was euro 2020 (in 2021) - end date -- Date.new( 2021, 7, 11 )
75
+ if Date.today > dataset.end_date ## tournament is over, look back
76
+ puts "Past matches:"
77
+ matches = dataset.past_matches
78
+ else ## world cup is upcoming /in-progress,look forward
79
+ puts "Upcoming matches:"
80
+ matches = dataset.upcoming_matches( limit: 18 )
81
+ end
82
+ end
83
+ end
84
+
85
+ print_matches( matches )
86
+ end
87
+
88
+
89
+ def self.print_matches( matches )
90
+ ## print games
91
+
92
+ today = Date.today
93
+
94
+ matches.each do |match|
95
+ print " %5s" % "\##{match['num']} " if match['num']
96
+
97
+ date = Date.strptime( match['date'], '%Y-%m-%d' )
98
+ print "#{date.strftime('%a %b/%d')} " ## e.g. Thu Jun/14
99
+ print "#{match['time']} " if match['time']
100
+
101
+ if date > today
102
+ diff = (date - today).to_i
103
+ print "%10s" % "(in #{diff}d) "
104
+ end
105
+
106
+
107
+ if match['team1'].is_a?( Hash )
108
+ print "%22s" % "#{match['team1']['name']} (#{match['team1']['code']})"
109
+ else
110
+ print "%22s" % "#{match['team1']}"
111
+ end
112
+
113
+
114
+ if match['score'].is_a?( Hash ) &&
115
+ match['score']['ft']
116
+ if match['score']['ft']
117
+ print " #{match['score']['ft'][0]}-#{match['score']['ft'][1]} "
118
+ end
119
+ if match['score']['et']
120
+ print "aet #{match['score']['et'][0]}-#{match['score']['et'][1]} "
121
+ end
122
+ if match['score']['p']
123
+ print "pen #{match['score']['p'][0]}-#{match['score']['p'][1]} "
124
+ end
125
+ elsif match['score1'] && match['score2']
126
+ ## todo/fix: add support for knockout scores
127
+ ## with score1et/score1p (extra time and penalty)
128
+ print " #{match['score1']}-#{match['score2']} "
129
+ print "(#{match['score1i']}-#{match['score2i']}) "
130
+ else
131
+ print " vs "
132
+ end
133
+
134
+ if match['team2'].is_a?( Hash )
135
+ print "%-22s" % "#{match['team2']['name']} (#{match['team2']['code']})"
136
+ else
137
+ print "%-22s" % "#{match['team2']}"
138
+ end
139
+
140
+
141
+ if match['group']
142
+ print " #{match['group']} /" ## group phase/stage
143
+ end
144
+
145
+ print " #{match['round']} " ## knock out (k.o.) phase/stage
146
+
147
+ if match['stadium']
148
+ print " @ #{match['stadium']['name']}, #{match['city']}"
149
+ end
150
+
151
+ print "\n"
152
+
153
+
154
+ if match['goals1'] && match['goals2']
155
+ print " ["
156
+ match['goals1'].each_with_index do |goal,i|
157
+ print " " if i > 0
158
+ print "#{goal['name']}"
159
+ print " #{goal['minute']}"
160
+ print "+#{goal['offset']}" if goal['offset']
161
+ print "'"
162
+ print " (o.g.)" if goal['owngoal']
163
+ print " (pen.)" if goal['penalty']
164
+ end
165
+ match['goals2'].each_with_index do |goal,i|
166
+ if i == 0
167
+ print "; "
168
+ else
169
+ print " "
170
+ end
171
+ print "#{goal['name']}"
172
+ print " #{goal['minute']}"
173
+ print "+#{goal['offset']}" if goal['offset']
174
+ print "'"
175
+ print " (o.g.)" if goal['owngoal']
176
+ print " (pen.)" if goal['penalty']
177
+ end
178
+ print "]\n"
179
+ end
180
+ end
181
+ end
182
+
183
+ end # module Footty
184
+
185
+
186
+
187
+ Footty.main if __FILE__ == $0
metadata CHANGED
@@ -1,31 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: footty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 2024.8.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-15 00:00:00.000000000 Z
11
+ date: 2024-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: logutils
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: fetcher
14
+ name: sportdb-quick
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - ">="
@@ -64,19 +50,20 @@ dependencies:
64
50
  requirements:
65
51
  - - "~>"
66
52
  - !ruby/object:Gem::Version
67
- version: '3.22'
53
+ version: '4.1'
68
54
  type: :development
69
55
  prerelease: false
70
56
  version_requirements: !ruby/object:Gem::Requirement
71
57
  requirements:
72
58
  - - "~>"
73
59
  - !ruby/object:Gem::Version
74
- version: '3.22'
60
+ version: '4.1'
75
61
  description: footty - football.db command line client for european "euro" championship
76
- 2020 (in 2021) and more - who is playing today?
77
- email: opensport@googlegroups.com
62
+ 2024 and more - who is playing today?
63
+ email: gerald.bauer@gmail.com
78
64
  executables:
79
65
  - footty
66
+ - ftty
80
67
  extensions: []
81
68
  extra_rdoc_files:
82
69
  - CHANGELOG.md
@@ -88,12 +75,10 @@ files:
88
75
  - README.md
89
76
  - Rakefile
90
77
  - bin/footty
78
+ - bin/ftty
91
79
  - lib/footty.rb
92
- - lib/footty/client.rb
80
+ - lib/footty/dataset.rb
93
81
  - lib/footty/version.rb
94
- - test/helper.rb
95
- - test/test_client_euro.rb
96
- - test/test_client_worldcup.rb
97
82
  homepage: https://github.com/sportdb/footty
98
83
  licenses:
99
84
  - Public Domain
@@ -108,16 +93,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
108
93
  requirements:
109
94
  - - ">="
110
95
  - !ruby/object:Gem::Version
111
- version: '2.3'
96
+ version: 3.1.0
112
97
  required_rubygems_version: !ruby/object:Gem::Requirement
113
98
  requirements:
114
99
  - - ">="
115
100
  - !ruby/object:Gem::Version
116
101
  version: '0'
117
102
  requirements: []
118
- rubygems_version: 3.1.4
103
+ rubygems_version: 3.4.10
119
104
  signing_key:
120
105
  specification_version: 4
121
106
  summary: footty - football.db command line client for european "euro" championship
122
- 2020 (in 2021) and more - who is playing today?
107
+ 2024 and more - who is playing today?
123
108
  test_files: []
data/lib/footty/client.rb DELETED
@@ -1,106 +0,0 @@
1
- module Footty
2
-
3
-
4
- class Client
5
-
6
- include LogUtils::Logging
7
-
8
-
9
- def initialize( league:, year: )
10
- @worker = Fetcher::Worker.new
11
-
12
- @league = league
13
- @year = year
14
- end
15
-
16
-
17
- APIS = {
18
- worldcup: 'https://github.com/openfootball/worldcup.json/raw/master/$year$/worldcup.json',
19
- euro: 'https://github.com/openfootball/euro.json/raw/master/$year$/euro.json'
20
- }
21
-
22
- ### note:
23
- ## cache ALL methods - only do one web request for match schedule & results
24
- def get_matches
25
- @data ||= begin
26
- str = APIS[ @league.downcase.to_sym ]
27
- str = str.gsub( '$year$', @year.to_s )
28
-
29
- get( str ) ## use "memoized" / cached result
30
- end
31
- end
32
-
33
-
34
-
35
-
36
- ## for testing lets you use /round/1 etc.
37
- def round( num )
38
- h = get_matches
39
- matches = h[ 'rounds' ][ num-1 ] ## note: rounds hash starts with zero (not 1)
40
- matches
41
- end
42
-
43
-
44
- def todays_matches( date: Date.today ) matches_for( date ); end
45
- def tomorrows_matches( date: Date.today ) matches_for( date+1 ); end
46
- def yesterdays_matches( date: Date.today ) matches_for( date-1 ); end
47
-
48
- def matches_for( date )
49
- hash = get_matches
50
- matches = select_matches( hash[ 'rounds' ] ) { |match| date == Date.parse( match['date'] ) }
51
- matches
52
- end
53
-
54
-
55
- def upcoming_matches( date: Date.today )
56
- ## note: includes todays matches for now
57
- hash = get_matches
58
- matches = select_matches( hash[ 'rounds' ] ) { |match| date <= Date.parse( match['date'] ) }
59
- matches
60
- end
61
-
62
- def past_matches( date: Date.today )
63
- hash = get_matches
64
- matches = select_matches( hash[ 'rounds' ] ) { |match| date > Date.parse( match['date'] ) }
65
- ## note reveserve matches (chronological order/last first)
66
- matches.reverse
67
- end
68
-
69
- private
70
-
71
- def select_matches( rounds )
72
- matches = []
73
- rounds.each do |round|
74
- round['matches'].each do |match|
75
- if yield( match )
76
- ## hack: add (outer) round to match
77
- match['round'] = round['name']
78
- matches << match
79
- else
80
- ## puts " skipping game play_date #{play_date}"
81
- end
82
- end
83
- end
84
- matches
85
- end
86
-
87
-
88
- def get( str )
89
- response = @worker.get_response( str )
90
-
91
- if response.code == '200'
92
- ##
93
- ## fix/fix/todo/check:
94
- ## do we need to force utf-8 encoding? yes!!!!
95
- ## check for teams w/ non-ascii names
96
- hash = JSON.parse( response.body )
97
- ## pp hash
98
- hash
99
- else
100
- logger.error "fetch HTTP - #{response.code} #{response.message}"
101
- nil
102
- end
103
- end
104
-
105
- end # class Client
106
- end # module Footty
data/test/helper.rb DELETED
@@ -1,10 +0,0 @@
1
- ## $:.unshift(File.dirname(__FILE__))
2
-
3
- ## minitest setup
4
-
5
- require 'minitest/autorun'
6
-
7
-
8
- ## our own code
9
-
10
- require 'footty'
@@ -1,103 +0,0 @@
1
- ###
2
- # to run use
3
- # ruby -I ./lib -I ./test test/test_client_euro.rb
4
-
5
- require 'helper'
6
-
7
-
8
-
9
- class TestClientEuro < MiniTest::Test
10
-
11
- def setup
12
- @client = Footty::Client.new( league: 'euro', year: 2020 )
13
- end
14
-
15
-
16
- def test_getters
17
- today = Date.new( 2021, 6, 15 )
18
-
19
- todays = @client.todays_matches( date: today )
20
- pp todays
21
- assert_equal 2, todays.size
22
-
23
- yesterdays = @client.yesterdays_matches( date: today )
24
- pp yesterdays
25
- assert_equal 3, yesterdays.size
26
-
27
- tomorrows = @client.tomorrows_matches( date: today )
28
- pp tomorrows
29
- assert_equal 3, tomorrows.size
30
-
31
- past = @client.past_matches( date: today )
32
- pp past
33
-
34
- upcoming = @client.upcoming_matches( date: today )
35
- pp upcoming
36
- end
37
-
38
-
39
- def test_todays_matches_2021_6_15
40
- today = Date.new( 2021, 6, 15 )
41
- ary = @client.todays_matches( date: today )
42
- pp ary
43
- =begin
44
- [{"num"=>31,
45
- "date"=>"2021-06-15",
46
- "team1"=>{"name"=>"Hungary", "code"=>"HUN"},
47
- "team2"=>{"name"=>"Portugal", "code"=>"POR"},
48
- "score1"=>nil,
49
- "score2"=>nil,
50
- "score1i"=>nil,
51
- "score2i"=>nil,
52
- "group"=>"Group F",
53
- "round"=>"Matchday 1"},
54
- ...
55
- =end
56
-
57
- assert_equal Array, ary.class ## for now just check return type (e.g. assume Array for parsed JSON data)
58
- assert_equal 2, ary.size
59
- assert_equal 'HUN', ary[0]['team1']['code']
60
- assert_equal 'POR', ary[0]['team2']['code']
61
- assert_equal 'Matchday 1', ary[0]['round']
62
- # assert_equal 5, ary[0]['score1']
63
- # assert_equal 0, ary[0]['score2']
64
- end
65
-
66
-
67
- def test_todays_matches_2021_6_10
68
- today = Date.new( 2021, 6, 10 )
69
- ary = @client.todays_matches( date: today )
70
- ## note: returns empty array if no matches scheduled/playing today
71
- pp ary
72
-
73
- assert_equal Array, ary.class ## for now just check return type (e.g. assume Array for parsed JSON data)
74
- assert ary.empty?
75
- end
76
-
77
-
78
- def test_euro_round_1
79
- h = @client.round( 1 )
80
-
81
- pp h
82
- =begin
83
- {"name"=>"Matchday 1",
84
- "matches"=>
85
- [{"num"=>1,
86
- "date"=>"2021-06-11",
87
- "team1"=>{"name"=>"Turkey", "code"=>"TUR"},
88
- "team2"=>{"name"=>"Italy", "code"=>"ITA"},
89
- "score1"=>0,
90
- "score2"=>3,
91
- "score1i"=>0,
92
- "score2i"=>0,
93
- "group"=>"Group A"},
94
- =end
95
-
96
- assert_equal 'TUR', h['matches'][0]['team1']['code']
97
- assert_equal 'ITA', h['matches'][0]['team2']['code']
98
- assert_equal 0, h['matches'][0]['score1']
99
- assert_equal 3, h['matches'][0]['score2']
100
- end
101
-
102
-
103
- end # class TestClientEuro
@@ -1,164 +0,0 @@
1
- ###
2
- # to run use
3
- # ruby -I ./lib -I ./test test/test_client_worldcup.rb
4
-
5
- require 'helper'
6
-
7
-
8
-
9
- class TestClientWorldCup < MiniTest::Test
10
-
11
- def setup
12
- @client = Footty::Client.new( league: 'worldcup', year: 2018 )
13
- end
14
-
15
-
16
- def test_getters
17
- today = Date.new( 2018, 6, 16 )
18
-
19
- todays = @client.todays_matches( date: today )
20
- pp todays
21
- assert_equal 4, todays.size
22
-
23
- yesterdays = @client.yesterdays_matches( date: today )
24
- pp yesterdays
25
- assert_equal 3, yesterdays.size
26
-
27
- tomorrows = @client.tomorrows_matches( date: today )
28
- pp tomorrows
29
- assert_equal 3, tomorrows.size
30
-
31
- past = @client.past_matches( date: today )
32
- pp past
33
-
34
- upcoming = @client.upcoming_matches( date: today )
35
- pp upcoming
36
- end
37
-
38
-
39
-
40
- def test_todays_matches_2018_6_14
41
- today = Date.new( 2018, 6, 14 )
42
- ary = @client.todays_matches( date: today )
43
- ## pp ary
44
- =begin
45
- [{"num"=>1,
46
- "date"=>"2018-06-14",
47
- "time"=>"18:00",
48
- "team1"=>{"name"=>"Russia", "code"=>"RUS"},
49
- "team2"=>{"name"=>"Saudi Arabia", "code"=>"KSA"},
50
- "score1"=>nil,
51
- "score2"=>nil,
52
- "score1i"=>nil,
53
- "score2i"=>nil,
54
- "group"=>"Group A",
55
- "stadium"=>{"key"=>"luzhniki", "name"=>"Luzhniki Stadium"},
56
- "city"=>"Moscow",
57
- "timezone"=>"UTC+3",
58
- "round"=>"Matchday 1"}]
59
- =end
60
-
61
- assert_equal Array, ary.class ## for now just check return type (e.g. assume Array for parsed JSON data)
62
- assert_equal 1, ary.size
63
- assert_equal 'RUS', ary[0]['team1']['code']
64
- assert_equal 'KSA', ary[0]['team2']['code']
65
- assert_equal 'Matchday 1', ary[0]['round']
66
- assert_equal 5, ary[0]['score1']
67
- assert_equal 0, ary[0]['score2']
68
- end
69
-
70
- def test_todays_matches_2018_6_10
71
- today = Date.new( 2018, 6, 10 )
72
- ary = @client.todays_matches( date: today )
73
- ## note: returns empty array if no matches scheduled/playing today
74
- pp ary
75
-
76
- assert_equal Array, ary.class ## for now just check return type (e.g. assume Array for parsed JSON data)
77
- assert ary.empty?
78
- end
79
-
80
- def test_world_2018_round_1
81
- h = @client.round( 1 )
82
-
83
- ## pp h
84
- =begin
85
- {"name"=>"Matchday 1",
86
- "matches"=>
87
- [{"num"=>1,
88
- "date"=>"2018-06-14",
89
- "time"=>"18:00",
90
- "team1"=>{"name"=>"Russia", "code"=>"RUS"},
91
- "team2"=>{"name"=>"Saudi Arabia", "code"=>"KSA"},
92
- "score1"=>nil,
93
- "score2"=>nil,
94
- "score1i"=>nil,
95
- "score2i"=>nil,
96
- "group"=>"Group A",
97
- "stadium"=>{"key"=>"luzhniki", "name"=>"Luzhniki Stadium"},
98
- "city"=>"Moscow",
99
- "timezone"=>"UTC+3"}]}
100
- =end
101
-
102
- assert_equal 'RUS', h['matches'][0]['team1']['code']
103
- assert_equal 'KSA', h['matches'][0]['team2']['code']
104
- assert_equal 5, h['matches'][0]['score1']
105
- assert_equal 0, h['matches'][0]['score2']
106
- end
107
-
108
-
109
- def test_world_2018_round_2
110
- h = @client.round( 2 )
111
-
112
- ## pp h
113
- =begin
114
- {"name"=>"Matchday 2",
115
- "matches"=>
116
- [{"num"=>2,
117
- "date"=>"2018-06-15",
118
- "time"=>"17:00",
119
- "team1"=>{"name"=>"Egypt", "code"=>"EGY"},
120
- "team2"=>{"name"=>"Uruguay", "code"=>"URU"},
121
- "score1"=>nil,
122
- "score2"=>nil,
123
- "score1i"=>nil,
124
- "score2i"=>nil,
125
- "group"=>"Group A",
126
- "stadium"=>{"key"=>"ekaterinburg", "name"=>"Ekaterinburg Arena"},
127
- "city"=>"Ekaterinburg",
128
- "timezone"=>"UTC+5"},
129
- {"num"=>3,
130
- "date"=>"2018-06-15",
131
- "time"=>"21:00",
132
- "team1"=>{"name"=>"Portugal", "code"=>"POR"},
133
- "team2"=>{"name"=>"Spain", "code"=>"ESP"},
134
- "score1"=>nil,
135
- "score2"=>nil,
136
- "score1i"=>nil,
137
- "score2i"=>nil,
138
- "group"=>"Group B",
139
- "stadium"=>{"key"=>"fisht", "name"=>"Fisht Stadium"},
140
- "city"=>"Sochi",
141
- "timezone"=>"UTC+3"},
142
- {"num"=>4,
143
- "date"=>"2018-06-15",
144
- "time"=>"18:00",
145
- "team1"=>{"name"=>"Morocco", "code"=>"MAR"},
146
- "team2"=>{"name"=>"Iran", "code"=>"IRN"},
147
- "score1"=>nil,
148
- "score2"=>nil,
149
- "score1i"=>nil,
150
- "score2i"=>nil,
151
- "group"=>"Group B",
152
- "stadium"=>{"key"=>"saintpetersburg", "name"=>"Saint Petersburg Stadium"},
153
- "city"=>"Saint Petersburg",
154
- "timezone"=>"UTC+3"}]}
155
- =end
156
-
157
- assert_equal 'EGY', h['matches'][0]['team1']['code']
158
- assert_equal 'URU', h['matches'][0]['team2']['code']
159
- assert_equal 0, h['matches'][0]['score1']
160
- assert_equal 1, h['matches'][0]['score2']
161
- end
162
-
163
-
164
- end # class TestClientWorldCup