citrus 2.3.7 → 2.4.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.
data/CHANGES CHANGED
@@ -1,3 +1,12 @@
1
+ = 2.4.0 / 2011-05-11
2
+
3
+ * Fixed a bug that prevented parsing nested blocks correctly (issue #21).
4
+
5
+ * Added URI example.
6
+
7
+ * Moved example grammars inside lib/citrus/grammars and added
8
+ lib/citrus/grammars.rb for easily requiring Citrus example grammars.
9
+
1
10
  = 2.3.7 / 2011-02-20
2
11
 
3
12
  * Fixed a bug that prevented forward slashes from being used inside character
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ task :default => :test
6
6
  # TESTS #######################################################################
7
7
 
8
8
  Rake::TestTask.new(:test) do |t|
9
- t.test_files = FileList['test/*_test.rb'] + FileList['examples/*_test.rb']
9
+ t.test_files = FileList['test/**/*_test.rb']
10
10
  end
11
11
 
12
12
  # DOCS ########################################################################
data/citrus.gemspec CHANGED
@@ -17,7 +17,6 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.files = Dir['benchmark/**'] +
19
19
  Dir['doc/**'] +
20
- Dir['examples/**'] +
21
20
  Dir['extras/**'] +
22
21
  Dir['lib/**/*.rb'] +
23
22
  Dir['test/**/*'] +
data/lib/citrus.rb CHANGED
@@ -648,6 +648,11 @@ module Citrus
648
648
  nil
649
649
  end
650
650
 
651
+ # Tests the given +obj+ for case equality with this rule.
652
+ def ===(obj)
653
+ !test(obj).nil?
654
+ end
655
+
651
656
  # Returns +true+ if this rule is a Terminal.
652
657
  def terminal?
653
658
  false
@@ -700,6 +705,8 @@ module Citrus
700
705
  end
701
706
  end
702
707
 
708
+ alias_method :eql?, :==
709
+
703
710
  def inspect # :nodoc:
704
711
  to_s
705
712
  end
@@ -872,6 +879,8 @@ module Citrus
872
879
  end
873
880
  end
874
881
 
882
+ alias_method :eql?, :==
883
+
875
884
  # Returns +true+ if this rule is a Terminal.
876
885
  def terminal? # :nodoc:
877
886
  true
@@ -915,6 +924,8 @@ module Citrus
915
924
  end
916
925
  end
917
926
 
927
+ alias_method :eql?, :==
928
+
918
929
  # Returns the Citrus notation of this rule as a string.
919
930
  def to_citrus # :nodoc:
920
931
  if case_sensitive?
@@ -1336,6 +1347,8 @@ module Citrus
1336
1347
  end
1337
1348
  end
1338
1349
 
1350
+ alias_method :eql?, :==
1351
+
1339
1352
  def inspect
1340
1353
  @string.inspect
1341
1354
  end
data/lib/citrus/file.rb CHANGED
@@ -73,7 +73,7 @@ module Citrus
73
73
  end
74
74
 
75
75
  rule :expression do
76
- all(:sequence, zero_or_more([ :bar, :sequence ])) {
76
+ all(:sequence, zero_or_more([['|', zero_or_one(:space)], :sequence])) {
77
77
  rules = captures[:sequence].map {|s| s.value }
78
78
  rules.length > 1 ? Choice.new(rules) : rules.first
79
79
  }
@@ -123,7 +123,7 @@ module Citrus
123
123
  end
124
124
 
125
125
  rule :grouping do
126
- all(:lparen, :expression, :rparen) {
126
+ all(['(', zero_or_one(:space)], :expression, [')', zero_or_one(:space)]) {
127
127
  expression.value
128
128
  }
129
129
  end
@@ -241,7 +241,11 @@ module Citrus
241
241
  end
242
242
 
243
243
  rule :tag do
244
- mod all(:lt, :module_name, :gt) do
244
+ mod all(
245
+ ['<', zero_or_one(:space)],
246
+ :module_name,
247
+ ['>', zero_or_one(:space)]
248
+ ) do
245
249
  include ModuleNameHelpers
246
250
 
247
251
  def value
@@ -251,7 +255,11 @@ module Citrus
251
255
  end
252
256
 
253
257
  rule :block do
254
- all(:lcurly, zero_or_more(any(:block, /[^{}]+/)), :rcurly) {
258
+ all(
259
+ '{',
260
+ zero_or_more(any(:block, /[^{}]+/)),
261
+ ['}', zero_or_one(:space)]
262
+ ) {
255
263
  proc = eval("Proc.new #{to_s}", TOPLEVEL_BINDING)
256
264
 
257
265
  # Attempt to detect if this is a module block using some
@@ -322,13 +330,6 @@ module Citrus
322
330
  rule :root_keyword, [ /\broot\b/, :space ]
323
331
  rule :rule_keyword, [ /\brule\b/, :space ]
324
332
  rule :end_keyword, [ /\bend\b/, :space ]
325
- rule :lparen, [ '(', :space ]
326
- rule :rparen, [ ')', :space ]
327
- rule :lcurly, [ '{', :space ]
328
- rule :rcurly, [ '}', :space ]
329
- rule :bar, [ '|', :space ]
330
- rule :lt, [ '<', :space ]
331
- rule :gt, [ '>', :space ]
332
333
 
333
334
  rule :constant, /[A-Z][a-zA-Z0-9_]*/
334
335
  rule :white, /[ \t\n\r]/
@@ -0,0 +1,11 @@
1
+ # Require this file to use any of the bundled Citrus grammars.
2
+ #
3
+ # require 'citrus/grammars'
4
+ # Citrus.require 'uri'
5
+ #
6
+ # match = UniformResourceIdentifier.parse(uri_string)
7
+ # # => #<Citrus::Match ... >
8
+
9
+ require 'citrus'
10
+
11
+ $LOAD_PATH.unshift(::File.expand_path('../grammars', __FILE__))
@@ -1,6 +1,6 @@
1
1
  module Citrus
2
2
  # The current version of Citrus as [major, minor, patch].
3
- VERSION = [2, 3, 7]
3
+ VERSION = [2, 4, 0]
4
4
 
5
5
  # Returns the current version of Citrus as a string.
6
6
  def self.version
@@ -0,0 +1,5 @@
1
+ rule method
2
+ (def space method_name statements ends) {
3
+ "#{method_name.value} = function() { #{statements.value} }"
4
+ }
5
+ end
data/test/grammar_test.rb CHANGED
@@ -118,7 +118,8 @@ class GrammarTest < Test::Unit::TestCase
118
118
  assert_equal('((a))', match)
119
119
  assert_equal(5, match.length)
120
120
 
121
- str = ('(' * 200) + 'a' + (')' * 200)
121
+ n = 100
122
+ str = ('(' * n) + 'a' + (')' * n)
122
123
  match = grammar.parse(str)
123
124
  assert(match)
124
125
  assert_equal(str, match)
@@ -1,8 +1,7 @@
1
- # This file contains a suite of tests for the Calc grammar found in calc.citrus.
1
+ require File.expand_path('../../helper', __FILE__)
2
+ require 'citrus/grammars'
2
3
 
3
- require 'citrus'
4
- Citrus.require File.expand_path('../calc', __FILE__)
5
- require 'test/unit'
4
+ Citrus.require 'calc'
6
5
 
7
6
  class CalcTest < Test::Unit::TestCase
8
7
  # A helper method that tests the successful parsing and evaluation of the
File without changes
@@ -1,9 +1,7 @@
1
- # This file contains a suite of tests for the EmailAddress grammar
2
- # found in email.citrus.
1
+ require File.expand_path('../../helper', __FILE__)
2
+ require 'citrus/grammars'
3
3
 
4
- require 'citrus'
5
- Citrus.require File.expand_path('../email', __FILE__)
6
- require 'test/unit'
4
+ Citrus.require 'email'
7
5
 
8
6
  class EmailAddressTest < Test::Unit::TestCase
9
7
  def test_addr_spec_valid
@@ -1,12 +1,7 @@
1
- examples = File.expand_path('..', __FILE__)
2
- $LOAD_PATH.unshift(examples) unless $LOAD_PATH.include?(examples)
1
+ require File.expand_path('../../helper', __FILE__)
2
+ require 'citrus/grammars'
3
3
 
4
- # This file contains a suite of tests for the IPAddress grammar found in
5
- # ipaddress.citrus.
6
-
7
- require 'citrus'
8
4
  Citrus.require 'ipaddress'
9
- require 'test/unit'
10
5
 
11
6
  class IPAddressTest < Test::Unit::TestCase
12
7
  def test_v4
File without changes
@@ -1,12 +1,7 @@
1
- examples = File.expand_path('..', __FILE__)
2
- $LOAD_PATH.unshift(examples) unless $LOAD_PATH.include?(examples)
1
+ require File.expand_path('../../helper', __FILE__)
2
+ require 'citrus/grammars'
3
3
 
4
- # This file contains a suite of tests for the IPv4Address grammar found in
5
- # ipv4address.citrus.
6
-
7
- require 'citrus'
8
4
  Citrus.require 'ipv4address'
9
- require 'test/unit'
10
5
 
11
6
  class IPv4AddressTest < Test::Unit::TestCase
12
7
  def test_dec_octet
File without changes
@@ -1,12 +1,7 @@
1
- examples = File.expand_path('..', __FILE__)
2
- $LOAD_PATH.unshift(examples) unless $LOAD_PATH.include?(examples)
1
+ require File.expand_path('../../helper', __FILE__)
2
+ require 'citrus/grammars'
3
3
 
4
- # This file contains a suite of tests for the IPv6Address grammar found in
5
- # ipv6address.citrus.
6
-
7
- require 'citrus'
8
4
  Citrus.require 'ipv6address'
9
- require 'test/unit'
10
5
 
11
6
  class IPv6AddressTest < Test::Unit::TestCase
12
7
  def test_hexdig
File without changes
@@ -0,0 +1,53 @@
1
+ require File.expand_path('../../helper', __FILE__)
2
+ require 'citrus/grammars'
3
+
4
+ Citrus.require 'uri'
5
+
6
+ class UniformResourceIdentifierTest < Test::Unit::TestCase
7
+ U = UniformResourceIdentifier
8
+
9
+ def test_uri
10
+ match = U.parse('http://www.example.com')
11
+ assert(match)
12
+ end
13
+
14
+ def test_uri_with_query_string
15
+ match = U.parse('http://www.example.com/?q=some+query')
16
+ assert(match)
17
+ end
18
+
19
+ def test_authority
20
+ match = U.parse('michael@', :root => :authority)
21
+ assert(match)
22
+ end
23
+
24
+ def test_host
25
+ match = U.parse('127.0.0.1', :root => :host)
26
+ assert(match)
27
+
28
+ match = U.parse('[12AD:34FC:A453:1922::]', :root => :host)
29
+ assert(match)
30
+ end
31
+
32
+ def test_userinfo
33
+ match = U.parse('michael', :root => :userinfo)
34
+ assert(match)
35
+
36
+ assert_raise(Citrus::ParseError) do
37
+ U.parse('michael@', :root => :userinfo)
38
+ end
39
+ end
40
+
41
+ def test_ipliteral
42
+ match = U.parse('[12AD:34FC:A453:1922::]', :root => :'IP-literal')
43
+ assert(match)
44
+ end
45
+
46
+ def test_ipvfuture
47
+ match = U.parse('v1.123:456:789', :root => :IPvFuture)
48
+ assert(match)
49
+
50
+ match = U.parse('v5A.ABCD:1234', :root => :IPvFuture)
51
+ assert(match)
52
+ end
53
+ end
@@ -118,7 +118,7 @@ x
118
118
  17
119
119
  MemoizedInputTest
120
120
  i
121
- 68
121
+ 92
122
122
  5
123
123
  66
124
124
  99
@@ -186,6 +186,30 @@ i
186
186
  49
187
187
  3
188
188
  4
189
+ 15
190
+ 5
191
+ 7
192
+ 13
193
+ 56
194
+ 14
195
+ 47
196
+ 50
197
+ 6
198
+ 1
199
+ 15
200
+ 99
201
+ 7
202
+ 15
203
+ 7
204
+ 16
205
+ 65
206
+ 67
207
+ 49
208
+ 2
209
+ 0
210
+ 49
211
+ 3
212
+ 4
189
213
  11
190
214
  I
191
215
  5
@@ -197,7 +221,7 @@ I
197
221
  0
198
222
  n
199
223
  p
200
- 13
224
+ 17
201
225
  x
202
226
  14
203
227
  test_memoized?
@@ -649,7 +673,7 @@ x
649
673
  16
650
674
  test_cache_hits1
651
675
  i
652
- 59
676
+ 60
653
677
  45
654
678
  0
655
679
  1
@@ -698,7 +722,8 @@ i
698
722
  1
699
723
  15
700
724
  5
701
- 80
725
+ 4
726
+ 3
702
727
  20
703
728
  0
704
729
  49
@@ -774,7 +799,7 @@ I
774
799
  I
775
800
  1d
776
801
  I
777
- 3b
802
+ 3c
778
803
  x
779
804
  58
780
805
  /Users/michael/Projects/citrus/test/memoized_input_test.rb
@@ -1073,11 +1098,461 @@ p
1073
1098
  x
1074
1099
  5
1075
1100
  input
1101
+ x
1102
+ 10
1103
+ LettersABC
1104
+ M
1105
+ 1
1106
+ p
1107
+ 2
1108
+ x
1109
+ 9
1110
+ for_block
1111
+ t
1112
+ n
1113
+ x
1114
+ 17
1115
+ MemoizedInputTest
1116
+ i
1117
+ 40
1118
+ 5
1119
+ 7
1120
+ 0
1121
+ 56
1122
+ 1
1123
+ 47
1124
+ 50
1125
+ 2
1126
+ 1
1127
+ 15
1128
+ 5
1129
+ 7
1130
+ 3
1131
+ 56
1132
+ 4
1133
+ 47
1134
+ 50
1135
+ 2
1136
+ 1
1137
+ 15
1138
+ 5
1139
+ 7
1140
+ 5
1141
+ 56
1142
+ 6
1143
+ 47
1144
+ 50
1145
+ 2
1146
+ 1
1147
+ 15
1148
+ 5
1149
+ 7
1150
+ 7
1151
+ 56
1152
+ 8
1153
+ 47
1154
+ 50
1155
+ 2
1156
+ 1
1157
+ 11
1158
+ I
1159
+ 4
1160
+ I
1161
+ 0
1162
+ I
1163
+ 0
1164
+ I
1165
+ 0
1166
+ I
1167
+ -2
1168
+ p
1169
+ 9
1170
+ x
1171
+ 3
1172
+ top
1173
+ M
1174
+ 1
1175
+ p
1176
+ 2
1177
+ x
1178
+ 9
1179
+ for_block
1180
+ t
1181
+ n
1182
+ x
1183
+ 17
1184
+ MemoizedInputTest
1185
+ i
1186
+ 39
1187
+ 5
1188
+ 5
1189
+ 7
1190
+ 0
1191
+ 7
1192
+ 1
1193
+ 7
1194
+ 2
1195
+ 47
1196
+ 49
1197
+ 3
1198
+ 3
1199
+ 5
1200
+ 7
1201
+ 1
1202
+ 7
1203
+ 0
1204
+ 7
1205
+ 2
1206
+ 47
1207
+ 49
1208
+ 3
1209
+ 3
1210
+ 5
1211
+ 7
1212
+ 1
1213
+ 7
1214
+ 2
1215
+ 7
1216
+ 0
1217
+ 47
1218
+ 49
1219
+ 3
1220
+ 3
1221
+ 47
1222
+ 49
1223
+ 4
1224
+ 3
1225
+ 11
1226
+ I
1227
+ 8
1228
+ I
1229
+ 0
1230
+ I
1231
+ 0
1232
+ I
1233
+ 0
1234
+ I
1235
+ -2
1236
+ p
1237
+ 5
1238
+ x
1239
+ 1
1240
+ a
1241
+ x
1242
+ 1
1243
+ b
1244
+ x
1245
+ 1
1246
+ c
1247
+ x
1248
+ 3
1249
+ all
1250
+ x
1251
+ 3
1252
+ any
1253
+ p
1254
+ 3
1255
+ I
1256
+ 0
1257
+ I
1258
+ 2e
1259
+ I
1260
+ 27
1261
+ x
1262
+ 58
1263
+ /Users/michael/Projects/citrus/test/memoized_input_test.rb
1264
+ p
1265
+ 0
1266
+ x
1267
+ 4
1268
+ rule
1269
+ x
1270
+ 1
1271
+ a
1272
+ M
1273
+ 1
1274
+ p
1275
+ 2
1276
+ x
1277
+ 9
1278
+ for_block
1279
+ t
1280
+ n
1281
+ x
1282
+ 17
1283
+ MemoizedInputTest
1284
+ i
1285
+ 4
1286
+ 7
1287
+ 0
1288
+ 64
1289
+ 11
1290
+ I
1291
+ 2
1292
+ I
1293
+ 0
1294
+ I
1295
+ 0
1296
+ I
1297
+ 0
1298
+ I
1299
+ -2
1300
+ p
1301
+ 1
1302
+ s
1303
+ 1
1304
+ a
1076
1305
  p
1306
+ 3
1307
+ I
1308
+ 0
1309
+ I
1310
+ 31
1311
+ I
1312
+ 4
1313
+ x
1314
+ 58
1315
+ /Users/michael/Projects/citrus/test/memoized_input_test.rb
1316
+ p
1317
+ 0
1318
+ x
1319
+ 1
1320
+ b
1321
+ M
1322
+ 1
1323
+ p
1324
+ 2
1325
+ x
1326
+ 9
1327
+ for_block
1328
+ t
1329
+ n
1330
+ x
1331
+ 17
1332
+ MemoizedInputTest
1333
+ i
1334
+ 4
1335
+ 7
1336
+ 0
1337
+ 64
1338
+ 11
1339
+ I
1340
+ 2
1341
+ I
1342
+ 0
1343
+ I
1344
+ 0
1345
+ I
1346
+ 0
1347
+ I
1348
+ -2
1349
+ p
1350
+ 1
1351
+ s
1352
+ 1
1353
+ b
1354
+ p
1355
+ 3
1356
+ I
1357
+ 0
1358
+ I
1359
+ 34
1360
+ I
1361
+ 4
1362
+ x
1363
+ 58
1364
+ /Users/michael/Projects/citrus/test/memoized_input_test.rb
1365
+ p
1366
+ 0
1367
+ x
1368
+ 1
1369
+ c
1370
+ M
1371
+ 1
1372
+ p
1373
+ 2
1374
+ x
1375
+ 9
1376
+ for_block
1377
+ t
1378
+ n
1379
+ x
1380
+ 17
1381
+ MemoizedInputTest
1382
+ i
1383
+ 4
1384
+ 7
1385
+ 0
1386
+ 64
1077
1387
  11
1078
1388
  I
1079
1389
  2
1080
1390
  I
1391
+ 0
1392
+ I
1393
+ 0
1394
+ I
1395
+ 0
1396
+ I
1397
+ -2
1398
+ p
1399
+ 1
1400
+ s
1401
+ 1
1402
+ c
1403
+ p
1404
+ 3
1405
+ I
1406
+ 0
1407
+ I
1408
+ 37
1409
+ I
1410
+ 4
1411
+ x
1412
+ 58
1413
+ /Users/michael/Projects/citrus/test/memoized_input_test.rb
1414
+ p
1415
+ 0
1416
+ p
1417
+ 9
1418
+ I
1419
+ 0
1420
+ I
1421
+ 2d
1422
+ I
1423
+ a
1424
+ I
1425
+ 30
1426
+ I
1427
+ 14
1428
+ I
1429
+ 33
1430
+ I
1431
+ 1e
1432
+ I
1433
+ 36
1434
+ I
1435
+ 28
1436
+ x
1437
+ 58
1438
+ /Users/michael/Projects/citrus/test/memoized_input_test.rb
1439
+ p
1440
+ 0
1441
+ x
1442
+ 16
1443
+ test_memoization
1444
+ M
1445
+ 1
1446
+ n
1447
+ n
1448
+ x
1449
+ 16
1450
+ test_memoization
1451
+ i
1452
+ 38
1453
+ 45
1454
+ 0
1455
+ 1
1456
+ 7
1457
+ 2
1458
+ 64
1459
+ 44
1460
+ 43
1461
+ 3
1462
+ 79
1463
+ 49
1464
+ 4
1465
+ 1
1466
+ 13
1467
+ 7
1468
+ 5
1469
+ 2
1470
+ 49
1471
+ 6
1472
+ 2
1473
+ 15
1474
+ 49
1475
+ 7
1476
+ 2
1477
+ 19
1478
+ 0
1479
+ 15
1480
+ 5
1481
+ 7
1482
+ 2
1483
+ 64
1484
+ 20
1485
+ 0
1486
+ 47
1487
+ 49
1488
+ 8
1489
+ 2
1490
+ 11
1491
+ I
1492
+ 7
1493
+ I
1494
+ 1
1495
+ I
1496
+ 0
1497
+ I
1498
+ 0
1499
+ n
1500
+ p
1501
+ 9
1502
+ x
1503
+ 10
1504
+ LettersABC
1505
+ n
1506
+ s
1507
+ 3
1508
+ bca
1509
+ x
1510
+ 4
1511
+ Hash
1512
+ x
1513
+ 16
1514
+ new_from_literal
1515
+ x
1516
+ 7
1517
+ memoize
1518
+ x
1519
+ 3
1520
+ []=
1521
+ x
1522
+ 5
1523
+ parse
1524
+ x
1525
+ 12
1526
+ assert_equal
1527
+ p
1528
+ 7
1529
+ I
1530
+ -1
1531
+ I
1532
+ 3b
1533
+ I
1534
+ 0
1535
+ I
1536
+ 3c
1537
+ I
1538
+ 1b
1539
+ I
1540
+ 3d
1541
+ I
1542
+ 26
1543
+ x
1544
+ 58
1545
+ /Users/michael/Projects/citrus/test/memoized_input_test.rb
1546
+ p
1547
+ 1
1548
+ x
1549
+ 5
1550
+ match
1551
+ p
1552
+ 15
1553
+ I
1554
+ 2
1555
+ I
1081
1556
  4
1082
1557
  I
1083
1558
  10
@@ -1097,6 +1572,14 @@ I
1097
1572
  26
1098
1573
  I
1099
1574
  44
1575
+ I
1576
+ 2c
1577
+ I
1578
+ 4e
1579
+ I
1580
+ 3b
1581
+ I
1582
+ 5c
1100
1583
  x
1101
1584
  58
1102
1585
  /Users/michael/Projects/citrus/test/memoized_input_test.rb