re_expand 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/Generator.rb CHANGED
@@ -17,217 +17,221 @@ require 'Scanner'
17
17
  require 'Node'
18
18
  require 'Asearch'
19
19
 
20
- class GenNode
21
- def initialize(id, state=[], s="", substrings=[], accept=false)
22
- @id = id
23
- @s = s
24
- @substrings = substrings
25
- @accept = accept
26
- @state = state
27
- end
28
-
29
- attr :id, true
30
- attr :s, true
31
- attr :substrings, true
32
- attr :accept, true
33
- attr :state, true
34
- end
35
-
36
- class Generator
37
- def initialize(s = nil)
38
- @s = (s ? [s] : [])
39
- @matchedlist = []
40
- @par = 0
41
- @commands = []
42
- end
43
-
44
- def add(pat,command)
45
- @s << pat
46
- @commands << command
47
- end
48
-
49
- def delete
50
- @s.pop
51
- @commands.pop
20
+ module ReExpand
21
+ class GenNode
22
+ def initialize(id, state=[], s="", substrings=[], accept=false)
23
+ @id = id
24
+ @s = s
25
+ @substrings = substrings
26
+ @accept = accept
27
+ @state = state
28
+ end
29
+
30
+ attr :id, true
31
+ attr :s, true
32
+ attr :substrings, true
33
+ attr :accept, true
34
+ attr :state, true
52
35
  end
53
-
54
- #
55
- # ルールを解析して状態遷移機械を作成し、patにマッチするもののリストを返す
56
- #
57
- def generate(pat, app = nil)
58
- res = [[],[],[]] # 曖昧度0,1,2のマッチ結果
59
- patterns = pat.split.map { |p| p.downcase }
60
-
61
- @asearch = Asearch.new(pat)
62
- scanner = Scanner.new(@s.join('|'))
63
-
64
- # HelpDataで指定した状態遷移機械全体を生成
65
- # (少し時間がかかる)
66
- (startnode, endnode) = regexp(scanner,true) # top level
67
-
68
- #
69
- # 状態遷移機械からDepth-Firstで文字列を生成する
70
- # n個のノードを経由して生成される状態の集合をlists[n]に入れる
71
- # 生成しながらマッチングも計算する
72
- #
73
- lists = []
74
- listed = [{},{},{}]
75
- #
76
- # 初期状態
36
+
37
+ class Generator
38
+ def initialize(s = nil)
39
+ @s = (s ? [s] : [])
40
+ @matchedlist = []
41
+ @par = 0
42
+ @commands = []
43
+ end
44
+
45
+ def add(pat,command)
46
+ @s << pat
47
+ @commands << command
48
+ end
49
+
50
+ def delete
51
+ @s.pop
52
+ @commands.pop
53
+ end
54
+
77
55
  #
78
- list = []
79
- list[0] = GenNode.new(startnode.id, @asearch.initstate)
80
- lists[0] = list
56
+ # ルールを解析して状態遷移機械を作成し、patにマッチするもののリストを返す
81
57
  #
82
- (0..1000).each { |length|
83
- break if app && app.inputPending
84
- list = lists[length]
85
- newlist = []
86
- # puts "#{length} - #{list.length}"
87
- list.each { |entry|
88
- srcnode = Node.node(entry.id)
89
- if list.length * srcnode.trans.length < 10000 then
90
- srcnode.trans.each { |trans|
91
- ss = entry.substrings.dup
92
- srcnode.pars.each { |i|
93
- ss[i-1] = ss[i-1].to_s + trans.arg
94
- }
95
- newstate = @asearch.state(entry.state, trans.str) # 新しいマッチング状態を計算してノードに保存
96
- s = entry.s + trans.str
97
- acceptno = trans.dest.accept
98
- newlist << GenNode.new(trans.dest.id, newstate, s, ss, acceptno)
99
- #
100
- # この時点で、マッチしているかどうかをstateとacceptpatで判断できる
101
- # マッチしてたら出力リストに加える
102
- #
103
- if acceptno then
104
- maxambig = 2
105
- (0..maxambig).each { |ambig|
106
- if !listed[ambig][s] then
107
- if (newstate[ambig] & @asearch.acceptpat) != 0 then # マッチ
108
- maxambig = ambig if ambig < maxambig # 曖昧度0でマッチすれば曖昧度1の検索は不要
109
- listed[ambig][s] = true
110
- sslen = ss.length
111
- if sslen > 0 then
112
- # patstr = "(.*)\t" * (sslen-1) + "(.*)"
113
- patstr = (["(.*)"] * sslen).join("\t")
114
- /#{patstr}/ =~ ss.join("\t")
58
+ def generate(pat, app = nil)
59
+ res = [[],[],[]] # 曖昧度0,1,2のマッチ結果
60
+ patterns = pat.split.map { |p| p.downcase }
61
+
62
+ @asearch = Asearch.new(pat)
63
+ scanner = Scanner.new(@s.join('|'))
64
+
65
+ # HelpDataで指定した状態遷移機械全体を生成
66
+ # (少し時間がかかる)
67
+ (startnode, endnode) = regexp(scanner,true) # top level
68
+
69
+ #
70
+ # 状態遷移機械からDepth-Firstで文字列を生成する
71
+ # n個のノードを経由して生成される状態の集合をlists[n]に入れる
72
+ # 生成しながらマッチングも計算する
73
+ #
74
+ lists = []
75
+ listed = [{},{},{}]
76
+ #
77
+ # 初期状態
78
+ #
79
+ list = []
80
+ list[0] = GenNode.new(startnode.id, @asearch.initstate)
81
+ lists[0] = list
82
+ #
83
+ (0..1000).each { |length|
84
+ break if app && app.inputPending
85
+ list = lists[length]
86
+ newlist = []
87
+ # puts "#{length} - #{list.length}"
88
+ list.each { |entry|
89
+ srcnode = Node.node(entry.id)
90
+ if list.length * srcnode.trans.length < 10000 then
91
+ srcnode.trans.each { |trans|
92
+ ss = entry.substrings.dup
93
+ srcnode.pars.each { |i|
94
+ ss[i-1] = ss[i-1].to_s + trans.arg
95
+ }
96
+ newstate = @asearch.state(entry.state, trans.str) # 新しいマッチング状態を計算してノードに保存
97
+ s = entry.s + trans.str
98
+ acceptno = trans.dest.accept
99
+ newlist << GenNode.new(trans.dest.id, newstate, s, ss, acceptno)
100
+ #
101
+ # この時点で、マッチしているかどうかをstateとacceptpatで判断できる
102
+ # マッチしてたら出力リストに加える
103
+ #
104
+ if acceptno then
105
+ maxambig = 2
106
+ (0..maxambig).each { |ambig|
107
+ if !listed[ambig][s] then
108
+ if (newstate[ambig] & @asearch.acceptpat) != 0 then # マッチ
109
+ maxambig = ambig if ambig < maxambig # 曖昧度0でマッチすれば曖昧度1の検索は不要
110
+ listed[ambig][s] = true
111
+ sslen = ss.length
112
+ if sslen > 0 then
113
+ # patstr = "(.*)\t" * (sslen-1) + "(.*)"
114
+ patstr = (["(.*)"] * sslen).join("\t")
115
+ /#{patstr}/ =~ ss.join("\t")
116
+ end
117
+ ## next if $1 == $2
118
+ # 'set date #{$2}' のような記述の$変数にsubstringの値を代入
119
+ File.open("/tmp/log","a"){ |f|
120
+ f.puts "#{s}-----" + eval('%('+@commands[acceptno]+')')
121
+ }
122
+ res[ambig] << [s, eval('%('+@commands[acceptno]+')')]
115
123
  end
116
- ## next if $1 == $2
117
- # 'set date #{$2}' のような記述の$変数にsubstringの値を代入
118
- File.open("/tmp/log","a"){ |f|
119
- f.puts "#{s}-----" + eval('%('+@commands[acceptno]+')')
120
- }
121
- res[ambig] << [s, eval('%('+@commands[acceptno]+')')]
122
124
  end
123
- end
124
- }
125
- end
126
- }
127
- end
125
+ }
126
+ end
127
+ }
128
+ end
129
+ }
130
+ break if newlist.length == 0
131
+ lists << newlist
132
+ break if res[0].length > 100
128
133
  }
129
- break if newlist.length == 0
130
- lists << newlist
131
- break if res[0].length > 100
132
- }
133
- [res[0], res[1], res[2]]
134
- end
135
-
136
- #
137
- # 正規表現をパースして状態遷移機械を作る
138
- #
139
- private
140
- # n1 n2
141
- # +-->□.....□--+
142
- # start / \ end
143
- # □ --->□.....□---> □
144
- # \ /
145
- # +-->□.....□--+
146
- #
147
- def regexp(s,toplevel=false) # regcat { '|' regcat }
148
- startnode = Node.new
149
- endnode = Node.new
150
- if toplevel then
151
- @pars = []
152
- @parno = 0
153
- @ruleid = 0
134
+ [res[0], res[1], res[2]]
154
135
  end
155
- startnode.pars = @pars
156
- endnode.pars = @pars
157
- (n1, n2) = regcat(s)
158
- startnode.addTrans('',n1)
159
- if toplevel then
160
- n2.accept = @ruleid
161
- end
162
- n2.addTrans('',endnode)
163
- while s.gettoken == '|' && s.nexttoken != '' do
136
+
137
+ #
138
+ # 正規表現をパースして状態遷移機械を作る
139
+ #
140
+ private
141
+ # n1 n2
142
+ # +-->□.....□--+
143
+ # start / \ end
144
+ # □ --->□.....□--->
145
+ # \ /
146
+ # +-->□.....□--+
147
+ #
148
+ def regexp(s,toplevel=false) # regcat { '|' regcat }
149
+ startnode = Node.new
150
+ endnode = Node.new
164
151
  if toplevel then
165
152
  @pars = []
166
153
  @parno = 0
167
- @ruleid += 1
154
+ @ruleid = 0
168
155
  end
156
+ startnode.pars = @pars
157
+ endnode.pars = @pars
169
158
  (n1, n2) = regcat(s)
170
159
  startnode.addTrans('',n1)
171
160
  if toplevel then
172
161
  n2.accept = @ruleid
173
162
  end
174
163
  n2.addTrans('',endnode)
175
- end
176
- s.ungettoken
177
- return [startnode, endnode]
178
- end
179
-
180
- def regcat(s) # regfactor { regfactor }
181
- (startnode, endnode) = regfactor(s)
182
- while s.gettoken !~ /^[\)\]\|]$/ && s.nexttoken != '' do
164
+ while s.gettoken == '|' && s.nexttoken != '' do
165
+ if toplevel then
166
+ @pars = []
167
+ @parno = 0
168
+ @ruleid += 1
169
+ end
170
+ (n1, n2) = regcat(s)
171
+ startnode.addTrans('',n1)
172
+ if toplevel then
173
+ n2.accept = @ruleid
174
+ end
175
+ n2.addTrans('',endnode)
176
+ end
183
177
  s.ungettoken
184
- (n1, n2) = regfactor(s)
185
- endnode.addTrans('',n1)
186
- endnode = n2
178
+ return [startnode, endnode]
187
179
  end
188
- s.ungettoken
189
- return [startnode, endnode]
190
- end
191
-
192
- def regfactor(s) # regterm [ '?' | '+' | '*' ]
193
- (startnode, endnode) = regterm(s)
194
- t = s.gettoken
195
- if t =~ /^[\?]$/ then
196
- startnode.addTrans('',endnode)
197
- elsif t =~ /^[\+]$/ then
198
- endnode.addTrans('',startnode)
199
- elsif t =~ /^[\*]$/ then
200
- startnode.addTrans('',endnode)
201
- endnode.addTrans('',startnode)
202
- else
180
+
181
+ def regcat(s) # regfactor { regfactor }
182
+ (startnode, endnode) = regfactor(s)
183
+ while s.gettoken !~ /^[\)\]\|]$/ && s.nexttoken != '' do
184
+ s.ungettoken
185
+ (n1, n2) = regfactor(s)
186
+ endnode.addTrans('',n1)
187
+ endnode = n2
188
+ end
203
189
  s.ungettoken
190
+ return [startnode, endnode]
204
191
  end
205
- return [startnode,endnode]
206
- end
207
-
208
- def regterm(s) # '(' regexp ')' | token
209
- t = s.gettoken
210
- if t == '(' then
211
- @parno += 1
212
- @pars.push(@parno)
213
- (n1, n2) = regexp(s)
214
- n1.pars = @pars.dup
192
+
193
+ def regfactor(s) # regterm [ '?' | '+' | '*' ]
194
+ (startnode, endnode) = regterm(s)
215
195
  t = s.gettoken
216
- if t == ')' then
217
- @pars.pop
218
- n2.pars = @pars.dup
219
- return [n1, n2]
196
+ if t =~ /^[\?]$/ then
197
+ startnode.addTrans('',endnode)
198
+ elsif t =~ /^[\+]$/ then
199
+ endnode.addTrans('',startnode)
200
+ elsif t =~ /^[\*]$/ then
201
+ startnode.addTrans('',endnode)
202
+ endnode.addTrans('',startnode)
220
203
  else
221
- puts 'missing )'
222
- exit
204
+ s.ungettoken
205
+ end
206
+ return [startnode,endnode]
207
+ end
208
+
209
+ def regterm(s) # '(' regexp ')' | token
210
+ t = s.gettoken
211
+ if t == '(' then
212
+ @parno += 1
213
+ @pars.push(@parno)
214
+ (n1, n2) = regexp(s)
215
+ n1.pars = @pars.dup
216
+ t = s.gettoken
217
+ if t == ')' then
218
+ @pars.pop
219
+ n2.pars = @pars.dup
220
+ return [n1, n2]
221
+ else
222
+ puts 'missing )'
223
+ exit
224
+ end
225
+ else
226
+ startnode = Node.new
227
+ startnode.pars = @pars.dup
228
+ endnode = Node.new
229
+ endnode.pars = @pars.dup
230
+ startnode.addTrans(t,endnode)
231
+ return [startnode, endnode]
223
232
  end
224
- else
225
- startnode = Node.new
226
- startnode.pars = @pars.dup
227
- endnode = Node.new
228
- endnode.pars = @pars.dup
229
- startnode.addTrans(t,endnode)
230
- return [startnode, endnode]
231
233
  end
232
234
  end
235
+
233
236
  end
237
+
data/lib/Node.rb CHANGED
@@ -8,56 +8,58 @@
8
8
  # ----------> □
9
9
  #
10
10
 
11
- class Trans
12
- def initialize(pat,dest)
13
- # pat にマッチしたら dest に遷移
14
- @pat = pat
15
- @dest = dest
16
- end
17
-
18
- attr_reader :pat, :dest
19
-
20
- def str
21
- @pat.split(/\t/)[0].to_s
22
- end
23
-
24
- def arg
25
- if @pat =~ /^(.*)\t(.*)$/ then
26
- return $2
27
- else
28
- return @pat
11
+ module ReExpand
12
+ class Trans
13
+ def initialize(pat,dest)
14
+ # pat にマッチしたら dest に遷移
15
+ @pat = pat
16
+ @dest = dest
17
+ end
18
+
19
+ attr_reader :pat, :dest
20
+
21
+ def str
22
+ @pat.split(/\t/)[0].to_s
23
+ end
24
+
25
+ def arg
26
+ if @pat =~ /^(.*)\t(.*)$/ then
27
+ return $2
28
+ else
29
+ return @pat
30
+ end
29
31
  end
30
32
  end
31
- end
32
-
33
- class Node
34
- @@id = 1
35
- @@nodes = {}
36
-
37
- def initialize
38
- @accept = nil
39
- @trans = []
40
- @id = @@id
41
- @@nodes[@id] = self
42
- @@id += 1
43
- @pars = []
44
- end
45
-
46
- attr_reader :id
47
- attr_reader :trans
48
- attr :accept, true
49
- attr :pars, true
50
-
51
- def addTrans(pat,dest)
52
- t = Trans.new(pat,dest)
53
- @trans << t
54
- end
55
-
56
- def Node.node(id) # ノードidからノードを取得
57
- @@nodes[id.to_i]
58
- end
59
-
60
- def Node.nodes
61
- @@nodes.values
33
+
34
+ class Node
35
+ @@id = 1
36
+ @@nodes = {}
37
+
38
+ def initialize
39
+ @accept = nil
40
+ @trans = []
41
+ @id = @@id
42
+ @@nodes[@id] = self
43
+ @@id += 1
44
+ @pars = []
45
+ end
46
+
47
+ attr_reader :id
48
+ attr_reader :trans
49
+ attr :accept, true
50
+ attr :pars, true
51
+
52
+ def addTrans(pat,dest)
53
+ t = Trans.new(pat,dest)
54
+ @trans << t
55
+ end
56
+
57
+ def Node.node(id) # ノードidからノードを取得
58
+ @@nodes[id.to_i]
59
+ end
60
+
61
+ def Node.nodes
62
+ @@nodes.values
63
+ end
62
64
  end
63
65
  end
data/lib/Scanner.rb CHANGED
@@ -5,55 +5,57 @@
5
5
 
6
6
  $KCODE = 'utf8'
7
7
 
8
- class Scanner
9
- def initialize(s)
10
- @s = s
11
- @a = s.split(//)
12
- @p = 0
13
- @t = ''
14
- @u = ''
15
- end
16
-
17
- def gettoken
18
- if @u != '' then
19
- @t = @u
20
- @u = ''
21
- return @t
22
- end
23
- if @p >= @a.length then
8
+ module ReExpand
9
+ class Scanner
10
+ def initialize(s)
11
+ @s = s
12
+ @a = s.split(//)
13
+ @p = 0
24
14
  @t = ''
25
- return ''
15
+ @u = ''
26
16
  end
27
- @t = @a[@p]
28
- if @t =~ /^[\(\|\)\*\?\[\]]$/ then
29
- @p += 1
30
- return @t
31
- elsif @t == '\\' then
32
- @p += 1
17
+
18
+ def gettoken
19
+ if @u != '' then
20
+ @t = @u
21
+ @u = ''
22
+ return @t
23
+ end
24
+ if @p >= @a.length then
25
+ @t = ''
26
+ return ''
27
+ end
33
28
  @t = @a[@p]
34
- @t = "\n" if @t == 'n'
35
- @t = "\t" if @t == 't'
36
- @p += 1
37
- return @t
38
- else
39
- @p += 1
40
- while @p < @a.length && @a[@p] !~ /^[\(\|\)\*\+\?\[\]\\]$/ do
41
- @t += @a[@p]
29
+ if @t =~ /^[\(\|\)\*\?\[\]]$/ then
30
+ @p += 1
31
+ return @t
32
+ elsif @t == '\\' then
42
33
  @p += 1
34
+ @t = @a[@p]
35
+ @t = "\n" if @t == 'n'
36
+ @t = "\t" if @t == 't'
37
+ @p += 1
38
+ return @t
39
+ else
40
+ @p += 1
41
+ while @p < @a.length && @a[@p] !~ /^[\(\|\)\*\+\?\[\]\\]$/ do
42
+ @t += @a[@p]
43
+ @p += 1
44
+ end
45
+ return @t
43
46
  end
44
- return @t
45
47
  end
46
- end
47
-
48
- def ungettoken
49
- if @u == '' then
50
- @u = @t
51
- else
52
- puts "Can't ungettoken(#{token})"
48
+
49
+ def ungettoken
50
+ if @u == '' then
51
+ @u = @t
52
+ else
53
+ puts "Can't ungettoken(#{token})"
54
+ end
55
+ end
56
+
57
+ def nexttoken
58
+ return @t
53
59
  end
54
- end
55
-
56
- def nexttoken
57
- return @t
58
60
  end
59
61
  end
data/lib/re_expand.rb CHANGED
@@ -3,7 +3,7 @@ $:.unshift(File.dirname(__FILE__)) unless
3
3
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
4
4
 
5
5
  module ReExpand
6
- VERSION = '0.0.1'
6
+ VERSION = '0.0.2'
7
7
  end
8
8
 
9
9
  require 'Generator'
@@ -14,7 +14,7 @@ require 'Scanner'
14
14
  class String
15
15
  # ExpandHelp用のライブラリを利用
16
16
  def expand(filterpat=' ')
17
- g = Generator.new
17
+ g = ReExpand::Generator.new
18
18
  g.add(self,'')
19
19
  strings = []
20
20
  if filterpat.class == String then
@@ -1,36 +1,32 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- require 'Generator'
4
-
5
- class GeneratorTest < Test::Unit::TestCase
6
- def setup
7
- end
8
-
9
- def teardown
10
- end
11
-
12
- def test_clock
13
- g = Generator.new
14
- g.add '(時計|時間|時刻)を(0|1|2|3|4|5|6|7|8|9|10|11|12)時に(セットする|設定する|あわせる)', 'set time #{$2}:00'
15
- res = g.generate(' 10 ')
16
- assert res[0].member?(['時刻を10時に設定する','set time 10:00'])
17
- assert res[0].member?(['時計を10時にセットする','set time 10:00'])
18
- assert !res[0].member?(['時計を8時にセットする','set time 8:00'])
19
- end
20
-
21
- def test_substring
22
- g = Generator.new
23
- g.add '(a)bcd(e(fg)h)i(jk)', '#{$1}/#{$2}/#{$3}/#{$4}'
24
- res = g.generate(' b ')
25
- assert res[0].member?(['abcdefghijk', 'a/efgh/fg/jk'])
26
- assert !res[0].member?(['abcdefghijk', 'a/fgh/fg/jk'])
27
- g.add '(ab|cd)efg(hij|klm)n', '#{$1}/#{$2}'
28
- res = g.generate(' ef ')
29
- assert res[0].member?(['abefghijn', 'ab/hij'])
30
- assert res[0].member?(['cdefgklmn', 'cd/klm'])
3
+ module ReExpand
4
+ class GeneratorTest < Test::Unit::TestCase
5
+ def setup
6
+ end
7
+
8
+ def teardown
9
+ end
10
+
11
+ def test_clock
12
+ g = Generator.new
13
+ g.add '(時計|時間|時刻)を(0|1|2|3|4|5|6|7|8|9|10|11|12)時に(セットする|設定する|あわせる)', 'set time #{$2}:00'
14
+ res = g.generate(' 10 ')
15
+ assert res[0].member?(['時刻を10時に設定する','set time 10:00'])
16
+ assert res[0].member?(['時計を10時にセットする','set time 10:00'])
17
+ assert !res[0].member?(['時計を8時にセットする','set time 8:00'])
18
+ end
19
+
20
+ def test_substring
21
+ g = Generator.new
22
+ g.add '(a)bcd(e(fg)h)i(jk)', '#{$1}/#{$2}/#{$3}/#{$4}'
23
+ res = g.generate(' b ')
24
+ assert res[0].member?(['abcdefghijk', 'a/efgh/fg/jk'])
25
+ assert !res[0].member?(['abcdefghijk', 'a/fgh/fg/jk'])
26
+ g.add '(ab|cd)efg(hij|klm)n', '#{$1}/#{$2}'
27
+ res = g.generate(' ef ')
28
+ assert res[0].member?(['abefghijn', 'ab/hij'])
29
+ assert res[0].member?(['cdefgklmn', 'cd/klm'])
30
+ end
31
31
  end
32
32
  end
33
-
34
-
35
-
36
-
data/test/test_scanner.rb CHANGED
@@ -1,27 +1,28 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- require 'Scanner'
4
-
5
- class ScannerTest < Test::Unit::TestCase
6
- def setup
7
- end
8
-
9
- def teardown
10
- end
11
-
12
- def test_1
13
- s = Scanner.new('abc*def')
14
- assert_equal s.gettoken, 'abc'
15
- assert_equal s.gettoken, '*'
16
- assert_equal s.gettoken, 'def'
17
- end
18
-
19
- def test_2
20
- s = Scanner.new("(a\tb|c\td)")
21
- assert_equal s.gettoken, "("
22
- assert_equal s.gettoken, "a\tb"
23
- assert_equal s.gettoken, '|'
24
- assert_equal s.gettoken, "c\td"
25
- assert_equal s.gettoken, ')'
3
+ module ReExpand
4
+ class ScannerTest < Test::Unit::TestCase
5
+ def setup
6
+ end
7
+
8
+ def teardown
9
+ end
10
+
11
+ def test_1
12
+ s = Scanner.new('abc*def')
13
+ assert_equal s.gettoken, 'abc'
14
+ assert_equal s.gettoken, '*'
15
+ assert_equal s.gettoken, 'def'
16
+ end
17
+
18
+ def test_2
19
+ s = Scanner.new("(a\tb|c\td)")
20
+ assert_equal s.gettoken, "("
21
+ assert_equal s.gettoken, "a\tb"
22
+ assert_equal s.gettoken, '|'
23
+ assert_equal s.gettoken, "c\td"
24
+ assert_equal s.gettoken, ')'
25
+ end
26
26
  end
27
27
  end
28
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: re_expand
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Toshiyuki Masui