tb 0.1 → 0.2

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.
Files changed (81) hide show
  1. data/README +156 -5
  2. data/bin/tb +2 -1110
  3. data/lib/tb.rb +4 -2
  4. data/lib/tb/catreader.rb +131 -0
  5. data/lib/tb/cmd_cat.rb +65 -0
  6. data/lib/tb/cmd_consecutive.rb +79 -0
  7. data/lib/tb/cmd_crop.rb +105 -0
  8. data/lib/tb/cmd_cross.rb +119 -0
  9. data/lib/tb/cmd_csv.rb +42 -0
  10. data/lib/tb/cmd_cut.rb +77 -0
  11. data/lib/tb/cmd_grep.rb +76 -0
  12. data/lib/tb/cmd_group.rb +82 -0
  13. data/lib/tb/cmd_gsub.rb +77 -0
  14. data/lib/tb/cmd_help.rb +98 -0
  15. data/lib/tb/cmd_join.rb +81 -0
  16. data/lib/tb/cmd_json.rb +60 -0
  17. data/lib/tb/cmd_ls.rb +273 -0
  18. data/lib/tb/cmd_mheader.rb +77 -0
  19. data/lib/tb/cmd_newfield.rb +59 -0
  20. data/lib/tb/cmd_pnm.rb +43 -0
  21. data/lib/tb/cmd_pp.rb +70 -0
  22. data/lib/tb/cmd_rename.rb +58 -0
  23. data/lib/tb/cmd_shape.rb +67 -0
  24. data/lib/tb/cmd_sort.rb +58 -0
  25. data/lib/tb/cmd_svn_log.rb +158 -0
  26. data/lib/tb/cmd_tsv.rb +43 -0
  27. data/lib/tb/cmd_yaml.rb +47 -0
  28. data/lib/tb/cmdmain.rb +45 -0
  29. data/lib/tb/cmdtop.rb +58 -0
  30. data/lib/tb/cmdutil.rb +327 -0
  31. data/lib/tb/csv.rb +30 -6
  32. data/lib/tb/fieldset.rb +39 -41
  33. data/lib/tb/pager.rb +132 -0
  34. data/lib/tb/pnm.rb +357 -0
  35. data/lib/tb/reader.rb +18 -128
  36. data/lib/tb/record.rb +3 -3
  37. data/lib/tb/ropen.rb +70 -0
  38. data/lib/tb/{pathfinder.rb → search.rb} +69 -34
  39. data/lib/tb/tsv.rb +29 -1
  40. data/sample/colors.ppm +0 -0
  41. data/sample/gradation.pgm +0 -0
  42. data/sample/langs.csv +46 -0
  43. data/sample/tbplot +293 -0
  44. data/test-all-cov.rb +65 -0
  45. data/test-all.rb +5 -0
  46. data/test/test_basic.rb +99 -2
  47. data/test/test_catreader.rb +27 -0
  48. data/test/test_cmd_cat.rb +118 -0
  49. data/test/test_cmd_consecutive.rb +90 -0
  50. data/test/test_cmd_crop.rb +101 -0
  51. data/test/test_cmd_cross.rb +113 -0
  52. data/test/test_cmd_csv.rb +129 -0
  53. data/test/test_cmd_cut.rb +100 -0
  54. data/test/test_cmd_grep.rb +89 -0
  55. data/test/test_cmd_group.rb +181 -0
  56. data/test/test_cmd_gsub.rb +103 -0
  57. data/test/test_cmd_help.rb +190 -0
  58. data/test/test_cmd_join.rb +197 -0
  59. data/test/test_cmd_json.rb +75 -0
  60. data/test/test_cmd_ls.rb +203 -0
  61. data/test/test_cmd_mheader.rb +86 -0
  62. data/test/test_cmd_newfield.rb +63 -0
  63. data/test/test_cmd_pnm.rb +35 -0
  64. data/test/test_cmd_pp.rb +62 -0
  65. data/test/test_cmd_rename.rb +91 -0
  66. data/test/test_cmd_shape.rb +50 -0
  67. data/test/test_cmd_sort.rb +105 -0
  68. data/test/test_cmd_tsv.rb +67 -0
  69. data/test/test_cmd_yaml.rb +55 -0
  70. data/test/test_cmdtty.rb +154 -0
  71. data/test/test_cmdutil.rb +43 -0
  72. data/test/test_csv.rb +10 -0
  73. data/test/test_fieldset.rb +42 -0
  74. data/test/test_pager.rb +142 -0
  75. data/test/test_pnm.rb +374 -0
  76. data/test/test_reader.rb +147 -0
  77. data/test/test_record.rb +49 -0
  78. data/test/test_search.rb +575 -0
  79. data/test/test_tsv.rb +7 -0
  80. metadata +108 -5
  81. data/lib/tb/qtsv.rb +0 -93
@@ -0,0 +1,147 @@
1
+ require 'tb'
2
+ require 'test/unit'
3
+ require 'tmpdir'
4
+
5
+ class TestTbReader < Test::Unit::TestCase
6
+ def test_load_csv
7
+ Dir.mktmpdir {|d|
8
+ open(i="#{d}/i.csv", "w") {|f| f << <<-"End".gsub(/^[ \t]+/, '') }
9
+ a,b
10
+ 1,3
11
+ 2,4
12
+ End
13
+ t = Tb.load_csv(i)
14
+ records = []
15
+ t.each_record {|record| records << record.to_h }
16
+ assert_equal(
17
+ [{"a"=>"1", "b"=>"3"},
18
+ {"a"=>"2", "b"=>"4"}],
19
+ records)
20
+ }
21
+ end
22
+
23
+ def test_load_tsv
24
+ Dir.mktmpdir {|d|
25
+ open(i="#{d}/i.tsv", "w") {|f| f << <<-"End".gsub(/^[ \t]+/, '') }
26
+ a\tb
27
+ 1\t3
28
+ 2\t4
29
+ End
30
+ t = Tb.load_tsv(i)
31
+ records = []
32
+ t.each_record {|record| records << record.to_h }
33
+ assert_equal(
34
+ [{"a"=>"1", "b"=>"3"},
35
+ {"a"=>"2", "b"=>"4"}],
36
+ records)
37
+ }
38
+ end
39
+
40
+ def test_parse_csv
41
+ csv = <<-'End'.gsub(/^[ \t]+/, '')
42
+ 1,2
43
+ 3,4
44
+ End
45
+ t = Tb.parse_csv(csv, 'a', 'b')
46
+ records = []
47
+ t.each_record {|record|
48
+ records << record.to_h
49
+ }
50
+ assert_equal(
51
+ [{"a"=>"1", "b"=>"2"},
52
+ {"a"=>"3", "b"=>"4"}],
53
+ records)
54
+ end
55
+
56
+ def test_parse_tsv
57
+ csv = <<-"End".gsub(/^[ \t]+/, '')
58
+ 1\t2
59
+ 3\t4
60
+ End
61
+ t = Tb.parse_tsv(csv, 'a', 'b')
62
+ records = []
63
+ t.each_record {|record|
64
+ records << record.to_h
65
+ }
66
+ assert_equal(
67
+ [{"a"=>"1", "b"=>"2"},
68
+ {"a"=>"3", "b"=>"4"}],
69
+ records)
70
+ end
71
+
72
+ def test_open
73
+ Dir.mktmpdir {|d|
74
+ open(ic="#{d}/c", "w") {|f| f << <<-"End".gsub(/^[ \t]+/, '') }
75
+ a,b
76
+ 1,3
77
+ End
78
+ open(it="#{d}/t", "w") {|f| f << <<-"End".gsub(/^[ \t]+/, '') }
79
+ a\tb
80
+ 1\t3
81
+ End
82
+ Tb::Reader.open("csv:#{ic}") {|r|
83
+ assert_equal(%w[a b], r.header)
84
+ assert_equal([%w[1 3]], r.read_all)
85
+ }
86
+ Tb::Reader.open("tsv:#{it}") {|r|
87
+ assert_equal(%w[a b], r.header)
88
+ assert_equal([%w[1 3]], r.read_all)
89
+ }
90
+ Tb::Reader.open(ic) {|r|
91
+ assert_equal(%w[a b], r.header)
92
+ assert_equal([%w[1 3]], r.read_all)
93
+ }
94
+ assert_raise(ArgumentError) { Tb::Reader.open(Object.new) }
95
+ }
96
+ end
97
+
98
+ def test_field_index
99
+ Dir.mktmpdir {|d|
100
+ open(i="#{d}/i.csv", "w") {|f| f << <<-"End".gsub(/^[ \t]+/, '') }
101
+ a,b
102
+ 1,3
103
+ End
104
+ Tb::Reader.open(i) {|r|
105
+ assert_equal(%w[a b], r.header)
106
+ assert_equal([%w[1 3]], r.read_all)
107
+ assert_equal("a", r.field_from_index(0))
108
+ assert_equal("b", r.field_from_index(1))
109
+ assert_raise(ArgumentError) { r.field_from_index(2) }
110
+ assert_equal(0, r.index_from_field("a"))
111
+ assert_equal(1, r.index_from_field("b"))
112
+ assert_raise(ArgumentError) { r.index_from_field("c") }
113
+ assert_raise(ArgumentError) { r.index_from_field("2") }
114
+ assert_equal("1", r.field_from_index_ex(2))
115
+ assert_equal(3, r.index_from_field_ex("2"))
116
+ }
117
+ }
118
+ end
119
+
120
+ def test_header_ignore_empty
121
+ csv = "\n" + <<-'End'.gsub(/^[ \t]+/, '')
122
+ a,b
123
+ 1,2
124
+ 3,4
125
+ End
126
+ t = Tb.parse_csv(csv)
127
+ records = []
128
+ t.each_record {|record|
129
+ records << record.to_h
130
+ }
131
+ assert_equal(
132
+ [{"a"=>"1", "b"=>"2"},
133
+ {"a"=>"3", "b"=>"4"}],
134
+ records)
135
+ end
136
+
137
+ def test_header_empty_only
138
+ csv = "\n"
139
+ t = Tb.parse_csv(csv)
140
+ records = []
141
+ t.each_record {|record|
142
+ records << record.to_h
143
+ }
144
+ assert_equal([], records)
145
+ end
146
+
147
+ end
@@ -2,6 +2,54 @@ require 'tb'
2
2
  require 'test/unit'
3
3
 
4
4
  class TestTbRecord < Test::Unit::TestCase
5
+ def test_pretty_print
6
+ t = Tb.new %w[fruit color],
7
+ %w[apple red],
8
+ %w[banana yellow],
9
+ %w[orange orange]
10
+ s = t.get_record(0).pretty_inspect
11
+ assert_match(/apple/, s)
12
+ assert_match(/red/, s)
13
+ end
14
+
15
+ def test_has_field?
16
+ t = Tb.new %w[fruit color],
17
+ %w[apple red],
18
+ %w[banana yellow],
19
+ %w[orange orange]
20
+ r = t.get_record(0)
21
+ assert_equal(true, r.has_field?("fruit"))
22
+ assert_equal(false, r.has_field?("price"))
23
+ end
24
+
25
+ def test_to_a
26
+ t = Tb.new %w[fruit color],
27
+ %w[apple red],
28
+ %w[banana yellow],
29
+ %w[orange orange]
30
+ assert_equal([["fruit", "apple"], ["color", "red"]], t.get_record(0).to_a)
31
+ end
32
+
33
+ def test_to_a_with_reserved
34
+ t = Tb.new %w[fruit color],
35
+ %w[apple red],
36
+ %w[banana yellow],
37
+ %w[orange orange]
38
+ assert_equal([["_recordid", 0], ["fruit", "apple"], ["color", "red"]], t.get_record(0).to_a_with_reserved)
39
+ end
40
+
41
+ def test_each_with_reserved
42
+ t = Tb.new %w[fruit color],
43
+ %w[apple red],
44
+ %w[banana yellow],
45
+ %w[orange orange]
46
+ result = []
47
+ t.get_record(0).each_with_reserved {|r|
48
+ result << r
49
+ }
50
+ assert_equal([["_recordid", 0], ["fruit", "apple"], ["color", "red"]], result)
51
+ end
52
+
5
53
  def test_values_at
6
54
  t = Tb.new %w[fruit color],
7
55
  %w[apple red],
@@ -9,4 +57,5 @@ class TestTbRecord < Test::Unit::TestCase
9
57
  %w[orange orange]
10
58
  assert_equal(["apple", "red"], t.get_record(0).values_at("fruit", "color"))
11
59
  end
60
+
12
61
  end
@@ -0,0 +1,575 @@
1
+ require 'tb'
2
+ require 'test/unit'
3
+
4
+ class TestTbPathFinder < Test::Unit::TestCase
5
+ def test_strary_to_aa
6
+ assert_equal([["a", "b"], ["c", "d"]],
7
+ Tb::Search.strary_to_aa(["ab", "cd"]))
8
+ end
9
+
10
+ def test_match
11
+ ret = Tb::Search.match(
12
+ "b",
13
+ [%w[a b],
14
+ %w[c d]])
15
+ spos, epos, _ = ret
16
+ assert_equal([1, 0], spos)
17
+ assert_equal([1, 0], epos)
18
+ end
19
+
20
+ def test_each_match_with_spos
21
+ res = []
22
+ Tb::Search.each_match(
23
+ "b",
24
+ [%w[a b],
25
+ %w[c d]],
26
+ [1,0]) {|spos, epos, cap|
27
+ res << [spos, epos, cap]
28
+ }
29
+ assert_equal(1, res.size)
30
+ spos, epos, _ = res[0]
31
+ assert_equal([1, 0], spos)
32
+ assert_equal([1, 0], epos)
33
+ end
34
+
35
+ def test_each_match_without_spos
36
+ res = []
37
+ Tb::Search.each_match(
38
+ "b",
39
+ [%w[a b],
40
+ %w[c d]]) {|spos, epos, cap|
41
+ res << [spos, epos, cap]
42
+ }
43
+ assert_equal(1, res.size)
44
+ spos, epos, _ = res[0]
45
+ assert_equal([1, 0], spos)
46
+ assert_equal([1, 0], epos)
47
+ end
48
+
49
+ def test_pat_nil
50
+ res = []
51
+ Tb::Search.each_match(
52
+ nil,
53
+ [%w[a b],
54
+ %w[c d]],
55
+ [1,0]) {|spos, epos, cap|
56
+ res << [spos, epos, cap]
57
+ }
58
+ assert_equal(1, res.size)
59
+ spos, epos, _ = res[0]
60
+ assert_equal([1, 0], spos)
61
+ assert_equal([1, 0], epos)
62
+ end
63
+
64
+ def test_pat_regexp1
65
+ res = []
66
+ Tb::Search.each_match(
67
+ /[bc]/,
68
+ [%w[a b],
69
+ %w[c d]]) {|spos, epos, cap|
70
+ res << [spos, epos, cap]
71
+ }
72
+ assert_equal(2, res.size)
73
+ assert_equal([[1,0], [1,0]], res[0][0..1])
74
+ assert_equal([[0,1], [0,1]], res[1][0..1])
75
+ end
76
+
77
+ def test_pat_regexp2
78
+ res = []
79
+ Tb::Search.each_match(
80
+ [:regexp, /[bc]/],
81
+ [%w[a b],
82
+ %w[c d]]) {|spos, epos, cap|
83
+ res << [spos, epos, cap]
84
+ }
85
+ assert_equal(2, res.size)
86
+ assert_equal([[1,0], [1,0]], res[0][0..1])
87
+ assert_equal([[0,1], [0,1]], res[1][0..1])
88
+ end
89
+
90
+ def test_pat_alt
91
+ res = []
92
+ Tb::Search.each_match(
93
+ [:alt, "b", "c"],
94
+ [%w[a b],
95
+ %w[c d]]) {|spos, epos, cap|
96
+ res << [spos, epos, cap]
97
+ }
98
+ assert_equal(2, res.size)
99
+ assert_equal([[1,0], [1,0]], res[0][0..1])
100
+ assert_equal([[0,1], [0,1]], res[1][0..1])
101
+ end
102
+
103
+ def test_pat_lit
104
+ res = []
105
+ Tb::Search.each_match(
106
+ [:lit, "b"],
107
+ [%w[a b],
108
+ %w[c d]]) {|spos, epos, cap|
109
+ res << [spos, epos, cap]
110
+ }
111
+ assert_equal(1, res.size)
112
+ assert_equal([[1,0], [1,0]], res[0][0..1])
113
+ end
114
+
115
+ def test_pat_nsew
116
+ res = []
117
+ Tb::Search.each_match(
118
+ [:cat, "b", :s, "d", :w, "c", :n, "a", :e, "b"],
119
+ [%w[a b],
120
+ %w[c d]]) {|spos, epos, cap|
121
+ res << [spos, epos, cap]
122
+ }
123
+ assert_equal(1, res.size)
124
+ assert_equal([[1,0], [1,0]], res[0][0..1])
125
+ end
126
+
127
+ def test_pat_direction8
128
+ res = []
129
+ Tb::Search.each_match(
130
+ [:cat, "b", :se, "f", :sw, "h", :nw, "d", :ne, "b"],
131
+ [%w[a b c],
132
+ %w[d e f],
133
+ %w[g h i]]) {|spos, epos, cap|
134
+ res << [spos, epos, cap]
135
+ }
136
+ assert_equal(1, res.size)
137
+ assert_equal([[1,0], [1,0]], res[0][0..1])
138
+ end
139
+
140
+ def test_pat_rmove
141
+ res = []
142
+ Tb::Search.each_match(
143
+ [:cat, "b",
144
+ [:rmove, 0, 1], "d",
145
+ [:rmove, -1, 0], "c",
146
+ [:rmove, 0, -1], "a",
147
+ [:rmove, 1, 0], "b"],
148
+ [%w[a b],
149
+ %w[c d]]) {|spos, epos, cap|
150
+ res << [spos, epos, cap]
151
+ }
152
+ assert_equal(1, res.size)
153
+ assert_equal([[1,0], [1,0]], res[0][0..1])
154
+ end
155
+
156
+ def test_pat_rep
157
+ res = []
158
+ Tb::Search.each_match(
159
+ [:cat, "a", :e, [:rep, "b", :e]],
160
+ [%w[a b b d],
161
+ %w[c d c d]]) {|spos, epos, cap|
162
+ res << [spos, epos, cap]
163
+ }
164
+ assert_equal(3, res.size)
165
+ assert_equal([[0,0], [3,0]], res[0][0..1])
166
+ assert_equal([[0,0], [2,0]], res[1][0..1])
167
+ assert_equal([[0,0], [1,0]], res[2][0..1])
168
+ end
169
+
170
+ def test_pat_rep_to_boundary
171
+ res = []
172
+ Tb::Search.each_match(
173
+ [:rep, "a", :e],
174
+ [%w[a a]],
175
+ [0,0]) {|spos, epos, cap|
176
+ res << [spos, epos, cap]
177
+ }
178
+ assert_equal(3, res.size)
179
+ assert_equal([[0,0], [2,0]], res[0][0..1])
180
+ assert_equal([[0,0], [1,0]], res[1][0..1])
181
+ assert_equal([[0,0], [0,0]], res[2][0..1])
182
+ end
183
+
184
+ def test_pat_rep1
185
+ res = []
186
+ Tb::Search.each_match(
187
+ [:cat, "a", :e, [:rep1, "b", :e]],
188
+ [%w[a b b d],
189
+ %w[c d c d]]) {|spos, epos, cap|
190
+ res << [spos, epos, cap]
191
+ }
192
+ assert_equal(2, res.size)
193
+ assert_equal([[0,0], [3,0]], res[0][0..1])
194
+ assert_equal([[0,0], [2,0]], res[1][0..1])
195
+ end
196
+
197
+ def test_pat_rep_nongreedy
198
+ res = []
199
+ Tb::Search.each_match(
200
+ [:cat, "a", :e, [:rep_nongreedy, "b", :e]],
201
+ [%w[a b b d],
202
+ %w[c d c d]]) {|spos, epos, cap|
203
+ res << [spos, epos, cap]
204
+ }
205
+ assert_equal(3, res.size)
206
+ assert_equal([[0,0], [1,0]], res[0][0..1])
207
+ assert_equal([[0,0], [2,0]], res[1][0..1])
208
+ assert_equal([[0,0], [3,0]], res[2][0..1])
209
+ end
210
+
211
+ def test_pat_rep1_nongreedy
212
+ res = []
213
+ Tb::Search.each_match(
214
+ [:cat, "a", :e, [:rep1_nongreedy, "b", :e]],
215
+ [%w[a b b d],
216
+ %w[c d c d]]) {|spos, epos, cap|
217
+ res << [spos, epos, cap]
218
+ }
219
+ assert_equal(2, res.size)
220
+ assert_equal([[0,0], [2,0]], res[0][0..1])
221
+ assert_equal([[0,0], [3,0]], res[1][0..1])
222
+ end
223
+
224
+ def test_pat_opt
225
+ res = []
226
+ Tb::Search.each_match(
227
+ [:cat, "a", :e, [:opt, "b", :e]],
228
+ [%w[a b b d],
229
+ %w[c d c d]]) {|spos, epos, cap|
230
+ res << [spos, epos, cap]
231
+ }
232
+ assert_equal(2, res.size)
233
+ assert_equal([[0,0], [2,0]], res[0][0..1])
234
+ assert_equal([[0,0], [1,0]], res[1][0..1])
235
+ end
236
+
237
+ def test_pat_opt_nongreedy
238
+ res = []
239
+ Tb::Search.each_match(
240
+ [:cat, "a", :e, [:opt_nongreedy, "b", :e]],
241
+ [%w[a b b d],
242
+ %w[c d c d]]) {|spos, epos, cap|
243
+ res << [spos, epos, cap]
244
+ }
245
+ assert_equal(2, res.size)
246
+ assert_equal([[0,0], [1,0]], res[0][0..1])
247
+ assert_equal([[0,0], [2,0]], res[1][0..1])
248
+ end
249
+
250
+ def test_pat_repn
251
+ res = []
252
+ Tb::Search.each_match(
253
+ [:cat, "a", :e, [:repn, 2, "b", :e]],
254
+ [%w[a b b b d],
255
+ %w[c d c d x]]) {|spos, epos, cap|
256
+ res << [spos, epos, cap]
257
+ }
258
+ assert_equal(1, res.size)
259
+ assert_equal([[0,0], [3,0]], res[0][0..1])
260
+ end
261
+
262
+ def test_pat_repeat
263
+ res = []
264
+ Tb::Search.each_match(
265
+ [:cat, "a", :e, [:repeat, :v, 1, 2, "b", :e]],
266
+ [%w[a b b b d],
267
+ %w[c d c d x]]) {|spos, epos, cap|
268
+ res << [spos, epos, cap]
269
+ }
270
+ assert_equal(2, res.size)
271
+ assert_equal([[0,0], [3,0]], res[0][0..1])
272
+ assert_equal(2, res[0][2][:v])
273
+ assert_equal([[0,0], [2,0]], res[1][0..1])
274
+ assert_equal(1, res[1][2][:v])
275
+ end
276
+
277
+ def test_pat_repeat_empty
278
+ res = []
279
+ Tb::Search.each_match(
280
+ [:rep, [:rep, "a", :e]],
281
+ [%w[a a b]],
282
+ [0,0]) {|spos, epos, cap|
283
+ res << [spos, epos, cap]
284
+ }
285
+ assert_equal(4, res.size)
286
+ assert_equal([[0,0], [2,0]], res[0][0..1])
287
+ assert_equal([[0,0], [2,0]], res[1][0..1])
288
+ assert_equal([[0,0], [1,0]], res[2][0..1])
289
+ assert_equal([[0,0], [0,0]], res[3][0..1])
290
+ end
291
+
292
+ def test_pat_bfs
293
+ res = []
294
+ Tb::Search.each_match(
295
+ [:bfs, [:pos], [:cat, [:alt, :e, :s], "a"]],
296
+ [%w[a a a a a],
297
+ %w[a b b b b],
298
+ %w[a b b b b]],
299
+ [0,0]) {|spos, epos, cap|
300
+ res << [spos, epos, cap]
301
+ }
302
+ assert_equal(7, res.size)
303
+ assert_equal([[0, 0], [0, 0], Tb::Search::EmptyState], res[0])
304
+ assert_equal([[0, 0], [1, 0], Tb::Search::EmptyState], res[1])
305
+ assert_equal([[0, 0], [0, 1], Tb::Search::EmptyState], res[2])
306
+ assert_equal([[0, 0], [2, 0], Tb::Search::EmptyState], res[3])
307
+ assert_equal([[0, 0], [0, 2], Tb::Search::EmptyState], res[4])
308
+ assert_equal([[0, 0], [3, 0], Tb::Search::EmptyState], res[5])
309
+ assert_equal([[0, 0], [4, 0], Tb::Search::EmptyState], res[6])
310
+ end
311
+
312
+ def test_pat_grid_start_goal
313
+ res = []
314
+ Tb::Search.each_match(
315
+ [:grid,
316
+ [:start, "b", "a"],
317
+ ["b", "a", "b"],
318
+ ["a", "b", :goal]],
319
+ [%w[a b a b a],
320
+ %w[b a b a b],
321
+ %w[a b a b a]]) {|spos, epos, cap|
322
+ res << [spos, epos, cap]
323
+ }
324
+ assert_equal(2, res.size)
325
+ assert_equal([[0, 0], [2, 2], Tb::Search::EmptyState], res[0])
326
+ assert_equal([[2, 0], [4, 2], Tb::Search::EmptyState], res[1])
327
+ end
328
+
329
+ def test_pat_grid_start_goal_with_pattern
330
+ res = []
331
+ Tb::Search.each_match(
332
+ [:grid,
333
+ [[:start, "a"], "b", "a"],
334
+ ["b", "a", "b"],
335
+ ["a", "b", [:goal, "a"]]],
336
+ [%w[a b a b a],
337
+ %w[b a b a b],
338
+ %w[a b a b a]]) {|spos, epos, cap|
339
+ res << [spos, epos, cap]
340
+ }
341
+ assert_equal(2, res.size)
342
+ assert_equal([[0, 0], [2, 2], Tb::Search::EmptyState], res[0])
343
+ assert_equal([[2, 0], [4, 2], Tb::Search::EmptyState], res[1])
344
+ end
345
+
346
+ def test_pat_grid_origin
347
+ res = []
348
+ Tb::Search.each_match(
349
+ [:grid,
350
+ ["a", "b", "a"],
351
+ ["b", :origin, "b"],
352
+ ["a", "b", "a"]],
353
+ [%w[a b a b a],
354
+ %w[b a b a b],
355
+ %w[a b a b a]]) {|spos, epos, cap|
356
+ res << [spos, epos, cap]
357
+ }
358
+ assert_equal(2, res.size)
359
+ assert_equal([[1, 1], [1, 1], Tb::Search::EmptyState], res[0])
360
+ assert_equal([[3, 1], [3, 1], Tb::Search::EmptyState], res[1])
361
+ end
362
+
363
+ def test_pat_grid_origin_with_pattern
364
+ res = []
365
+ Tb::Search.each_match(
366
+ [:grid,
367
+ ["a", "b", "a"],
368
+ ["b", [:origin, "a"], "b"],
369
+ ["a", "b", "a"]],
370
+ [%w[a b a b a],
371
+ %w[b a b a b],
372
+ %w[a b a b a]]) {|spos, epos, cap|
373
+ res << [spos, epos, cap]
374
+ }
375
+ assert_equal(2, res.size)
376
+ assert_equal([[1, 1], [1, 1], Tb::Search::EmptyState], res[0])
377
+ assert_equal([[3, 1], [3, 1], Tb::Search::EmptyState], res[1])
378
+ end
379
+
380
+ def test_pat_capval
381
+ res = []
382
+ Tb::Search.each_match(
383
+ [:capval, :name],
384
+ [%w[a b]]) {|spos, epos, cap|
385
+ res << [spos, epos, cap]
386
+ }
387
+ assert_equal(2, res.size)
388
+ assert_equal([[0, 0], [0, 0], Tb::Search::State.make(:name => "a")], res[0])
389
+ assert_equal([[1, 0], [1, 0], Tb::Search::State.make(:name => "b")], res[1])
390
+ end
391
+
392
+ def test_pat_capval_outside
393
+ res = []
394
+ Tb::Search.each_match(
395
+ [:cat, :n, [:capval, :name]],
396
+ [%w[a b]],
397
+ [0,0]) {|spos, epos, cap|
398
+ res << [spos, epos, cap]
399
+ }
400
+ assert_equal(1, res.size)
401
+ assert_equal([[0, 0], [0, -1], Tb::Search::State.make(:name => nil)], res[0])
402
+ end
403
+
404
+ def test_pat_refval
405
+ res = []
406
+ Tb::Search.each_match(
407
+ [:cat, [:capval, :name], [:rep1, :e, [:refval, :name]]],
408
+ [%w[a a b b b c]]) {|spos, epos, cap|
409
+ res << [spos, epos, cap]
410
+ }
411
+ assert_equal(4, res.size)
412
+ assert_equal([[0, 0], [1, 0], Tb::Search::State.make(:name => "a")], res[0])
413
+ assert_equal([[2, 0], [4, 0], Tb::Search::State.make(:name => "b")], res[1])
414
+ assert_equal([[2, 0], [3, 0], Tb::Search::State.make(:name => "b")], res[2])
415
+ assert_equal([[3, 0], [4, 0], Tb::Search::State.make(:name => "b")], res[3])
416
+ end
417
+
418
+ def test_pat_tmp_pos
419
+ res = []
420
+ Tb::Search.each_match(
421
+ [:cat, "a", [:tmp_pos, 1, 0, "b"]],
422
+ [%w[a b a a b b]]) {|spos, epos, cap|
423
+ res << [spos, epos, cap]
424
+ }
425
+ assert_equal(2, res.size)
426
+ assert_equal([[0, 0], [0, 0], Tb::Search::EmptyState], res[0])
427
+ assert_equal([[3, 0], [3, 0], Tb::Search::EmptyState], res[1])
428
+ end
429
+
430
+ def test_pat_save_pos
431
+ res = []
432
+ Tb::Search.each_match(
433
+ [:cat, "a", [:save_pos, :n]],
434
+ [%w[a b a a b b]]) {|spos, epos, cap|
435
+ res << [spos, epos, cap]
436
+ }
437
+ assert_equal(3, res.size)
438
+ assert_equal([[0, 0], [0, 0], Tb::Search::State.make(:n => [0,0])], res[0])
439
+ assert_equal([[2, 0], [2, 0], Tb::Search::State.make(:n => [2,0])], res[1])
440
+ assert_equal([[3, 0], [3, 0], Tb::Search::State.make(:n => [3,0])], res[2])
441
+ end
442
+
443
+ def test_pat_push_pos
444
+ res = []
445
+ Tb::Search.each_match(
446
+ [:rep1, "a", [:push_pos, :n], :e],
447
+ [%w[a b a a b b]]) {|spos, epos, cap|
448
+ res << [spos, epos, cap]
449
+ }
450
+ assert_equal(4, res.size)
451
+ assert_equal([[0, 0], [1, 0], Tb::Search::State.make(:n => [[0,0]])], res[0])
452
+ assert_equal([[2, 0], [4, 0], Tb::Search::State.make(:n => [[2,0],[3,0]])], res[1])
453
+ assert_equal([[2, 0], [3, 0], Tb::Search::State.make(:n => [[2,0]])], res[2])
454
+ assert_equal([[3, 0], [4, 0], Tb::Search::State.make(:n => [[3,0]])], res[3])
455
+ end
456
+
457
+ def test_pat_pop_pos
458
+ res = []
459
+ Tb::Search.each_match(
460
+ [:cat, [:push_pos, :n], "a", :e, "b", [:pop_pos, :n]],
461
+ [%w[a b a a b b]]) {|spos, epos, cap|
462
+ res << [spos, epos, cap]
463
+ }
464
+ assert_equal(2, res.size)
465
+ assert_equal([[0, 0], [0, 0], Tb::Search::State.make(:n => [])], res[0])
466
+ assert_equal([[3, 0], [3, 0], Tb::Search::State.make(:n => [])], res[1])
467
+ end
468
+
469
+ def test_pat_update
470
+ res = []
471
+ Tb::Search.each_match(
472
+ [:cat,
473
+ [:capval, :n],
474
+ [:update, lambda {|st| st.merge(:n => st[:n].succ) }],
475
+ :e,
476
+ [:refval, :n]],
477
+ [%w[a a b b b c]]) {|spos, epos, cap|
478
+ res << [spos, epos, cap]
479
+ }
480
+ assert_equal(2, res.size)
481
+ assert_equal([[1, 0], [2, 0], Tb::Search::State.make(:n => "b")], res[0])
482
+ assert_equal([[4, 0], [5, 0], Tb::Search::State.make(:n => "c")], res[1])
483
+ end
484
+
485
+ def test_pat_assert
486
+ res = []
487
+ Tb::Search.each_match(
488
+ [:cat,
489
+ [:capval, :n],
490
+ [:assert, lambda {|st| st[:n] == 'a' }]],
491
+ [%w[a a b b b c]]) {|spos, epos, cap|
492
+ res << [spos, epos, cap]
493
+ }
494
+ assert_equal(2, res.size)
495
+ assert_equal([[0, 0], [0, 0], Tb::Search::State.make(:n => "a")], res[0])
496
+ assert_equal([[1, 0], [1, 0], Tb::Search::State.make(:n => "a")], res[1])
497
+ end
498
+
499
+ def test_pat_invalid_tag_in_array
500
+ assert_raise(ArgumentError) {
501
+ Tb::Search.each_match(
502
+ [:foo],
503
+ [%w[a b c]]) {|spos, epos, cap|
504
+ }
505
+ }
506
+ end
507
+
508
+ def test_pat_invalid
509
+ assert_raise(ArgumentError) {
510
+ Tb::Search.each_match(
511
+ Object.new,
512
+ [%w[a b c]]) {|spos, epos, cap|
513
+ }
514
+ }
515
+ end
516
+
517
+ def test_emptystate_to_h
518
+ s = Tb::Search::EmptyState
519
+ assert_equal({}, s.to_h)
520
+ end
521
+
522
+ def test_emptystate_fetch
523
+ s = Tb::Search::EmptyState
524
+ assert_equal("foo", s.fetch(:k) {|k| assert_equal(:k, k); "foo" })
525
+ assert_equal("bar", s.fetch(:k, "bar"))
526
+ if defined? KeyError
527
+ assert_raise(KeyError) { s.fetch(:k) } # Ruby 1.9
528
+ else
529
+ assert_raise(IndexError) { s.fetch(:k) } # Ruby 1.8
530
+ end
531
+ end
532
+
533
+ def test_emptystate_values_at
534
+ s = Tb::Search::EmptyState
535
+ assert_equal([], s.values_at())
536
+ assert_equal([nil, nil, nil], s.values_at(:x, :y, :z))
537
+ end
538
+
539
+ def test_emptystate_keys
540
+ s = Tb::Search::EmptyState
541
+ assert_equal([], s.keys)
542
+ end
543
+
544
+ def test_emptystate_reject
545
+ s = Tb::Search::EmptyState
546
+ assert_equal(Tb::Search::EmptyState, s.reject {|k, v| flunk })
547
+ end
548
+
549
+ def test_emptystate_inspect
550
+ s = Tb::Search::EmptyState
551
+ assert_kind_of(String, s.inspect)
552
+ end
553
+
554
+ def test_state_fetch
555
+ s = Tb::Search::State.make(:k => 1)
556
+ assert_equal(1, s.fetch(:k))
557
+ assert_equal(:foo, s.fetch(:x) {|k| assert_equal(:x, k); :foo })
558
+ if defined? KeyError
559
+ assert_raise(KeyError) { s.fetch(:x) } # Ruby 1.9
560
+ else
561
+ assert_raise(IndexError) { s.fetch(:x) } # Ruby 1.8
562
+ end
563
+ end
564
+
565
+ def test_state_keys
566
+ s = Tb::Search::State.make(:k => 1)
567
+ assert_equal([:k], s.keys)
568
+ end
569
+
570
+ def test_state_inspect
571
+ s = Tb::Search::State.make(:k => 1)
572
+ assert_kind_of(String, s.inspect)
573
+ end
574
+
575
+ end