citrus 1.1.0 → 1.2.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.
@@ -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