sportdb-parser 0.7.2 → 0.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -1
- data/Manifest.txt +8 -3
- data/Rakefile +23 -0
- data/lib/sportdb/parser/debuggable.rb +53 -0
- data/lib/sportdb/parser/lexer-logger.rb +20 -0
- data/lib/sportdb/parser/lexer-on_goal.rb +1 -6
- data/lib/sportdb/parser/lexer-on_prop_misc.rb +14 -1
- data/lib/sportdb/parser/lexer-on_top.rb +8 -0
- data/lib/sportdb/parser/lexer-tokenize.rb +22 -3
- data/lib/sportdb/parser/lexer.rb +27 -51
- data/lib/sportdb/parser/parse_tree--core.rb +29 -0
- data/lib/sportdb/parser/parse_tree-match.rb +309 -0
- data/lib/sportdb/parser/parse_tree-props.rb +233 -0
- data/lib/sportdb/parser/parse_tree.rb +202 -0
- data/lib/sportdb/parser/parser-top.rb +102 -0
- data/lib/sportdb/parser/parser.rb +1069 -909
- data/lib/sportdb/parser/token-geo.rb +1 -1
- data/lib/sportdb/parser/token-goals.rb +0 -8
- data/lib/sportdb/parser/token-prop.rb +40 -0
- data/lib/sportdb/parser/token.rb +33 -0
- data/lib/sportdb/parser/version.rb +2 -2
- data/lib/sportdb/parser.rb +45 -47
- metadata +10 -5
- data/lib/sportdb/parser/racc_parser.rb +0 -92
- data/lib/sportdb/parser/racc_tree.rb +0 -524
- /data/lib/sportdb/parser/{parser_runtime.rb → parser-runtime.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4b9d6cc209285ddfacdf76565fd43541500cac28c516edeecf779c65c98fe556
|
|
4
|
+
data.tar.gz: 329531cc04507bd0a5bc3f8e3488a2e2539ddebe955a48e37aa6d07760135777
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 57949562e6cd27b1d8058afa549e1d24a8cfd820590d14407d8ed5b34c2095b451ca53065057ef24b86db2dee5d69570cbb054830bd3796ae5b400008da343cf
|
|
7
|
+
data.tar.gz: 2e1b841018e66468d65727947290f30e143340789b271de27c4edd2fb18e169b04446bcc203433329ba343174138d42de112d9801eb608de8c7c5b9144d5c920
|
data/CHANGELOG.md
CHANGED
data/Manifest.txt
CHANGED
|
@@ -3,6 +3,8 @@ Manifest.txt
|
|
|
3
3
|
README.md
|
|
4
4
|
Rakefile
|
|
5
5
|
lib/sportdb/parser.rb
|
|
6
|
+
lib/sportdb/parser/debuggable.rb
|
|
7
|
+
lib/sportdb/parser/lexer-logger.rb
|
|
6
8
|
lib/sportdb/parser/lexer-on_goal.rb
|
|
7
9
|
lib/sportdb/parser/lexer-on_group_def.rb
|
|
8
10
|
lib/sportdb/parser/lexer-on_prop_lineup.rb
|
|
@@ -16,10 +18,13 @@ lib/sportdb/parser/lexer-tokenize.rb
|
|
|
16
18
|
lib/sportdb/parser/lexer.rb
|
|
17
19
|
lib/sportdb/parser/lexer_buffer.rb
|
|
18
20
|
lib/sportdb/parser/lexer_token.rb
|
|
21
|
+
lib/sportdb/parser/parse_tree--core.rb
|
|
22
|
+
lib/sportdb/parser/parse_tree-match.rb
|
|
23
|
+
lib/sportdb/parser/parse_tree-props.rb
|
|
24
|
+
lib/sportdb/parser/parse_tree.rb
|
|
25
|
+
lib/sportdb/parser/parser-runtime.rb
|
|
26
|
+
lib/sportdb/parser/parser-top.rb
|
|
19
27
|
lib/sportdb/parser/parser.rb
|
|
20
|
-
lib/sportdb/parser/parser_runtime.rb
|
|
21
|
-
lib/sportdb/parser/racc_parser.rb
|
|
22
|
-
lib/sportdb/parser/racc_tree.rb
|
|
23
28
|
lib/sportdb/parser/token-date--helpers.rb
|
|
24
29
|
lib/sportdb/parser/token-date--names.rb
|
|
25
30
|
lib/sportdb/parser/token-date.rb
|
data/Rakefile
CHANGED
|
@@ -28,3 +28,26 @@ Hoe.spec 'sportdb-parser' do
|
|
|
28
28
|
required_ruby_version: '>= 3.1.0'
|
|
29
29
|
}
|
|
30
30
|
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
###
|
|
35
|
+
## add our own g task to build parser.rb (via racc & erb)
|
|
36
|
+
|
|
37
|
+
desc 'Generate parser.rb (via racc & erb)'
|
|
38
|
+
task g: 'lib/sportdb/parser/parser.rb'
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
file 'lib/sportdb/parser/parser.rb' => 'fbtxt/parser.y' do |t|
|
|
42
|
+
puts " [racc] generate parser.rb from parser.y"
|
|
43
|
+
## sh "racc -v -o #{t.name} #{t.source}"
|
|
44
|
+
sh "racc -o #{t.name} #{t.source}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
file 'fbtxt/parser.y' => FileList['fbtxt/grammar/*.y'] do |t|
|
|
49
|
+
puts " [erb] generate parser.y; merge grammar/*"
|
|
50
|
+
Dir.chdir( 'fbtxt' ) do
|
|
51
|
+
sh "erb parser.y.erb > parser.y"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
###
|
|
2
|
+
## debugg(able) mix-in helper
|
|
3
|
+
## used for lexer & parser
|
|
4
|
+
|
|
5
|
+
module Debuggable
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.extend(ClassMethods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
def debug=(value)
|
|
12
|
+
raise ArgumentError, "true|false required for debug flag; got #{value}" unless value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
|
13
|
+
@debug=value;
|
|
14
|
+
end
|
|
15
|
+
def debug() @debug || false; end ## note - default to false
|
|
16
|
+
|
|
17
|
+
def debug?() @debug == true; end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
########
|
|
22
|
+
## InstanceMethods
|
|
23
|
+
def debug?() self.class.debug?; end
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
## todo/check - allow/support multiple msg args - why? why not?
|
|
27
|
+
|
|
28
|
+
## note - use trace for debug for now - why? why not?
|
|
29
|
+
def _trace( *args ) __log__( :DEBUG, *args ); end
|
|
30
|
+
|
|
31
|
+
def _info( *args ) __log__( :INFO, *args ); end
|
|
32
|
+
def _warn( *args) __log__( :WARN, *args ); end
|
|
33
|
+
def _error( *args ) __log__( :ERROR, *args ); end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
def __log__( level, *args ) ## :DEBUG, :INFO, :WARN, :ERROR, :FATAL etc.
|
|
39
|
+
|
|
40
|
+
if level == :DEBUG && !debug?
|
|
41
|
+
## print nothing
|
|
42
|
+
else
|
|
43
|
+
msg = args.map do |arg|
|
|
44
|
+
arg.to_str
|
|
45
|
+
end.join(' | ')
|
|
46
|
+
|
|
47
|
+
fout = level == :WARN || level == :ERROR || level == :FATAL ? STDERR : STDOUT
|
|
48
|
+
|
|
49
|
+
## todo/check/fix - add/use/check for "local" logger
|
|
50
|
+
fout.puts "#{level} [#{self.class.name}] -- #{msg}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end # module Debuggable
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
module SportDb
|
|
3
|
+
class Lexer
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def log( msg )
|
|
7
|
+
## append msg to ./logs.txt
|
|
8
|
+
## use ./errors.txt - why? why not?
|
|
9
|
+
##
|
|
10
|
+
## change to ./logs_lexer.txt or such - why? why not?
|
|
11
|
+
## auto-add/prepend [Lexer] and timestamp!!! to msg - why? why not?
|
|
12
|
+
File.open( './logs.txt', 'a:utf-8' ) do |f|
|
|
13
|
+
f.write( "[Lexer] " + msg )
|
|
14
|
+
f.write( "\n" )
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
end # class Lexer
|
|
20
|
+
end # module SportDb
|
|
@@ -6,7 +6,6 @@ class Lexer
|
|
|
6
6
|
|
|
7
7
|
GOAL_RE = Regexp.union(
|
|
8
8
|
SPACES_RE,
|
|
9
|
-
GOAL_NONE_RE,
|
|
10
9
|
GOAL_MINUTE_RE,
|
|
11
10
|
GOAL_MINUTE_NA_RE,
|
|
12
11
|
GOAL_COUNT_RE,
|
|
@@ -16,15 +15,11 @@ GOAL_RE = Regexp.union(
|
|
|
16
15
|
## todo/fix - add ANY_RE !!!!
|
|
17
16
|
)
|
|
18
17
|
|
|
18
|
+
|
|
19
19
|
def _on_goal( m, ctx: )
|
|
20
20
|
|
|
21
21
|
if m[:space] || m[:spaces]
|
|
22
22
|
nil ## skip space(s)
|
|
23
|
-
elsif m[:goals_none] ## note - eats-up semicolon!! e.g. -; or - ;
|
|
24
|
-
# was:[:GOALS_NONE,"<|GOALS_NONE|>"]
|
|
25
|
-
## use literal text!!
|
|
26
|
-
Token.new( :GOALS_NONE, m[:goals_none],
|
|
27
|
-
lineno: ctx.lineno, offset: m.offset(:goals_none))
|
|
28
23
|
elsif m[:goal_sep_alt]
|
|
29
24
|
# was: [:GOAL_SEP_ALT, "<|GOAL_SEP_ALT|>" ] ## e.g. dash (-) WITH leading & trailing space required
|
|
30
25
|
Token.new( :GOAL_SEP_ALT, m[:goal_sep_alt],
|
|
@@ -7,9 +7,12 @@ class Lexer
|
|
|
7
7
|
## todo/fix - use custom (limited) prop basics too
|
|
8
8
|
PROP_CARDS_RE = Regexp.union(
|
|
9
9
|
SPACES_RE,
|
|
10
|
+
CARDS_NONE_LEFT_RE,
|
|
11
|
+
CARDS_NONE_RIGHT_RE,
|
|
10
12
|
MINUTE_RE,
|
|
11
13
|
PROP_NAME_RE,
|
|
12
|
-
|
|
14
|
+
CARDS_SEP_ALT_RE, ## note - add dash (-) with (required) spaces
|
|
15
|
+
/ (?<sym> [;,]) /x
|
|
13
16
|
## todo/fix - add ANY_RE here too!!!
|
|
14
17
|
)
|
|
15
18
|
|
|
@@ -18,6 +21,16 @@ def _on_prop_cards( m, ctx: ) ## note - m is MatchData object
|
|
|
18
21
|
|
|
19
22
|
if m[:space] || m[:spaces]
|
|
20
23
|
nil ## skip space(s)
|
|
24
|
+
elsif m[:cards_none_left]
|
|
25
|
+
Token.new(:CARDS_NONE_LEFT, m[0],
|
|
26
|
+
lineno: ctx.lineno, offset: m.offset(0))
|
|
27
|
+
elsif m[:cards_none_right]
|
|
28
|
+
Token.new(:CARDS_NONE_RIGHT, m[0],
|
|
29
|
+
lineno: ctx.lineno, offset: m.offset(0))
|
|
30
|
+
elsif m[:cards_sep_alt]
|
|
31
|
+
Token.new( :CARDS_SEP_ALT, m[0],
|
|
32
|
+
lineno: ctx.lineno, offset: m.offset(0))
|
|
33
|
+
|
|
21
34
|
elsif m[:prop_name]
|
|
22
35
|
Token.new(:PROP_NAME, m[:name],
|
|
23
36
|
lineno: ctx.lineno, offset: m.offset(:prop_name))
|
|
@@ -46,6 +46,14 @@ def _on_top( m, ctx: ) ## note - m is MatchData object
|
|
|
46
46
|
lineno: ctx.lineno, offset: m.offset(:inline_awd))
|
|
47
47
|
elsif m[:inline_canc] then Token.new(:INLINE_CANC, m[:inline_canc],
|
|
48
48
|
lineno: ctx.lineno, offset: m.offset(:inline_canc))
|
|
49
|
+
|
|
50
|
+
elsif m[:inline_round_short] then Token.new(:INLINE_ROUND_SHORT, m[0],
|
|
51
|
+
lineno: ctx.lineno, offset: m.offset(0),
|
|
52
|
+
value: m[:inline_round_text])
|
|
53
|
+
elsif m[:inline_round_big] then Token.new(:INLINE_ROUND_BIG, m[0],
|
|
54
|
+
lineno: ctx.lineno, offset: m.offset(0),
|
|
55
|
+
value: m[:inline_round_text])
|
|
56
|
+
|
|
49
57
|
elsif m[:status] then Token.new(:STATUS, m[:status],
|
|
50
58
|
lineno: ctx.lineno, offset: m.offset(:status),
|
|
51
59
|
value: _build_status( m ))
|
|
@@ -138,7 +138,8 @@ def _tokenize_line( line, lineno )
|
|
|
138
138
|
### todo/fix - add prop yellow/red cards too - why? why not?
|
|
139
139
|
## todo/fix - separate sent off and red card
|
|
140
140
|
## sent-off - incl. red card, yellow/red card and the era before red cards!!
|
|
141
|
-
if ['sent
|
|
141
|
+
if ['sent-off',
|
|
142
|
+
'sent off'].include?( key.downcase)
|
|
142
143
|
@re = PROP_CARDS_RE ## use CARDS_RE ???
|
|
143
144
|
tokens << Token.new(:PROP_SENTOFF, m[:key],
|
|
144
145
|
lineno: lineno, offset: m.offset(:key))
|
|
@@ -150,6 +151,18 @@ def _tokenize_line( line, lineno )
|
|
|
150
151
|
@re = PROP_CARDS_RE
|
|
151
152
|
tokens << Token.new(:PROP_YELLOWCARDS, m[:key],
|
|
152
153
|
lineno: lineno, offset: m.offset(:key))
|
|
154
|
+
|
|
155
|
+
## todo: check allow yellow/red cards: or such as key!!!
|
|
156
|
+
## check for alternate spellings
|
|
157
|
+
## 'yellow/red cards' - note - meaning closes to yellow or red !!
|
|
158
|
+
## thus use yellow-red cards as default/standard - why? why not?
|
|
159
|
+
elsif ['yellow-red cards',
|
|
160
|
+
'yellowred cards'].include?( key.downcase )
|
|
161
|
+
@re = PROP_CARDS_RE
|
|
162
|
+
tokens << Token.new(:PROP_YELLOWREDCARDS, m[:key],
|
|
163
|
+
lineno: lineno, offset: m.offset(:key))
|
|
164
|
+
|
|
165
|
+
|
|
153
166
|
elsif ['ref', 'referee',
|
|
154
167
|
'refs', 'referees' ## note - allow/support assistant refs
|
|
155
168
|
].include?( key.downcase )
|
|
@@ -354,7 +367,9 @@ def _tokenize_line( line, lineno )
|
|
|
354
367
|
when '>' then @geo_count = 0;
|
|
355
368
|
Token.literal( ',', lineno: lineno, offset: m.offset(:sym))
|
|
356
369
|
## note - treat geo sep > (ascii) like comma for now!!!
|
|
357
|
-
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
when '[','▪'
|
|
358
373
|
##
|
|
359
374
|
## todo/fix
|
|
360
375
|
## add virtual geo_end token!!!
|
|
@@ -363,6 +378,7 @@ def _tokenize_line( line, lineno )
|
|
|
363
378
|
@re = RE
|
|
364
379
|
pos = old_pos
|
|
365
380
|
next ## backtrack (resume new loop step)
|
|
381
|
+
## fix-fix-fix merge '▪' with '['
|
|
366
382
|
else
|
|
367
383
|
Token.literal( m[:sym], lineno: lineno, offset: m.offset(:sym))
|
|
368
384
|
end
|
|
@@ -426,7 +442,10 @@ def _tokenize_line( line, lineno )
|
|
|
426
442
|
@re == PROP_PENALTIES_RE ||
|
|
427
443
|
@re == PROP_ATTENDANCE_RE ||
|
|
428
444
|
@re == PROP_REFEREE_RE
|
|
429
|
-
|
|
445
|
+
|
|
446
|
+
## note - add :CARDS_SEP_ALT (aka -)!!! too
|
|
447
|
+
## maybe later CARDS_NONE_LEFT too - why? why not?
|
|
448
|
+
if [',', '-', ';', :CARDS_SEP_ALT].include?( tokens[-1].type)
|
|
430
449
|
## continue/stay in PROP_RE mode
|
|
431
450
|
## todo/check - auto-add PROP_CONT token or such
|
|
432
451
|
## to help parser with possible NEWLINE
|
data/lib/sportdb/parser/lexer.rb
CHANGED
|
@@ -1,57 +1,30 @@
|
|
|
1
1
|
|
|
2
2
|
module SportDb
|
|
3
|
-
class Lexer
|
|
4
|
-
|
|
5
|
-
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## change to ./logs_lexer.txt or such - why? why not?
|
|
12
|
-
## auto-add/prepend [Lexer] and timestamp!!! to msg - why? why not?
|
|
13
|
-
File.open( './logs.txt', 'a:utf-8' ) do |f|
|
|
14
|
-
f.write( msg )
|
|
15
|
-
f.write( "\n" )
|
|
4
|
+
class LexerResult
|
|
5
|
+
attr_reader :tokens, :errors
|
|
6
|
+
def initialize( tokens, errors=[] )
|
|
7
|
+
@tokens, @errors = tokens, errors
|
|
16
8
|
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _trace( *args )
|
|
21
|
-
if debug?
|
|
22
|
-
print "[DEBUG] Lexer -- "
|
|
23
|
-
args.each { |arg| puts args }
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def _warn( *args )
|
|
28
|
-
print "!! [WARN] Lexer -- "
|
|
29
|
-
args.each { |arg| puts args }
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def _info( *args )
|
|
33
|
-
print "[INFO] Lexer -- "
|
|
34
|
-
args.each { |arg| puts args }
|
|
35
|
-
end
|
|
36
9
|
|
|
37
|
-
|
|
38
|
-
def
|
|
10
|
+
def ok?() @errors.size == 0; end
|
|
11
|
+
def nok?() !ok?; end
|
|
12
|
+
end # class LexerResult
|
|
39
13
|
|
|
40
14
|
|
|
41
15
|
|
|
16
|
+
class Lexer
|
|
17
|
+
include Debuggable ## auto-adds debug?, _trace, _info, etc.
|
|
42
18
|
|
|
43
19
|
|
|
44
|
-
def initialize( txt
|
|
45
|
-
raise ArgumentError, "text as string expected for lexer; got #{txt.class
|
|
20
|
+
def initialize( txt )
|
|
21
|
+
raise ArgumentError, "text as string expected for lexer; got #{txt.class}" unless txt.is_a?(String)
|
|
46
22
|
|
|
47
23
|
@txt = txt
|
|
48
|
-
@debug = debug
|
|
49
24
|
end
|
|
50
25
|
|
|
51
26
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def tokenize_with_errors
|
|
27
|
+
def tokenize_with_errors( flatten: true )
|
|
55
28
|
|
|
56
29
|
tokens_by_line = [] ## note: add tokens line-by-line (flatten later)
|
|
57
30
|
errors = [] ## keep a list of errors - why? why not?
|
|
@@ -91,13 +64,12 @@ def tokenize_with_errors
|
|
|
91
64
|
## strip (inline) end-of-line comments (from line)
|
|
92
65
|
## check/discuss: make - inline comment require trailing space
|
|
93
66
|
## e.g. #1 vs # 1 - why? why not?
|
|
94
|
-
line = line.sub( / [ ]* ## (eat-up) optional leading space(s)
|
|
67
|
+
line = line.sub( / [ ]* ## (eat-up) optional leading space(s) too - why? why not?
|
|
95
68
|
\#{1,}.*?
|
|
96
69
|
\z
|
|
97
70
|
/x, '' )
|
|
98
71
|
|
|
99
72
|
|
|
100
|
-
####
|
|
101
73
|
# support __END__ marker to cut-off input
|
|
102
74
|
break if line.match?( /\A [ ]* ## optional leading space(s)
|
|
103
75
|
__END__
|
|
@@ -138,6 +110,10 @@ def tokenize_with_errors
|
|
|
138
110
|
tokens_by_line << more_tokens
|
|
139
111
|
errors += more_errors
|
|
140
112
|
end
|
|
113
|
+
|
|
114
|
+
## output last line from tokens by line in debug mode
|
|
115
|
+
_trace( " #{tokens_by_line[-1].size} token(s): " + tokens_by_line[-1].pretty_inspect )
|
|
116
|
+
|
|
141
117
|
end # each line
|
|
142
118
|
|
|
143
119
|
|
|
@@ -226,10 +202,10 @@ def tokenize_with_errors
|
|
|
226
202
|
## puts "tokens_by_line:"
|
|
227
203
|
## pp tokens_by_line
|
|
228
204
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
205
|
+
if flatten
|
|
206
|
+
## flatten tokens
|
|
207
|
+
tokens = []
|
|
208
|
+
tokens_by_line.each do |tok_line|
|
|
233
209
|
|
|
234
210
|
## if debug?
|
|
235
211
|
## pp tok_line
|
|
@@ -243,12 +219,12 @@ def tokenize_with_errors
|
|
|
243
219
|
## use last - why? why not?
|
|
244
220
|
tokens << Token.newline( lineno: tok_line[0].lineno )
|
|
245
221
|
end
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
end
|
|
251
|
-
|
|
222
|
+
end
|
|
223
|
+
[tokens,errors]
|
|
224
|
+
else
|
|
225
|
+
[tokens_by_line, errors]
|
|
226
|
+
end
|
|
227
|
+
end # method tokenize
|
|
252
228
|
|
|
253
229
|
|
|
254
230
|
end # class Lexer
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
# module JsonSerializable
|
|
4
|
+
# def to_json(*args)
|
|
5
|
+
# as_json.to_json(*args)
|
|
6
|
+
# end
|
|
7
|
+
# end
|
|
8
|
+
|
|
9
|
+
###
|
|
10
|
+
## add as_json to Object/Array/Hash
|
|
11
|
+
class Object
|
|
12
|
+
def as_json(*)
|
|
13
|
+
self
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class Array
|
|
18
|
+
def as_json(*)
|
|
19
|
+
map { |v| v.as_json }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Hash
|
|
24
|
+
def as_json(*)
|
|
25
|
+
each_with_object({}) do |(k, v), h|
|
|
26
|
+
h[k.to_s] = v.as_json
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|