citrus 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README +12 -25
  2. data/citrus.gemspec +2 -2
  3. data/doc/example.rdoc +15 -28
  4. data/lib/citrus.rb +33 -29
  5. metadata +3 -3
data/README CHANGED
@@ -236,21 +236,13 @@ interpret them. The following example shows one way to do this.
236
236
 
237
237
  grammar Addition
238
238
  rule additive
239
- (number plus term) {
239
+ (number plus term:(additive | number)) {
240
240
  def value
241
241
  number.value + term.value
242
242
  end
243
243
  }
244
244
  end
245
245
 
246
- rule term
247
- (additive | number) {
248
- def value
249
- first.value
250
- end
251
- }
252
- end
253
-
254
246
  rule number
255
247
  ([0-9]+ space) {
256
248
  def value
@@ -268,26 +260,21 @@ interpret them. The following example shows one way to do this.
268
260
  end
269
261
  end
270
262
 
271
- In this version of the grammar the additive rule has been refactored to use the
272
- term rule. This makes it a little cleaner to define our semantic blocks. It's
263
+ In this version of the grammar we have added two semantic blocks, one each for
264
+ the additive and number rules. These blocks contain methods that will be present
265
+ on all match objects that result from matches of those particular rules. It's
273
266
  easiest to explain what is going on here by starting with the lowest level
274
267
  block, which is defined within the number rule.
275
268
 
276
269
  The semantic block associated with the number rule defines one method, value.
277
- This method will be present on all matches that result from this rule. Inside
278
- this method, we can see that the value of a number match is determined to be
279
- its text value, stripped of white space and converted to an integer.
280
-
281
- Similarly, the block that is applied to term matches also defines a value
282
- method. However, this method works a bit differently. Since a term matches an
283
- additive or a number a term match will contain one submatch, the match that
284
- resulted from either additive or number. The first method retrieves the first
285
- submatch. So, the value of a term is determined to be the value of its first
286
- submatch.
287
-
288
- Finally, the additive rule also extends its matches with a value method. Here,
289
- the value of an additive is determined to be the values of its number and term
290
- matches added together using Ruby's addition operator.
270
+ Inside this method, we can see that the value of a number match is determined to
271
+ be its text value, stripped of white space and converted to an integer.
272
+
273
+ The additive rule also extends its matches with a value method. Notice the use
274
+ of the "term" label within the rule definition. This label allows the match that
275
+ is created by either the additive or the number rule to be retrieved using the
276
+ "term" label. The value of an additive is determined to be the values of its
277
+ number and term matches added together using Ruby's addition operator.
291
278
 
292
279
  Since additive is the first rule defined in the grammar, any match that results
293
280
  from parsing a string with this grammar will have a value method that can be
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'citrus'
3
- s.version = '1.3.0'
4
- s.date = '2010-06-21'
3
+ s.version = '1.4.0'
4
+ s.date = '2010-06-22'
5
5
 
6
6
  s.summary = 'Parsing Expressions for Ruby'
7
7
  s.description = 'Parsing Expressions for Ruby'
@@ -51,21 +51,13 @@ interpret them. The following example shows one way to do this.
51
51
 
52
52
  grammar Addition
53
53
  rule additive
54
- (number plus term) {
54
+ (number plus term:(additive | number)) {
55
55
  def value
56
56
  number.value + term.value
57
57
  end
58
58
  }
59
59
  end
60
60
 
61
- rule term
62
- (additive | number) {
63
- def value
64
- first.value
65
- end
66
- }
67
- end
68
-
69
61
  rule number
70
62
  ([0-9]+ space) {
71
63
  def value
@@ -83,26 +75,21 @@ interpret them. The following example shows one way to do this.
83
75
  end
84
76
  end
85
77
 
86
- In this version of the grammar the additive rule has been refactored to use the
87
- term rule. This makes it a little cleaner to define our semantic blocks. It's
78
+ In this version of the grammar we have added two semantic blocks, one each for
79
+ the +additive+ and +number+ rules. These blocks contain methods that will be present
80
+ on all match objects that result from matches of those particular rules. It's
88
81
  easiest to explain what is going on here by starting with the lowest level
89
- block, which is defined within the number rule.
90
-
91
- The semantic block associated with the number rule defines one method, value.
92
- This method will be present on all matches that result from this rule. Inside
93
- this method, we can see that the value of a number match is determined to be
94
- its text value, stripped of white space and converted to an integer.
95
-
96
- Similarly, the block that is applied to term matches also defines a value
97
- method. However, this method works a bit differently. Since a term matches an
98
- additive or a number a term match will contain one submatch, the match that
99
- resulted from either additive or number. The first method retrieves the first
100
- submatch. So, the value of a term is determined to be the value of its first
101
- submatch.
102
-
103
- Finally, the additive rule also extends its matches with a value method. Here,
104
- the value of an additive is determined to be the values of its number and term
105
- matches added together using Ruby's addition operator.
82
+ block, which is defined within the +number+ rule.
83
+
84
+ The semantic block associated with the +number+ rule defines one method, +value+.
85
+ Inside this method, we can see that the value of a number match is determined to
86
+ be its text value, stripped of white space and converted to an integer.
87
+
88
+ The +additive+ rule also extends its matches with a +value+ method. Notice the use
89
+ of the "term" label within the rule definition. This label allows the match that
90
+ is created by either the +additive+ or the +number+ rule to be retrieved using the
91
+ "term" label. The value of an additive is determined to be the values of its
92
+ number and term matches added together using Ruby's addition operator.
106
93
 
107
94
  Since additive is the first rule defined in the grammar, any match that results
108
95
  from parsing a string with this grammar will have a value method that can be
@@ -4,7 +4,7 @@
4
4
  #
5
5
  # http://mjijackson.com/citrus
6
6
  module Citrus
7
- VERSION = [1, 3, 0]
7
+ VERSION = [1, 4, 0]
8
8
 
9
9
  Infinity = 1.0 / 0
10
10
 
@@ -418,15 +418,15 @@ module Citrus
418
418
 
419
419
  private
420
420
 
421
- def extend_match(match)
422
- match.extend(ext) if ext
421
+ def extend_match(match, name)
422
+ match.extensions << ext if ext
423
+ match.names << name if name
424
+ match
423
425
  end
424
426
 
425
427
  def create_match(data, offset)
426
428
  match = Match.new(data, offset)
427
- extend_match(match)
428
- match.names << name if name
429
- match
429
+ extend_match(match, name)
430
430
  end
431
431
  end
432
432
 
@@ -458,12 +458,7 @@ module Citrus
458
458
  # +nil+ if no match can be made.
459
459
  def match(input, offset=0)
460
460
  m = input.match(rule, offset)
461
- if m
462
- extend_match(m)
463
- # This proxy's name should be added to the names of the match.
464
- m.names << name if name
465
- m
466
- end
461
+ extend_match(m, name) if m
467
462
  end
468
463
  end
469
464
 
@@ -584,8 +579,8 @@ module Citrus
584
579
  # Returns the Match for this rule on +input+ at the given +offset+, +nil+ if
585
580
  # no match can be made.
586
581
  def match(input, offset=0)
587
- result = input[offset, input.length - offset].match(rule)
588
- create_match(result, offset) if result && result.begin(0) == 0
582
+ m = input[offset, input.length - offset].match(rule)
583
+ create_match(m, offset) if m && m.begin(0) == 0
589
584
  end
590
585
  end
591
586
 
@@ -693,12 +688,7 @@ module Citrus
693
688
  # the value of its label.
694
689
  def match(input, offset=0)
695
690
  m = rule.match(input, offset)
696
- if m
697
- extend_match(m)
698
- # This label's name should be added to the names of the match.
699
- m.names << label_name
700
- m
701
- end
691
+ extend_match(m, label_name) if m
702
692
  end
703
693
 
704
694
  # Returns the Citrus notation of this rule as a string.
@@ -800,12 +790,7 @@ module Citrus
800
790
  def match(input, offset=0)
801
791
  rules.each do |rule|
802
792
  m = input.match(rule, offset)
803
- if m
804
- extend_match(m)
805
- # This choice's name should be added to the names of the match.
806
- m.names << name if name
807
- return m
808
- end
793
+ return extend_match(m, name) if m
809
794
  end
810
795
  nil
811
796
  end
@@ -882,6 +867,11 @@ module Citrus
882
867
  names.include?(name)
883
868
  end
884
869
 
870
+ # An array of all extension modules of this match.
871
+ def extensions
872
+ @extensions ||= []
873
+ end
874
+
885
875
  # An array of all sub-matches of this match.
886
876
  def matches
887
877
  @matches ||= []
@@ -944,9 +934,23 @@ module Citrus
944
934
  # Uses #match to allow sub-matches of this match to be called by name as
945
935
  # instance methods.
946
936
  def method_missing(sym, *args)
947
- m = first(sym)
948
- return m if m
949
- raise 'No match named "%s" in %s (%s)' % [sym, self, name]
937
+ # Extend this object only when needed and immediately redefine
938
+ # #method_missing so that the new version is used on all future calls.
939
+ extensions.each {|e| extend(e) } if @extensions
940
+ redefine_method_missing!
941
+ __send__(sym, *args)
942
+ end
943
+
944
+ private
945
+
946
+ def redefine_method_missing! # :nodoc:
947
+ instance_eval(<<-RUBY, __FILE__, __LINE__ + 1)
948
+ def method_missing(sym, *args)
949
+ m = first(sym)
950
+ return m if m
951
+ raise 'No match named "%s" in %s (%s)' % [sym, self, name]
952
+ end
953
+ RUBY
950
954
  end
951
955
  end
952
956
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 1
7
- - 3
7
+ - 4
8
8
  - 0
9
- version: 1.3.0
9
+ version: 1.4.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-06-21 00:00:00 -06:00
17
+ date: 2010-06-22 00:00:00 -06:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency