citrus 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ grammar SeqPar
2
+ rule statement
3
+ 'par ' (statement ' ')+ 'end'
4
+ | 'sequence' ' ' (statement ' ')+ 'end'
5
+ | 'seq' ' ' (statement ' ')+ 'end'
6
+ | ('fit' [\s] (statement ' ')+ 'end') {
7
+ def foo
8
+ "foo"
9
+ end
10
+ }
11
+ | 'art'+ [ ] (statement ' ')+ 'end'
12
+ | [A-Z] [a-zA-z0-9]*
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ f1(x) = a*x
2
+ a = 0.5
3
+ fit f1(x) 'before.dat' using 1:2 via a
4
+
5
+ f2(x) = b*x
6
+ b = 0.5
7
+ fit f2(x) 'after.dat' using 1:2 via b
8
+
9
+ set xlabel "Length of input"
10
+ set ylabel "CPU time to parse"
11
+
12
+ plot a*x title 'a*x (Before)',\
13
+ b*x title 'b*x (After)',\
14
+ "before.dat" using 1:2 title 'Before', \
15
+ "after.dat" using 1:2 title 'After'
@@ -0,0 +1,110 @@
1
+ # Benchmarking written by Bernard Lambeau and Jason Garber of the Treetop
2
+ # project.
3
+ #
4
+ # To test your optimizations:
5
+ # 1. Run ruby seqpar.rb
6
+ # 2. cp after.dat before.dat
7
+ # 3. Make your modifications to the Citrus code
8
+ # 4. Run ruby seqpar.rb
9
+ # 5. Run gnuplot seqpar.gnuplot
10
+ #
11
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
12
+ require 'citrus'
13
+ require 'benchmark'
14
+
15
+ srand(47562) # So it runs the same each time
16
+
17
+ class Array
18
+ def sum
19
+ inject(0) {|m, x| m + x }
20
+ end
21
+
22
+ def mean
23
+ sum / size
24
+ end
25
+ end
26
+
27
+ class SeqParBenchmark
28
+ OPERATORS = ["seq", "fit", "art" * 5, "par", "sequence"]
29
+
30
+ def initialize
31
+ @where = File.expand_path('..', __FILE__)
32
+ Citrus.load(File.join(@where, 'seqpar'))
33
+ @grammar = SeqPar
34
+ end
35
+
36
+ # Checks the grammar
37
+ def check
38
+ [ "Task",
39
+ "seq Task end",
40
+ "par Task end",
41
+ "seq Task Task end",
42
+ "par Task Task end",
43
+ "par seq Task end Task end",
44
+ "par seq seq Task end end Task end",
45
+ "seq Task par seq Task end Task end Task end"
46
+ ].each do |input|
47
+ @grammar.parse(input)
48
+ end
49
+ end
50
+
51
+ # Generates an input text
52
+ def generate(depth=0)
53
+ return "Task" if depth > 7
54
+ return "seq #{generate(depth + 1)} end" if depth == 0
55
+
56
+ which = rand(OPERATORS.length)
57
+
58
+ case which
59
+ when 0
60
+ "Task"
61
+ else
62
+ raise unless OPERATORS[which]
63
+ buffer = "#{OPERATORS[which]} "
64
+ 0.upto(rand(4) + 1) do
65
+ buffer << generate(depth + 1) << " "
66
+ end
67
+ buffer << "end"
68
+ buffer
69
+ end
70
+ end
71
+
72
+ # Launches benchmarking
73
+ def benchmark
74
+ number_by_size = Hash.new {|h,k| h[k] = 0}
75
+ time_by_size = Hash.new {|h,k| h[k] = 0}
76
+ 0.upto(250) do |i|
77
+ input = generate
78
+ length = input.length
79
+ puts "Launching #{i}: #{input.length}"
80
+ # puts input
81
+ tms = Benchmark.measure { @grammar.parse(input) }
82
+ number_by_size[length] += 1
83
+ time_by_size[length] += tms.total * 1000
84
+ end
85
+ # puts number_by_size.inspect
86
+ # puts time_by_size.inspect
87
+
88
+ File.open(File.join(@where, 'after.dat'), 'w') do |dat|
89
+ number_by_size.keys.sort.each do |size|
90
+ dat << "#{size} #{(time_by_size[size]/number_by_size[size]).truncate}\n"
91
+ end
92
+ end
93
+
94
+ if File.exists?(File.join(@where, 'before.dat'))
95
+ before = {}
96
+ performance_increases = []
97
+ File.foreach(File.join(@where, 'before.dat')) do |line|
98
+ size, time = line.split(' ')
99
+ before[size] = time
100
+ end
101
+ File.foreach(File.join(@where, 'after.dat')) do |line|
102
+ size, time = line.split(' ')
103
+ performance_increases << (before[size].to_f - time.to_f) / before[size].to_f unless time == "0" || before[size] == "0"
104
+ end
105
+ puts "Average performance increase: #{(performance_increases.mean * 100 * 10).round / 10.0}%"
106
+ end
107
+ end
108
+ end
109
+
110
+ SeqParBenchmark.new.benchmark
data/citrus.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'citrus'
3
- s.version = '1.1.0'
4
- s.date = '2010-05-18'
3
+ s.version = '1.2.0'
4
+ s.date = '2010-06-02'
5
5
 
6
6
  s.summary = 'Parsing Expressions for Ruby'
7
7
  s.description = 'Parsing Expressions for Ruby'
@@ -11,9 +11,12 @@ Gem::Specification.new do |s|
11
11
 
12
12
  s.require_paths = %w< lib >
13
13
 
14
- s.files = Dir['lib/**/*.rb'] +
14
+ s.files = Dir['benchmark/*.rb'] +
15
+ Dir['benchmark/*.citrus'] +
16
+ Dir['benchmark/*.gnuplot'] +
15
17
  Dir['examples/**/*'] +
16
18
  Dir['extras/**/*'] +
19
+ Dir['lib/**/*.rb'] +
17
20
  Dir['test/*.rb'] +
18
21
  %w< citrus.gemspec Rakefile README >
19
22
 
data/extras/citrus.vim CHANGED
@@ -15,8 +15,8 @@ syn case match
15
15
 
16
16
  syn match ctDoubleColon "::" contained
17
17
  syn match ctConstant "\u\w*" contained
18
- syn match ctVariable "\l\w*" contained
19
18
  syn match ctModule "\(\(::\)\?\u\w*\)\+" contains=ctDoubleColon,ctConstant contained
19
+ syn match ctVariable "\a[a-zA-Z_-]*" contained
20
20
 
21
21
  " Comments
22
22
  syn match ctComment "#.*" contains=@Spell
@@ -56,7 +56,7 @@ syn match ctRule "\<rule\>" nextgroup=ctVariable skipwhite skipnl containe
56
56
 
57
57
  " Blocks
58
58
  syn region ctGrammarBlock start="\<grammar\>" matchgroup=ctGrammar end="\<end\>" contains=ctComment,ctGrammar,ctInclude,ctRoot,ctRuleBlock fold
59
- syn region ctRuleBlock start="\<rule\>" matchgroup=ctRule end="\<end\>" contains=ALLBUT,ctRequire,ctGrammar,ctInclude,ctRoot,ctConstant,ctVariable fold
59
+ syn region ctRuleBlock start="\<rule\>" matchgroup=ctRule end="\<end\>" contains=ALLBUT,ctRequire,ctGrammar,ctInclude,ctRoot,ctConstant fold
60
60
 
61
61
  " Groups
62
62
  hi def link ctComment Comment
@@ -84,7 +84,7 @@ hi def link ctStringDelimiter Delimiter
84
84
  hi def link ctRegexpSpecial ctStringSpecial
85
85
  hi def link ctStringSpecial Special
86
86
 
87
- hi def link ctQuantifier ctOperator
87
+ hi def link ctQuantifier Number
88
88
  hi def link ctOperator Operator
89
89
 
90
90
  let b:current_syntax = "citrus"
data/lib/citrus.rb CHANGED
@@ -4,11 +4,11 @@
4
4
  #
5
5
  # http://github.com/mjijackson/citrus
6
6
  module Citrus
7
- VERSION = [1, 1, 0]
7
+ VERSION = [1, 2, 0]
8
8
 
9
9
  Infinity = 1.0 / 0
10
10
 
11
- autoload 'File', 'citrus/file'
11
+ autoload :File, 'citrus/file'
12
12
 
13
13
  # Returns the current version of Citrus as a string.
14
14
  def self.version
@@ -28,8 +28,7 @@ module Citrus
28
28
  # Evaluates the given Citrus parsing expression grammar +code+ in the global
29
29
  # scope. Returns an array of any grammar modules that were created.
30
30
  def self.eval(code)
31
- file = File.parse(code)
32
- file.value
31
+ File.parse(code).value
33
32
  end
34
33
 
35
34
  # This error is raised whenever a parse fails.
@@ -147,7 +146,6 @@ module Citrus
147
146
  # grammar.
148
147
  def rule(name, obj=nil)
149
148
  sym = name.to_sym
150
-
151
149
  obj = Proc.new.call if block_given?
152
150
 
153
151
  if obj
@@ -166,7 +164,8 @@ module Citrus
166
164
  raise "Cannot create rule \"#{name}\": " + e.message
167
165
  end
168
166
 
169
- # Gets/sets the +name+ of the root rule of this grammar.
167
+ # Gets/sets the +name+ of the root rule of this grammar. If no root rule is
168
+ # explicitly specified, the name of this grammar's first rule is returned.
170
169
  def root(name=nil)
171
170
  @root = name.to_sym if name
172
171
  # The first rule in a grammar is the default root.
@@ -241,24 +240,47 @@ module Citrus
241
240
  rule
242
241
  end
243
242
 
244
- # Parses the given +string+ from the given +offset+ using the rules in this
245
- # grammar. A ParseError is raised if there is no match made or if
246
- # +consume_all+ is +true+ and the entire input string cannot be consumed.
247
- def parse(string, offset=0, enable_memo=false, consume_all=true)
248
- raise "No root rule specified" unless root
243
+ # Parses the given input +string+ using the given +options+. If no match can
244
+ # be made, a ParseError is raised. See #default_parse_options for a detailed
245
+ # description of available parse options.
246
+ def parse(string, options={})
247
+ opts = default_parse_options.merge(options)
248
+
249
+ raise "No root rule specified" unless opts[:root]
249
250
 
250
- root_rule = rule(root)
251
+ root_rule = rule(opts[:root])
251
252
  raise "No rule named \"#{root}\"" unless root_rule
252
253
 
253
- input = Input.new(string, enable_memo)
254
- match = input.match(root_rule, offset)
254
+ input = Input.new(string, opts[:enable_memo])
255
+ match = input.match(root_rule, opts[:offset])
255
256
 
256
- if !match || (consume_all && match.length != string.length)
257
+ if !match || (opts[:consume_all] && match.length != string.length)
257
258
  raise ParseError.new(input)
258
259
  end
259
260
 
260
261
  match
261
262
  end
263
+
264
+ # The default set of options that is used in #parse. The options hash may
265
+ # have any of the following keys:
266
+ #
267
+ # offset:: The offset at which the parse should start. Defaults to 0.
268
+ # root:: The name of the root rule to use for the parse. Defaults
269
+ # to the name supplied by calling #root.
270
+ # consume_all:: If this is +true+ and the entire input string cannot be
271
+ # consumed, a ParseError will be raised. Defaults to +true+.
272
+ # enable_memo:: If this is +true+ the matches generated during a parse are
273
+ # memoized. This technique (also known as Packrat parsing)
274
+ # guarantees parsers will operate in linear time but costs
275
+ # significantly more in terms of time and memory required.
276
+ # Defaults to +false+.
277
+ def default_parse_options
278
+ { :offset => 0,
279
+ :root => root,
280
+ :consume_all => true,
281
+ :enable_memo => false
282
+ }
283
+ end
262
284
  end
263
285
 
264
286
  # This class represents the core of the parsing algorithm. It wraps the input
@@ -339,11 +361,11 @@ module Citrus
339
361
  end
340
362
  end
341
363
 
342
- @uniq_id = 0
364
+ @unique_id = 0
343
365
 
344
366
  # Generates a new rule id.
345
367
  def self.new_id
346
- @uniq_id += 1
368
+ @unique_id += 1
347
369
  end
348
370
 
349
371
  # The grammar this rule belongs to.
@@ -397,7 +419,7 @@ module Citrus
397
419
  private
398
420
 
399
421
  def extend_match(match)
400
- match.extend(ext) if ext
422
+ match.ext = ext if ext
401
423
  end
402
424
 
403
425
  def create_match(data, offset)
@@ -446,15 +468,15 @@ module Citrus
446
468
  end
447
469
 
448
470
  # An Alias is a Proxy for a rule in the same grammar. It is used in rule
449
- # definitions when a rule calls some other rule by name. The PEG notation is
450
- # simply the name of another rule without any other punctuation, e.g.:
471
+ # definitions when a rule calls some other rule by name. The Citrus notation
472
+ # is simply the name of another rule without any other punctuation, e.g.:
451
473
  #
452
474
  # name
453
475
  #
454
476
  class Alias
455
477
  include Proxy
456
478
 
457
- # Returns the PEG notation of this rule as a string.
479
+ # Returns the Citrus notation of this rule as a string.
458
480
  def to_s
459
481
  rule_name.to_s
460
482
  end
@@ -473,15 +495,15 @@ module Citrus
473
495
 
474
496
  # A Super is a Proxy for a rule of the same name that was defined previously
475
497
  # in the grammar's inheritance chain. Thus, Super's work like Ruby's +super+,
476
- # only for rules in a grammar instead of methods in a module. The PEG notation
477
- # is the word +super+ without any other punctuation, e.g.:
498
+ # only for rules in a grammar instead of methods in a module. The Citrus
499
+ # notation is the word +super+ without any other punctuation, e.g.:
478
500
  #
479
501
  # super
480
502
  #
481
503
  class Super
482
504
  include Proxy
483
505
 
484
- # Returns the PEG notation of this rule as a string.
506
+ # Returns the Citrus notation of this rule as a string.
485
507
  def to_s
486
508
  'super'
487
509
  end
@@ -510,13 +532,13 @@ module Citrus
510
532
  # The actual String or Regexp object this rule uses to match.
511
533
  attr_reader :rule
512
534
 
513
- # Returns the PEG notation of this rule as a string.
535
+ # Returns the Citrus notation of this rule as a string.
514
536
  def to_s
515
537
  rule.inspect
516
538
  end
517
539
  end
518
540
 
519
- # A FixedWidth is a Terminal that matches based on its length. The PEG
541
+ # A FixedWidth is a Terminal that matches based on its length. The Citrus
520
542
  # notation is any sequence of characters enclosed in either single or double
521
543
  # quotes, e.g.:
522
544
  #
@@ -540,13 +562,13 @@ module Citrus
540
562
 
541
563
  # An Expression is a Terminal that has the same semantics as a regular
542
564
  # expression in Ruby. The expression must match at the beginning of the input
543
- # (index 0). The PEG notation is identical to Ruby's regular expression
565
+ # (index 0). The Citrus notation is identical to Ruby's regular expression
544
566
  # notation, e.g.:
545
567
  #
546
568
  # /expr/
547
569
  #
548
- # Character classes and the dot symbol may also be used in PEG notation for
549
- # compatibility with other PEG implementations, e.g.:
570
+ # Character classes and the dot symbol may also be used in Citrus notation for
571
+ # compatibility with other parsing expression implementations, e.g.:
550
572
  #
551
573
  # [a-zA-Z]
552
574
  # .
@@ -602,7 +624,7 @@ module Citrus
602
624
  end
603
625
 
604
626
  # An AndPredicate is a Predicate that contains a rule that must match. Upon
605
- # success an empty match is returned and no input is consumed. The PEG
627
+ # success an empty match is returned and no input is consumed. The Citrus
606
628
  # notation is any expression preceeded by an ampersand, e.g.:
607
629
  #
608
630
  # &expr
@@ -616,14 +638,14 @@ module Citrus
616
638
  create_match('', offset) if input.match(rule, offset)
617
639
  end
618
640
 
619
- # Returns the PEG notation of this rule as a string.
641
+ # Returns the Citrus notation of this rule as a string.
620
642
  def to_s
621
643
  '&' + rule.embed
622
644
  end
623
645
  end
624
646
 
625
647
  # A NotPredicate is a Predicate that contains a rule that must not match. Upon
626
- # success an empty match is returned and no input is consumed. The PEG
648
+ # success an empty match is returned and no input is consumed. The Citrus
627
649
  # notation is any expression preceeded by an exclamation mark, e.g.:
628
650
  #
629
651
  # !expr
@@ -637,14 +659,14 @@ module Citrus
637
659
  create_match('', offset) unless input.match(rule, offset)
638
660
  end
639
661
 
640
- # Returns the PEG notation of this rule as a string.
662
+ # Returns the Citrus notation of this rule as a string.
641
663
  def to_s
642
664
  '!' + rule.embed
643
665
  end
644
666
  end
645
667
 
646
668
  # A Label is a Predicate that applies a new name to any matches made by its
647
- # rule. The PEG notation is any sequence of word characters (i.e.
669
+ # rule. The Citrus notation is any sequence of word characters (i.e.
648
670
  # <tt>[a-zA-Z0-9_]</tt>) followed by a colon, followed by any other
649
671
  # expression, e.g.:
650
672
  #
@@ -673,14 +695,14 @@ module Citrus
673
695
  end
674
696
  end
675
697
 
676
- # Returns the PEG notation of this rule as a string.
698
+ # Returns the Citrus notation of this rule as a string.
677
699
  def to_s
678
700
  label.to_s + ':' + rule.embed
679
701
  end
680
702
  end
681
703
 
682
704
  # A Repeat is a Predicate that specifies a minimum and maximum number of times
683
- # its rule must match. The PEG notation is an integer, +N+, followed by an
705
+ # its rule must match. The Citrus notation is an integer, +N+, followed by an
684
706
  # asterisk, followed by another integer, +M+, all of which follow any other
685
707
  # expression, e.g.:
686
708
  #
@@ -721,23 +743,29 @@ module Citrus
721
743
  create_match(matches, offset) if @range.include?(matches.length)
722
744
  end
723
745
 
746
+ # The minimum number of times this rule must match.
747
+ def min
748
+ @range.begin
749
+ end
750
+
751
+ # The maximum number of times this rule may match.
752
+ def max
753
+ @range.end
754
+ end
755
+
724
756
  # Returns the operator this rule uses as a string. Will be one of
725
757
  # <tt>+</tt>, <tt>?</tt>, or <tt>N*M</tt>.
726
758
  def operator
727
- unless @operator
728
- m = [@range.begin, @range.end].map do |n|
729
- n == 0 || n == Infinity ? '' : n.to_s
759
+ @operator ||= case [min, max]
760
+ when [0, 0] then ''
761
+ when [0, 1] then '?'
762
+ when [1, Infinity] then '+'
763
+ else
764
+ [min, max].map {|n| n == 0 || n == Infinity ? '' : n.to_s }.join('*')
730
765
  end
731
- @operator = case m
732
- when ['', '1'] then '?'
733
- when ['1', ''] then '+'
734
- else m.join('*')
735
- end
736
- end
737
- @operator
738
766
  end
739
767
 
740
- # Returns the PEG notation of this rule as a string.
768
+ # Returns the Citrus notation of this rule as a string.
741
769
  def to_s
742
770
  rule.embed + operator
743
771
  end
@@ -753,8 +781,8 @@ module Citrus
753
781
  end
754
782
  end
755
783
 
756
- # A Choice is a List where only one rule must match. The PEG notation is two
757
- # or more expressions separated by a vertical bar, e.g.:
784
+ # A Choice is a List where only one rule must match. The Citrus notation is
785
+ # two or more expressions separated by a vertical bar, e.g.:
758
786
  #
759
787
  # expr | expr
760
788
  #
@@ -771,14 +799,14 @@ module Citrus
771
799
  nil
772
800
  end
773
801
 
774
- # Returns the PEG notation of this rule as a string.
802
+ # Returns the Citrus notation of this rule as a string.
775
803
  def to_s
776
804
  rules.map {|r| r.embed }.join(' | ')
777
805
  end
778
806
  end
779
807
 
780
- # A Sequence is a List where all rules must match. The PEG notation is two or
781
- # more expressions separated by a space, e.g.:
808
+ # A Sequence is a List where all rules must match. The Citrus notation is two
809
+ # or more expressions separated by a space, e.g.:
782
810
  #
783
811
  # expr expr
784
812
  #
@@ -799,7 +827,7 @@ module Citrus
799
827
  create_match(matches, offset) if matches.length == rules.length
800
828
  end
801
829
 
802
- # Returns the PEG notation of this rule as a string.
830
+ # Returns the Citrus notation of this rule as a string.
803
831
  def to_s
804
832
  rules.map {|r| r.embed }.join(' ')
805
833
  end
@@ -829,6 +857,9 @@ module Citrus
829
857
  # the label.
830
858
  attr_accessor :name
831
859
 
860
+ # A module that will be used to extend this match.
861
+ attr_accessor :ext
862
+
832
863
  # The offset in the input at which this match occurred.
833
864
  attr_reader :offset
834
865
 
@@ -894,9 +925,23 @@ module Citrus
894
925
  # Uses #match to allow sub-matches of this match to be called by name as
895
926
  # instance methods.
896
927
  def method_missing(sym, *args)
897
- m = first(sym)
898
- return m if m
899
- raise 'No match named "%s" in %s (%s)' % [sym, self, name]
928
+ # Extend this object only when needed and immediately redefine
929
+ # #method_missing so that the new version is used on all future calls.
930
+ extend(ext) if ext
931
+ redefine_method_missing!
932
+ __send__(sym, *args)
933
+ end
934
+
935
+ private
936
+
937
+ def redefine_method_missing! # :nodoc:
938
+ instance_eval(<<-RUBY, __FILE__, __LINE__ + 1)
939
+ def method_missing(sym, *args)
940
+ m = first(sym)
941
+ return m if m
942
+ raise 'No match named "%s" in %s (%s)' % [sym, self, name]
943
+ end
944
+ RUBY
900
945
  end
901
946
  end
902
947
  end
data/lib/citrus/file.rb CHANGED
@@ -179,7 +179,7 @@ module Citrus
179
179
  end
180
180
 
181
181
  rule :rule_name do
182
- all(/[a-z][a-zA-Z0-9_]*/, :space) {
182
+ all(/[a-z][a-zA-Z_-]*/, :space) {
183
183
  def value
184
184
  first.text
185
185
  end
@@ -6,6 +6,6 @@ end
6
6
 
7
7
  Citrus.load(File.dirname(__FILE__) + '/../examples/calc')
8
8
 
9
- class CalcPEGTest < Test::Unit::TestCase
9
+ class CalcFileTest < Test::Unit::TestCase
10
10
  include CalcTests
11
11
  end
data/test/file_test.rb CHANGED
@@ -333,6 +333,10 @@ class CitrusFileTest < Test::Unit::TestCase
333
333
  match = grammar.parse('some_rule ')
334
334
  assert(match)
335
335
  assert('some_rule', match.value)
336
+
337
+ assert_raise ParseError do
338
+ match = grammar.parse('some_rule1')
339
+ end
336
340
  end
337
341
 
338
342
  def test_terminal
data/test/repeat_test.rb CHANGED
@@ -51,22 +51,27 @@ class RepeatTest < Test::Unit::TestCase
51
51
  end
52
52
 
53
53
  def test_operator
54
- rule = Repeat.new(1, 2, '')
54
+ rule = Repeat.new(1, 2)
55
55
  assert_equal('1*2', rule.operator)
56
56
  end
57
57
 
58
+ def test_operator_empty
59
+ rule = Repeat.new(0, 0)
60
+ assert_equal('', rule.operator)
61
+ end
62
+
58
63
  def test_operator_asterisk
59
- rule = Repeat.new(0, Infinity, '')
64
+ rule = Repeat.new(0, Infinity)
60
65
  assert_equal('*', rule.operator)
61
66
  end
62
67
 
63
68
  def test_operator_question_mark
64
- rule = Repeat.new(0, 1, '')
69
+ rule = Repeat.new(0, 1)
65
70
  assert_equal('?', rule.operator)
66
71
  end
67
72
 
68
73
  def test_operator_plus
69
- rule = Repeat.new(1, Infinity, '')
74
+ rule = Repeat.new(1, Infinity)
70
75
  assert_equal('+', rule.operator)
71
76
  end
72
77
 
data/test/rule_test.rb CHANGED
@@ -3,7 +3,9 @@ require File.dirname(__FILE__) + '/helper'
3
3
  class RuleTest < Test::Unit::TestCase
4
4
 
5
5
  module MatchModule
6
- def a_test; end
6
+ def a_test
7
+ :test
8
+ end
7
9
  end
8
10
 
9
11
  NumericProc = Proc.new {
@@ -23,8 +25,7 @@ class RuleTest < Test::Unit::TestCase
23
25
  rule.ext = MatchModule
24
26
  match = rule.match(input('a'))
25
27
  assert(match)
26
- assert_kind_of(MatchModule, match)
27
- assert_respond_to(match, :a_test)
28
+ assert_equal(:test, match.a_test)
28
29
  end
29
30
 
30
31
  def test_numeric_proc
@@ -41,7 +42,6 @@ class RuleTest < Test::Unit::TestCase
41
42
  rule.ext = NumericModule
42
43
  match = rule.match(input('1'))
43
44
  assert(match)
44
- assert_kind_of(NumericModule, match)
45
45
  assert_equal(1, match.to_i)
46
46
  assert_instance_of(Float, match.to_f)
47
47
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 1
7
- - 1
7
+ - 2
8
8
  - 0
9
- version: 1.1.0
9
+ version: 1.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Michael Jackson
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-18 00:00:00 -06:00
17
+ date: 2010-06-02 00:00:00 -06:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -50,17 +50,20 @@ extensions: []
50
50
  extra_rdoc_files:
51
51
  - README
52
52
  files:
53
- - lib/citrus/debug.rb
54
- - lib/citrus/file.rb
55
- - lib/citrus/sugar.rb
56
- - lib/citrus.rb
53
+ - benchmark/seqpar.rb
54
+ - benchmark/seqpar.citrus
55
+ - benchmark/seqpar.gnuplot
57
56
  - examples/calc.citrus
58
57
  - examples/calc.rb
59
58
  - examples/calc_sugar.rb
60
59
  - extras/citrus.vim
60
+ - lib/citrus/debug.rb
61
+ - lib/citrus/file.rb
62
+ - lib/citrus/sugar.rb
63
+ - lib/citrus.rb
61
64
  - test/alias_test.rb
62
65
  - test/and_predicate_test.rb
63
- - test/calc_peg_test.rb
66
+ - test/calc_file_test.rb
64
67
  - test/calc_sugar_test.rb
65
68
  - test/calc_test.rb
66
69
  - test/choice_test.rb
@@ -117,7 +120,7 @@ summary: Parsing Expressions for Ruby
117
120
  test_files:
118
121
  - test/alias_test.rb
119
122
  - test/and_predicate_test.rb
120
- - test/calc_peg_test.rb
123
+ - test/calc_file_test.rb
121
124
  - test/calc_sugar_test.rb
122
125
  - test/calc_test.rb
123
126
  - test/choice_test.rb