kpeg 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -15,10 +15,14 @@ All grammars start with with the class/module name that will be your parser
15
15
 
16
16
  %% name = Example::Parser
17
17
 
18
- After that a block of ruby code can be defined that will be added into the class body of your parser. Attributes that are defines in this block can be accessed within your parser as instance variables
18
+ After that a block of ruby code can be defined that will be added into the class body of your parser. Attributes that are defined in this block can be accessed within your parser as instance variables. Methods can also be defined in this block and used in action blocks as well.
19
19
 
20
20
  %% {
21
21
  attr_accessor :something_cool
22
+
23
+ def something_awesome
24
+ # do something awesome
25
+ end
22
26
  }
23
27
 
24
28
  ### Defining literals
@@ -36,52 +40,50 @@ Literals can also accept multiple definitions
36
40
 
37
41
  vowel = "a" | "e" | "i" | "o" | "u"
38
42
  alpha = /[A-Z]/ | /[a-z]/
39
-
40
43
 
41
44
  ### Defining Rules for Values
42
45
 
43
46
  Before you can start parsing a string you will need to define rules that you will use to accept or reject that string. There are many different types of rules available in kpeg
44
47
 
45
48
  The most basic of these rules is a string capture
46
-
49
+
47
50
  alpha = < /[A-Za-z]/ > { text }
48
-
51
+
49
52
 
50
53
  While this looks very much like the ALPHA literal defined above it differs in one important way, the text captured by the rule defined between the < and > symbols will be set as the text variable in block that follows. You can also explicitly define the variable that you would like but only with existing rules or literals.
51
-
54
+
52
55
  letter = alpha:a { a }
53
-
56
+
54
57
  Additionally blocks can return true or false values based upon an expression within the block. To return true if a test passes do the following:
55
58
 
56
59
  match_greater_than_10 = < num:n > &{ n > 10 }
57
-
60
+
58
61
  To test and return a false value if the test passes do the following:
59
62
 
60
63
  do_not_match_greater_than_10 = < num:n > !{ n > 10 }
61
-
64
+
62
65
  Rules can also act like functions and take parameters. An example of this is lifted from the [Email List Validator](https://github.com/larb/email_address_validator), where an ascii value is passed in and the character is evaluated against it returning a true if it matches
63
-
66
+
64
67
  d(num) = <.> &{ text[0] == num }
65
68
 
66
69
  Rules support some regular expression syntax for matching
67
-
70
+
68
71
  + maybe ?
69
- + many
70
- + kleene *
71
- + groupings ()
72
+ + many +
73
+ + kleene *
74
+ + groupings ()
72
75
 
73
76
  Examples
74
77
 
75
78
  letters = alpha+
76
79
  words = alpha+ space* period?
77
80
  sentence = (letters+ | space+)+
78
-
81
+
79
82
  Kpeg also allows a rule to define the acceptable number of matches in the form of a range. In regular expressions this is often denoted with syntax like {0,3}. Kpeg uses this syntax to accomplish match ranges [min, max].
80
83
 
81
84
  matches_3_to_5_times = letter[3,5]
82
85
  matches_3_to_any_times = letter[3,*]
83
-
84
-
86
+
85
87
  ### Defining Actions
86
88
 
87
89
  Illustrated above in some of the examples, kpeg allows you to perform actions based upon a match that are described in block provided or in the rule definition itself.
@@ -89,6 +91,16 @@ Illustrated above in some of the examples, kpeg allows you to perform actions ba
89
91
  num = /[1-9][0-9]*/
90
92
  sum = < num:n1 "+" num:n2 > { n1 + n2 }
91
93
 
94
+ As of version 0.8 an alternate syntax has been added for calling defined methods as actions.
95
+
96
+ %% {
97
+ def add(n1, n2){
98
+ n1 + n2
99
+ }
100
+ }
101
+ num = /[1-9][0-9]*/
102
+ sum = < num:n1 "+" num:n2 > ~add(n1, n2)
103
+
92
104
  ### Referencing an external grammar
93
105
 
94
106
  Kpeg allows you to run a rule that is defined in an external grammar. This is useful if there is a defined set of rules that you would like to reuse in another parser. To do this, create your grammar and generate a parser using the kpeg command line tool.
@@ -100,7 +112,7 @@ Once you have the generated parser, include that file into your new grammar
100
112
  %{
101
113
  require "literals.kpeg.rb"
102
114
  }
103
-
115
+
104
116
  Then create a variable to hold to foreign interface and pass it the class name of your parser. In this case my parser class name is Literal
105
117
 
106
118
  %foreign_grammer = Literal
@@ -114,21 +126,21 @@ You can then use rules defined in the foreign grammar in the local grammar file
114
126
  Kpeg allows comments to be added to the grammar file by using the # symbol
115
127
 
116
128
  # This is a comment in my grammar
117
-
129
+
118
130
  ## Generating and running your parser
119
131
 
120
132
  Before you can generate your parser you will need to define a root rule. This will be the first rule run against the string provided to the parser
121
133
 
122
134
  root = sentence
123
-
135
+
124
136
  To generate the parser run the kpeg command with the kpeg file(s) as an argument. This will generate a ruby file with the same name as your grammar file.
125
137
 
126
138
  kpeg example.kpeg
127
-
139
+
128
140
  Include your generated parser file into an application that you want to use the parser in and run it. Create a new instance of the parser and pass in the string you want to evaluate. When parse is called on the parser instance it will return a true if the sting is matched, or false if it doesn't.
129
141
 
130
142
  require "example.kpeg.rb"
131
-
143
+
132
144
  parser = Example::Parser.new(string_to_evaluate)
133
145
  parser.parse
134
146
 
@@ -140,6 +152,20 @@ Per vito, you can get the current line or current column in the following way
140
152
  column = { current_column }
141
153
  foo = line:line ... { # use line here }
142
154
 
155
+ ## AST Generation
156
+
157
+ As of Kpeg 0.8 a parser can now generate an AST. To define an AST node use the following syntax
158
+
159
+ %% assign = ast Assignment(name, value)
160
+
161
+ Once you have a defined AST node, it can be used in your grammar like so
162
+
163
+ assignment = identifier:i space* = space* value:v ~assign(i,v)
164
+
165
+ This will create a new Assign node that you can add into your AST.
166
+
167
+ For a good example of usage check out [Talon](https://github.com/evanphx/talon)
168
+
143
169
  ## Examples
144
170
 
145
171
  There are several examples available in the /examples directory. The upper parser has a readme with a step by step description of the grammar.
@@ -153,3 +179,5 @@ There are several examples available in the /examples directory. The upper parse
153
179
  [Callisto](https://github.com/dwaite/Callisto)
154
180
 
155
181
  [Doodle](https://github.com/vito/doodle)
182
+
183
+ [Kanbanpad](https://kanbanpad.com) (uses kpeg for parsing of the 'enter something' bar)
@@ -263,7 +263,11 @@ module KPeg
263
263
  code << indentify("_tmp = _tmp ? nil : true\n", indent)
264
264
  code << indentify("self.pos = #{ss}\n", indent)
265
265
  when RuleReference
266
- code << indentify("_tmp = apply(:#{method_name op.rule_name})\n", indent)
266
+ if op.arguments
267
+ code << indentify("_tmp = apply_with_args(:#{method_name op.rule_name}, #{op.arguments[1..-2]})\n", indent)
268
+ else
269
+ code << indentify("_tmp = apply(:#{method_name op.rule_name})\n", indent)
270
+ end
267
271
  when InvokeRule
268
272
  if op.arguments
269
273
  code << indentify("_tmp = #{method_name op.rule_name}#{op.arguments}\n", indent)
@@ -32,8 +32,8 @@ module KPeg
32
32
  end
33
33
 
34
34
  attr_reader :string
35
- attr_reader :result, :failing_rule_offset
36
- attr_accessor :pos
35
+ attr_reader :failing_rule_offset
36
+ attr_accessor :result, :pos
37
37
 
38
38
  include Position
39
39
 
@@ -218,6 +218,7 @@ module KPeg
218
218
  begin
219
219
  if val = __send__(rule, *args)
220
220
  other.pos = @pos
221
+ other.result = @result
221
222
  else
222
223
  other.set_failed_rule "#{self.class}##{rule}"
223
224
  end
@@ -228,6 +229,43 @@ module KPeg
228
229
  end
229
230
  end
230
231
 
232
+ def apply_with_args(rule, *args)
233
+ memo_key = [rule, args]
234
+ if m = @memoizations[memo_key][@pos]
235
+ m.inc!
236
+
237
+ prev = @pos
238
+ @pos = m.pos
239
+ if m.ans.kind_of? LeftRecursive
240
+ m.ans.detected = true
241
+ return nil
242
+ end
243
+
244
+ @result = m.result
245
+
246
+ return m.ans
247
+ else
248
+ lr = LeftRecursive.new(false)
249
+ m = MemoEntry.new(lr, @pos)
250
+ @memoizations[memo_key][@pos] = m
251
+ start_pos = @pos
252
+
253
+ ans = __send__ rule, *args
254
+
255
+ m.move! ans, @pos, @result
256
+
257
+ # Don't bother trying to grow the left recursion
258
+ # if it's failing straight away (thus there is no seed)
259
+ if ans and lr.detected
260
+ return grow_lr(rule, args, start_pos, m)
261
+ else
262
+ return ans
263
+ end
264
+
265
+ return ans
266
+ end
267
+ end
268
+
231
269
  def apply(rule)
232
270
  if m = @memoizations[rule][@pos]
233
271
  m.inc!
@@ -255,7 +293,7 @@ module KPeg
255
293
  # Don't bother trying to grow the left recursion
256
294
  # if it's failing straight away (thus there is no seed)
257
295
  if ans and lr.detected
258
- return grow_lr(rule, start_pos, m)
296
+ return grow_lr(rule, nil, start_pos, m)
259
297
  else
260
298
  return ans
261
299
  end
@@ -264,12 +302,16 @@ module KPeg
264
302
  end
265
303
  end
266
304
 
267
- def grow_lr(rule, start_pos, m)
305
+ def grow_lr(rule, args, start_pos, m)
268
306
  while true
269
307
  @pos = start_pos
270
308
  @result = m.result
271
309
 
272
- ans = __send__ rule
310
+ if args
311
+ ans = __send__ rule, *args
312
+ else
313
+ ans = __send__ rule
314
+ end
273
315
  return nil unless ans
274
316
 
275
317
  break if @pos <= m.pos
@@ -20,8 +20,8 @@ class KPeg::FormatParser
20
20
  end
21
21
 
22
22
  attr_reader :string
23
- attr_reader :result, :failing_rule_offset
24
- attr_accessor :pos
23
+ attr_reader :failing_rule_offset
24
+ attr_accessor :result, :pos
25
25
 
26
26
  # STANDALONE START
27
27
  def current_column(target=pos)
@@ -234,6 +234,7 @@ class KPeg::FormatParser
234
234
  begin
235
235
  if val = __send__(rule, *args)
236
236
  other.pos = @pos
237
+ other.result = @result
237
238
  else
238
239
  other.set_failed_rule "#{self.class}##{rule}"
239
240
  end
@@ -244,6 +245,43 @@ class KPeg::FormatParser
244
245
  end
245
246
  end
246
247
 
248
+ def apply_with_args(rule, *args)
249
+ memo_key = [rule, args]
250
+ if m = @memoizations[memo_key][@pos]
251
+ m.inc!
252
+
253
+ prev = @pos
254
+ @pos = m.pos
255
+ if m.ans.kind_of? LeftRecursive
256
+ m.ans.detected = true
257
+ return nil
258
+ end
259
+
260
+ @result = m.result
261
+
262
+ return m.ans
263
+ else
264
+ lr = LeftRecursive.new(false)
265
+ m = MemoEntry.new(lr, @pos)
266
+ @memoizations[memo_key][@pos] = m
267
+ start_pos = @pos
268
+
269
+ ans = __send__ rule, *args
270
+
271
+ m.move! ans, @pos, @result
272
+
273
+ # Don't bother trying to grow the left recursion
274
+ # if it's failing straight away (thus there is no seed)
275
+ if ans and lr.detected
276
+ return grow_lr(rule, args, start_pos, m)
277
+ else
278
+ return ans
279
+ end
280
+
281
+ return ans
282
+ end
283
+ end
284
+
247
285
  def apply(rule)
248
286
  if m = @memoizations[rule][@pos]
249
287
  m.inc!
@@ -271,7 +309,7 @@ class KPeg::FormatParser
271
309
  # Don't bother trying to grow the left recursion
272
310
  # if it's failing straight away (thus there is no seed)
273
311
  if ans and lr.detected
274
- return grow_lr(rule, start_pos, m)
312
+ return grow_lr(rule, nil, start_pos, m)
275
313
  else
276
314
  return ans
277
315
  end
@@ -280,12 +318,16 @@ class KPeg::FormatParser
280
318
  end
281
319
  end
282
320
 
283
- def grow_lr(rule, start_pos, m)
321
+ def grow_lr(rule, args, start_pos, m)
284
322
  while true
285
323
  @pos = start_pos
286
324
  @result = m.result
287
325
 
288
- ans = __send__ rule
326
+ if args
327
+ ans = __send__ rule, *args
328
+ else
329
+ ans = __send__ rule
330
+ end
289
331
  return nil unless ans
290
332
 
291
333
  break if @pos <= m.pos
@@ -536,7 +578,7 @@ class KPeg::FormatParser
536
578
  return _tmp
537
579
  end
538
580
 
539
- # dbl_escapes = ("\\\"" { '"' } | "\\n" { "\n" } | "\\t" { "\t" } | "\\b" { "\b" } | "\\\\" { "\\" })
581
+ # dbl_escapes = ("n" { "\n" } | "s" { " " } | "r" { "\r" } | "t" { "\t" } | "v" { "\v" } | "f" { "\f" } | "b" { "\b" } | "a" { "\a" } | "e" { "\e" } | "\\" { "\\" } | "\"" { "\"" } | num_escapes)
540
582
  def _dbl_escapes
541
583
 
542
584
  _save = self.pos
@@ -544,12 +586,12 @@ class KPeg::FormatParser
544
586
 
545
587
  _save1 = self.pos
546
588
  while true # sequence
547
- _tmp = match_string("\\\"")
589
+ _tmp = match_string("n")
548
590
  unless _tmp
549
591
  self.pos = _save1
550
592
  break
551
593
  end
552
- @result = begin; '"' ; end
594
+ @result = begin; "\n" ; end
553
595
  _tmp = true
554
596
  unless _tmp
555
597
  self.pos = _save1
@@ -562,12 +604,12 @@ class KPeg::FormatParser
562
604
 
563
605
  _save2 = self.pos
564
606
  while true # sequence
565
- _tmp = match_string("\\n")
607
+ _tmp = match_string("s")
566
608
  unless _tmp
567
609
  self.pos = _save2
568
610
  break
569
611
  end
570
- @result = begin; "\n" ; end
612
+ @result = begin; " " ; end
571
613
  _tmp = true
572
614
  unless _tmp
573
615
  self.pos = _save2
@@ -580,12 +622,12 @@ class KPeg::FormatParser
580
622
 
581
623
  _save3 = self.pos
582
624
  while true # sequence
583
- _tmp = match_string("\\t")
625
+ _tmp = match_string("r")
584
626
  unless _tmp
585
627
  self.pos = _save3
586
628
  break
587
629
  end
588
- @result = begin; "\t" ; end
630
+ @result = begin; "\r" ; end
589
631
  _tmp = true
590
632
  unless _tmp
591
633
  self.pos = _save3
@@ -598,12 +640,12 @@ class KPeg::FormatParser
598
640
 
599
641
  _save4 = self.pos
600
642
  while true # sequence
601
- _tmp = match_string("\\b")
643
+ _tmp = match_string("t")
602
644
  unless _tmp
603
645
  self.pos = _save4
604
646
  break
605
647
  end
606
- @result = begin; "\b" ; end
648
+ @result = begin; "\t" ; end
607
649
  _tmp = true
608
650
  unless _tmp
609
651
  self.pos = _save4
@@ -616,12 +658,12 @@ class KPeg::FormatParser
616
658
 
617
659
  _save5 = self.pos
618
660
  while true # sequence
619
- _tmp = match_string("\\\\")
661
+ _tmp = match_string("v")
620
662
  unless _tmp
621
663
  self.pos = _save5
622
664
  break
623
665
  end
624
- @result = begin; "\\" ; end
666
+ @result = begin; "\v" ; end
625
667
  _tmp = true
626
668
  unless _tmp
627
669
  self.pos = _save5
@@ -629,6 +671,117 @@ class KPeg::FormatParser
629
671
  break
630
672
  end # end sequence
631
673
 
674
+ break if _tmp
675
+ self.pos = _save
676
+
677
+ _save6 = self.pos
678
+ while true # sequence
679
+ _tmp = match_string("f")
680
+ unless _tmp
681
+ self.pos = _save6
682
+ break
683
+ end
684
+ @result = begin; "\f" ; end
685
+ _tmp = true
686
+ unless _tmp
687
+ self.pos = _save6
688
+ end
689
+ break
690
+ end # end sequence
691
+
692
+ break if _tmp
693
+ self.pos = _save
694
+
695
+ _save7 = self.pos
696
+ while true # sequence
697
+ _tmp = match_string("b")
698
+ unless _tmp
699
+ self.pos = _save7
700
+ break
701
+ end
702
+ @result = begin; "\b" ; end
703
+ _tmp = true
704
+ unless _tmp
705
+ self.pos = _save7
706
+ end
707
+ break
708
+ end # end sequence
709
+
710
+ break if _tmp
711
+ self.pos = _save
712
+
713
+ _save8 = self.pos
714
+ while true # sequence
715
+ _tmp = match_string("a")
716
+ unless _tmp
717
+ self.pos = _save8
718
+ break
719
+ end
720
+ @result = begin; "\a" ; end
721
+ _tmp = true
722
+ unless _tmp
723
+ self.pos = _save8
724
+ end
725
+ break
726
+ end # end sequence
727
+
728
+ break if _tmp
729
+ self.pos = _save
730
+
731
+ _save9 = self.pos
732
+ while true # sequence
733
+ _tmp = match_string("e")
734
+ unless _tmp
735
+ self.pos = _save9
736
+ break
737
+ end
738
+ @result = begin; "\e" ; end
739
+ _tmp = true
740
+ unless _tmp
741
+ self.pos = _save9
742
+ end
743
+ break
744
+ end # end sequence
745
+
746
+ break if _tmp
747
+ self.pos = _save
748
+
749
+ _save10 = self.pos
750
+ while true # sequence
751
+ _tmp = match_string("\\")
752
+ unless _tmp
753
+ self.pos = _save10
754
+ break
755
+ end
756
+ @result = begin; "\\" ; end
757
+ _tmp = true
758
+ unless _tmp
759
+ self.pos = _save10
760
+ end
761
+ break
762
+ end # end sequence
763
+
764
+ break if _tmp
765
+ self.pos = _save
766
+
767
+ _save11 = self.pos
768
+ while true # sequence
769
+ _tmp = match_string("\"")
770
+ unless _tmp
771
+ self.pos = _save11
772
+ break
773
+ end
774
+ @result = begin; "\"" ; end
775
+ _tmp = true
776
+ unless _tmp
777
+ self.pos = _save11
778
+ end
779
+ break
780
+ end # end sequence
781
+
782
+ break if _tmp
783
+ self.pos = _save
784
+ _tmp = apply(:_num_escapes)
632
785
  break if _tmp
633
786
  self.pos = _save
634
787
  break
@@ -638,6 +791,67 @@ class KPeg::FormatParser
638
791
  return _tmp
639
792
  end
640
793
 
794
+ # num_escapes = (< /[0-7]{3}/ > { [text.to_i(8)].pack("U") } | "x" < /[0-9a-fA-F]{2}/ > { [text.to_i(16)].pack("U") })
795
+ def _num_escapes
796
+
797
+ _save = self.pos
798
+ while true # choice
799
+
800
+ _save1 = self.pos
801
+ while true # sequence
802
+ _text_start = self.pos
803
+ _tmp = scan(/\A(?-mix:[0-7]{3})/)
804
+ if _tmp
805
+ text = get_text(_text_start)
806
+ end
807
+ unless _tmp
808
+ self.pos = _save1
809
+ break
810
+ end
811
+ @result = begin; [text.to_i(8)].pack("U") ; end
812
+ _tmp = true
813
+ unless _tmp
814
+ self.pos = _save1
815
+ end
816
+ break
817
+ end # end sequence
818
+
819
+ break if _tmp
820
+ self.pos = _save
821
+
822
+ _save2 = self.pos
823
+ while true # sequence
824
+ _tmp = match_string("x")
825
+ unless _tmp
826
+ self.pos = _save2
827
+ break
828
+ end
829
+ _text_start = self.pos
830
+ _tmp = scan(/\A(?-mix:[0-9a-fA-F]{2})/)
831
+ if _tmp
832
+ text = get_text(_text_start)
833
+ end
834
+ unless _tmp
835
+ self.pos = _save2
836
+ break
837
+ end
838
+ @result = begin; [text.to_i(16)].pack("U") ; end
839
+ _tmp = true
840
+ unless _tmp
841
+ self.pos = _save2
842
+ end
843
+ break
844
+ end # end sequence
845
+
846
+ break if _tmp
847
+ self.pos = _save
848
+ break
849
+ end # end choice
850
+
851
+ set_failed_rule :_num_escapes unless _tmp
852
+ return _tmp
853
+ end
854
+
641
855
  # dbl_seq = < /[^\\"]+/ > { text }
642
856
  def _dbl_seq
643
857
 
@@ -664,58 +878,52 @@ class KPeg::FormatParser
664
878
  return _tmp
665
879
  end
666
880
 
667
- # dbl_not_quote = (dbl_escapes:s | dbl_seq:s)+:ary { ary }
881
+ # dbl_not_quote = ("\\" dbl_escapes:s | dbl_seq:s)*:ary { Array(ary) }
668
882
  def _dbl_not_quote
669
883
 
670
884
  _save = self.pos
671
885
  while true # sequence
672
- _save1 = self.pos
673
886
  _ary = []
887
+ while true
674
888
 
675
- _save2 = self.pos
676
- while true # choice
677
- _tmp = apply(:_dbl_escapes)
678
- s = @result
679
- break if _tmp
680
- self.pos = _save2
681
- _tmp = apply(:_dbl_seq)
682
- s = @result
683
- break if _tmp
684
- self.pos = _save2
685
- break
686
- end # end choice
687
-
688
- if _tmp
689
- _ary << @result
690
- while true
889
+ _save2 = self.pos
890
+ while true # choice
691
891
 
692
892
  _save3 = self.pos
693
- while true # choice
893
+ while true # sequence
894
+ _tmp = match_string("\\")
895
+ unless _tmp
896
+ self.pos = _save3
897
+ break
898
+ end
694
899
  _tmp = apply(:_dbl_escapes)
695
900
  s = @result
696
- break if _tmp
697
- self.pos = _save3
698
- _tmp = apply(:_dbl_seq)
699
- s = @result
700
- break if _tmp
701
- self.pos = _save3
901
+ unless _tmp
902
+ self.pos = _save3
903
+ end
702
904
  break
703
- end # end choice
905
+ end # end sequence
704
906
 
705
- _ary << @result if _tmp
706
- break unless _tmp
707
- end
708
- _tmp = true
709
- @result = _ary
710
- else
711
- self.pos = _save1
907
+ break if _tmp
908
+ self.pos = _save2
909
+ _tmp = apply(:_dbl_seq)
910
+ s = @result
911
+ break if _tmp
912
+ self.pos = _save2
913
+ break
914
+ end # end choice
915
+
916
+ _ary << @result if _tmp
917
+ break unless _tmp
712
918
  end
919
+ _tmp = true
920
+ @result = _ary
713
921
  ary = @result
714
922
  unless _tmp
715
923
  self.pos = _save
716
924
  break
717
925
  end
718
- @result = begin; ary ; end
926
+ @result = begin; Array(ary) ; end
719
927
  _tmp = true
720
928
  unless _tmp
721
929
  self.pos = _save
@@ -808,54 +1016,36 @@ class KPeg::FormatParser
808
1016
  return _tmp
809
1017
  end
810
1018
 
811
- # sgl_not_quote = (sgl_escape_quote | sgl_seq)+:segs { segs.join }
1019
+ # sgl_not_quote = (sgl_escape_quote | sgl_seq)*:segs { Array(segs) }
812
1020
  def _sgl_not_quote
813
1021
 
814
1022
  _save = self.pos
815
1023
  while true # sequence
816
- _save1 = self.pos
817
1024
  _ary = []
1025
+ while true
818
1026
 
819
- _save2 = self.pos
820
- while true # choice
821
- _tmp = apply(:_sgl_escape_quote)
822
- break if _tmp
823
- self.pos = _save2
824
- _tmp = apply(:_sgl_seq)
825
- break if _tmp
826
- self.pos = _save2
827
- break
828
- end # end choice
829
-
830
- if _tmp
831
- _ary << @result
832
- while true
833
-
834
- _save3 = self.pos
835
- while true # choice
836
- _tmp = apply(:_sgl_escape_quote)
837
- break if _tmp
838
- self.pos = _save3
839
- _tmp = apply(:_sgl_seq)
840
- break if _tmp
841
- self.pos = _save3
842
- break
843
- end # end choice
1027
+ _save2 = self.pos
1028
+ while true # choice
1029
+ _tmp = apply(:_sgl_escape_quote)
1030
+ break if _tmp
1031
+ self.pos = _save2
1032
+ _tmp = apply(:_sgl_seq)
1033
+ break if _tmp
1034
+ self.pos = _save2
1035
+ break
1036
+ end # end choice
844
1037
 
845
- _ary << @result if _tmp
846
- break unless _tmp
847
- end
848
- _tmp = true
849
- @result = _ary
850
- else
851
- self.pos = _save1
1038
+ _ary << @result if _tmp
1039
+ break unless _tmp
852
1040
  end
1041
+ _tmp = true
1042
+ @result = _ary
853
1043
  segs = @result
854
1044
  unless _tmp
855
1045
  self.pos = _save
856
1046
  break
857
1047
  end
858
- @result = begin; segs.join ; end
1048
+ @result = begin; Array(segs) ; end
859
1049
  _tmp = true
860
1050
  unless _tmp
861
1051
  self.pos = _save
@@ -867,7 +1057,7 @@ class KPeg::FormatParser
867
1057
  return _tmp
868
1058
  end
869
1059
 
870
- # sgl_string = "'" sgl_not_quote:s "'" { @g.str(s) }
1060
+ # sgl_string = "'" sgl_not_quote:s "'" { @g.str(s.join) }
871
1061
  def _sgl_string
872
1062
 
873
1063
  _save = self.pos
@@ -888,7 +1078,7 @@ class KPeg::FormatParser
888
1078
  self.pos = _save
889
1079
  break
890
1080
  end
891
- @result = begin; @g.str(s) ; end
1081
+ @result = begin; @g.str(s.join) ; end
892
1082
  _tmp = true
893
1083
  unless _tmp
894
1084
  self.pos = _save
@@ -1401,7 +1591,7 @@ class KPeg::FormatParser
1401
1591
  return _tmp
1402
1592
  end
1403
1593
 
1404
- # value = (value:v ":" var:n { @g.t(v,n) } | value:v "?" { @g.maybe(v) } | value:v "+" { @g.many(v) } | value:v "*" { @g.kleene(v) } | value:v mult_range:r { @g.multiple(v, *r) } | "&" value:v { @g.andp(v) } | "!" value:v { @g.notp(v) } | "(" - expression:o - ")" { o } | "@<" - expression:o - ">" { @g.bounds(o) } | "<" - expression:o - ">" { @g.collect(o) } | curly_block | "~" method:m < nested_paren? > { @g.action("#{m}#{text}") } | "." { @g.dot } | "@" var:name !(- "=") { @g.invoke(name) } | "^" var:name < nested_paren? > { @g.foreign_invoke("parent", name, text) } | "%" var:gram "." var:name < nested_paren? > { @g.foreign_invoke(gram, name, text) } | var:name < nested_paren? > !(- "=") { text.empty? ? @g.ref(name) : @g.invoke(name, text) } | char_range | regexp | string)
1594
+ # value = (value:v ":" var:n { @g.t(v,n) } | value:v "?" { @g.maybe(v) } | value:v "+" { @g.many(v) } | value:v "*" { @g.kleene(v) } | value:v mult_range:r { @g.multiple(v, *r) } | "&" value:v { @g.andp(v) } | "!" value:v { @g.notp(v) } | "(" - expression:o - ")" { o } | "@<" - expression:o - ">" { @g.bounds(o) } | "<" - expression:o - ">" { @g.collect(o) } | curly_block | "~" method:m < nested_paren? > { @g.action("#{m}#{text}") } | "." { @g.dot } | "@" var:name < nested_paren? > !(- "=") { @g.invoke(name, text.empty? ? nil : text) } | "^" var:name < nested_paren? > { @g.foreign_invoke("parent", name, text) } | "%" var:gram "." var:name < nested_paren? > { @g.foreign_invoke(gram, name, text) } | var:name < nested_paren? > !(- "=") { @g.ref(name, nil, text.empty? ? nil : text) } | char_range | regexp | string)
1405
1595
  def _value
1406
1596
 
1407
1597
  _save = self.pos
@@ -1771,29 +1961,43 @@ class KPeg::FormatParser
1771
1961
  self.pos = _save14
1772
1962
  break
1773
1963
  end
1964
+ _text_start = self.pos
1774
1965
  _save15 = self.pos
1775
-
1966
+ _tmp = apply(:_nested_paren)
1967
+ unless _tmp
1968
+ _tmp = true
1969
+ self.pos = _save15
1970
+ end
1971
+ if _tmp
1972
+ text = get_text(_text_start)
1973
+ end
1974
+ unless _tmp
1975
+ self.pos = _save14
1976
+ break
1977
+ end
1776
1978
  _save16 = self.pos
1979
+
1980
+ _save17 = self.pos
1777
1981
  while true # sequence
1778
1982
  _tmp = apply(:__hyphen_)
1779
1983
  unless _tmp
1780
- self.pos = _save16
1984
+ self.pos = _save17
1781
1985
  break
1782
1986
  end
1783
1987
  _tmp = match_string("=")
1784
1988
  unless _tmp
1785
- self.pos = _save16
1989
+ self.pos = _save17
1786
1990
  end
1787
1991
  break
1788
1992
  end # end sequence
1789
1993
 
1790
1994
  _tmp = _tmp ? nil : true
1791
- self.pos = _save15
1995
+ self.pos = _save16
1792
1996
  unless _tmp
1793
1997
  self.pos = _save14
1794
1998
  break
1795
1999
  end
1796
- @result = begin; @g.invoke(name) ; end
2000
+ @result = begin; @g.invoke(name, text.empty? ? nil : text) ; end
1797
2001
  _tmp = true
1798
2002
  unless _tmp
1799
2003
  self.pos = _save14
@@ -1804,37 +2008,37 @@ class KPeg::FormatParser
1804
2008
  break if _tmp
1805
2009
  self.pos = _save
1806
2010
 
1807
- _save17 = self.pos
2011
+ _save18 = self.pos
1808
2012
  while true # sequence
1809
2013
  _tmp = match_string("^")
1810
2014
  unless _tmp
1811
- self.pos = _save17
2015
+ self.pos = _save18
1812
2016
  break
1813
2017
  end
1814
2018
  _tmp = apply(:_var)
1815
2019
  name = @result
1816
2020
  unless _tmp
1817
- self.pos = _save17
2021
+ self.pos = _save18
1818
2022
  break
1819
2023
  end
1820
2024
  _text_start = self.pos
1821
- _save18 = self.pos
2025
+ _save19 = self.pos
1822
2026
  _tmp = apply(:_nested_paren)
1823
2027
  unless _tmp
1824
2028
  _tmp = true
1825
- self.pos = _save18
2029
+ self.pos = _save19
1826
2030
  end
1827
2031
  if _tmp
1828
2032
  text = get_text(_text_start)
1829
2033
  end
1830
2034
  unless _tmp
1831
- self.pos = _save17
2035
+ self.pos = _save18
1832
2036
  break
1833
2037
  end
1834
2038
  @result = begin; @g.foreign_invoke("parent", name, text) ; end
1835
2039
  _tmp = true
1836
2040
  unless _tmp
1837
- self.pos = _save17
2041
+ self.pos = _save18
1838
2042
  end
1839
2043
  break
1840
2044
  end # end sequence
@@ -1842,48 +2046,48 @@ class KPeg::FormatParser
1842
2046
  break if _tmp
1843
2047
  self.pos = _save
1844
2048
 
1845
- _save19 = self.pos
2049
+ _save20 = self.pos
1846
2050
  while true # sequence
1847
2051
  _tmp = match_string("%")
1848
2052
  unless _tmp
1849
- self.pos = _save19
2053
+ self.pos = _save20
1850
2054
  break
1851
2055
  end
1852
2056
  _tmp = apply(:_var)
1853
2057
  gram = @result
1854
2058
  unless _tmp
1855
- self.pos = _save19
2059
+ self.pos = _save20
1856
2060
  break
1857
2061
  end
1858
2062
  _tmp = match_string(".")
1859
2063
  unless _tmp
1860
- self.pos = _save19
2064
+ self.pos = _save20
1861
2065
  break
1862
2066
  end
1863
2067
  _tmp = apply(:_var)
1864
2068
  name = @result
1865
2069
  unless _tmp
1866
- self.pos = _save19
2070
+ self.pos = _save20
1867
2071
  break
1868
2072
  end
1869
2073
  _text_start = self.pos
1870
- _save20 = self.pos
2074
+ _save21 = self.pos
1871
2075
  _tmp = apply(:_nested_paren)
1872
2076
  unless _tmp
1873
2077
  _tmp = true
1874
- self.pos = _save20
2078
+ self.pos = _save21
1875
2079
  end
1876
2080
  if _tmp
1877
2081
  text = get_text(_text_start)
1878
2082
  end
1879
2083
  unless _tmp
1880
- self.pos = _save19
2084
+ self.pos = _save20
1881
2085
  break
1882
2086
  end
1883
2087
  @result = begin; @g.foreign_invoke(gram, name, text) ; end
1884
2088
  _tmp = true
1885
2089
  unless _tmp
1886
- self.pos = _save19
2090
+ self.pos = _save20
1887
2091
  end
1888
2092
  break
1889
2093
  end # end sequence
@@ -1891,54 +2095,54 @@ class KPeg::FormatParser
1891
2095
  break if _tmp
1892
2096
  self.pos = _save
1893
2097
 
1894
- _save21 = self.pos
2098
+ _save22 = self.pos
1895
2099
  while true # sequence
1896
2100
  _tmp = apply(:_var)
1897
2101
  name = @result
1898
2102
  unless _tmp
1899
- self.pos = _save21
2103
+ self.pos = _save22
1900
2104
  break
1901
2105
  end
1902
2106
  _text_start = self.pos
1903
- _save22 = self.pos
2107
+ _save23 = self.pos
1904
2108
  _tmp = apply(:_nested_paren)
1905
2109
  unless _tmp
1906
2110
  _tmp = true
1907
- self.pos = _save22
2111
+ self.pos = _save23
1908
2112
  end
1909
2113
  if _tmp
1910
2114
  text = get_text(_text_start)
1911
2115
  end
1912
2116
  unless _tmp
1913
- self.pos = _save21
2117
+ self.pos = _save22
1914
2118
  break
1915
2119
  end
1916
- _save23 = self.pos
1917
-
1918
2120
  _save24 = self.pos
2121
+
2122
+ _save25 = self.pos
1919
2123
  while true # sequence
1920
2124
  _tmp = apply(:__hyphen_)
1921
2125
  unless _tmp
1922
- self.pos = _save24
2126
+ self.pos = _save25
1923
2127
  break
1924
2128
  end
1925
2129
  _tmp = match_string("=")
1926
2130
  unless _tmp
1927
- self.pos = _save24
2131
+ self.pos = _save25
1928
2132
  end
1929
2133
  break
1930
2134
  end # end sequence
1931
2135
 
1932
2136
  _tmp = _tmp ? nil : true
1933
- self.pos = _save23
2137
+ self.pos = _save24
1934
2138
  unless _tmp
1935
- self.pos = _save21
2139
+ self.pos = _save22
1936
2140
  break
1937
2141
  end
1938
- @result = begin; text.empty? ? @g.ref(name) : @g.invoke(name, text) ; end
2142
+ @result = begin; @g.ref(name, nil, text.empty? ? nil : text) ; end
1939
2143
  _tmp = true
1940
2144
  unless _tmp
1941
- self.pos = _save21
2145
+ self.pos = _save22
1942
2146
  end
1943
2147
  break
1944
2148
  end # end sequence
@@ -2871,14 +3075,15 @@ class KPeg::FormatParser
2871
3075
  Rules[:_kleene] = rule_info("kleene", "\"*\"")
2872
3076
  Rules[:_var] = rule_info("var", "< (\"-\" | /[a-zA-Z][\\-_a-zA-Z0-9]*/) > { text }")
2873
3077
  Rules[:_method] = rule_info("method", "< /[a-zA-Z_][a-zA-Z0-9_]*/ > { text }")
2874
- Rules[:_dbl_escapes] = rule_info("dbl_escapes", "(\"\\\\\\\"\" { '\"' } | \"\\\\n\" { \"\\n\" } | \"\\\\t\" { \"\\t\" } | \"\\\\b\" { \"\\b\" } | \"\\\\\\\\\" { \"\\\\\" })")
3078
+ Rules[:_dbl_escapes] = rule_info("dbl_escapes", "(\"n\" { \"\\n\" } | \"s\" { \" \" } | \"r\" { \"\\r\" } | \"t\" { \"\\t\" } | \"v\" { \"\\v\" } | \"f\" { \"\\f\" } | \"b\" { \"\\b\" } | \"a\" { \"\\a\" } | \"e\" { \"\\e\" } | \"\\\\\" { \"\\\\\" } | \"\\\"\" { \"\\\"\" } | num_escapes)")
3079
+ Rules[:_num_escapes] = rule_info("num_escapes", "(< /[0-7]{3}/ > { [text.to_i(8)].pack(\"U\") } | \"x\" < /[0-9a-fA-F]{2}/ > { [text.to_i(16)].pack(\"U\") })")
2875
3080
  Rules[:_dbl_seq] = rule_info("dbl_seq", "< /[^\\\\\"]+/ > { text }")
2876
- Rules[:_dbl_not_quote] = rule_info("dbl_not_quote", "(dbl_escapes:s | dbl_seq:s)+:ary { ary }")
3081
+ Rules[:_dbl_not_quote] = rule_info("dbl_not_quote", "(\"\\\\\" dbl_escapes:s | dbl_seq:s)*:ary { Array(ary) }")
2877
3082
  Rules[:_dbl_string] = rule_info("dbl_string", "\"\\\"\" dbl_not_quote:s \"\\\"\" { @g.str(s.join) }")
2878
3083
  Rules[:_sgl_escape_quote] = rule_info("sgl_escape_quote", "\"\\\\'\" { \"'\" }")
2879
3084
  Rules[:_sgl_seq] = rule_info("sgl_seq", "< /[^']/ > { text }")
2880
- Rules[:_sgl_not_quote] = rule_info("sgl_not_quote", "(sgl_escape_quote | sgl_seq)+:segs { segs.join }")
2881
- Rules[:_sgl_string] = rule_info("sgl_string", "\"'\" sgl_not_quote:s \"'\" { @g.str(s) }")
3085
+ Rules[:_sgl_not_quote] = rule_info("sgl_not_quote", "(sgl_escape_quote | sgl_seq)*:segs { Array(segs) }")
3086
+ Rules[:_sgl_string] = rule_info("sgl_string", "\"'\" sgl_not_quote:s \"'\" { @g.str(s.join) }")
2882
3087
  Rules[:_string] = rule_info("string", "(dbl_string | sgl_string)")
2883
3088
  Rules[:_not_slash] = rule_info("not_slash", "< (\"\\\\/\" | /[^\\/]/)+ > { text }")
2884
3089
  Rules[:_regexp_opts] = rule_info("regexp_opts", "< [a-z]* > { text }")
@@ -2891,7 +3096,7 @@ class KPeg::FormatParser
2891
3096
  Rules[:_curly_block] = rule_info("curly_block", "curly")
2892
3097
  Rules[:_curly] = rule_info("curly", "\"{\" < (/[^{}\"']+/ | string | curly)* > \"}\" { @g.action(text) }")
2893
3098
  Rules[:_nested_paren] = rule_info("nested_paren", "\"(\" (/[^()\"']+/ | string | nested_paren)* \")\"")
2894
- Rules[:_value] = rule_info("value", "(value:v \":\" var:n { @g.t(v,n) } | value:v \"?\" { @g.maybe(v) } | value:v \"+\" { @g.many(v) } | value:v \"*\" { @g.kleene(v) } | value:v mult_range:r { @g.multiple(v, *r) } | \"&\" value:v { @g.andp(v) } | \"!\" value:v { @g.notp(v) } | \"(\" - expression:o - \")\" { o } | \"@<\" - expression:o - \">\" { @g.bounds(o) } | \"<\" - expression:o - \">\" { @g.collect(o) } | curly_block | \"~\" method:m < nested_paren? > { @g.action(\"\#{m}\#{text}\") } | \".\" { @g.dot } | \"@\" var:name !(- \"=\") { @g.invoke(name) } | \"^\" var:name < nested_paren? > { @g.foreign_invoke(\"parent\", name, text) } | \"%\" var:gram \".\" var:name < nested_paren? > { @g.foreign_invoke(gram, name, text) } | var:name < nested_paren? > !(- \"=\") { text.empty? ? @g.ref(name) : @g.invoke(name, text) } | char_range | regexp | string)")
3099
+ Rules[:_value] = rule_info("value", "(value:v \":\" var:n { @g.t(v,n) } | value:v \"?\" { @g.maybe(v) } | value:v \"+\" { @g.many(v) } | value:v \"*\" { @g.kleene(v) } | value:v mult_range:r { @g.multiple(v, *r) } | \"&\" value:v { @g.andp(v) } | \"!\" value:v { @g.notp(v) } | \"(\" - expression:o - \")\" { o } | \"@<\" - expression:o - \">\" { @g.bounds(o) } | \"<\" - expression:o - \">\" { @g.collect(o) } | curly_block | \"~\" method:m < nested_paren? > { @g.action(\"\#{m}\#{text}\") } | \".\" { @g.dot } | \"@\" var:name < nested_paren? > !(- \"=\") { @g.invoke(name, text.empty? ? nil : text) } | \"^\" var:name < nested_paren? > { @g.foreign_invoke(\"parent\", name, text) } | \"%\" var:gram \".\" var:name < nested_paren? > { @g.foreign_invoke(gram, name, text) } | var:name < nested_paren? > !(- \"=\") { @g.ref(name, nil, text.empty? ? nil : text) } | char_range | regexp | string)")
2895
3100
  Rules[:_spaces] = rule_info("spaces", "(space | comment)+")
2896
3101
  Rules[:_values] = rule_info("values", "(values:s spaces value:v { @g.seq(s, v) } | value:l spaces value:r { @g.seq(l, r) } | value)")
2897
3102
  Rules[:_choose_cont] = rule_info("choose_cont", "- \"|\" - values:v { v }")
data/lib/kpeg/grammar.rb CHANGED
@@ -396,13 +396,14 @@ module KPeg
396
396
  end
397
397
 
398
398
  class RuleReference < Operator
399
- def initialize(name, grammar=nil)
399
+ def initialize(name, grammar=nil, args=nil)
400
400
  super()
401
401
  @rule_name = name
402
402
  @grammar = grammar
403
+ @arguments = args
403
404
  end
404
405
 
405
- attr_reader :rule_name
406
+ attr_reader :rule_name, :arguments
406
407
 
407
408
  def match(x)
408
409
  if @grammar and @grammar != x.grammar
@@ -421,14 +422,19 @@ module KPeg
421
422
  def ==(obj)
422
423
  case obj
423
424
  when RuleReference
424
- @rule_name == obj.rule_name
425
+ @rule_name == obj.rule_name and @arguments == obj.arguments
425
426
  else
426
427
  super
427
428
  end
428
429
  end
429
430
 
430
431
  def inspect
431
- inspect_type "ref", @rule_name
432
+ if @arguments
433
+ body = "#{@rule_name} #{@arguments}"
434
+ else
435
+ body = @rule_name
436
+ end
437
+ inspect_type "ref", body
432
438
  end
433
439
  end
434
440
 
@@ -807,14 +813,14 @@ module KPeg
807
813
  NotPredicate.new Grammar.resolve(node)
808
814
  end
809
815
 
810
- def ref(name, other_grammar=nil)
811
- RuleReference.new name.to_s, other_grammar
816
+ def ref(name, other_grammar=nil, args=nil)
817
+ RuleReference.new name.to_s, other_grammar, args
812
818
  end
813
819
 
814
820
  def invoke(name, args=nil)
815
821
  InvokeRule.new name.to_s, args
816
822
  end
817
-
823
+
818
824
  # Invoke a rule defined on a foreign grammar
819
825
  # == Parameters:
820
826
  # gram::
@@ -132,10 +132,14 @@ module KPeg
132
132
  render_op io, op.op
133
133
  end
134
134
  when RuleReference
135
- io.print op.rule_name
136
- when InvokeRule
137
135
  if op.arguments
138
136
  io.print "#{op.rule_name}#{op.arguments}"
137
+ else
138
+ io.print "#{op.rule_name}"
139
+ end
140
+ when InvokeRule
141
+ if op.arguments
142
+ io.print "@#{op.rule_name}#{op.arguments}"
139
143
  else
140
144
  io.print "@#{op.rule_name}"
141
145
  end
data/lib/kpeg/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module KPeg
2
- VERSION = "0.8.2"
2
+ VERSION = "0.8.3"
3
3
  end
@@ -799,7 +799,7 @@ class Test < KPeg::CompiledParser
799
799
  return _tmp
800
800
  end
801
801
 
802
- # root = greeting(1,2)
802
+ # root = @greeting(1,2)
803
803
  def _root
804
804
  _tmp = _greeting(1,2)
805
805
  set_failed_rule :_root unless _tmp
@@ -808,7 +808,7 @@ class Test < KPeg::CompiledParser
808
808
 
809
809
  Rules = {}
810
810
  Rules[:_greeting] = rule_info("greeting", "\\\"hello\\\"")
811
- Rules[:_root] = rule_info("root", "greeting(1,2)")
811
+ Rules[:_root] = rule_info("root", "@greeting(1,2)")
812
812
  end
813
813
  STR
814
814
 
@@ -27,6 +27,10 @@ class TestKPegFormat < Test::Unit::TestCase
27
27
  assert_rule G.ref("b"), match("a=b"), "a"
28
28
  end
29
29
 
30
+ def test_apply_with_arg
31
+ assert_rule G.ref("b", nil, "(x)"), match("a=b(x)"), "a"
32
+ end
33
+
30
34
  def test_invoke
31
35
  assert_rule G.invoke("b"), match("a=@b"), "a"
32
36
  end
@@ -107,7 +111,7 @@ b(p) = x
107
111
 
108
112
 
109
113
  def test_invoke_with_multiple_args
110
- assert_rule G.invoke("b", "(1,2)"), match("a=b(1,2)"), "a"
114
+ assert_rule G.invoke("b", "(1,2)"), match("a=@b(1,2)"), "a"
111
115
  end
112
116
 
113
117
  def test_invoke_foreign_rule
@@ -140,7 +144,11 @@ b(p) = x
140
144
  end
141
145
 
142
146
  def test_string
147
+ assert_rule G.str(""), match('a=""')
143
148
  assert_rule G.str("hello"), match('a="hello"')
149
+ assert_rule G.str("hello\ngoodbye"), match('a="hello\ngoodbye"')
150
+ assert_rule G.str("\n\s\r\t\v\f\b\a\r\\\"\012\x1b"),
151
+ match('a="\n\s\r\t\v\f\b\a\r\\\\\\"\012\x1b"')
144
152
  assert_rule G.str("h\"ello"), match('a="h\"ello"')
145
153
  end
146
154
 
@@ -453,7 +461,7 @@ fact = fact "*" num
453
461
  def test_allow_ends_with_comment
454
462
  path = File.expand_path("../inputs/comments.kpeg", __FILE__)
455
463
  parser = KPeg::FormatParser.new File.read(path), true
456
- assert true, parser.parse
464
+ assert_equal true, parser.parse
457
465
  end
458
466
 
459
467
  def test_roundtrip
@@ -36,7 +36,7 @@ class TestKPegGrammarRenderer < Test::Unit::TestCase
36
36
  gr = KPeg::GrammarRenderer.new(gram)
37
37
  gr.render(io)
38
38
 
39
- assert_equal "root = greeting(1,2)\n", io.string
39
+ assert_equal "root = @greeting(1,2)\n", io.string
40
40
  end
41
41
 
42
42
  def test_foreign_invoke
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kpeg
3
3
  version: !ruby/object:Gem::Version
4
- hash: 59
4
+ hash: 57
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 8
9
- - 2
10
- version: 0.8.2
9
+ - 3
10
+ version: 0.8.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Evan Phoenix
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-04-18 00:00:00 -07:00
18
+ date: 2011-05-05 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency