jeffrafter-cucumber 0.1.10

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.
Files changed (242) hide show
  1. data/History.txt +262 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +241 -0
  4. data/README.txt +41 -0
  5. data/Rakefile +8 -0
  6. data/TODO.txt +26 -0
  7. data/bin/cucumber +6 -0
  8. data/config/hoe.rb +69 -0
  9. data/config/requirements.rb +15 -0
  10. data/cucumber.yml +1 -0
  11. data/examples/calculator_ruby_features/Rakefile +6 -0
  12. data/examples/calculator_ruby_features/features/addition.rb +23 -0
  13. data/examples/calculator_ruby_features/features/step_definitons/calculator_steps.rb +43 -0
  14. data/examples/cs/README.textile +22 -0
  15. data/examples/cs/Rakefile +12 -0
  16. data/examples/cs/features/hello.feature +11 -0
  17. data/examples/cs/features/step_definitons/hello_steps.rb +25 -0
  18. data/examples/cs/features/step_definitons/tree_steps.rb +14 -0
  19. data/examples/cs/features/tree.feature +9 -0
  20. data/examples/cs/src/Hello.cs +18 -0
  21. data/examples/dos_line_endings/Rakefile +6 -0
  22. data/examples/dos_line_endings/features/dos_line_endings.feature +9 -0
  23. data/examples/i18n/README.textile +18 -0
  24. data/examples/i18n/Rakefile +16 -0
  25. data/examples/i18n/ar/Rakefile +6 -0
  26. data/examples/i18n/ar/features/addition.feature +17 -0
  27. data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +32 -0
  28. data/examples/i18n/ar/lib/calculator.rb +10 -0
  29. data/examples/i18n/da/Rakefile +6 -0
  30. data/examples/i18n/da/features/step_definitons/kalkulator_steps.rb +22 -0
  31. data/examples/i18n/da/features/summering.feature +17 -0
  32. data/examples/i18n/da/lib/kalkulator.rb +11 -0
  33. data/examples/i18n/de/Rakefile +6 -0
  34. data/examples/i18n/de/features/addition.feature +17 -0
  35. data/examples/i18n/de/features/division.feature +10 -0
  36. data/examples/i18n/de/features/step_definitons/calculator_steps.rb +30 -0
  37. data/examples/i18n/de/lib/calculator.rb +14 -0
  38. data/examples/i18n/en/Rakefile +6 -0
  39. data/examples/i18n/en/features/addition.feature +17 -0
  40. data/examples/i18n/en/features/division.feature +10 -0
  41. data/examples/i18n/en/features/step_definitons/calculator_steps.rb +31 -0
  42. data/examples/i18n/en/lib/calculator.rb +14 -0
  43. data/examples/i18n/es/Rakefile +6 -0
  44. data/examples/i18n/es/features/adicion.feature +17 -0
  45. data/examples/i18n/es/features/step_definitons/calculador_steps.rb +22 -0
  46. data/examples/i18n/es/lib/calculador.rb +11 -0
  47. data/examples/i18n/et/Rakefile +6 -0
  48. data/examples/i18n/et/features/liitmine.feature +17 -0
  49. data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +26 -0
  50. data/examples/i18n/et/lib/kalkulaator.rb +10 -0
  51. data/examples/i18n/fr/Rakefile +6 -0
  52. data/examples/i18n/fr/features/addition.feature +13 -0
  53. data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +22 -0
  54. data/examples/i18n/fr/lib/calculatrice.rb +10 -0
  55. data/examples/i18n/id/Rakefile +6 -0
  56. data/examples/i18n/id/features/addition.feature +17 -0
  57. data/examples/i18n/id/features/division.feature +10 -0
  58. data/examples/i18n/id/features/step_definitons/calculator_steps.rb +31 -0
  59. data/examples/i18n/id/lib/calculator.rb +14 -0
  60. data/examples/i18n/it/Rakefile +6 -0
  61. data/examples/i18n/it/features/somma.feature +10 -0
  62. data/examples/i18n/it/features/step_definitons/calcolatrice_steps.rb +22 -0
  63. data/examples/i18n/it/lib/calcolatrice.rb +11 -0
  64. data/examples/i18n/ja/README.txt +5 -0
  65. data/examples/i18n/ja/Rakefile +6 -0
  66. data/examples/i18n/ja/features/addition.feature +17 -0
  67. data/examples/i18n/ja/features/division.feature +10 -0
  68. data/examples/i18n/ja/features/step_definitons/calculator_steps.rb +30 -0
  69. data/examples/i18n/ja/lib/calculator.rb +14 -0
  70. data/examples/i18n/lt/Rakefile +6 -0
  71. data/examples/i18n/lt/features/addition.feature +17 -0
  72. data/examples/i18n/lt/features/division.feature +10 -0
  73. data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +31 -0
  74. data/examples/i18n/lt/lib/calculator.rb +14 -0
  75. data/examples/i18n/no/Rakefile +6 -0
  76. data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +22 -0
  77. data/examples/i18n/no/features/summering.feature +17 -0
  78. data/examples/i18n/no/lib/kalkulator.rb +11 -0
  79. data/examples/i18n/pt/Rakefile +6 -0
  80. data/examples/i18n/pt/features/adicao.feature +10 -0
  81. data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +22 -0
  82. data/examples/i18n/pt/lib/calculadora.rb +10 -0
  83. data/examples/i18n/ro/Rakefile +6 -0
  84. data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +22 -0
  85. data/examples/i18n/ro/features/suma.feature +10 -0
  86. data/examples/i18n/ro/lib/calculator.rb +11 -0
  87. data/examples/i18n/se/Rakefile +6 -0
  88. data/examples/i18n/se/features/step_definitons/kalkulator_steps.rb +22 -0
  89. data/examples/i18n/se/features/summering.feature +17 -0
  90. data/examples/i18n/se/lib/kalkulator.rb +11 -0
  91. data/examples/i18n/zh-CN/Rakefile +6 -0
  92. data/examples/i18n/zh-CN/features/addition.feature +17 -0
  93. data/examples/i18n/zh-CN/features/step_definitons/calculator_steps.rb +24 -0
  94. data/examples/i18n/zh-CN/lib/calculator.rb +10 -0
  95. data/examples/java/README.textile +22 -0
  96. data/examples/java/Rakefile +12 -0
  97. data/examples/java/features/hello.feature +11 -0
  98. data/examples/java/features/step_definitons/hello_steps.rb +25 -0
  99. data/examples/java/features/step_definitons/tree_steps.rb +14 -0
  100. data/examples/java/features/tree.feature +9 -0
  101. data/examples/java/src/cucumber/demo/Hello.java +16 -0
  102. data/examples/selenium/Rakefile +6 -0
  103. data/examples/selenium/features/search.feature +9 -0
  104. data/examples/selenium/features/step_definitons/stories_steps.rb +41 -0
  105. data/examples/test_unit/Rakefile +6 -0
  106. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +26 -0
  107. data/examples/test_unit/features/test_unit.feature +9 -0
  108. data/examples/tickets/Rakefile +11 -0
  109. data/examples/tickets/cucumber.yml +2 -0
  110. data/examples/tickets/features/step_definitons/tickets_steps.rb +32 -0
  111. data/examples/tickets/features/tickets.feature +24 -0
  112. data/examples/watir/Rakefile +6 -0
  113. data/examples/watir/features/search.feature +9 -0
  114. data/examples/watir/features/step_definitons/stories_steps.rb +51 -0
  115. data/features/see_features.feature +8 -0
  116. data/features/steps/features_steps.rb +9 -0
  117. data/gem_tasks/deployment.rake +34 -0
  118. data/gem_tasks/environment.rake +7 -0
  119. data/gem_tasks/features.rake +6 -0
  120. data/gem_tasks/fix_cr_lf.rake +10 -0
  121. data/gem_tasks/flog.rake +4 -0
  122. data/gem_tasks/gemspec.rake +6 -0
  123. data/gem_tasks/rspec.rake +35 -0
  124. data/gem_tasks/treetop.rake +41 -0
  125. data/lib/autotest/cucumber.rb +6 -0
  126. data/lib/autotest/cucumber_mixin.rb +109 -0
  127. data/lib/autotest/cucumber_rails.rb +6 -0
  128. data/lib/autotest/cucumber_rails_rspec.rb +6 -0
  129. data/lib/autotest/cucumber_rspec.rb +6 -0
  130. data/lib/autotest/discover.rb +9 -0
  131. data/lib/cucumber/broadcaster.rb +20 -0
  132. data/lib/cucumber/cli.rb +303 -0
  133. data/lib/cucumber/core_ext/proc.rb +69 -0
  134. data/lib/cucumber/core_ext/string.rb +28 -0
  135. data/lib/cucumber/executor.rb +190 -0
  136. data/lib/cucumber/formatters/ansicolor.rb +109 -0
  137. data/lib/cucumber/formatters/autotest_formatter.rb +23 -0
  138. data/lib/cucumber/formatters/cucumber.css +132 -0
  139. data/lib/cucumber/formatters/cucumber.js +11 -0
  140. data/lib/cucumber/formatters/html_formatter.rb +128 -0
  141. data/lib/cucumber/formatters/jquery.js +32 -0
  142. data/lib/cucumber/formatters/pretty_formatter.rb +234 -0
  143. data/lib/cucumber/formatters/profile_formatter.rb +92 -0
  144. data/lib/cucumber/formatters/progress_formatter.rb +58 -0
  145. data/lib/cucumber/formatters.rb +1 -0
  146. data/lib/cucumber/languages.yml +258 -0
  147. data/lib/cucumber/model/table.rb +28 -0
  148. data/lib/cucumber/model.rb +1 -0
  149. data/lib/cucumber/platform.rb +12 -0
  150. data/lib/cucumber/rails/rspec.rb +12 -0
  151. data/lib/cucumber/rails/world.rb +73 -0
  152. data/lib/cucumber/rake/task.rb +101 -0
  153. data/lib/cucumber/step_methods.rb +49 -0
  154. data/lib/cucumber/step_mother.rb +95 -0
  155. data/lib/cucumber/tree/feature.rb +63 -0
  156. data/lib/cucumber/tree/features.rb +21 -0
  157. data/lib/cucumber/tree/given_scenario.rb +13 -0
  158. data/lib/cucumber/tree/scenario.rb +174 -0
  159. data/lib/cucumber/tree/step.rb +134 -0
  160. data/lib/cucumber/tree/table.rb +26 -0
  161. data/lib/cucumber/tree/top_down_visitor.rb +23 -0
  162. data/lib/cucumber/tree.rb +18 -0
  163. data/lib/cucumber/treetop_parser/feature.treetop.erb +206 -0
  164. data/lib/cucumber/treetop_parser/feature_ar.rb +1591 -0
  165. data/lib/cucumber/treetop_parser/feature_cy.rb +1591 -0
  166. data/lib/cucumber/treetop_parser/feature_da.rb +1591 -0
  167. data/lib/cucumber/treetop_parser/feature_de.rb +1591 -0
  168. data/lib/cucumber/treetop_parser/feature_en-tx.rb +1591 -0
  169. data/lib/cucumber/treetop_parser/feature_en.rb +1591 -0
  170. data/lib/cucumber/treetop_parser/feature_es.rb +1591 -0
  171. data/lib/cucumber/treetop_parser/feature_et.rb +1591 -0
  172. data/lib/cucumber/treetop_parser/feature_fr.rb +1591 -0
  173. data/lib/cucumber/treetop_parser/feature_id.rb +1591 -0
  174. data/lib/cucumber/treetop_parser/feature_it.rb +1591 -0
  175. data/lib/cucumber/treetop_parser/feature_ja.rb +1591 -0
  176. data/lib/cucumber/treetop_parser/feature_lt.rb +1591 -0
  177. data/lib/cucumber/treetop_parser/feature_nl.rb +1591 -0
  178. data/lib/cucumber/treetop_parser/feature_no.rb +1591 -0
  179. data/lib/cucumber/treetop_parser/feature_parser.rb +34 -0
  180. data/lib/cucumber/treetop_parser/feature_pl.rb +1591 -0
  181. data/lib/cucumber/treetop_parser/feature_pt.rb +1591 -0
  182. data/lib/cucumber/treetop_parser/feature_ro.rb +1591 -0
  183. data/lib/cucumber/treetop_parser/feature_ro2.rb +1591 -0
  184. data/lib/cucumber/treetop_parser/feature_ru.rb +1591 -0
  185. data/lib/cucumber/treetop_parser/feature_se.rb +1591 -0
  186. data/lib/cucumber/treetop_parser/feature_zh-CN.rb +1591 -0
  187. data/lib/cucumber/version.rb +9 -0
  188. data/lib/cucumber.rb +38 -0
  189. data/rails_generators/cucumber/USAGE +11 -0
  190. data/rails_generators/cucumber/cucumber_generator.rb +30 -0
  191. data/rails_generators/cucumber/templates/cucumber +7 -0
  192. data/rails_generators/cucumber/templates/cucumber.rake +7 -0
  193. data/rails_generators/cucumber/templates/env.rb +8 -0
  194. data/rails_generators/cucumber/templates/webrat_steps.rb +95 -0
  195. data/rails_generators/feature/USAGE +12 -0
  196. data/rails_generators/feature/feature_generator.rb +16 -0
  197. data/rails_generators/feature/templates/feature.erb +28 -0
  198. data/rails_generators/feature/templates/steps.erb +22 -0
  199. data/script/console +10 -0
  200. data/script/console.cmd +1 -0
  201. data/script/destroy +14 -0
  202. data/script/destroy.cmd +1 -0
  203. data/script/generate +14 -0
  204. data/script/generate.cmd +1 -0
  205. data/script/txt2html +74 -0
  206. data/script/txt2html.cmd +1 -0
  207. data/setup.rb +1585 -0
  208. data/spec/cucumber/broadcaster_spec.rb +27 -0
  209. data/spec/cucumber/cli_spec.rb +412 -0
  210. data/spec/cucumber/core_ext/proc_spec.rb +45 -0
  211. data/spec/cucumber/core_ext/string_spec.rb +34 -0
  212. data/spec/cucumber/executor_spec.rb +298 -0
  213. data/spec/cucumber/formatters/ansicolor_spec.rb +35 -0
  214. data/spec/cucumber/formatters/autotest_formatter_spec.rb +26 -0
  215. data/spec/cucumber/formatters/features.html +269 -0
  216. data/spec/cucumber/formatters/html_formatter_spec.rb +74 -0
  217. data/spec/cucumber/formatters/pretty_formatter_spec.rb +204 -0
  218. data/spec/cucumber/formatters/profile_formatter_spec.rb +192 -0
  219. data/spec/cucumber/formatters/progress_formatter_spec.rb +65 -0
  220. data/spec/cucumber/model/table_spec.rb +20 -0
  221. data/spec/cucumber/rails/stubs/mini_rails.rb +17 -0
  222. data/spec/cucumber/rails/stubs/test_help.rb +1 -0
  223. data/spec/cucumber/rails/world_spec.rb +11 -0
  224. data/spec/cucumber/sell_cucumbers.feature +19 -0
  225. data/spec/cucumber/step_mother_spec.rb +74 -0
  226. data/spec/cucumber/tree/feature_spec.rb +43 -0
  227. data/spec/cucumber/tree/row_scenario_spec.rb +55 -0
  228. data/spec/cucumber/tree/scenario_spec.rb +76 -0
  229. data/spec/cucumber/tree/step_spec.rb +50 -0
  230. data/spec/cucumber/treetop_parser/empty_feature.feature +4 -0
  231. data/spec/cucumber/treetop_parser/empty_scenario.feature +9 -0
  232. data/spec/cucumber/treetop_parser/feature_parser_spec.rb +98 -0
  233. data/spec/cucumber/treetop_parser/fit_scenario.feature +8 -0
  234. data/spec/cucumber/treetop_parser/given_scenario.feature +9 -0
  235. data/spec/cucumber/treetop_parser/multiline_steps.feature +17 -0
  236. data/spec/cucumber/treetop_parser/multiple_tables.feature +29 -0
  237. data/spec/cucumber/treetop_parser/spaces.feature +10 -0
  238. data/spec/cucumber/treetop_parser/test_dos.feature +25 -0
  239. data/spec/cucumber/treetop_parser/with_comments.feature +10 -0
  240. data/spec/spec.opts +2 -0
  241. data/spec/spec_helper.rb +20 -0
  242. metadata +335 -0
@@ -0,0 +1,21 @@
1
+ module Cucumber
2
+ module Tree
3
+ class Features
4
+ def initialize
5
+ @features = []
6
+ end
7
+
8
+ def length
9
+ @features.length
10
+ end
11
+
12
+ def <<(feature)
13
+ @features << feature
14
+ end
15
+
16
+ def accept(visitor)
17
+ @features.each{|feature| visitor.visit_feature(feature)}
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ module Cucumber
2
+ module Tree
3
+ class GivenScenario
4
+ def initialize(scenario, name, line)
5
+ @scenario, @name, @line = scenario, name, line
6
+ end
7
+
8
+ def steps
9
+ @scenario.given_scenario_steps(@name)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,174 @@
1
+ module Cucumber
2
+ module Tree
3
+ class BaseScenario
4
+ attr_reader :feature
5
+
6
+ def file
7
+ @feature.file
8
+ end
9
+
10
+ def accept(visitor)
11
+ steps.each do |step|
12
+ if step.row?
13
+ visitor.visit_row_step(step)
14
+ else
15
+ visitor.visit_regular_step(step)
16
+ end
17
+ end
18
+ end
19
+
20
+ def at_line?(l)
21
+ line == l || steps.map{|s| s.line}.index(l)
22
+ end
23
+
24
+ def previous_step(step)
25
+ i = steps.index(step)
26
+ raise "Couldn't find #{step} among #{steps}" if i.nil?
27
+ steps[i-1]
28
+ end
29
+
30
+ def pending?
31
+ steps.empty?
32
+ end
33
+
34
+ end
35
+
36
+ class Scenario < BaseScenario
37
+ MIN_PADDING = 2
38
+ INDENT = 2
39
+
40
+ # If a table follows, the header will be stored here. Weird, but convenient.
41
+ attr_reader :table_header
42
+ attr_accessor :table_column_widths
43
+ attr_reader :name, :line
44
+
45
+ def initialize(feature, name, line, &proc)
46
+ @feature, @name, @line = feature, name, line
47
+ @steps_and_given_scenarios = []
48
+ instance_eval(&proc) if block_given?
49
+ end
50
+
51
+ def table_header= header
52
+ @table_header = header
53
+ update_table_column_widths header
54
+ end
55
+
56
+ def steps
57
+ @steps ||= @steps_and_given_scenarios.map{|step| step.steps}.flatten
58
+ end
59
+
60
+ def given_scenario_steps(name)
61
+ sibling_named(name).steps
62
+ end
63
+
64
+ def sibling_named(name)
65
+ @feature.scenario_named(name)
66
+ end
67
+
68
+ def length
69
+ @length ||= Cucumber.language['scenario'].jlength + 2 + (@name.nil? ? 0 : @name.jlength)
70
+ end
71
+
72
+ def max_line_length
73
+ [length, max_step_length].max
74
+ end
75
+
76
+ def padding_length
77
+ padding = (max_line_length - length) + MIN_PADDING
78
+ padding += INDENT if length != max_line_length
79
+ padding
80
+ end
81
+
82
+ def step_padding_length(step)
83
+ padding = (max_line_length - step.length) + MIN_PADDING
84
+ padding -= INDENT if length == max_line_length
85
+ padding
86
+ end
87
+
88
+ def max_step_length
89
+ @max_step_length ||= (steps.map{|step| step.length}.max || 0)
90
+ end
91
+
92
+ def update_table_column_widths values
93
+ @table_column_widths ||= [0] * values.size
94
+ @table_column_widths = @table_column_widths.zip(values).map {|max, value| [max, value.size].max}
95
+ end
96
+
97
+ def row?
98
+ false
99
+ end
100
+
101
+ def create_step(keyword, name, line)
102
+ step = Step.new(self, keyword, name, line)
103
+ @steps_and_given_scenarios << step
104
+ step
105
+ end
106
+
107
+ def create_given_scenario(name, line)
108
+ given_scenario = GivenScenario.new(self, name, line)
109
+ @steps_and_given_scenarios << given_scenario
110
+ given_scenario
111
+ end
112
+
113
+ def Given(name)
114
+ create_step('Given', name, *caller[0].split(':')[1].to_i)
115
+ end
116
+
117
+ def When(name)
118
+ create_step('When', name, *caller[0].split(':')[1].to_i)
119
+ end
120
+
121
+ def Then(name)
122
+ create_step('Then', name, *caller[0].split(':')[1].to_i)
123
+ end
124
+
125
+ def And(name)
126
+ create_step('And', name, *caller[0].split(':')[1].to_i)
127
+ end
128
+
129
+ end
130
+
131
+ class RowScenario < BaseScenario
132
+ attr_reader :line
133
+
134
+ def initialize(feature, template_scenario, values, line)
135
+ @feature, @template_scenario, @values, @line = feature, template_scenario, values, line
136
+ template_scenario.update_table_column_widths values
137
+ end
138
+
139
+ def row?
140
+ true
141
+ end
142
+
143
+ def name
144
+ @template_scenario.name
145
+ end
146
+
147
+ #We can only cache steps once the template scenarios steps have been bound in order to know what arity the steps have
148
+ def steps
149
+ if template_steps_bound?
150
+ @unbound_steps = nil
151
+ @bound_steps ||= build_steps
152
+ else
153
+ @unbound_steps ||= build_steps
154
+ end
155
+ end
156
+
157
+ private
158
+ def build_steps
159
+ @template_scenario.steps.map do |template_step|
160
+ args = []
161
+ template_step.arity.times do
162
+ args << @values.shift
163
+ end
164
+ RowStep.new(self, template_step, args)
165
+ end
166
+ end
167
+
168
+ def template_steps_bound?
169
+ @template_steps_bound ||= @template_scenario.steps.inject(0) { |arity_sum, step| arity_sum + step.arity } != 0
170
+ end
171
+
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,134 @@
1
+ module Cucumber
2
+ module Tree
3
+ class BaseStep
4
+ attr_reader :scenario
5
+ attr_accessor :error
6
+
7
+ def self.new_id!
8
+ @next_id ||= -1
9
+ @next_id += 1
10
+ end
11
+
12
+ attr_reader :error
13
+
14
+ def file
15
+ @scenario.file
16
+ end
17
+
18
+ def steps
19
+ self
20
+ end
21
+
22
+ def length
23
+ keyword.jlength + 1 + name.jlength
24
+ end
25
+
26
+ if defined?(JRUBY_VERSION)
27
+ PENDING_ADJUSTMENT = 2
28
+ REGULAR_ADJUSTMENT = 1
29
+ else
30
+ PENDING_ADJUSTMENT = 3
31
+ REGULAR_ADJUSTMENT = 2
32
+ end
33
+
34
+ def execute_in(world, regexp, args, proc)
35
+ strip_pos = nil
36
+ begin
37
+ proc.call_in(world, *args)
38
+ rescue ArityMismatchError => e
39
+ e.backtrace[0] = proc.to_backtrace_line
40
+ strip_pos = e.backtrace.index("#{__FILE__}:#{__LINE__ - 3}:in `execute_in'")
41
+ format_error(strip_pos, proc, e)
42
+ rescue => e
43
+ method_line = "#{__FILE__}:#{__LINE__ - 6}:in `execute_in'"
44
+ method_line_pos = e.backtrace.index(method_line)
45
+ if method_line_pos
46
+ strip_pos = method_line_pos - (Pending === e ? PENDING_ADJUSTMENT : REGULAR_ADJUSTMENT)
47
+ else
48
+ # This happens with rails, because they screw up the backtrace
49
+ # before we get here (injecting erb stacktrace and such)
50
+ end
51
+ format_error(strip_pos, proc, e)
52
+ end
53
+ end
54
+
55
+ def format_error(strip_pos, proc, e)
56
+ @error = e
57
+ # Remove lines underneath the plain text step
58
+ e.backtrace[strip_pos..-1] = nil unless strip_pos.nil?
59
+ e.backtrace.flatten
60
+ # Replace the step line with something more readable
61
+ e.backtrace.replace(e.backtrace.map{|l| l.gsub(/`#{proc.meth}'/, "`#{keyword} #{proc.name}'")})
62
+ if row?
63
+ e.backtrace << "#{file}:#{line}:in `#{proc.name}'"
64
+ else
65
+ e.backtrace << "#{file}:#{line}:in `#{keyword} #{name}'"
66
+ end
67
+ raise e
68
+ end
69
+
70
+ def id
71
+ @id ||= self.class.new_id!
72
+ end
73
+
74
+ def actual_keyword
75
+ keyword == Cucumber.language['and'] ? previous_step.actual_keyword : keyword
76
+ end
77
+
78
+ def previous_step
79
+ @scenario.previous_step(self)
80
+ end
81
+
82
+ def padding_length
83
+ @scenario.step_padding_length(self)
84
+ end
85
+ end
86
+
87
+ class Step < BaseStep
88
+ attr_reader :keyword, :name, :line
89
+ attr_accessor :arity, :extra_args
90
+
91
+ def row?
92
+ false
93
+ end
94
+
95
+ def initialize(scenario, keyword, name, line)
96
+ @scenario, @keyword, @name, @line = scenario, keyword, name, line
97
+ @extra_args = []
98
+ @arity = 0
99
+ end
100
+
101
+ def regexp_args_proc(step_mother)
102
+ regexp, args, proc = step_mother.regexp_args_proc(name)
103
+ @arity = args.length
104
+ [regexp, (args + extra_args), proc]
105
+ end
106
+
107
+ def format(regexp, format=nil, &proc)
108
+ regexp.nil? ? name : name.gzub(regexp, format, &proc)
109
+ end
110
+ end
111
+
112
+ class RowStep < BaseStep
113
+ attr_reader :keyword
114
+
115
+ def initialize(scenario, step, args)
116
+ @scenario, @step, @args = scenario, step, args
117
+ end
118
+
119
+ def regexp_args_proc(step_mother)
120
+ regexp, _, proc = @step.regexp_args_proc(step_mother)
121
+ [regexp, @args, proc]
122
+ end
123
+
124
+ def row?
125
+ true
126
+ end
127
+
128
+ def line
129
+ @scenario.line
130
+ end
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,26 @@
1
+ module Cucumber
2
+ module Tree
3
+ class Table
4
+ def initialize(rows)
5
+ @rows = rows
6
+ end
7
+
8
+ def |(cell)
9
+ @row ||= []
10
+ if cell == self
11
+ line = *caller[0].split(':')[1].to_i
12
+ @row.instance_eval %{
13
+ def line
14
+ #{line}
15
+ end
16
+ }
17
+ @rows << @row
18
+ @row = nil
19
+ else
20
+ @row << cell.to_s
21
+ end
22
+ self
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ module Cucumber
2
+ module Tree
3
+ class TopDownVisitor
4
+ def visit_features(features)
5
+ features.accept(self)
6
+ end
7
+
8
+ def visit_feature(feature)
9
+ feature.accept(self)
10
+ end
11
+
12
+ def visit_header(header)
13
+ end
14
+
15
+ def visit_scenario(scenario)
16
+ scenario.accept(self)
17
+ end
18
+
19
+ def visit_step(step)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ %w{features feature scenario step given_scenario table top_down_visitor}.each{|f| require "cucumber/tree/#{f}"}
2
+ require 'cucumber/core_ext/proc'
3
+ require 'cucumber/core_ext/string'
4
+
5
+ module Cucumber
6
+ module Tree
7
+ def Feature(header, &proc)
8
+ feature = Feature.new("Feature: " + header, &proc)
9
+ feature.file, _, _ = *caller[0].split(':')
10
+ features << feature
11
+ feature
12
+ end
13
+
14
+ def features #:nodoc:
15
+ @features ||= Tree::Features.new
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,206 @@
1
+ module Cucumber
2
+ # :stopdoc:
3
+ module TreetopParser
4
+ grammar Feature
5
+ rule root
6
+ space? header scenario_sequence space? {
7
+ def compile
8
+ feature = Tree::Feature.new(header.text_value.strip)
9
+ scenario_sequence.compile(feature)
10
+ feature
11
+ end
12
+ }
13
+ end
14
+
15
+ rule header
16
+ (!(scenario_keyword / comment_to_eol) .)+
17
+ end
18
+
19
+ rule scenario_sequence
20
+ head:scenario? tail:(space scenario_or_table)* {
21
+ def compile(feature)
22
+ ([head] + tail).each do |scenario_or_table|
23
+ scenario_or_table.compile(feature) if scenario_or_table.respond_to?(:compile)
24
+ end
25
+ end
26
+
27
+ def tail
28
+ super.elements.map { |elt| elt.scenario_or_table }
29
+ end
30
+ }
31
+ end
32
+
33
+ rule scenario
34
+ scenario_keyword space? name:line_to_eol steps:(space step_sequence)? {
35
+ def compile(feature)
36
+ line = input.line_of(interval.first)
37
+ scenario = feature.add_scenario(name.text_value.strip, line)
38
+ steps.step_sequence.compile(scenario) if steps.respond_to?(:step_sequence)
39
+ # TODO - GET RID OF THIS last_scenario NASTINESS
40
+ # Use a better datastructure, like a linked list...
41
+ Feature.last_scenario = scenario
42
+ end
43
+ }
44
+ end
45
+
46
+ rule scenario_or_table
47
+ scenario / more_examples
48
+ end
49
+
50
+ rule more_examples
51
+ more_examples_keyword table {
52
+ def compile(f)
53
+ table.compile(f)
54
+ end
55
+ }
56
+ end
57
+
58
+ rule table
59
+ space head:table_line body:(blank* eol space? table_line)* {
60
+ def compile(feature)
61
+ Feature.last_scenario.table_header = head.cell_values
62
+ body.each do |table_line|
63
+ feature.add_row_scenario(Feature.last_scenario, table_line.cell_values, table_line.line)
64
+ end
65
+ end
66
+
67
+ def matrix
68
+ ([head] + body).map do |table_line|
69
+ table_line.cell_values # We're losing the line - we'll get it back when we make our own class
70
+ end
71
+ end
72
+
73
+ def to_arg
74
+ Model::Table.new(matrix)
75
+ end
76
+
77
+ def body
78
+ super.elements.map { |elt| elt.table_line }
79
+ end
80
+ }
81
+ end
82
+
83
+ rule table_line
84
+ separator cells:(blank* cell_value blank* separator)+ {
85
+ def cell_values
86
+ cells.elements.map { |elt| elt.cell_value.text_value.strip }
87
+ end
88
+
89
+ def line
90
+ input.line_of(interval.first)
91
+ end
92
+ }
93
+ end
94
+
95
+ rule cell_value
96
+ (!(separator / eol) .)*
97
+ end
98
+
99
+ rule step_sequence
100
+ head:step tail:(space step)* {
101
+ def compile(scenario)
102
+ ([head] + tail).each do |step|
103
+ step.compile(scenario)
104
+ end
105
+ end
106
+
107
+ def tail
108
+ super.elements.map { |elt| elt.step }
109
+ end
110
+ }
111
+ end
112
+
113
+ rule step
114
+ given_scenario / plain_step
115
+ end
116
+
117
+ rule given_scenario
118
+ given_scenario_keyword space? name:line_to_eol {
119
+ def compile(scenario)
120
+ line = input.line_of(interval.first)
121
+ scenario.create_given_scenario(name.text_value.strip, line)
122
+ end
123
+ }
124
+ end
125
+
126
+ rule plain_step
127
+ step_keyword space? name:line_to_eol multi:multiline_arg? {
128
+ def compile(scenario)
129
+ line = input.line_of(interval.first)
130
+ step = scenario.create_step(step_keyword.text_value, name.text_value.strip, line)
131
+
132
+ if multi.respond_to?(:to_arg)
133
+ step.extra_args << multi.to_arg
134
+ end
135
+ end
136
+ }
137
+ end
138
+
139
+ rule multiline_arg
140
+ table / multiline_string
141
+ end
142
+
143
+ rule multiline_string
144
+ eol indent:space triple_quote string:(!triple_quote .)* triple_quote {
145
+ def to_arg
146
+ indent_length = indent.text_value.length
147
+ significant_lines = string.text_value.split("\n")[1..-2]
148
+ significant_lines.map do |l|
149
+ l[indent_length..-1]
150
+ end.join("\n")
151
+ end
152
+ }
153
+ end
154
+
155
+ rule triple_quote
156
+ '"""'
157
+ end
158
+
159
+ rule separator
160
+ '|'
161
+ end
162
+
163
+ rule space
164
+ (white / comment_to_eol)+
165
+ end
166
+
167
+ rule line_to_eol
168
+ (!eol .)*
169
+ end
170
+
171
+ rule comment_to_eol
172
+ '#' line_to_eol
173
+ end
174
+
175
+ rule white
176
+ blank / eol
177
+ end
178
+
179
+ rule blank
180
+ [ \t]
181
+ end
182
+
183
+ rule eol
184
+ ("\r" "\n"?) / "\n"
185
+ end
186
+
187
+ rule step_keyword
188
+ "<%= words['given'] %>" / "<%= words['when'] %>" / "<%= words['then'] %>" / "<%= words['and'] %>" / "<%= words['but'] %>"
189
+ end
190
+
191
+ rule scenario_keyword
192
+ "<%= words['scenario'] %>" ":"?
193
+ end
194
+
195
+ rule more_examples_keyword
196
+ "<%= words['more_examples'] %>" ":"?
197
+ end
198
+
199
+ rule given_scenario_keyword
200
+ "<%= words['given_scenario'] %>" ":"?
201
+ end
202
+
203
+ end
204
+
205
+ end
206
+ end