citrus 2.4.1 → 2.5.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 +13 -0
- data/Rakefile +1 -1
- data/lib/citrus.rb +87 -35
- data/lib/citrus/file.rb +2 -1
- data/lib/citrus/version.rb +1 -1
- data/test/_files/rule6.citrus +1 -0
- data/test/_files/rule7.citrus +3 -0
- data/test/alias_test.rb +0 -2
- data/test/grammar_test.rb +25 -2
- data/test/input_test.rb +15 -0
- data/test/match_test.rb +25 -1
- data/test/super_test.rb +0 -4
- metadata +37 -51
data/CHANGES
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
= 2.5.0 / 2014-03-13
|
2
|
+
|
3
|
+
* Inputs may be generated from many different sources, including Pathname and
|
4
|
+
IO objects (thanks blambeau).
|
5
|
+
|
6
|
+
* Matches keep track of their offset in the original source (thanks
|
7
|
+
blambeau).
|
8
|
+
|
9
|
+
* Citrus.load no longer raises Citrus::LoadError for files that can't be found
|
10
|
+
or are not readable. Users must rescue Errno::ENOENT instead, for example.
|
11
|
+
|
12
|
+
* Removed a few ruby warnings (thanks tbuehlmann)
|
13
|
+
|
1
14
|
= 2.4.1 / 2011-11-04
|
2
15
|
|
3
16
|
* Fixed a bug that prevented rule names from starting with "super".
|
data/Rakefile
CHANGED
@@ -15,7 +15,7 @@ desc "Generate API documentation"
|
|
15
15
|
task :api => 'lib/citrus.rb' do |t|
|
16
16
|
output_dir = ENV['OUTPUT_DIR'] || 'api'
|
17
17
|
rm_rf output_dir
|
18
|
-
sh((<<-SH).gsub(
|
18
|
+
sh((<<-SH).gsub(/\s+/, ' ').strip)
|
19
19
|
hanna
|
20
20
|
--op #{output_dir}
|
21
21
|
--promiscuous
|
data/lib/citrus.rb
CHANGED
@@ -73,9 +73,6 @@ module Citrus
|
|
73
73
|
force = options.delete(:force)
|
74
74
|
|
75
75
|
if force || !cache[file]
|
76
|
-
raise LoadError, "Cannot find file #{file}" unless ::File.file?(file)
|
77
|
-
raise LoadError, "Cannot read file #{file}" unless ::File.readable?(file)
|
78
|
-
|
79
76
|
begin
|
80
77
|
cache[file] = eval(::File.read(file), options)
|
81
78
|
rescue SyntaxError => e
|
@@ -117,7 +114,10 @@ module Citrus
|
|
117
114
|
end
|
118
115
|
|
119
116
|
# A base class for all Citrus errors.
|
120
|
-
class Error <
|
117
|
+
class Error < StandardError; end
|
118
|
+
|
119
|
+
# Raised when Citrus.require can't find the file to load.
|
120
|
+
class LoadError < Error; end
|
121
121
|
|
122
122
|
# Raised when a parse fails.
|
123
123
|
class ParseError < Error
|
@@ -156,9 +156,6 @@ module Citrus
|
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
159
|
-
# Raised when Citrus.load fails to load a file.
|
160
|
-
class LoadError < Error; end
|
161
|
-
|
162
159
|
# Raised when Citrus::File.parse fails.
|
163
160
|
class SyntaxError < Error
|
164
161
|
# The +error+ given here is an instance of Citrus::ParseError.
|
@@ -173,14 +170,19 @@ module Citrus
|
|
173
170
|
# An Input is a scanner that is responsible for executing rules at different
|
174
171
|
# positions in the input string and persisting event streams.
|
175
172
|
class Input < StringScanner
|
176
|
-
def initialize(
|
177
|
-
super(
|
173
|
+
def initialize(source)
|
174
|
+
super(source_text(source))
|
175
|
+
@source = source
|
178
176
|
@max_offset = 0
|
179
177
|
end
|
180
178
|
|
181
179
|
# The maximum offset in the input that was successfully parsed.
|
182
180
|
attr_reader :max_offset
|
183
181
|
|
182
|
+
# The initial source passed at construction. Typically a String
|
183
|
+
# or a Pathname.
|
184
|
+
attr_reader :source
|
185
|
+
|
184
186
|
def reset # :nodoc:
|
185
187
|
@max_offset = 0
|
186
188
|
super
|
@@ -263,8 +265,24 @@ module Citrus
|
|
263
265
|
events[-1]
|
264
266
|
end
|
265
267
|
|
268
|
+
# Returns the scanned string.
|
269
|
+
alias_method :to_str, :string
|
270
|
+
|
266
271
|
private
|
267
272
|
|
273
|
+
# Returns the text to parse from +source+.
|
274
|
+
def source_text(source)
|
275
|
+
if source.respond_to?(:to_path)
|
276
|
+
::File.read(source.to_path)
|
277
|
+
elsif source.respond_to?(:read)
|
278
|
+
source.read
|
279
|
+
elsif source.respond_to?(:to_str)
|
280
|
+
source.to_str
|
281
|
+
else
|
282
|
+
raise ArgumentError, "Unable to parse from #{source}", caller
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
268
286
|
# Appends all events for +rule+ at the given +position+ to +events+.
|
269
287
|
def apply_rule(rule, position, events)
|
270
288
|
rule.exec(self, events)
|
@@ -361,17 +379,24 @@ module Citrus
|
|
361
379
|
super
|
362
380
|
end
|
363
381
|
|
364
|
-
# Parses the given +
|
382
|
+
# Parses the given +source+ using this grammar's root rule. Accepts the same
|
365
383
|
# +options+ as Rule#parse, plus the following:
|
366
384
|
#
|
367
385
|
# root:: The name of the root rule to start parsing at. Defaults to this
|
368
386
|
# grammar's #root.
|
369
|
-
def parse(
|
387
|
+
def parse(source, options={})
|
370
388
|
rule_name = options.delete(:root) || root
|
371
389
|
raise Error, "No root rule specified" unless rule_name
|
372
390
|
rule = rule(rule_name)
|
373
391
|
raise Error, "No rule named \"#{rule_name}\"" unless rule
|
374
|
-
rule.parse(
|
392
|
+
rule.parse(source, options)
|
393
|
+
end
|
394
|
+
|
395
|
+
# Parses the contents of the file at the given +path+ using this grammar's
|
396
|
+
# #root rule. Accepts the same +options+ as #parse.
|
397
|
+
def parse_file(path, options={})
|
398
|
+
path = Pathname.new(path.to_str) unless Pathname === path
|
399
|
+
parse(path, options)
|
375
400
|
end
|
376
401
|
|
377
402
|
# Returns the name of this grammar as a string.
|
@@ -455,9 +480,16 @@ module Citrus
|
|
455
480
|
# Gets/sets the +name+ of the root rule of this grammar. If no root rule is
|
456
481
|
# explicitly specified, the name of this grammar's first rule is returned.
|
457
482
|
def root(name=nil)
|
458
|
-
|
459
|
-
|
460
|
-
|
483
|
+
if name
|
484
|
+
@root = name.to_sym
|
485
|
+
else
|
486
|
+
# The first rule in a grammar is the default root.
|
487
|
+
if instance_variable_defined?(:@root)
|
488
|
+
@root
|
489
|
+
else
|
490
|
+
rule_names.first
|
491
|
+
end
|
492
|
+
end
|
461
493
|
end
|
462
494
|
|
463
495
|
# Creates a new rule that will match any single character. A block may be
|
@@ -623,10 +655,11 @@ module Citrus
|
|
623
655
|
# +false+.
|
624
656
|
# offset:: The offset in +string+ at which to start parsing. Defaults
|
625
657
|
# to 0.
|
626
|
-
def parse(
|
658
|
+
def parse(source, options={})
|
627
659
|
opts = default_options.merge(options)
|
628
660
|
|
629
|
-
input = (opts[:memoize] ? MemoizedInput : Input).new(
|
661
|
+
input = (opts[:memoize] ? MemoizedInput : Input).new(source)
|
662
|
+
string = input.string
|
630
663
|
input.pos = opts[:offset] if opts[:offset] > 0
|
631
664
|
|
632
665
|
events = input.exec(self)
|
@@ -636,7 +669,7 @@ module Citrus
|
|
636
669
|
raise ParseError, input
|
637
670
|
end
|
638
671
|
|
639
|
-
Match.new(
|
672
|
+
Match.new(input, events, opts[:offset])
|
640
673
|
end
|
641
674
|
|
642
675
|
# Tests whether or not this rule matches on the given +string+. Returns the
|
@@ -1239,14 +1272,13 @@ module Citrus
|
|
1239
1272
|
# instantiated as needed. This class provides several convenient tree
|
1240
1273
|
# traversal methods that help when examining and interpreting parse results.
|
1241
1274
|
class Match
|
1242
|
-
def initialize(
|
1243
|
-
@
|
1275
|
+
def initialize(input, events=[], offset=0)
|
1276
|
+
@input = input
|
1277
|
+
@offset = offset
|
1278
|
+
@captures = nil
|
1279
|
+
@matches = nil
|
1244
1280
|
|
1245
1281
|
if events.length > 0
|
1246
|
-
if events[-1] != string.length
|
1247
|
-
raise ArgumentError, "Invalid events for length #{string.length}"
|
1248
|
-
end
|
1249
|
-
|
1250
1282
|
elisions = []
|
1251
1283
|
|
1252
1284
|
while events[0].elide?
|
@@ -1261,18 +1293,35 @@ module Citrus
|
|
1261
1293
|
end
|
1262
1294
|
else
|
1263
1295
|
# Create a default stream of events for the given string.
|
1296
|
+
string = input.to_str
|
1264
1297
|
events = [Rule.for(string), CLOSE, string.length]
|
1265
1298
|
end
|
1266
1299
|
|
1267
1300
|
@events = events
|
1268
1301
|
end
|
1269
1302
|
|
1303
|
+
# The original Input this Match was generated on.
|
1304
|
+
attr_reader :input
|
1305
|
+
|
1306
|
+
# The index of this match in the #input.
|
1307
|
+
attr_reader :offset
|
1308
|
+
|
1270
1309
|
# The array of events for this match.
|
1271
1310
|
attr_reader :events
|
1272
1311
|
|
1273
1312
|
# Returns the length of this match.
|
1274
1313
|
def length
|
1275
|
-
|
1314
|
+
events.last
|
1315
|
+
end
|
1316
|
+
|
1317
|
+
# Convenient shortcut for +input.source+
|
1318
|
+
def source
|
1319
|
+
(input.respond_to?(:source) && input.source) || input
|
1320
|
+
end
|
1321
|
+
|
1322
|
+
# Returns the slice of the source text that this match captures.
|
1323
|
+
def string
|
1324
|
+
@string ||= input.to_str[offset, length]
|
1276
1325
|
end
|
1277
1326
|
|
1278
1327
|
# Returns a hash of capture names to arrays of matches with that name,
|
@@ -1296,16 +1345,18 @@ module Citrus
|
|
1296
1345
|
# Allows methods of this match's string to be called directly and provides
|
1297
1346
|
# a convenient interface for retrieving the first match with a given name.
|
1298
1347
|
def method_missing(sym, *args, &block)
|
1299
|
-
|
1300
|
-
|
1348
|
+
unless defined?(Citrus::METHOD_MISSING_WARNED)
|
1349
|
+
warn("[`#{sym}`] Citrus::Match#method_missing is unsafe and will be removed in 3.0. Use captures.")
|
1350
|
+
Citrus.send(:const_set, :METHOD_MISSING_WARNED, true)
|
1351
|
+
end
|
1352
|
+
if string.respond_to?(sym)
|
1353
|
+
string.__send__(sym, *args, &block)
|
1301
1354
|
else
|
1302
1355
|
captures[sym].first
|
1303
1356
|
end
|
1304
1357
|
end
|
1305
1358
|
|
1306
|
-
|
1307
|
-
@string
|
1308
|
-
end
|
1359
|
+
alias_method :to_s, :string
|
1309
1360
|
|
1310
1361
|
# This alias allows strings to be compared to the string value of Match
|
1311
1362
|
# objects. It is most useful in assertions in unit tests, e.g.:
|
@@ -1339,9 +1390,9 @@ module Citrus
|
|
1339
1390
|
def ==(other)
|
1340
1391
|
case other
|
1341
1392
|
when String
|
1342
|
-
|
1393
|
+
string == other
|
1343
1394
|
when Match
|
1344
|
-
|
1395
|
+
string == other.to_s
|
1345
1396
|
else
|
1346
1397
|
super
|
1347
1398
|
end
|
@@ -1350,7 +1401,7 @@ module Citrus
|
|
1350
1401
|
alias_method :eql?, :==
|
1351
1402
|
|
1352
1403
|
def inspect
|
1353
|
-
|
1404
|
+
string.inspect
|
1354
1405
|
end
|
1355
1406
|
|
1356
1407
|
# Prints the entire subtree of this match using the given +indent+ to
|
@@ -1372,7 +1423,7 @@ module Citrus
|
|
1372
1423
|
rule = stack.pop
|
1373
1424
|
|
1374
1425
|
space = indent * (stack.size / 3)
|
1375
|
-
string =
|
1426
|
+
string = self.string.slice(os, event)
|
1376
1427
|
lines[start] = "#{space}#{string.inspect} rule=#{rule}, offset=#{os}, length=#{event}"
|
1377
1428
|
|
1378
1429
|
last_length = event unless last_length
|
@@ -1425,7 +1476,7 @@ module Citrus
|
|
1425
1476
|
os = stack.pop
|
1426
1477
|
start = stack.pop
|
1427
1478
|
|
1428
|
-
match = Match.new(
|
1479
|
+
match = Match.new(input, @events[start..index], @offset + os)
|
1429
1480
|
capture!(rule, match)
|
1430
1481
|
|
1431
1482
|
if stack.size == 1
|
@@ -1518,6 +1569,7 @@ class Object
|
|
1518
1569
|
# end
|
1519
1570
|
#
|
1520
1571
|
def grammar(name, &block)
|
1572
|
+
warn("Object#grammar will no longer be available by default in citrus 3.0; You should require 'citrus/core_ext'.")
|
1521
1573
|
namespace = respond_to?(:const_set) ? self : Object
|
1522
1574
|
namespace.const_set(name, Citrus::Grammar.new(&block))
|
1523
1575
|
rescue NameError
|
data/lib/citrus/file.rb
CHANGED
@@ -165,7 +165,7 @@ module Citrus
|
|
165
165
|
end
|
166
166
|
|
167
167
|
rule :super do
|
168
|
-
|
168
|
+
ext(:super_keyword) {
|
169
169
|
Super.new
|
170
170
|
}
|
171
171
|
end
|
@@ -329,6 +329,7 @@ module Citrus
|
|
329
329
|
rule :grammar_keyword, [ /\bgrammar\b/, :space ]
|
330
330
|
rule :root_keyword, [ /\broot\b/, :space ]
|
331
331
|
rule :rule_keyword, [ /\brule\b/, :space ]
|
332
|
+
rule :super_keyword, [ /\bsuper\b/, :space ]
|
332
333
|
rule :end_keyword, [ /\bend\b/, :space ]
|
333
334
|
|
334
335
|
rule :constant, /[A-Z][a-zA-Z0-9_]*/
|
data/lib/citrus/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
rule super end
|
data/test/alias_test.rb
CHANGED
@@ -12,7 +12,6 @@ class AliasTest < Test::Unit::TestCase
|
|
12
12
|
rule :b, 'abc'
|
13
13
|
}
|
14
14
|
rule_a = grammar.rule(:a)
|
15
|
-
rule_b = grammar.rule(:b)
|
16
15
|
events = rule_a.exec(Input.new('abc'))
|
17
16
|
assert_equal([rule_a, CLOSE, 3], events)
|
18
17
|
end
|
@@ -36,7 +35,6 @@ class AliasTest < Test::Unit::TestCase
|
|
36
35
|
rule :b, :a
|
37
36
|
}
|
38
37
|
rule_b2 = grammar2.rule(:b)
|
39
|
-
rule_a1 = grammar1.rule(:a)
|
40
38
|
events = rule_b2.exec(Input.new('abc'))
|
41
39
|
assert_equal([rule_b2, CLOSE, 3], events)
|
42
40
|
end
|
data/test/grammar_test.rb
CHANGED
@@ -74,7 +74,7 @@ class GrammarTest < Test::Unit::TestCase
|
|
74
74
|
rule(:num) { all(1, 2, 3) }
|
75
75
|
}
|
76
76
|
assert_raise ParseError do
|
77
|
-
|
77
|
+
grammar.parse('12')
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
@@ -99,7 +99,7 @@ class GrammarTest < Test::Unit::TestCase
|
|
99
99
|
rule(:alphanum) { any(/[a-z]/, 0..9) }
|
100
100
|
}
|
101
101
|
assert_raise ParseError do
|
102
|
-
|
102
|
+
grammar.parse('A')
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
@@ -126,6 +126,29 @@ class GrammarTest < Test::Unit::TestCase
|
|
126
126
|
assert_equal(str.length, match.length)
|
127
127
|
end
|
128
128
|
|
129
|
+
def test_parse_file
|
130
|
+
grammar = Grammar.new {
|
131
|
+
rule("words"){ rep(any(" ", /[a-z]+/)) }
|
132
|
+
}
|
133
|
+
|
134
|
+
require 'tempfile'
|
135
|
+
Tempfile.open('citrus') do |tmp|
|
136
|
+
tmp << "abd def"
|
137
|
+
tmp.close
|
138
|
+
|
139
|
+
match = grammar.parse_file(tmp.path)
|
140
|
+
|
141
|
+
assert(match)
|
142
|
+
assert_instance_of(Input, match.input)
|
143
|
+
assert_instance_of(Pathname, match.source)
|
144
|
+
|
145
|
+
match.matches.each do |m|
|
146
|
+
assert_instance_of(Input, m.input)
|
147
|
+
assert_instance_of(Pathname, m.source)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
129
152
|
def test_global_grammar
|
130
153
|
assert_raise ArgumentError do
|
131
154
|
grammar(:abc)
|
data/test/input_test.rb
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
require File.expand_path('../helper', __FILE__)
|
2
2
|
|
3
3
|
class InputTest < Test::Unit::TestCase
|
4
|
+
def test_new
|
5
|
+
# to_str
|
6
|
+
assert_equal('abc', Input.new('abc').string)
|
7
|
+
|
8
|
+
# read
|
9
|
+
selftext = ::File.read(__FILE__)
|
10
|
+
::File.open(__FILE__, 'r') do |io|
|
11
|
+
assert_equal(selftext, Input.new(io).string)
|
12
|
+
end
|
13
|
+
|
14
|
+
# to_path
|
15
|
+
path = Struct.new(:to_path).new(__FILE__)
|
16
|
+
assert_equal(selftext, Input.new(path).string)
|
17
|
+
end
|
18
|
+
|
4
19
|
def test_memoized?
|
5
20
|
assert_equal(false, Input.new('').memoized?)
|
6
21
|
end
|
data/test/match_test.rb
CHANGED
@@ -20,6 +20,23 @@ class MatchTest < Test::Unit::TestCase
|
|
20
20
|
assert_equal(false, match2 == match1)
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_source
|
24
|
+
match1 = Match.new('abcdef')
|
25
|
+
assert_equal 'abcdef', match1.source
|
26
|
+
|
27
|
+
path = Struct.new(:to_path).new(__FILE__)
|
28
|
+
match2 = Match.new(Input.new(path))
|
29
|
+
assert_equal path, match2.source
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_string
|
33
|
+
match1 = Match.new('abcdef')
|
34
|
+
assert_equal 'abcdef', match1.string
|
35
|
+
|
36
|
+
match2 = Match.new('abcdef', [Rule.for('bcd'), -1, 3], 1)
|
37
|
+
assert_equal 'bcd', match2.string
|
38
|
+
end
|
39
|
+
|
23
40
|
def test_matches
|
24
41
|
a = Rule.for('a')
|
25
42
|
b = Rule.for('b')
|
@@ -59,11 +76,18 @@ class MatchTest < Test::Unit::TestCase
|
|
59
76
|
CLOSE, 3
|
60
77
|
]
|
61
78
|
|
62
|
-
match.matches.
|
79
|
+
match.matches.each_with_index do |m, i|
|
63
80
|
assert_equal(sub_events, m.events)
|
81
|
+
assert_equal(i*3, m.offset)
|
82
|
+
assert_equal(3, m.length)
|
83
|
+
assert_equal("abc", m.string)
|
64
84
|
assert_equal("abc", m)
|
65
85
|
assert(m.matches)
|
66
86
|
assert_equal(3, m.matches.length)
|
87
|
+
m.matches.each_with_index do |m2,i2|
|
88
|
+
assert_equal(i*3+i2, m2.offset)
|
89
|
+
assert_equal(1, m2.length)
|
90
|
+
end
|
67
91
|
end
|
68
92
|
end
|
69
93
|
|
data/test/super_test.rb
CHANGED
@@ -18,7 +18,6 @@ class SuperTest < Test::Unit::TestCase
|
|
18
18
|
rule_2a = grammar2.rule(:a)
|
19
19
|
rule_2a_als = rule_2a.rules[0]
|
20
20
|
rule_2a_sup = rule_2a.rules[1]
|
21
|
-
rule_1a = grammar1.rule(:a)
|
22
21
|
|
23
22
|
events = rule_2a.exec(Input.new('abc'))
|
24
23
|
assert_equal([
|
@@ -58,12 +57,9 @@ class SuperTest < Test::Unit::TestCase
|
|
58
57
|
rule :a, any(sup, :b)
|
59
58
|
rule :b, sup
|
60
59
|
}
|
61
|
-
rule_1a = grammar1.rule(:a)
|
62
|
-
rule_1b = grammar1.rule(:b)
|
63
60
|
rule_2a = grammar2.rule(:a)
|
64
61
|
rule_2a_sup = rule_2a.rules[0]
|
65
62
|
rule_2a_als = rule_2a.rules[1]
|
66
|
-
rule_2b = grammar2.rule(:b)
|
67
63
|
|
68
64
|
events = rule_2a.exec(Input.new('abc'))
|
69
65
|
assert_equal([
|
metadata
CHANGED
@@ -1,47 +1,40 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: citrus
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.5.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 2
|
8
|
-
- 4
|
9
|
-
- 1
|
10
|
-
version: 2.4.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Michael Jackson
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2014-03-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
22
15
|
name: rake
|
23
|
-
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
25
17
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
33
22
|
type: :development
|
34
|
-
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
35
30
|
description: Parsing Expressions for Ruby
|
36
31
|
email: mjijackson@gmail.com
|
37
32
|
executables: []
|
38
|
-
|
39
33
|
extensions: []
|
40
|
-
|
41
|
-
extra_rdoc_files:
|
34
|
+
extra_rdoc_files:
|
42
35
|
- README.md
|
43
36
|
- CHANGES
|
44
|
-
files:
|
37
|
+
files:
|
45
38
|
- benchmark/seqpar.citrus
|
46
39
|
- benchmark/seqpar.gnuplot
|
47
40
|
- benchmark/seqpar.rb
|
@@ -69,6 +62,8 @@ files:
|
|
69
62
|
- test/_files/rule3.citrus
|
70
63
|
- test/_files/rule4.citrus
|
71
64
|
- test/_files/rule5.citrus
|
65
|
+
- test/_files/rule6.citrus
|
66
|
+
- test/_files/rule7.citrus
|
72
67
|
- test/alias_test.rb
|
73
68
|
- test/and_predicate_test.rb
|
74
69
|
- test/but_predicate_test.rb
|
@@ -99,46 +94,37 @@ files:
|
|
99
94
|
- Rakefile
|
100
95
|
- README.md
|
101
96
|
- CHANGES
|
102
|
-
has_rdoc: true
|
103
97
|
homepage: http://mjijackson.com/citrus
|
104
98
|
licenses: []
|
105
|
-
|
106
99
|
post_install_message:
|
107
|
-
rdoc_options:
|
100
|
+
rdoc_options:
|
108
101
|
- --line-numbers
|
109
102
|
- --inline-source
|
110
103
|
- --title
|
111
104
|
- Citrus
|
112
105
|
- --main
|
113
106
|
- Citrus
|
114
|
-
require_paths:
|
107
|
+
require_paths:
|
115
108
|
- lib
|
116
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
110
|
none: false
|
118
|
-
requirements:
|
119
|
-
- -
|
120
|
-
- !ruby/object:Gem::Version
|
121
|
-
|
122
|
-
|
123
|
-
- 0
|
124
|
-
version: "0"
|
125
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
116
|
none: false
|
127
|
-
requirements:
|
128
|
-
- -
|
129
|
-
- !ruby/object:Gem::Version
|
130
|
-
|
131
|
-
segments:
|
132
|
-
- 0
|
133
|
-
version: "0"
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
134
121
|
requirements: []
|
135
|
-
|
136
122
|
rubyforge_project:
|
137
|
-
rubygems_version: 1.
|
123
|
+
rubygems_version: 1.8.23
|
138
124
|
signing_key:
|
139
125
|
specification_version: 3
|
140
126
|
summary: Parsing Expressions for Ruby
|
141
|
-
test_files:
|
127
|
+
test_files:
|
142
128
|
- test/alias_test.rb
|
143
129
|
- test/and_predicate_test.rb
|
144
130
|
- test/but_predicate_test.rb
|