score-formats 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/Manifest.txt +13 -0
- data/README.md +29 -0
- data/Rakefile +27 -0
- data/lib/score-formats.rb +72 -0
- data/lib/score-formats/formats.rb +239 -0
- data/lib/score-formats/parser.rb +129 -0
- data/lib/score-formats/score.rb +165 -0
- data/lib/score-formats/version.rb +19 -0
- data/lib/score/formats.rb +5 -0
- data/test/helper.rb +12 -0
- data/test/test_formats.rb +129 -0
- data/test/test_score.rb +76 -0
- metadata +91 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0ce70736d26500e8d3866ae96a2f75e6ce8c1725
|
4
|
+
data.tar.gz: 16e29461a44bb4c232039b82f38d805596b47acf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28ed77625082a2f1b29713b03cf92354df0799c8b0189f5e40e4ccddbad34cb6e14b286b580adee97304cb3b84e8c14064dd26c33efcfea80e94e4caa7354d6e
|
7
|
+
data.tar.gz: bf023b724232b5ca987615d223c8d8aef928a3afcf7b9807e1f1b9167fbabfc2a80d78404220cb5de6633585be885ea5e9f05c0770d28da59a1cb89d827b63b7
|
data/CHANGELOG.md
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
CHANGELOG.md
|
2
|
+
Manifest.txt
|
3
|
+
README.md
|
4
|
+
Rakefile
|
5
|
+
lib/score-formats.rb
|
6
|
+
lib/score-formats/formats.rb
|
7
|
+
lib/score-formats/parser.rb
|
8
|
+
lib/score-formats/score.rb
|
9
|
+
lib/score-formats/version.rb
|
10
|
+
lib/score/formats.rb
|
11
|
+
test/helper.rb
|
12
|
+
test/test_formats.rb
|
13
|
+
test/test_score.rb
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# score-formats - read / parse and print sports match scores (incl. half time, full time, extra time, penalties and more)
|
2
|
+
|
3
|
+
|
4
|
+
* home :: [github.com/sportdb/sport.db](https://github.com/sportdb/sport.db)
|
5
|
+
* bugs :: [github.com/sportdb/sport.db/issues](https://github.com/sportdb/sport.db/issues)
|
6
|
+
* gem :: [rubygems.org/gems/score-formats](https://rubygems.org/gems/score-formats)
|
7
|
+
* rdoc :: [rubydoc.info/gems/score-formats](http://rubydoc.info/gems/score-formats)
|
8
|
+
* forum :: [opensport](http://groups.google.com/group/opensport)
|
9
|
+
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
|
14
|
+
to be done
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
## License
|
20
|
+
|
21
|
+
The `score-formats` scripts are dedicated to the public domain.
|
22
|
+
Use it as you please with no restrictions whatsoever.
|
23
|
+
|
24
|
+
|
25
|
+
## Questions? Comments?
|
26
|
+
|
27
|
+
Send them along to the
|
28
|
+
[Open Sports & Friends Forum/Mailing List](http://groups.google.com/group/opensport).
|
29
|
+
Thanks!
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'hoe'
|
2
|
+
require './lib/score-formats/version.rb'
|
3
|
+
|
4
|
+
Hoe.spec 'score-formats' do
|
5
|
+
|
6
|
+
self.version = ScoreFormats::VERSION
|
7
|
+
|
8
|
+
self.summary = "score-formats - read / parse and print sports match scores (incl. half time, full time, extra time, penalties and more)"
|
9
|
+
self.description = summary
|
10
|
+
|
11
|
+
self.urls = ['https://github.com/sportdb/sport.db']
|
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.licenses = ['Public Domain']
|
21
|
+
|
22
|
+
self.extra_deps = []
|
23
|
+
|
24
|
+
self.spec_extras = {
|
25
|
+
required_ruby_version: '>= 2.2.2'
|
26
|
+
}
|
27
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'date'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
|
6
|
+
###
|
7
|
+
# our own code
|
8
|
+
require 'score-formats/version' # let version always go first
|
9
|
+
|
10
|
+
## todo/fix: make logging class configurable - lets you use logutils etc.
|
11
|
+
module ScoreFormats
|
12
|
+
module Logging
|
13
|
+
def logger() @logger ||= Logger.new; end
|
14
|
+
|
15
|
+
class Logger ## for now use quick "dummy" logger to
|
16
|
+
def debug( msg ) puts "[debug] #{msg}"; end
|
17
|
+
end # class Logger
|
18
|
+
end # module Logging
|
19
|
+
end # module ScoreFormats
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
require 'score-formats/score'
|
24
|
+
require 'score-formats/formats'
|
25
|
+
require 'score-formats/parser'
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
module ScoreFormats
|
30
|
+
def self.lang
|
31
|
+
@@lang ||= :en ## defaults to english (:en)
|
32
|
+
end
|
33
|
+
def self.lang=( value )
|
34
|
+
@@lang = value.to_sym ## note: make sure lang is always a symbol for now (NOT a string)
|
35
|
+
@@lang ## todo/check: remove =() method always returns passed in value? double check
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.parser( lang: ) ## find parser
|
39
|
+
lang = lang.to_sym ## note: make sure lang is always a symbol for now (NOT a string)
|
40
|
+
|
41
|
+
## note: cache all "built-in" lang versions (e.g. formats == nil)
|
42
|
+
@@parser ||= {}
|
43
|
+
parser = @@parser[ lang ] ||= ScoreParser.new( lang: lang )
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.parse( line, lang: ScoreFormats.lang )
|
47
|
+
parser( lang: lang ).parse( line )
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.find!( line, lang: ScoreFormats.lang )
|
51
|
+
parser( lang: lang ).find!( line )
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
##
|
58
|
+
# add more convenience / shortcut helpers / named ctors to score class itself
|
59
|
+
|
60
|
+
class Score
|
61
|
+
def self.parse( line, lang: ScoreFormats.lang )
|
62
|
+
ScoreFormats.parse( line, lang: lang )
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.find!( line, lang: ScoreFormats.lang )
|
66
|
+
ScoreFormats.find!( line, lang: lang )
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
puts ScoreFormats.banner # say hello
|
@@ -0,0 +1,239 @@
|
|
1
|
+
|
2
|
+
module ScoreFormats
|
3
|
+
|
4
|
+
## todo/check: use ‹› (unicode chars) to mark optional parts in regex constant name - why? why not?
|
5
|
+
|
6
|
+
#####
|
7
|
+
# english helpers (penalty, extra time, ...)
|
8
|
+
P_EN = '(?: p | pen\.? | pso )' # e.g. p, pen, pen., PSO, etc.
|
9
|
+
ET_EN = '(?: aet | a\.e\.t\.? )' # note: make last . optional (e.g a.e.t) allowed too
|
10
|
+
|
11
|
+
|
12
|
+
## note: allow SPECIAL cases WITHOUT full time scores (just a.e.t or pen. + a.e.t.)
|
13
|
+
## 3-4 pen. 2-2 a.e.t.
|
14
|
+
## 2-2 a.e.t.
|
15
|
+
EN__P_ET__RE = /\b
|
16
|
+
(?:
|
17
|
+
(?<score1p>\d{1,2})
|
18
|
+
[ ]* - [ ]* # note: sep in optional block; CANNOT use a reference
|
19
|
+
(?<score2p>\d{1,2})
|
20
|
+
[ ]* #{P_EN} [ ]*
|
21
|
+
)? # note: make penalty (P) score optional for now
|
22
|
+
(?<score1et>\d{1,2})
|
23
|
+
[ ]* - [ ]*
|
24
|
+
(?<score2et>\d{1,2})
|
25
|
+
[ ]* #{ET_EN}
|
26
|
+
(?=[ \]]|$)/xi ## todo/check: remove loakahead assertion here - why require space?
|
27
|
+
## note: \b works only after non-alphanum e.g. )
|
28
|
+
|
29
|
+
|
30
|
+
## e.g. 3-4 pen. 2-2 a.e.t. (1-1, 1-1) or
|
31
|
+
## 3-4 pen. 2-2 a.e.t. (1-1, ) or
|
32
|
+
## 3-4 pen. 2-2 a.e.t. (1-1) or
|
33
|
+
## 2-2 a.e.t. (1-1, 1-1) or
|
34
|
+
## 2-2 a.e.t. (1-1, ) or
|
35
|
+
## 2-2 a.e.t. (1-1)
|
36
|
+
|
37
|
+
EN__P_ET_FT_HT__RE = /\b
|
38
|
+
(?:
|
39
|
+
(?<score1p>\d{1,2})
|
40
|
+
[ ]* - [ ]* # note: sep in optional block; CANNOT use a reference
|
41
|
+
(?<score2p>\d{1,2})
|
42
|
+
[ ]* #{P_EN} [ ]*
|
43
|
+
)? # note: make penalty (P) score optional for now
|
44
|
+
(?<score1et>\d{1,2})
|
45
|
+
[ ]* - [ ]*
|
46
|
+
(?<score2et>\d{1,2})
|
47
|
+
[ ]* #{ET_EN} [ ]*
|
48
|
+
\(
|
49
|
+
[ ]*
|
50
|
+
(?<score1>\d{1,2})
|
51
|
+
[ ]* - [ ]*
|
52
|
+
(?<score2>\d{1,2})
|
53
|
+
[ ]*
|
54
|
+
(?:
|
55
|
+
, [ ]*
|
56
|
+
(?: (?<score1i>\d{1,2})
|
57
|
+
[ ]* - [ ]*
|
58
|
+
(?<score2i>\d{1,2})
|
59
|
+
[ ]*
|
60
|
+
)?
|
61
|
+
)? # note: make half time (HT) score optional for now
|
62
|
+
\)
|
63
|
+
(?=[ \]]|$)/xi ## todo/check: remove loakahead assertion here - why require space?
|
64
|
+
## note: \b works only after non-alphanum e.g. )
|
65
|
+
|
66
|
+
###
|
67
|
+
## special case for case WITHOUT extra time!!
|
68
|
+
## same as above (but WITHOUT extra time and pen required)
|
69
|
+
EN__P_FT_HT__RE = /\b
|
70
|
+
(?<score1p>\d{1,2})
|
71
|
+
[ ]* - [ ]* # note: sep in optional block; CANNOT use a reference
|
72
|
+
(?<score2p>\d{1,2})
|
73
|
+
[ ]* #{P_EN} [ ]*
|
74
|
+
\(
|
75
|
+
[ ]*
|
76
|
+
(?<score1>\d{1,2})
|
77
|
+
[ ]* - [ ]*
|
78
|
+
(?<score2>\d{1,2})
|
79
|
+
[ ]*
|
80
|
+
(?:
|
81
|
+
, [ ]*
|
82
|
+
(?: (?<score1i>\d{1,2})
|
83
|
+
[ ]* - [ ]*
|
84
|
+
(?<score2i>\d{1,2})
|
85
|
+
[ ]*
|
86
|
+
)?
|
87
|
+
)? # note: make half time (HT) score optional for now
|
88
|
+
\)
|
89
|
+
(?=[ \]]|$)/xi ## todo/check: remove loakahead assertion here - why require space?
|
90
|
+
## note: \b works only after non-alphanum e.g. )
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
## e.g. 2-1 (1-1) or
|
95
|
+
## 2-1
|
96
|
+
## note: for now add here used in Brazil / Portugal
|
97
|
+
## e.g 1x1 or 1X1 or 0x2 or 3x3 too
|
98
|
+
## todo/check/fix: move to its own use PT__FT_HT etc!!!!
|
99
|
+
|
100
|
+
EN__FT_HT__RE = /\b
|
101
|
+
(?<score1>\d{1,2})
|
102
|
+
[ ]* (?<sep>[x-]) [ ]*
|
103
|
+
(?<score2>\d{1,2})
|
104
|
+
(?:
|
105
|
+
[ ]* \( [ ]*
|
106
|
+
(?<score1i>\d{1,2})
|
107
|
+
[ ]* \k<sep> [ ]*
|
108
|
+
(?<score2i>\d{1,2})
|
109
|
+
[ ]* \)
|
110
|
+
)? # note: make half time (HT) score optional for now
|
111
|
+
(?=[ \]]|$)/xi ## todo/check: remove loakahead assertion here - why require space?
|
112
|
+
## note: \b works only after non-alphanum e.g. )
|
113
|
+
|
114
|
+
|
115
|
+
#####
|
116
|
+
# deutsch / german helpers (penalty, extra time, ...)
|
117
|
+
## todo add more marker e.g. im Elf. or such!!!
|
118
|
+
P_DE = '(?: ie | i\.e\.? )' # e.g. iE, i.E., i.E etc.
|
119
|
+
ET_DE = '(?: nv | n\.v\.? )' # e.g. nV, n.V., n.V etc.
|
120
|
+
|
121
|
+
|
122
|
+
## support alternate all-in-one score e.g.
|
123
|
+
## i.E. 2:4, n.V. 3:3 (1:1, 1:1) or
|
124
|
+
## n.V. 3:2 (2:2, 1:2)
|
125
|
+
DE__P_ET_FT_HT__RE = /\b
|
126
|
+
(?:
|
127
|
+
#{P_DE}
|
128
|
+
[ ]*
|
129
|
+
(?<score1p>\d{1,2})
|
130
|
+
[ ]* : [ ]*
|
131
|
+
(?<score2p>\d{1,2})
|
132
|
+
[ ]* (?:, [ ]*)?
|
133
|
+
)? # note: make penalty (P) score optional for now
|
134
|
+
#{ET_DE}
|
135
|
+
[ ]*
|
136
|
+
(?<score1et>\d{1,2})
|
137
|
+
[ ]* : [ ]*
|
138
|
+
(?<score2et>\d{1,2})
|
139
|
+
[ ]*
|
140
|
+
\(
|
141
|
+
[ ]*
|
142
|
+
(?<score1>\d{1,2})
|
143
|
+
[ ]* : [ ]*
|
144
|
+
(?<score2>\d{1,2})
|
145
|
+
[ ]*
|
146
|
+
(?:
|
147
|
+
, [ ]*
|
148
|
+
(?:
|
149
|
+
(?<score1i>\d{1,2})
|
150
|
+
[ ]* : [ ]*
|
151
|
+
(?<score2i>\d{1,2})
|
152
|
+
[ ]*
|
153
|
+
)?
|
154
|
+
)? # note: make half time (HT) score optional for now
|
155
|
+
\)
|
156
|
+
(?=[ \]]|$)
|
157
|
+
/xi
|
158
|
+
|
159
|
+
## support all-in-one "literal form e.g.
|
160
|
+
# 2:2 (1:1, 1:0) n.V. 5:1 i.E. or
|
161
|
+
# 2-2 (1-1, 1-0) n.V. 5-1 i.E.
|
162
|
+
DE__ET_FT_HT_P__RE = /\b
|
163
|
+
(?<score1et>\d{1,2})
|
164
|
+
[ ]* (?<sep>[:-]) [ ]* ## note: for now allow : or - as separator!!
|
165
|
+
(?<score2et>\d{1,2})
|
166
|
+
[ ]*
|
167
|
+
\(
|
168
|
+
[ ]*
|
169
|
+
(?<score1>\d{1,2})
|
170
|
+
[ ]* \k<sep> [ ]*
|
171
|
+
(?<score2>\d{1,2})
|
172
|
+
[ ]*
|
173
|
+
(?:
|
174
|
+
, [ ]*
|
175
|
+
(?:
|
176
|
+
(?<score1i>\d{1,2})
|
177
|
+
[ ]* \k<sep> [ ]*
|
178
|
+
(?<score2i>\d{1,2})
|
179
|
+
[ ]*
|
180
|
+
)?
|
181
|
+
)? # note: make half time (HT) score optional for now
|
182
|
+
\)
|
183
|
+
[ ]*
|
184
|
+
#{ET_DE}
|
185
|
+
(?:
|
186
|
+
[ ]*
|
187
|
+
(?<score1p>\d{1,2})
|
188
|
+
[ ]* \k<sep> [ ]*
|
189
|
+
(?<score2p>\d{1,2})
|
190
|
+
[ ]*
|
191
|
+
#{P_DE}
|
192
|
+
)? # note: make penalty (P) score optional for now
|
193
|
+
(?=[ \]]|$)
|
194
|
+
/xi ## todo/check: remove loakahead assertion here - why require space?
|
195
|
+
## note: \b works only after non-alphanum e.g. )
|
196
|
+
|
197
|
+
|
198
|
+
## e.g. 2:1 (1:1) or
|
199
|
+
## 2-1 (1-1) or
|
200
|
+
## 2:1 or
|
201
|
+
## 2-1
|
202
|
+
DE__FT_HT__RE = /\b
|
203
|
+
(?<score1>\d{1,2})
|
204
|
+
[ ]* (?<sep>[:-]) [ ]*
|
205
|
+
(?<score2>\d{1,2})
|
206
|
+
(?:
|
207
|
+
[ ]* \( [ ]*
|
208
|
+
(?<score1i>\d{1,2})
|
209
|
+
[ ]* \k<sep> [ ]*
|
210
|
+
(?<score2i>\d{1,2})
|
211
|
+
[ ]* \)
|
212
|
+
)? # note: make half time (HT) score optional for now
|
213
|
+
(?=[ \]]|$)/x ## todo/check: remove loakahead assertion here - why require space?
|
214
|
+
## note: \b works only after non-alphanum e.g. )
|
215
|
+
|
216
|
+
|
217
|
+
#############################################
|
218
|
+
# map tables - 1) regex, 2) tag - note: order matters; first come-first matched/served
|
219
|
+
|
220
|
+
|
221
|
+
FORMATS_EN = [
|
222
|
+
[ EN__P_ET_FT_HT__RE, '[SCORE.EN__P?_ET_(FT_HT?)]' ], # e.g. 5-1 pen. 2-2 a.e.t. (1-1, 1-0)
|
223
|
+
[ EN__P_FT_HT__RE, '[SCORE.EN__P_(FT_HT?)]' ], # e.g. 5-1 pen. (1-1)
|
224
|
+
[ EN__P_ET__RE, '[SCORE.EN__P?_ET]' ], # e.g. 2-2 a.e.t. or 5-1 pen. 2-2 a.e.t.
|
225
|
+
[ EN__FT_HT__RE, '[SCORE.EN__FT_(HT)?]' ], # e.g. 1-1 (1-0)
|
226
|
+
]
|
227
|
+
|
228
|
+
FORMATS_DE = [
|
229
|
+
[ DE__ET_FT_HT_P__RE, '[SCORE.DE__ET_(FT_HT?)_P?]' ], # e.g. 2:2 (1:1, 1:0) n.V. 5:1 i.E.
|
230
|
+
[ DE__P_ET_FT_HT__RE, '[SCORE.DE__P?_ET_(FT_HT?)]' ], # e.g. i.E. 2:4, n.V. 3:3 (1:1, 1:1)
|
231
|
+
[ DE__FT_HT__RE, '[SCORE.DE__FT_(HT)?]' ], # e.g. 1:1 (1:0)
|
232
|
+
]
|
233
|
+
|
234
|
+
FORMATS = {
|
235
|
+
en: FORMATS_EN,
|
236
|
+
de: FORMATS_DE,
|
237
|
+
}
|
238
|
+
|
239
|
+
end # module ScoreFormats
|
@@ -0,0 +1,129 @@
|
|
1
|
+
|
2
|
+
module ScoreFormats
|
3
|
+
|
4
|
+
class ScoreParser
|
5
|
+
|
6
|
+
include Logging
|
7
|
+
|
8
|
+
def initialize( lang: )
|
9
|
+
@lang = lang.to_sym ## note: make sure lang is always a symbol for now (NOT a string)
|
10
|
+
|
11
|
+
## fallback to english if lang not available
|
12
|
+
## todo/fix: add/issue warning - why? why not?
|
13
|
+
@formats = FORMATS[ @lang ] || FORMATS[ :en ]
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def parse( line )
|
18
|
+
|
19
|
+
##########
|
20
|
+
## todo/fix/check: add unicode to regular dash conversion - why? why not?
|
21
|
+
## e.g. – becomes - (yes, the letters a different!!!)
|
22
|
+
#############
|
23
|
+
|
24
|
+
score = nil
|
25
|
+
@formats.each do |format|
|
26
|
+
re = format[0]
|
27
|
+
m = re.match( line )
|
28
|
+
if m
|
29
|
+
score = parse_matchdata( m )
|
30
|
+
break
|
31
|
+
end
|
32
|
+
# no match; continue; try next regex pattern
|
33
|
+
end
|
34
|
+
|
35
|
+
## todo/fix - raise ArgumentError - invalid score; no format match found
|
36
|
+
score # note: nil if no match found
|
37
|
+
end # method parse
|
38
|
+
|
39
|
+
|
40
|
+
def find!( line )
|
41
|
+
### fix: add and match all-in-one literal first, followed by
|
42
|
+
|
43
|
+
# note: always call after find_dates !!!
|
44
|
+
# scores match date-like patterns!! e.g. 10-11 or 10:00 etc.
|
45
|
+
# -- note: score might have two digits too
|
46
|
+
|
47
|
+
### fix: depending on language allow 1:1 or 1-1
|
48
|
+
## do NOT allow mix and match
|
49
|
+
## e.g. default to en is 1-1
|
50
|
+
## de is 1:1 etc.
|
51
|
+
|
52
|
+
|
53
|
+
# extract score from line
|
54
|
+
# and return it
|
55
|
+
# note: side effect - removes date from line string
|
56
|
+
|
57
|
+
score = nil
|
58
|
+
@formats.each do |format|
|
59
|
+
re = format[0]
|
60
|
+
tag = format[1]
|
61
|
+
m = re.match( line )
|
62
|
+
if m
|
63
|
+
score = parse_matchdata( m )
|
64
|
+
line.sub!( m[0], tag )
|
65
|
+
break
|
66
|
+
end
|
67
|
+
# no match; continue; try next regex pattern
|
68
|
+
end
|
69
|
+
|
70
|
+
score # note: nil if no match found
|
71
|
+
end # method find!
|
72
|
+
|
73
|
+
private
|
74
|
+
def parse_matchdata( m )
|
75
|
+
# convert regex match_data captures to hash
|
76
|
+
# - note: cannont use match_data like a hash (e.g. raises exception if key/name not present/found)
|
77
|
+
h = {}
|
78
|
+
# - note: do NOT forget to turn name into symbol for lookup in new hash (name.to_sym)
|
79
|
+
m.names.each { |name| h[name.to_sym] = m[name] } # or use match_data.names.zip( match_data.captures ) - more cryptic but "elegant"??
|
80
|
+
|
81
|
+
## puts "[parse_date_time] match_data:"
|
82
|
+
## pp h
|
83
|
+
logger.debug " [parse_matchdata] hash: >#{h.inspect}<"
|
84
|
+
|
85
|
+
score1i = nil # half time (ht) scores
|
86
|
+
score2i = nil
|
87
|
+
|
88
|
+
score1 = nil # full time (ft) scores
|
89
|
+
score2 = nil
|
90
|
+
|
91
|
+
score1et = nil # extra time (et) scores
|
92
|
+
score2et = nil
|
93
|
+
|
94
|
+
score1p = nil # penalty (p) scores
|
95
|
+
score2p = nil
|
96
|
+
|
97
|
+
|
98
|
+
if h[:score1i] && h[:score2i] ## note: half time (HT) score is optional now
|
99
|
+
score1i = h[:score1i].to_i
|
100
|
+
score2i = h[:score2i].to_i
|
101
|
+
end
|
102
|
+
|
103
|
+
if h[:score1] && h[:score2] ## note: full time (FT) score can be optional too!!!
|
104
|
+
score1 = h[:score1].to_i
|
105
|
+
score2 = h[:score2].to_i
|
106
|
+
end
|
107
|
+
|
108
|
+
if h[:score1et] && h[:score2et]
|
109
|
+
score1et = h[:score1et].to_i
|
110
|
+
score2et = h[:score2et].to_i
|
111
|
+
end
|
112
|
+
|
113
|
+
if h[:score1p] && h[:score2p]
|
114
|
+
score1p = h[:score1p].to_i
|
115
|
+
score2p = h[:score2p].to_i
|
116
|
+
end
|
117
|
+
|
118
|
+
score = Score.new( score1i, score2i,
|
119
|
+
score1, score2,
|
120
|
+
score1et, score2et,
|
121
|
+
score1p, score2p )
|
122
|
+
score
|
123
|
+
end # method parse_matchdata
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
end # class ScoreParser
|
128
|
+
end # module ScoreFormats
|
129
|
+
|
@@ -0,0 +1,165 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
## note: make Score top-level and use like Date - yes, yes, yes - why? why not?
|
4
|
+
class Score
|
5
|
+
|
6
|
+
SCORE_SPLIT_RE = %r{^ [ ]*
|
7
|
+
([0-9]+)
|
8
|
+
[ ]*
|
9
|
+
[:x–-] ## note: allow some unicode dashes too
|
10
|
+
[ ]*
|
11
|
+
([0-9]+)
|
12
|
+
[ ]* $}xi
|
13
|
+
|
14
|
+
def self.split( str ) ## note: return array of two integers or empty array
|
15
|
+
## e.g. allow/support
|
16
|
+
## 1-1 or 1 - 1 - "english" style
|
17
|
+
## 1:1 - "german / deutsch" style
|
18
|
+
## 1x1 1X1 - "brazil/portugese" style
|
19
|
+
|
20
|
+
## note: add unicode "fancy" dash too (e.g. –)
|
21
|
+
## add some more - why? why not?
|
22
|
+
|
23
|
+
if m=SCORE_SPLIT_RE.match(str)
|
24
|
+
[m[1].to_i, m[2].to_i]
|
25
|
+
else
|
26
|
+
# no match - warn if str is not empty? why? why not?
|
27
|
+
##
|
28
|
+
## todo/fix:
|
29
|
+
## do NOT warn on
|
30
|
+
## assert_equal [], Score.split( '-' )
|
31
|
+
## assert_equal [], Score.split( '-:-' )
|
32
|
+
## assert_equal [], Score.split( '?' )
|
33
|
+
## for now - add more?
|
34
|
+
|
35
|
+
puts "!! WARN - cannot match (split) score format >#{str}<" unless str.empty?
|
36
|
+
[]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
attr_reader :score1i, :score2i, # half time (ht) score
|
44
|
+
:score1, :score2, # full time (ft) score
|
45
|
+
:score1et, :score2et, # extra time (et) score
|
46
|
+
:score1p, :score2p # penalty (p) score
|
47
|
+
## todo/fix: add :score1agg, score2agg too - why? why not?!!!
|
48
|
+
## add state too e.g. canceled or abadoned etc - why? why not?
|
49
|
+
|
50
|
+
## alternate accessor via array e.g. ft[0] and ft[1]
|
51
|
+
def ft() [@score1, @score2]; end ## e.g. 90 mins (in football)
|
52
|
+
def ht() [@score1i, @score2i]; end ## e.g. 45 mins
|
53
|
+
def et() [@score1et, @score2et]; end ## e.g. 90+15mins
|
54
|
+
def p() [@score1p, @score2p]; end ## e.g. note - starts "fresh" score from 0-0
|
55
|
+
alias_method :pen, :p ## add alias - why? why not?
|
56
|
+
|
57
|
+
## todo/check: allow one part missing why? why not?
|
58
|
+
## e.g. 1-nil or nil-1 - why? why not?
|
59
|
+
def ft?() @score1 && @score2; end
|
60
|
+
def ht?() @score1i && @score2i; end
|
61
|
+
def et?() @score1et && @score2et; end
|
62
|
+
def p?() @score1p && @score2p; end
|
63
|
+
alias_method :pen?, :p?
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
def initialize( *values )
|
68
|
+
## note: for now always assumes integers
|
69
|
+
## todo/check - check/require integer args - why? why not?
|
70
|
+
|
71
|
+
### todo/fix: add more init options
|
72
|
+
## allow kwargs (keyword args) via hash - why? why not?
|
73
|
+
## use kwargs for "perfect" init where you can only set the half time (ht) score
|
74
|
+
## or only the penalty or other "edge" cases
|
75
|
+
## allow int pairs e.g. [1,2], [2,2]
|
76
|
+
## allow values array MUST be of size 8 (or 4 or 6) - why? why not?
|
77
|
+
|
78
|
+
raise ArgumentError, "expected even integer number (pairs), but got #{values.size}" if values.size % 2 == 1
|
79
|
+
|
80
|
+
if values.size == 2
|
81
|
+
@score1 = values[0] # full time (ft) score
|
82
|
+
@score2 = values[1]
|
83
|
+
|
84
|
+
@score1i = @score2i = nil
|
85
|
+
@score1et = @score2et = nil
|
86
|
+
@score1p = @score2p = nil
|
87
|
+
else
|
88
|
+
@score1i = values[0] # half time (ht) score
|
89
|
+
@score2i = values[1]
|
90
|
+
|
91
|
+
@score1 = values[2] # full time (ft) score
|
92
|
+
@score2 = values[3]
|
93
|
+
|
94
|
+
@score1et = values[4] # extra time (et) score
|
95
|
+
@score2et = values[5]
|
96
|
+
|
97
|
+
@score1p = values[6] # penalty (p) score
|
98
|
+
@score2p = values[7]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
def to_h( format = :default )
|
105
|
+
case format.to_sym
|
106
|
+
when :default, :std
|
107
|
+
## check/todo: only add entries if ft, ht, etc. have values (non-null) or always - why? why not?
|
108
|
+
h = {}
|
109
|
+
h[:ht] = [@score1i, @score2i] if @score1i || @score2i
|
110
|
+
h[:ft] = [@score1, @score2] if @score1 || @score2
|
111
|
+
h[:et] = [@score1et, @score2et] if @score1et || @score2et
|
112
|
+
h[:p] = [@score1p, @score2p] if @score1p || @score2p
|
113
|
+
h
|
114
|
+
when :db
|
115
|
+
## use a "flat" structure with "internal" std names
|
116
|
+
{ score1i: @score1i, score2i: @score2i,
|
117
|
+
score1: @score1, score2: @score2,
|
118
|
+
score1et: @score1et, score2et: @score2et,
|
119
|
+
score1p: @score1p, score2p: @score2p
|
120
|
+
}
|
121
|
+
else
|
122
|
+
puts "!! ERROR: unknown score to_h format >#{format}<"
|
123
|
+
exit 1
|
124
|
+
end
|
125
|
+
end
|
126
|
+
alias_method :to_hash, :to_h ## add alias - why? why not?
|
127
|
+
|
128
|
+
|
129
|
+
def values
|
130
|
+
## todo/ fix: always return complete array
|
131
|
+
## e.g. [score1i, score2i, score1, score2, score1et, score2et, score1p, score2p]
|
132
|
+
|
133
|
+
## todo: how to handle game w/o extra time
|
134
|
+
# but w/ optional penalty ??? e.g. used in copa liberatores, for example
|
135
|
+
# retrun 0,0 or nil,nil for extra time score ?? or -1, -1 ??
|
136
|
+
# for now use nil,nil
|
137
|
+
score = []
|
138
|
+
score += [@score1i, @score2i] if @score1p || @score2p || @score1et || @score2et || @score1 || score2 || score1i || score2i
|
139
|
+
score += [@score1, @score2] if @score1p || @score2p || @score1et || @score2et || @score1 || score2
|
140
|
+
score += [@score1et, @score2et] if @score1p || @score2p || @score1et || @score2et
|
141
|
+
score += [@score1p, @score2p] if @score1p || @score2p
|
142
|
+
score
|
143
|
+
end
|
144
|
+
|
145
|
+
def to_a
|
146
|
+
## pairs with values
|
147
|
+
pairs = []
|
148
|
+
## note: allow 1-nil, nil-1 for now in pairs (or use && and NOT ||) - why? why not?
|
149
|
+
pairs << [@score1i, @score2i] if @score1i || @score2i
|
150
|
+
pairs << [@score1, @score2] if @score1 || @score2
|
151
|
+
pairs << [@score1et, @score2et] if @score1et || @score2et
|
152
|
+
pairs << [@score1p, @score2p] if @score1p || @score2p
|
153
|
+
|
154
|
+
if pairs.empty?
|
155
|
+
pairs # e.g. return []
|
156
|
+
elsif pairs.size == 1
|
157
|
+
pairs[0] # return single pair "unwrapped" e.g. [0,1] instead of [[0,1]] - why? why not?
|
158
|
+
else
|
159
|
+
pairs
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
end # class Score
|
164
|
+
|
165
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module ScoreFormats
|
3
|
+
MAJOR = 0 ## todo: namespace inside version or something - why? why not??
|
4
|
+
MINOR = 0
|
5
|
+
PATCH = 1
|
6
|
+
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
7
|
+
|
8
|
+
def self.version
|
9
|
+
VERSION
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.banner
|
13
|
+
"score-formats/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.root
|
17
|
+
File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
|
18
|
+
end
|
19
|
+
end # module ScoreFormats
|
data/test/helper.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
###
|
2
|
+
# to run use
|
3
|
+
# ruby -I ./lib -I ./test test/test_formats.rb
|
4
|
+
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
class TestFormats < MiniTest::Test
|
9
|
+
|
10
|
+
def test_de
|
11
|
+
ScoreFormats.lang = :de
|
12
|
+
data = [
|
13
|
+
[ '10:0', [nil,nil, 10,0]],
|
14
|
+
[ '1:22', [nil,nil, 1,22]],
|
15
|
+
[ '1-22', [nil,nil, 1,22]],
|
16
|
+
|
17
|
+
## do not support three digits for now - why? why not?
|
18
|
+
[ '1:222', nil],
|
19
|
+
[ '111:0', nil],
|
20
|
+
[ '1-222', nil],
|
21
|
+
[ '111-0', nil],
|
22
|
+
|
23
|
+
[ '2:2 (1:1, 1:0) n.V. 5:1 i.E.', [1,0, 1,1, 2,2, 5,1]],
|
24
|
+
[ '2:2 (1:1, 1:0) n.V.', [1,0, 1,1, 2,2]],
|
25
|
+
[ '2:2 (1:1, ) n.V. 5:1 i.E.', [nil,nil, 1,1, 2,2, 5,1]],
|
26
|
+
[ '2:2 (1:1, ) n.V.', [nil,nil, 1,1, 2,2]],
|
27
|
+
|
28
|
+
[ '2:2 (1:1) n.V. 5:1 i.E.', [nil,nil, 1,1, 2,2, 5,1]],
|
29
|
+
[ '2:2 (1:1) n.V.', [nil,nil, 1,1, 2,2]],
|
30
|
+
|
31
|
+
[ '2-2 (1-1, 1-0) n.V. 5-1 i.E.', [1,0, 1,1, 2,2, 5,1]],
|
32
|
+
[ '2-2 (1-1, 1-0) n.V.', [1,0, 1,1, 2,2]],
|
33
|
+
[ '2-2 (1-1, ) n.V. 5-1 i.E.', [nil,nil, 1,1, 2,2, 5,1]],
|
34
|
+
[ '2-2 (1-1, ) n.V.', [nil,nil, 1,1, 2,2]],
|
35
|
+
|
36
|
+
[ '2 : 2 ( 1 : 1 , 1 : 0 ) n.V. 5 : 1 i.E.', [1,0, 1,1, 2,2, 5,1]],
|
37
|
+
[ '2 : 2 ( 1 : 1 , 1 : 0 ) n.V.', [1,0, 1,1, 2,2]],
|
38
|
+
[ '2 : 2 ( 1 : 1 , ) n.V. 5 : 1 i.E.', [nil,nil, 1,1, 2,2, 5,1]],
|
39
|
+
[ '2 : 2 ( 1 : 1 , ) n.V.', [nil,nil, 1,1, 2,2]],
|
40
|
+
|
41
|
+
## alternate format
|
42
|
+
['i.E. 2:4, n.V. 3:3 (1:1, 1:0)', [1,0, 1,1, 3,3, 2,4]],
|
43
|
+
['iE 2:4 nV 3:3 (1:1, 1:0)', [1,0, 1,1, 3,3, 2,4]],
|
44
|
+
['i.E. 2:4 n.V. 3:3 (1:1, 1:0)', [1,0, 1,1, 3,3, 2,4]],
|
45
|
+
['i.E. 2:4, n.V. 3:3 (1:1)', [nil, nil, 1,1, 3,3, 2,4]],
|
46
|
+
['i.E. 2:4 n.V. 3:3 (1:1)', [nil, nil, 1,1, 3,3, 2,4]],
|
47
|
+
['n.V. 3:2 (2:2, 1:2)', [1,2, 2,2, 3,2]],
|
48
|
+
['n.V. 3:2 (2:2)', [nil, nil, 2,2, 3,2]],
|
49
|
+
]
|
50
|
+
|
51
|
+
assert_score( data )
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_en
|
55
|
+
ScoreFormats.lang = :en
|
56
|
+
|
57
|
+
data = [
|
58
|
+
[ '1-22', [nil,nil, 1, 22]],
|
59
|
+
[ '1x22', [nil,nil, 1, 22]],
|
60
|
+
[ '1X22', [nil,nil, 1,22]],
|
61
|
+
|
62
|
+
## do not support three digits for now - why? why not?
|
63
|
+
[ '1-222', nil],
|
64
|
+
[ '111-0', nil],
|
65
|
+
[ '111x0', nil],
|
66
|
+
[ '111X0', nil],
|
67
|
+
|
68
|
+
## do not support colon sep for now in en locale - why? why not?
|
69
|
+
[ '2:1', nil],
|
70
|
+
[ '2:1 (1:1)', nil],
|
71
|
+
|
72
|
+
|
73
|
+
[ '2-1 (1-1)', [1,1, 2,1]],
|
74
|
+
[ '2x1 (1x1)', [1,1, 2,1]],
|
75
|
+
[ '2X1 (1X1)', [1,1, 2,1]],
|
76
|
+
|
77
|
+
[ '2-1 a.e.t. (1-1, 0-0)', [0,0, 1,1, 2,1]],
|
78
|
+
[ '2-1aet (1-1, 0-0)', [0,0, 1,1, 2,1]],
|
79
|
+
[ '2-1 A.E.T. (1-1, 0-0)', [0,0, 1,1, 2,1]],
|
80
|
+
[ '2-1AET (1-1, 0-0)', [0,0, 1,1, 2,1]],
|
81
|
+
[ '2-1 a.e.t.', [nil,nil,nil,nil, 2,1]],
|
82
|
+
|
83
|
+
[ '3-4 pen. 2-2 a.e.t. (1-1, 1-1)', [1,1, 1,1, 2,2, 3,4]],
|
84
|
+
[ '3-4 pen 2-2 a.e.t. (1-1, 1-1)', [1,1, 1,1, 2,2, 3,4]],
|
85
|
+
[ '3-4 pen 2-2 a.e.t. (1-1, 1-1)', [1,1, 1,1, 2,2, 3,4]],
|
86
|
+
[ '3-4p 2-2aet (1-1, 1-1)', [1,1, 1,1, 2,2, 3,4]],
|
87
|
+
[ '3-4PSO 2-2AET (1-1, 1-1)', [1,1, 1,1, 2,2, 3,4]],
|
88
|
+
[ '3-4 pen. 2-2 a.e.t.', [nil,nil,nil,nil, 2,2, 3,4]],
|
89
|
+
|
90
|
+
[ '4-3 pen. 1-0 a.e.t. (1-0, )', [nil,nil, 1,0, 1,0, 4,3]],
|
91
|
+
[ '3-4 pen. 2-1 a.e.t. (2-1, )', [nil,nil, 2,1, 2,1, 3,4]],
|
92
|
+
[ '4-1 a.e.t. (3-1, )', [nil,nil, 3,1, 4,1]],
|
93
|
+
[ '3-4aet (1-1,)', [nil,nil, 1,1, 3,4]],
|
94
|
+
[ '3-4 a.e.t. (1-1,)', [nil,nil, 1,1, 3,4]],
|
95
|
+
|
96
|
+
[ '4-3 pen. 1-0 a.e.t. (1-0)', [nil,nil, 1,0, 1,0, 4,3]],
|
97
|
+
[ '3-4 pen. 2-1 a.e.t. (2-1)', [nil,nil, 2,1, 2,1, 3,4]],
|
98
|
+
[ '4-1 a.e.t. (3-1)', [nil,nil, 3,1, 4,1]],
|
99
|
+
[ '3-4aet (1-1)', [nil,nil, 1,1, 3,4]],
|
100
|
+
[ '3-4 a.e.t. (1-1)', [nil,nil, 1,1, 3,4]],
|
101
|
+
|
102
|
+
[ '3-1 pen (1-1)', [nil,nil, 1,1, nil, nil, 3,1]],
|
103
|
+
|
104
|
+
## try with more "liberal" spaces
|
105
|
+
[ '2 - 1 ( 1 - 1 )', [1,1, 2,1]],
|
106
|
+
[ '2 - 1 a.e.t. ( 1 - 1 , 0 - 0 )', [0,0, 1,1, 2,1]],
|
107
|
+
[ '4 - 1 a.e.t. ( 3 - 1, )', [nil,nil, 3,1, 4,1]],
|
108
|
+
]
|
109
|
+
|
110
|
+
assert_score( data )
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
def assert_score( data )
|
115
|
+
data.each do |rec|
|
116
|
+
line = rec[0].dup
|
117
|
+
exp = rec[1]
|
118
|
+
|
119
|
+
score = ScoreFormats.find!( line )
|
120
|
+
## pp score
|
121
|
+
|
122
|
+
if exp.nil?
|
123
|
+
assert_nil score, "failed >#{rec[0]}< - >#{line}<"
|
124
|
+
else
|
125
|
+
assert_equal exp, score.values, "failed >#{rec[0]}< - >#{line}<"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end # class TestScores
|
data/test/test_score.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
###
|
2
|
+
# to run use
|
3
|
+
# ruby -I ./lib -I ./test test/test_score.rb
|
4
|
+
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
class TestScore < MiniTest::Test
|
9
|
+
|
10
|
+
def test_split
|
11
|
+
assert_equal [], Score.split( '' )
|
12
|
+
assert_equal [], Score.split( '-' )
|
13
|
+
assert_equal [], Score.split( '-:-' )
|
14
|
+
assert_equal [], Score.split( '?' )
|
15
|
+
|
16
|
+
assert_equal [0,1], Score.split( '0-1' )
|
17
|
+
assert_equal [0,1], Score.split( ' 0 - 1 ' )
|
18
|
+
assert_equal [0,1], Score.split( '0:1' )
|
19
|
+
assert_equal [0,1], Score.split( ' 0 : 1 ' )
|
20
|
+
assert_equal [0,1], Score.split( '0x1' )
|
21
|
+
assert_equal [0,1], Score.split( '0X1' )
|
22
|
+
|
23
|
+
assert_equal [10,11], Score.split( '10 - 11' )
|
24
|
+
assert_equal [10,11], Score.split( '10 : 11' )
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_to_h
|
28
|
+
assert_equal Hash( ft: [1,0] ), Score.parse( '1-0' ).to_h
|
29
|
+
assert_equal Hash( ht: [1,0],
|
30
|
+
ft: [3,2] ), Score.parse( '3-2 (1-0)' ).to_h
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def test_new_et_al
|
35
|
+
score = Score.new
|
36
|
+
assert_equal [], score.to_a
|
37
|
+
assert_equal [], score.values
|
38
|
+
assert_equal [nil,nil], score.ft
|
39
|
+
assert_equal [nil,nil], score.ht
|
40
|
+
assert_equal Hash({}), score.to_h ## e.g. {} - empty hash
|
41
|
+
assert_equal Hash( score1i: nil, score2i: nil,
|
42
|
+
score1: nil, score2: nil,
|
43
|
+
score1et: nil, score2et: nil,
|
44
|
+
score1p: nil, score2p: nil ), score.to_h( :db )
|
45
|
+
|
46
|
+
|
47
|
+
[
|
48
|
+
Score.new( 0, 1 ),
|
49
|
+
Score.new( nil, nil, 0, 1 ),
|
50
|
+
].each do |score|
|
51
|
+
assert_equal [0,1], score.to_a
|
52
|
+
assert_equal [nil,nil,0,1], score.values
|
53
|
+
assert_equal [nil,nil], score.ht
|
54
|
+
assert_equal [0,1], score.ft
|
55
|
+
assert_equal Hash(ft: [0,1]), score.to_h
|
56
|
+
assert_equal Hash( score1i: nil, score2i: nil,
|
57
|
+
score1: 0, score2: 1,
|
58
|
+
score1et: nil, score2et: nil,
|
59
|
+
score1p: nil, score2p: nil ), score.to_h( :db )
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
score = Score.new( 0, 1, 2, 3 )
|
64
|
+
assert_equal [[0,1],[2,3]], score.to_a
|
65
|
+
assert_equal [0,1,2,3], score.values
|
66
|
+
assert_equal [0,1], score.ht
|
67
|
+
assert_equal [2,3], score.ft
|
68
|
+
assert_equal Hash(ht: [0,1],
|
69
|
+
ft: [2,3]), score.to_h
|
70
|
+
assert_equal Hash( score1i: 0, score2i: 1,
|
71
|
+
score1: 2, score2: 3,
|
72
|
+
score1et: nil, score2et: nil,
|
73
|
+
score1p: nil, score2p: nil ), score.to_h( :db )
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: score-formats
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gerald Bauer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-08-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rdoc
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hoe
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.16'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.16'
|
41
|
+
description: score-formats - read / parse and print sports match scores (incl. half
|
42
|
+
time, full time, extra time, penalties and more)
|
43
|
+
email: opensport@googlegroups.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files:
|
47
|
+
- CHANGELOG.md
|
48
|
+
- Manifest.txt
|
49
|
+
- README.md
|
50
|
+
files:
|
51
|
+
- CHANGELOG.md
|
52
|
+
- Manifest.txt
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- lib/score-formats.rb
|
56
|
+
- lib/score-formats/formats.rb
|
57
|
+
- lib/score-formats/parser.rb
|
58
|
+
- lib/score-formats/score.rb
|
59
|
+
- lib/score-formats/version.rb
|
60
|
+
- lib/score/formats.rb
|
61
|
+
- test/helper.rb
|
62
|
+
- test/test_formats.rb
|
63
|
+
- test/test_score.rb
|
64
|
+
homepage: https://github.com/sportdb/sport.db
|
65
|
+
licenses:
|
66
|
+
- Public Domain
|
67
|
+
metadata: {}
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options:
|
70
|
+
- "--main"
|
71
|
+
- README.md
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 2.2.2
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 2.5.2
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: score-formats - read / parse and print sports match scores (incl. half time,
|
90
|
+
full time, extra time, penalties and more)
|
91
|
+
test_files: []
|