aslakhellesoy-cucumber 0.1.99.1 → 0.1.99.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,11 +10,19 @@ on how to use alternatives.
10
10
  **** CALL FOR TRANSLATORS ****
11
11
  Since the grammar has changed, there are some new keywords. We have to rely on the community
12
12
  to provide updated translations. This is much easier than before - just update languages.yml.
13
- There is no static code generation anymore.
13
+ There is no static code generation anymore. To list all languages:
14
14
 
15
- There are some exciting new feaqtures, so upgrading is not in vain. Tagging, Autoformatting,
16
- Auto aliasing of keywords in all languages, much better Ruby 1.9 support and improved output
17
- for multiline arguments should make the upgrade worthwhile.
15
+ cucumber --lang help
16
+
17
+ And to list the keywords for a particular language:
18
+
19
+ cucumber --lang en-lol help
20
+
21
+ So just go ahead and list the language of your choice and send us updated translations.
22
+
23
+ There are some really awesome new features in this release: Tagging, Autoformatting, automatic
24
+ aliasing of keywords in all languages, much better Ruby 1.9 support and improved output
25
+ for multiline arguments are some of the highlights.
18
26
 
19
27
  This version also brings Cucumber even closer to Java. Although it has been possible to
20
28
  run Cucumber on JRuby since v0.1.11, it has required that step definitions be defined
@@ -65,9 +73,9 @@ pure Ruby users have been enjoying for a while.
65
73
  * It's no longer necessary to compile the Treetop grammar when adding a new language. Localised parser is generated at runtime.
66
74
 
67
75
  === Removed features
68
- * "GivenScenario" is gone. Instead you can use "Background" or call Steps from Steps.
76
+ * "GivenScenario" is gone. Instead you can call Steps from Steps, or wait for "Background (#153)"
69
77
  * "More Examples" is gone. "Scenario" + "More Examples" is no longer supported. Use "Scenario Outline" + "Examples" instead.
70
- * Pure Ruby features are no longer supported
78
+ * Pure Ruby features are no longer supported.
71
79
 
72
80
  == 0.1.16.x (Master)
73
81
 
@@ -193,8 +193,9 @@ lib/cucumber/parser.rb
193
193
  lib/cucumber/parser/basic.rb
194
194
  lib/cucumber/parser/feature.rb
195
195
  lib/cucumber/parser/feature.tt
196
- lib/cucumber/parser/file_parser.rb
197
196
  lib/cucumber/parser/i18n.tt
197
+ lib/cucumber/parser/table.rb
198
+ lib/cucumber/parser/table.tt
198
199
  lib/cucumber/parser/treetop_ext.rb
199
200
  lib/cucumber/platform.rb
200
201
  lib/cucumber/rails/rspec.rb
@@ -9,15 +9,33 @@ Given "be_empty" do
9
9
  end
10
10
 
11
11
  Given "nested step is called" do
12
- Given "nested step"
12
+ Given "I like mushroom", Cucumber::Ast::Table.new([
13
+ %w{sponge bob},
14
+ %w{is cool}
15
+ ])
13
16
  end
14
17
 
15
- Given "nested step" do
16
- @magic = 'mushroom'
18
+ Given 'nested step is called using text table' do
19
+ Given "I like mushroom", table(%{
20
+ | sponge | bob |
21
+ | is | cool |
22
+ })
23
+
24
+ # Alternative syntax (file and line will be reported on parse error)
25
+ # Given "I like mushroom", table(<<-EOT, __FILE__, __LINE__)
26
+ # | sponge | bob |
27
+ # | is | cool
28
+ # EOT
29
+ end
30
+
31
+ Given "I like $what" do |what, table|
32
+ @magic = what
33
+ @tool = table.raw[0][0]
17
34
  end
18
35
 
19
36
  Then "nested step should be executed" do
20
37
  @magic.should == 'mushroom'
38
+ @tool.should == 'sponge'
21
39
  end
22
40
 
23
41
  Given /^the following table$/ do |table|
@@ -9,6 +9,10 @@ Feature: Cucumber
9
9
  Scenario: Call step from step
10
10
  Given nested step is called
11
11
  Then nested step should be executed
12
+
13
+ Scenario: Call step from step using text table
14
+ Given nested step is called using text table
15
+ Then nested step should be executed
12
16
 
13
17
  Scenario: Reading a table
14
18
  Given the following table
@@ -12,6 +12,8 @@ require 'cucumber/broadcaster'
12
12
  require 'cucumber/core_ext/exception'
13
13
 
14
14
  module Cucumber
15
+ KEYWORD_KEYS = %w{name native encoding feature background scenario scenario_outline examples given when then but}
16
+
15
17
  class << self
16
18
  attr_reader :lang
17
19
 
@@ -22,6 +24,10 @@ module Cucumber
22
24
  Parser.load_parser(keyword_hash)
23
25
  end
24
26
 
27
+ def language_complete?(lang)
28
+ KEYWORD_KEYS.detect{|key| keyword_hash(lang)[key].nil?}
29
+ end
30
+
25
31
  # File mode that accounts for Ruby platform and current language
26
32
  def file_mode(m)
27
33
  Cucumber::RUBY_1_9 ? "#{m}:#{keyword_hash['encoding']}" : m
@@ -78,7 +78,7 @@ module Cucumber
78
78
  if v == 'help'
79
79
  list_languages
80
80
  elsif args==['help']
81
- list_keywords('en', v)
81
+ list_keywords(v)
82
82
  else
83
83
  @options[:lang] = v
84
84
  end
@@ -364,23 +364,22 @@ Defined profiles in cucumber.yml:
364
364
  raw = Cucumber::LANGUAGES.keys.sort.map do |lang|
365
365
  [lang, Cucumber::LANGUAGES[lang]['name'], Cucumber::LANGUAGES[lang]['native']]
366
366
  end
367
- print_table(raw)
367
+ print_lang_table(raw, {:check_lang=>true})
368
368
  end
369
369
 
370
- def list_keywords(ref, lang)
370
+ def list_keywords(lang)
371
371
  unless Cucumber::LANGUAGES[lang]
372
372
  exit_with_error("No language with key #{v}")
373
373
  end
374
- Cucumber.load_language(lang)
375
- raw = %w{feature background scenario scenario_outline examples given when then but}.map do |key|
376
- [Cucumber::LANGUAGES[ref][key], Cucumber::LANGUAGES[lang][key]]
374
+ raw = Cucumber::KEYWORD_KEYS.map do |key|
375
+ [key, Cucumber::LANGUAGES[lang][key]]
377
376
  end
378
- print_table(raw)
377
+ print_lang_table(raw, {})
379
378
  end
380
379
 
381
- def print_table(raw)
380
+ def print_lang_table(raw, options)
382
381
  table = Ast::Table.new(raw)
383
- formatter = Formatter::Pretty.new(nil, @out_stream, {}, '')
382
+ formatter = Formatter::Pretty.new(nil, @out_stream, options, '')
384
383
 
385
384
  def formatter.visit_table_row(table_row, status)
386
385
  @col = 1
@@ -388,7 +387,15 @@ Defined profiles in cucumber.yml:
388
387
  end
389
388
 
390
389
  def formatter.visit_table_cell_value(value, width, status)
391
- status = :comment if @col == 1
390
+ if @col == 1
391
+ if(@options[:check_lang])
392
+ @incomplete = Cucumber.language_complete?(value)
393
+ end
394
+ status = :comment
395
+ elsif @incomplete
396
+ status = :failed
397
+ end
398
+
392
399
  @col += 1
393
400
  super(value, width, status)
394
401
  end
@@ -52,6 +52,7 @@
52
52
  feature: Egenskab
53
53
  background: Baggrund
54
54
  scenario: Scenarie
55
+ scenario_outline: Abstrakt Scenario
55
56
  examples: Eksempler
56
57
  given: Givet
57
58
  when: Når
@@ -115,8 +116,6 @@
115
116
  encoding: UTF-8
116
117
  feature: Omadus
117
118
  scenario: Stsenaarium
118
- scenario_outline: Scenario Outline
119
- examples: Examples
120
119
  given: Eeldades
121
120
  when: Kui
122
121
  then: Siis
@@ -215,7 +214,7 @@
215
214
  feature: Egenskap
216
215
  background: Bakgrunn
217
216
  scenario: Scenario
218
- scenario_outline: Scenarioskisse
217
+ scenario_outline: Abstrakt Scenario
219
218
  examples: Eksempler
220
219
  given: Gitt
221
220
  when: Når
@@ -284,6 +283,8 @@
284
283
  feature: Egenskap
285
284
  background: Bakgrund
286
285
  scenario: Scenario
286
+ scenario_outline: Abstrakt Scenario
287
+ examples: Exempel
287
288
  given: Givet
288
289
  when: När
289
290
  then: Så
@@ -1,11 +1,8 @@
1
1
  require 'erb'
2
- require 'treetop'
3
- require 'treetop/runtime'
4
- require 'treetop/ruby_extensions'
5
2
  require 'cucumber/platform'
6
3
  require 'cucumber/ast'
7
- require 'cucumber/parser/file_parser'
8
4
  require 'cucumber/parser/treetop_ext'
5
+ require 'cucumber/parser/table'
9
6
 
10
7
  module Cucumber
11
8
  # Classes in this module parse feature files and translate the parse tree
@@ -10,10 +10,10 @@ module Cucumber
10
10
  @root || :feature
11
11
  end
12
12
 
13
- include FileParser
14
-
15
13
  include I18n
16
14
 
15
+ include Table
16
+
17
17
  module Feature0
18
18
  end
19
19
 
@@ -976,271 +976,6 @@ module Cucumber
976
976
  return r0
977
977
  end
978
978
 
979
- module Table0
980
- def build
981
- Ast::Table.new(raw)
982
- end
983
-
984
- def raw
985
- elements.map{|e| e.build}
986
- end
987
- end
988
-
989
- def _nt_table
990
- start_index = index
991
- if node_cache[:table].has_key?(index)
992
- cached = node_cache[:table][index]
993
- @index = cached.interval.end if cached
994
- return cached
995
- end
996
-
997
- s0, i0 = [], index
998
- loop do
999
- r1 = _nt_table_row
1000
- if r1
1001
- s0 << r1
1002
- else
1003
- break
1004
- end
1005
- end
1006
- if s0.empty?
1007
- self.index = i0
1008
- r0 = nil
1009
- else
1010
- r0 = SyntaxNode.new(input, i0...index, s0)
1011
- r0.extend(Table0)
1012
- end
1013
-
1014
- node_cache[:table][start_index] = r0
1015
-
1016
- return r0
1017
- end
1018
-
1019
- module TableRow0
1020
- def cell
1021
- elements[0]
1022
- end
1023
-
1024
- end
1025
-
1026
- module TableRow1
1027
- def cells
1028
- elements[2]
1029
- end
1030
-
1031
- end
1032
-
1033
- module TableRow2
1034
- def build
1035
- row = cells.elements.map do |elt|
1036
- value = elt.cell.text_value.strip
1037
- value.empty? ? nil : value
1038
- end
1039
-
1040
- class << row
1041
- attr_accessor :line
1042
- end
1043
- row.line = cells.line
1044
-
1045
- row
1046
- end
1047
- end
1048
-
1049
- def _nt_table_row
1050
- start_index = index
1051
- if node_cache[:table_row].has_key?(index)
1052
- cached = node_cache[:table_row][index]
1053
- @index = cached.interval.end if cached
1054
- return cached
1055
- end
1056
-
1057
- i0, s0 = index, []
1058
- s1, i1 = [], index
1059
- loop do
1060
- r2 = _nt_space
1061
- if r2
1062
- s1 << r2
1063
- else
1064
- break
1065
- end
1066
- end
1067
- r1 = SyntaxNode.new(input, i1...index, s1)
1068
- s0 << r1
1069
- if r1
1070
- if input.index('|', index) == index
1071
- r3 = (SyntaxNode).new(input, index...(index + 1))
1072
- @index += 1
1073
- else
1074
- terminal_parse_failure('|')
1075
- r3 = nil
1076
- end
1077
- s0 << r3
1078
- if r3
1079
- s4, i4 = [], index
1080
- loop do
1081
- i5, s5 = index, []
1082
- r6 = _nt_cell
1083
- s5 << r6
1084
- if r6
1085
- if input.index('|', index) == index
1086
- r7 = (SyntaxNode).new(input, index...(index + 1))
1087
- @index += 1
1088
- else
1089
- terminal_parse_failure('|')
1090
- r7 = nil
1091
- end
1092
- s5 << r7
1093
- end
1094
- if s5.last
1095
- r5 = (SyntaxNode).new(input, i5...index, s5)
1096
- r5.extend(TableRow0)
1097
- else
1098
- self.index = i5
1099
- r5 = nil
1100
- end
1101
- if r5
1102
- s4 << r5
1103
- else
1104
- break
1105
- end
1106
- end
1107
- if s4.empty?
1108
- self.index = i4
1109
- r4 = nil
1110
- else
1111
- r4 = SyntaxNode.new(input, i4...index, s4)
1112
- end
1113
- s0 << r4
1114
- if r4
1115
- s8, i8 = [], index
1116
- loop do
1117
- r9 = _nt_space
1118
- if r9
1119
- s8 << r9
1120
- else
1121
- break
1122
- end
1123
- end
1124
- r8 = SyntaxNode.new(input, i8...index, s8)
1125
- s0 << r8
1126
- if r8
1127
- i10 = index
1128
- s11, i11 = [], index
1129
- loop do
1130
- r12 = _nt_eol
1131
- if r12
1132
- s11 << r12
1133
- else
1134
- break
1135
- end
1136
- end
1137
- if s11.empty?
1138
- self.index = i11
1139
- r11 = nil
1140
- else
1141
- r11 = SyntaxNode.new(input, i11...index, s11)
1142
- end
1143
- if r11
1144
- r10 = r11
1145
- else
1146
- r13 = _nt_eof
1147
- if r13
1148
- r10 = r13
1149
- else
1150
- self.index = i10
1151
- r10 = nil
1152
- end
1153
- end
1154
- s0 << r10
1155
- end
1156
- end
1157
- end
1158
- end
1159
- if s0.last
1160
- r0 = (SyntaxNode).new(input, i0...index, s0)
1161
- r0.extend(TableRow1)
1162
- r0.extend(TableRow2)
1163
- else
1164
- self.index = i0
1165
- r0 = nil
1166
- end
1167
-
1168
- node_cache[:table_row][start_index] = r0
1169
-
1170
- return r0
1171
- end
1172
-
1173
- module Cell0
1174
- end
1175
-
1176
- def _nt_cell
1177
- start_index = index
1178
- if node_cache[:cell].has_key?(index)
1179
- cached = node_cache[:cell][index]
1180
- @index = cached.interval.end if cached
1181
- return cached
1182
- end
1183
-
1184
- s0, i0 = [], index
1185
- loop do
1186
- i1, s1 = index, []
1187
- i2 = index
1188
- i3 = index
1189
- if input.index('|', index) == index
1190
- r4 = (SyntaxNode).new(input, index...(index + 1))
1191
- @index += 1
1192
- else
1193
- terminal_parse_failure('|')
1194
- r4 = nil
1195
- end
1196
- if r4
1197
- r3 = r4
1198
- else
1199
- r5 = _nt_eol
1200
- if r5
1201
- r3 = r5
1202
- else
1203
- self.index = i3
1204
- r3 = nil
1205
- end
1206
- end
1207
- if r3
1208
- r2 = nil
1209
- else
1210
- self.index = i2
1211
- r2 = SyntaxNode.new(input, index...index)
1212
- end
1213
- s1 << r2
1214
- if r2
1215
- if index < input_length
1216
- r6 = (SyntaxNode).new(input, index...(index + 1))
1217
- @index += 1
1218
- else
1219
- terminal_parse_failure("any character")
1220
- r6 = nil
1221
- end
1222
- s1 << r6
1223
- end
1224
- if s1.last
1225
- r1 = (SyntaxNode).new(input, i1...index, s1)
1226
- r1.extend(Cell0)
1227
- else
1228
- self.index = i1
1229
- r1 = nil
1230
- end
1231
- if r1
1232
- s0 << r1
1233
- else
1234
- break
1235
- end
1236
- end
1237
- r0 = SyntaxNode.new(input, i0...index, s0)
1238
-
1239
- node_cache[:cell][start_index] = r0
1240
-
1241
- return r0
1242
- end
1243
-
1244
979
  module LineToEol0
1245
980
  end
1246
981
 
@@ -1570,120 +1305,6 @@ module Cucumber
1570
1305
  return r0
1571
1306
  end
1572
1307
 
1573
- def _nt_space
1574
- start_index = index
1575
- if node_cache[:space].has_key?(index)
1576
- cached = node_cache[:space][index]
1577
- @index = cached.interval.end if cached
1578
- return cached
1579
- end
1580
-
1581
- if input.index(Regexp.new('[ \\t]'), index) == index
1582
- r0 = (SyntaxNode).new(input, index...(index + 1))
1583
- @index += 1
1584
- else
1585
- r0 = nil
1586
- end
1587
-
1588
- node_cache[:space][start_index] = r0
1589
-
1590
- return r0
1591
- end
1592
-
1593
- module Eol0
1594
- end
1595
-
1596
- def _nt_eol
1597
- start_index = index
1598
- if node_cache[:eol].has_key?(index)
1599
- cached = node_cache[:eol][index]
1600
- @index = cached.interval.end if cached
1601
- return cached
1602
- end
1603
-
1604
- i0 = index
1605
- if input.index("\n", index) == index
1606
- r1 = (SyntaxNode).new(input, index...(index + 1))
1607
- @index += 1
1608
- else
1609
- terminal_parse_failure("\n")
1610
- r1 = nil
1611
- end
1612
- if r1
1613
- r0 = r1
1614
- else
1615
- i2, s2 = index, []
1616
- if input.index("\r", index) == index
1617
- r3 = (SyntaxNode).new(input, index...(index + 1))
1618
- @index += 1
1619
- else
1620
- terminal_parse_failure("\r")
1621
- r3 = nil
1622
- end
1623
- s2 << r3
1624
- if r3
1625
- if input.index("\n", index) == index
1626
- r5 = (SyntaxNode).new(input, index...(index + 1))
1627
- @index += 1
1628
- else
1629
- terminal_parse_failure("\n")
1630
- r5 = nil
1631
- end
1632
- if r5
1633
- r4 = r5
1634
- else
1635
- r4 = SyntaxNode.new(input, index...index)
1636
- end
1637
- s2 << r4
1638
- end
1639
- if s2.last
1640
- r2 = (SyntaxNode).new(input, i2...index, s2)
1641
- r2.extend(Eol0)
1642
- else
1643
- self.index = i2
1644
- r2 = nil
1645
- end
1646
- if r2
1647
- r0 = r2
1648
- else
1649
- self.index = i0
1650
- r0 = nil
1651
- end
1652
- end
1653
-
1654
- node_cache[:eol][start_index] = r0
1655
-
1656
- return r0
1657
- end
1658
-
1659
- def _nt_eof
1660
- start_index = index
1661
- if node_cache[:eof].has_key?(index)
1662
- cached = node_cache[:eof][index]
1663
- @index = cached.interval.end if cached
1664
- return cached
1665
- end
1666
-
1667
- i0 = index
1668
- if index < input_length
1669
- r1 = (SyntaxNode).new(input, index...(index + 1))
1670
- @index += 1
1671
- else
1672
- terminal_parse_failure("any character")
1673
- r1 = nil
1674
- end
1675
- if r1
1676
- r0 = nil
1677
- else
1678
- self.index = i0
1679
- r0 = SyntaxNode.new(input, index...index)
1680
- end
1681
-
1682
- node_cache[:eof][start_index] = r0
1683
-
1684
- return r0
1685
- end
1686
-
1687
1308
  end
1688
1309
 
1689
1310
  class FeatureParser < Treetop::Runtime::CompiledParser
@@ -4,8 +4,8 @@ module Cucumber
4
4
  # Treetop will then generate the parser in-memory. When you're happy, just generate
5
5
  # the rb file with tt feature.tt
6
6
  grammar Feature
7
- include FileParser
8
7
  include I18n
8
+ include Table
9
9
 
10
10
  rule feature
11
11
  white comment white tags white header:(!(scenario_outline / scenario) .)* feature_elements {
@@ -119,40 +119,6 @@ module Cucumber
119
119
  table / py_string
120
120
  end
121
121
 
122
- rule table
123
- table_row+ {
124
- def build
125
- Ast::Table.new(raw)
126
- end
127
-
128
- def raw
129
- elements.map{|e| e.build}
130
- end
131
- }
132
- end
133
-
134
- rule table_row
135
- space* '|' cells:(cell '|')+ space* (eol+ / eof) {
136
- def build
137
- row = cells.elements.map do |elt|
138
- value = elt.cell.text_value.strip
139
- value.empty? ? nil : value
140
- end
141
-
142
- class << row
143
- attr_accessor :line
144
- end
145
- row.line = cells.line
146
-
147
- row
148
- end
149
- }
150
- end
151
-
152
- rule cell
153
- (!('|' / eol) .)*
154
- end
155
-
156
122
  rule line_to_eol
157
123
  (!eol .)+
158
124
  end
@@ -189,18 +155,6 @@ module Cucumber
189
155
  (space / eol)*
190
156
  end
191
157
 
192
- rule space
193
- [ \t]
194
- end
195
-
196
- rule eol
197
- "\n" / ("\r" "\n"?)
198
- end
199
-
200
- rule eof
201
- !.
202
- end
203
-
204
158
  end
205
159
  end
206
160
  end
@@ -21,6 +21,7 @@ module Cucumber
21
21
  rule examples_keyword
22
22
  '<%= keywords['examples'] %>' ':'?
23
23
  end
24
+
24
25
  end
25
26
  end
26
27
  end
@@ -0,0 +1,396 @@
1
+ module Cucumber
2
+ module Parser
3
+ module Table
4
+ include Treetop::Runtime
5
+
6
+ def root
7
+ @root || :table
8
+ end
9
+
10
+ module Table0
11
+ def build
12
+ Ast::Table.new(raw)
13
+ end
14
+
15
+ def raw
16
+ elements.map{|e| e.build}
17
+ end
18
+ end
19
+
20
+ def _nt_table
21
+ start_index = index
22
+ if node_cache[:table].has_key?(index)
23
+ cached = node_cache[:table][index]
24
+ @index = cached.interval.end if cached
25
+ return cached
26
+ end
27
+
28
+ s0, i0 = [], index
29
+ loop do
30
+ r1 = _nt_table_row
31
+ if r1
32
+ s0 << r1
33
+ else
34
+ break
35
+ end
36
+ end
37
+ if s0.empty?
38
+ self.index = i0
39
+ r0 = nil
40
+ else
41
+ r0 = SyntaxNode.new(input, i0...index, s0)
42
+ r0.extend(Table0)
43
+ end
44
+
45
+ node_cache[:table][start_index] = r0
46
+
47
+ return r0
48
+ end
49
+
50
+ module TableRow0
51
+ def cell
52
+ elements[0]
53
+ end
54
+
55
+ end
56
+
57
+ module TableRow1
58
+ def cells
59
+ elements[2]
60
+ end
61
+
62
+ end
63
+
64
+ module TableRow2
65
+ def build
66
+ row = cells.elements.map do |elt|
67
+ value = elt.cell.text_value.strip
68
+ value.empty? ? nil : value
69
+ end
70
+
71
+ class << row
72
+ attr_accessor :line
73
+ end
74
+ row.line = cells.line
75
+
76
+ row
77
+ end
78
+ end
79
+
80
+ def _nt_table_row
81
+ start_index = index
82
+ if node_cache[:table_row].has_key?(index)
83
+ cached = node_cache[:table_row][index]
84
+ @index = cached.interval.end if cached
85
+ return cached
86
+ end
87
+
88
+ i0, s0 = index, []
89
+ s1, i1 = [], index
90
+ loop do
91
+ r2 = _nt_space
92
+ if r2
93
+ s1 << r2
94
+ else
95
+ break
96
+ end
97
+ end
98
+ r1 = SyntaxNode.new(input, i1...index, s1)
99
+ s0 << r1
100
+ if r1
101
+ if input.index('|', index) == index
102
+ r3 = (SyntaxNode).new(input, index...(index + 1))
103
+ @index += 1
104
+ else
105
+ terminal_parse_failure('|')
106
+ r3 = nil
107
+ end
108
+ s0 << r3
109
+ if r3
110
+ s4, i4 = [], index
111
+ loop do
112
+ i5, s5 = index, []
113
+ r6 = _nt_cell
114
+ s5 << r6
115
+ if r6
116
+ if input.index('|', index) == index
117
+ r7 = (SyntaxNode).new(input, index...(index + 1))
118
+ @index += 1
119
+ else
120
+ terminal_parse_failure('|')
121
+ r7 = nil
122
+ end
123
+ s5 << r7
124
+ end
125
+ if s5.last
126
+ r5 = (SyntaxNode).new(input, i5...index, s5)
127
+ r5.extend(TableRow0)
128
+ else
129
+ self.index = i5
130
+ r5 = nil
131
+ end
132
+ if r5
133
+ s4 << r5
134
+ else
135
+ break
136
+ end
137
+ end
138
+ if s4.empty?
139
+ self.index = i4
140
+ r4 = nil
141
+ else
142
+ r4 = SyntaxNode.new(input, i4...index, s4)
143
+ end
144
+ s0 << r4
145
+ if r4
146
+ s8, i8 = [], index
147
+ loop do
148
+ r9 = _nt_space
149
+ if r9
150
+ s8 << r9
151
+ else
152
+ break
153
+ end
154
+ end
155
+ r8 = SyntaxNode.new(input, i8...index, s8)
156
+ s0 << r8
157
+ if r8
158
+ i10 = index
159
+ s11, i11 = [], index
160
+ loop do
161
+ r12 = _nt_eol
162
+ if r12
163
+ s11 << r12
164
+ else
165
+ break
166
+ end
167
+ end
168
+ if s11.empty?
169
+ self.index = i11
170
+ r11 = nil
171
+ else
172
+ r11 = SyntaxNode.new(input, i11...index, s11)
173
+ end
174
+ if r11
175
+ r10 = r11
176
+ else
177
+ r13 = _nt_eof
178
+ if r13
179
+ r10 = r13
180
+ else
181
+ self.index = i10
182
+ r10 = nil
183
+ end
184
+ end
185
+ s0 << r10
186
+ end
187
+ end
188
+ end
189
+ end
190
+ if s0.last
191
+ r0 = (SyntaxNode).new(input, i0...index, s0)
192
+ r0.extend(TableRow1)
193
+ r0.extend(TableRow2)
194
+ else
195
+ self.index = i0
196
+ r0 = nil
197
+ end
198
+
199
+ node_cache[:table_row][start_index] = r0
200
+
201
+ return r0
202
+ end
203
+
204
+ module Cell0
205
+ end
206
+
207
+ def _nt_cell
208
+ start_index = index
209
+ if node_cache[:cell].has_key?(index)
210
+ cached = node_cache[:cell][index]
211
+ @index = cached.interval.end if cached
212
+ return cached
213
+ end
214
+
215
+ s0, i0 = [], index
216
+ loop do
217
+ i1, s1 = index, []
218
+ i2 = index
219
+ i3 = index
220
+ if input.index('|', index) == index
221
+ r4 = (SyntaxNode).new(input, index...(index + 1))
222
+ @index += 1
223
+ else
224
+ terminal_parse_failure('|')
225
+ r4 = nil
226
+ end
227
+ if r4
228
+ r3 = r4
229
+ else
230
+ r5 = _nt_eol
231
+ if r5
232
+ r3 = r5
233
+ else
234
+ self.index = i3
235
+ r3 = nil
236
+ end
237
+ end
238
+ if r3
239
+ r2 = nil
240
+ else
241
+ self.index = i2
242
+ r2 = SyntaxNode.new(input, index...index)
243
+ end
244
+ s1 << r2
245
+ if r2
246
+ if index < input_length
247
+ r6 = (SyntaxNode).new(input, index...(index + 1))
248
+ @index += 1
249
+ else
250
+ terminal_parse_failure("any character")
251
+ r6 = nil
252
+ end
253
+ s1 << r6
254
+ end
255
+ if s1.last
256
+ r1 = (SyntaxNode).new(input, i1...index, s1)
257
+ r1.extend(Cell0)
258
+ else
259
+ self.index = i1
260
+ r1 = nil
261
+ end
262
+ if r1
263
+ s0 << r1
264
+ else
265
+ break
266
+ end
267
+ end
268
+ r0 = SyntaxNode.new(input, i0...index, s0)
269
+
270
+ node_cache[:cell][start_index] = r0
271
+
272
+ return r0
273
+ end
274
+
275
+ def _nt_space
276
+ start_index = index
277
+ if node_cache[:space].has_key?(index)
278
+ cached = node_cache[:space][index]
279
+ @index = cached.interval.end if cached
280
+ return cached
281
+ end
282
+
283
+ if input.index(Regexp.new('[ \\t]'), index) == index
284
+ r0 = (SyntaxNode).new(input, index...(index + 1))
285
+ @index += 1
286
+ else
287
+ r0 = nil
288
+ end
289
+
290
+ node_cache[:space][start_index] = r0
291
+
292
+ return r0
293
+ end
294
+
295
+ module Eol0
296
+ end
297
+
298
+ def _nt_eol
299
+ start_index = index
300
+ if node_cache[:eol].has_key?(index)
301
+ cached = node_cache[:eol][index]
302
+ @index = cached.interval.end if cached
303
+ return cached
304
+ end
305
+
306
+ i0 = index
307
+ if input.index("\n", index) == index
308
+ r1 = (SyntaxNode).new(input, index...(index + 1))
309
+ @index += 1
310
+ else
311
+ terminal_parse_failure("\n")
312
+ r1 = nil
313
+ end
314
+ if r1
315
+ r0 = r1
316
+ else
317
+ i2, s2 = index, []
318
+ if input.index("\r", index) == index
319
+ r3 = (SyntaxNode).new(input, index...(index + 1))
320
+ @index += 1
321
+ else
322
+ terminal_parse_failure("\r")
323
+ r3 = nil
324
+ end
325
+ s2 << r3
326
+ if r3
327
+ if input.index("\n", index) == index
328
+ r5 = (SyntaxNode).new(input, index...(index + 1))
329
+ @index += 1
330
+ else
331
+ terminal_parse_failure("\n")
332
+ r5 = nil
333
+ end
334
+ if r5
335
+ r4 = r5
336
+ else
337
+ r4 = SyntaxNode.new(input, index...index)
338
+ end
339
+ s2 << r4
340
+ end
341
+ if s2.last
342
+ r2 = (SyntaxNode).new(input, i2...index, s2)
343
+ r2.extend(Eol0)
344
+ else
345
+ self.index = i2
346
+ r2 = nil
347
+ end
348
+ if r2
349
+ r0 = r2
350
+ else
351
+ self.index = i0
352
+ r0 = nil
353
+ end
354
+ end
355
+
356
+ node_cache[:eol][start_index] = r0
357
+
358
+ return r0
359
+ end
360
+
361
+ def _nt_eof
362
+ start_index = index
363
+ if node_cache[:eof].has_key?(index)
364
+ cached = node_cache[:eof][index]
365
+ @index = cached.interval.end if cached
366
+ return cached
367
+ end
368
+
369
+ i0 = index
370
+ if index < input_length
371
+ r1 = (SyntaxNode).new(input, index...(index + 1))
372
+ @index += 1
373
+ else
374
+ terminal_parse_failure("any character")
375
+ r1 = nil
376
+ end
377
+ if r1
378
+ r0 = nil
379
+ else
380
+ self.index = i0
381
+ r0 = SyntaxNode.new(input, index...index)
382
+ end
383
+
384
+ node_cache[:eof][start_index] = r0
385
+
386
+ return r0
387
+ end
388
+
389
+ end
390
+
391
+ class TableParser < Treetop::Runtime::CompiledParser
392
+ include Table
393
+ end
394
+
395
+ end
396
+ end
@@ -0,0 +1,53 @@
1
+ module Cucumber
2
+ module Parser
3
+ grammar Table
4
+
5
+ rule table
6
+ table_row+ {
7
+ def build
8
+ Ast::Table.new(raw)
9
+ end
10
+
11
+ def raw
12
+ elements.map{|e| e.build}
13
+ end
14
+ }
15
+ end
16
+
17
+ rule table_row
18
+ space* '|' cells:(cell '|')+ space* (eol+ / eof) {
19
+ def build
20
+ row = cells.elements.map do |elt|
21
+ value = elt.cell.text_value.strip
22
+ value.empty? ? nil : value
23
+ end
24
+
25
+ class << row
26
+ attr_accessor :line
27
+ end
28
+ row.line = cells.line
29
+
30
+ row
31
+ end
32
+ }
33
+ end
34
+
35
+ rule cell
36
+ (!('|' / eol) .)*
37
+ end
38
+
39
+ rule space
40
+ [ \t]
41
+ end
42
+
43
+ rule eol
44
+ "\n" / ("\r" "\n"?)
45
+ end
46
+
47
+ rule eof
48
+ !.
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -1,3 +1,46 @@
1
+ require 'treetop'
2
+ require 'treetop/runtime'
3
+ require 'treetop/ruby_extensions'
4
+
5
+ module Cucumber
6
+ module Parser
7
+ module TreetopExt
8
+ FILE_LINE_PATTERN = /^([\w\W]*?):([\d:]+)$/
9
+
10
+ # Parses a file and returns a Cucumber::Ast
11
+ def parse_file(file)
12
+ _, path, lines = *FILE_LINE_PATTERN.match(file)
13
+ if path
14
+ lines = lines.split(':').map { |line| line.to_i }
15
+ else
16
+ path = file
17
+ lines = []
18
+ end
19
+
20
+ feature = File.open(path, Cucumber.file_mode('r')) do |io|
21
+ parse_or_fail(io.read, path)
22
+ end
23
+ feature.lines = lines
24
+ feature
25
+ end
26
+ end
27
+
28
+ class SyntaxError < StandardError
29
+ def initialize(parser, file, line_offset)
30
+ tf = parser.terminal_failures
31
+ expected = tf.size == 1 ? tf[0].expected_string.inspect : "one of #{tf.map{|f| f.expected_string.inspect}.uniq*', '}"
32
+ after = parser.input[parser.index...parser.failure_index]
33
+ found = parser.input[parser.failure_index..parser.failure_index]
34
+
35
+ line = parser.failure_line + line_offset
36
+ message = "#{file}:#{line}:#{parser.failure_column}: " +
37
+ "Parse error, expected #{expected}. After #{after.inspect}. Found: #{found.inspect}"
38
+ super(message)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
1
44
  module Treetop
2
45
  module Runtime
3
46
  class SyntaxNode
@@ -5,5 +48,20 @@ module Treetop
5
48
  input.line_of(interval.first)
6
49
  end
7
50
  end
51
+
52
+ class CompiledParser
53
+ include Cucumber::Parser::TreetopExt
54
+
55
+ def parse_or_fail(s, file=nil, line=0)
56
+ parse_tree = parse(s)
57
+ if parse_tree.nil?
58
+ raise Cucumber::Parser::SyntaxError.new(self, file, line)
59
+ else
60
+ ast = parse_tree.build
61
+ ast.file = file
62
+ ast
63
+ end
64
+ end
65
+ end
8
66
  end
9
67
  end
@@ -24,9 +24,13 @@ module Cucumber
24
24
 
25
25
  attr_reader :regexp
26
26
 
27
- def initialize(regexp, &proc)
27
+ def initialize(pattern, &proc)
28
28
  raise MissingProc if proc.nil?
29
- @regexp, @proc = regexp, proc
29
+ if String === pattern
30
+ p = pattern.gsub(/\$\w+/, '(.*)')
31
+ pattern = Regexp.new("^#{p}$")
32
+ end
33
+ @regexp, @proc = pattern, proc
30
34
  end
31
35
 
32
36
  #:stopdoc:
@@ -130,12 +130,22 @@ module Cucumber
130
130
  # Call a step from within a step definition
131
131
  def __cucumber_invoke(name, *multiline_arguments)
132
132
  begin
133
- @__cucumber_step_mother.step_definition(name).execute(name, self, *multiline_arguments)
133
+ # TODO: Very similar to code in Step. Refactor. Get back StepInvocation?
134
+ # Make more similar to JBehave?
135
+ step_definition = @__cucumber_step_mother.step_definition(name)
136
+ matched_args = step_definition.matched_args(name)
137
+ args = (matched_args + multiline_arguments)
138
+ step_definition.execute(name, self, *args)
134
139
  rescue Exception => e
135
140
  @__cucumber_current_step.exception = e
136
141
  raise e
137
142
  end
138
143
  end
144
+
145
+ def table(text, file=nil, line=0)
146
+ @table_parser ||= Parser::TableParser.new
147
+ @table_parser.parse_or_fail(text.strip, file, line)
148
+ end
139
149
 
140
150
  def pending(message = "TODO")
141
151
  if block_given?
@@ -3,7 +3,7 @@ module Cucumber #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
5
  TINY = 99
6
- PATCH = 1 # Set to nil for official release
6
+ PATCH = 2 # Set to nil for official release
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PATCH].compact.join('.')
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aslakhellesoy-cucumber
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.99.1
4
+ version: 0.1.99.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Aslak Helles\xC3\xB8y"
@@ -172,7 +172,6 @@ files:
172
172
  - examples/jbehave/features/support/env.rb
173
173
  - examples/jbehave/features/trading.feature
174
174
  - examples/jbehave/pom.xml
175
- - examples/jbehave/target/maven-archiver/pom.properties
176
175
  - examples/selenium/Rakefile
177
176
  - examples/selenium/features/search.feature
178
177
  - examples/selenium/features/step_definitons/stories_steps.rb
@@ -259,8 +258,9 @@ files:
259
258
  - lib/cucumber/parser/basic.rb
260
259
  - lib/cucumber/parser/feature.rb
261
260
  - lib/cucumber/parser/feature.tt
262
- - lib/cucumber/parser/file_parser.rb
263
261
  - lib/cucumber/parser/i18n.tt
262
+ - lib/cucumber/parser/table.rb
263
+ - lib/cucumber/parser/table.tt
264
264
  - lib/cucumber/parser/treetop_ext.rb
265
265
  - lib/cucumber/platform.rb
266
266
  - lib/cucumber/rails/rspec.rb
@@ -1,50 +0,0 @@
1
- module Cucumber
2
- module Parser
3
- module FileParser
4
- FILE_LINE_PATTERN = /^([\w\W]*?):([\d:]+)$/
5
-
6
- # Parses a file and returns a Cucumber::Ast
7
- def parse_file(file)
8
- _, path, lines = *FILE_LINE_PATTERN.match(file)
9
- if path
10
- lines = lines.split(':').map { |line| line.to_i }
11
- else
12
- path = file
13
- lines = []
14
- end
15
-
16
- feature = File.open(path, Cucumber.file_mode('r')) do |io|
17
- parse_or_fail(io.read, path)
18
- end
19
- feature.lines = lines
20
- feature
21
- end
22
-
23
- def parse_or_fail(s, file=nil)
24
- parse_tree = parse(s)
25
- if parse_tree.nil?
26
- raise SyntaxError.new(file, self)
27
- else
28
- ast = parse_tree.build
29
- ast.file = file
30
- ast
31
- end
32
- end
33
- end
34
-
35
- class SyntaxError < StandardError
36
- def initialize(file, parser)
37
- tf = parser.terminal_failures
38
- expected = tf.size == 1 ? tf[0].expected_string.inspect : "one of #{tf.map{|f| f.expected_string.inspect}.uniq*', '}"
39
- after = parser.input[parser.index...parser.failure_index]
40
- found = parser.input[parser.failure_index..parser.failure_index]
41
- @message = "#{file}:#{parser.failure_line}:#{parser.failure_column}: " +
42
- "Parse error, expected #{expected}. After #{after.inspect}. Found: #{found.inspect}"
43
- end
44
-
45
- def message
46
- @message
47
- end
48
- end
49
- end
50
- end