yard-cucumber 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. data/.rspec +3 -0
  2. data/History.txt +190 -0
  3. data/README.md +145 -0
  4. data/Rakefile +17 -0
  5. data/city.gemspec +66 -0
  6. data/example/README.md +8 -0
  7. data/example/child_feature/README.md +21 -0
  8. data/example/child_feature/child.feature +11 -0
  9. data/example/child_feature/grandchild_feature/grandchild.feature +12 -0
  10. data/example/empty.feature +2 -0
  11. data/example/scenario.feature +63 -0
  12. data/example/scenario_outline.feature +80 -0
  13. data/example/step_definitions/example.step.rb +109 -0
  14. data/example/step_definitions/first.step.rb +21 -0
  15. data/example/step_definitions/support/env.rb +7 -0
  16. data/example/step_definitions/support/env_support.rb +12 -0
  17. data/example/step_definitions/support/support.rb +6 -0
  18. data/example/tags.feature +18 -0
  19. data/example/transform.feature +13 -0
  20. data/lib/cucumber/city_builder.rb +209 -0
  21. data/lib/docserver/default/fulldoc/html/js/cucumber.js +85 -0
  22. data/lib/docserver/default/layout/html/headers.erb +13 -0
  23. data/lib/docserver/doc_server/full_list/html/full_list.erb +37 -0
  24. data/lib/docserver/doc_server/full_list/html/setup.rb +18 -0
  25. data/lib/templates/default/feature/html/feature.erb +39 -0
  26. data/lib/templates/default/feature/html/no_steps_defined.erb +1 -0
  27. data/lib/templates/default/feature/html/outline.erb +42 -0
  28. data/lib/templates/default/feature/html/pystring.erb +3 -0
  29. data/lib/templates/default/feature/html/scenario.erb +55 -0
  30. data/lib/templates/default/feature/html/setup.rb +55 -0
  31. data/lib/templates/default/feature/html/steps.erb +39 -0
  32. data/lib/templates/default/feature/html/table.erb +20 -0
  33. data/lib/templates/default/featuredirectory/html/alpha_table.erb +26 -0
  34. data/lib/templates/default/featuredirectory/html/directory.erb +32 -0
  35. data/lib/templates/default/featuredirectory/html/setup.rb +41 -0
  36. data/lib/templates/default/featuretags/html/namespace.erb +131 -0
  37. data/lib/templates/default/featuretags/html/setup.rb +34 -0
  38. data/lib/templates/default/fulldoc/html/css/common.css +214 -0
  39. data/lib/templates/default/fulldoc/html/full_list.erb +36 -0
  40. data/lib/templates/default/fulldoc/html/full_list_features.erb +28 -0
  41. data/lib/templates/default/fulldoc/html/full_list_stepdefinitions.erb +11 -0
  42. data/lib/templates/default/fulldoc/html/full_list_steps.erb +13 -0
  43. data/lib/templates/default/fulldoc/html/full_list_tags.erb +12 -0
  44. data/lib/templates/default/fulldoc/html/index.erb +24 -0
  45. data/lib/templates/default/fulldoc/html/js/cucumber.js +314 -0
  46. data/lib/templates/default/fulldoc/html/setup.rb +72 -0
  47. data/lib/templates/default/layout/html/headers.erb +14 -0
  48. data/lib/templates/default/layout/html/search.erb +7 -0
  49. data/lib/templates/default/requirements/html/alpha_table.erb +26 -0
  50. data/lib/templates/default/requirements/html/requirements.erb +50 -0
  51. data/lib/templates/default/requirements/html/setup.rb +51 -0
  52. data/lib/templates/default/steptransformers/html/header.erb +12 -0
  53. data/lib/templates/default/steptransformers/html/index.erb +10 -0
  54. data/lib/templates/default/steptransformers/html/setup.rb +94 -0
  55. data/lib/templates/default/steptransformers/html/transformers.erb +74 -0
  56. data/lib/templates/default/steptransformers/html/undefinedsteps.erb +26 -0
  57. data/lib/templates/default/tag/html/alpha_table.erb +32 -0
  58. data/lib/templates/default/tag/html/setup.rb +27 -0
  59. data/lib/templates/default/tag/html/tag.erb +35 -0
  60. data/lib/yard/code_objects/cucumber/base.rb +32 -0
  61. data/lib/yard/code_objects/cucumber/feature.rb +18 -0
  62. data/lib/yard/code_objects/cucumber/namespace_object.rb +45 -0
  63. data/lib/yard/code_objects/cucumber/scenario.rb +26 -0
  64. data/lib/yard/code_objects/cucumber/scenario_outline.rb +66 -0
  65. data/lib/yard/code_objects/cucumber/step.rb +35 -0
  66. data/lib/yard/code_objects/cucumber/tag.rb +27 -0
  67. data/lib/yard/code_objects/step_definition.rb +7 -0
  68. data/lib/yard/code_objects/step_transform.rb +7 -0
  69. data/lib/yard/code_objects/step_transformer.rb +51 -0
  70. data/lib/yard/handlers/cucumber/base.rb +22 -0
  71. data/lib/yard/handlers/cucumber/feature_handler.rb +93 -0
  72. data/lib/yard/handlers/legacy/step_definition_handler.rb +46 -0
  73. data/lib/yard/handlers/legacy/step_transform_handler.rb +24 -0
  74. data/lib/yard/handlers/step_definition_handler.rb +22 -0
  75. data/lib/yard/handlers/step_transform_handler.rb +23 -0
  76. data/lib/yard/parser/cucumber/feature.rb +46 -0
  77. data/lib/yard/parser/source_parser.rb +54 -0
  78. data/lib/yard/rake/city_task.rb +12 -0
  79. data/lib/yard/server/adapter.rb +29 -0
  80. data/lib/yard/server/commands/list_command.rb +25 -0
  81. data/lib/yard/server/router.rb +31 -0
  82. data/lib/yard/templates/helpers/base_helper.rb +26 -0
  83. data/lib/yard-cucumber.rb +53 -0
  84. metadata +173 -0
@@ -0,0 +1,74 @@
1
+ <% @items.each do |item| %>
2
+
3
+ <div class="transformer <%= @item_type.gsub(/\s/,'') %> <%= "nodefinitions" if item.steps.nil? || item.steps.empty? %>">
4
+ <a name="<%= anchor_for item %>"></a>
5
+ <div class="title">
6
+ <span class="pre"><%= h item.keyword %></span>
7
+ <span class="name"><%= link_constants item %></span>
8
+ <a style="float: right;" href="http://rubular.com/?regex=<%= urlencode item.value %>" target="_blank">Rubular</a>
9
+ <div style="clear: both;"></div>
10
+ </div>
11
+
12
+ <div class="details">
13
+
14
+ <div class="meta" style="clear: right;">
15
+ <div class="file"><%= h item.location %></div>
16
+ </div>
17
+
18
+
19
+ <!-- Comments -->
20
+ <div>
21
+ <%= display_comments_for item %>
22
+ </div>
23
+
24
+
25
+ <!-- Source Code -->
26
+ <div class="method_details_list">
27
+ <table class="source_code">
28
+ <tr>
29
+ <td>
30
+ <pre class="lines"><%= "" %><%= h format_lines(item) %></pre>
31
+ </td>
32
+ <td>
33
+ <pre class="code"><%= "" %><%= html_syntax_highlight item.source %></pre>
34
+ </td>
35
+ </tr>
36
+ </table>
37
+ </div>
38
+
39
+ <!-- Matching Step Instances -->
40
+ <% if item.steps.length > 0 %>
41
+ <div class='showSteps'>
42
+ [<a href='#' class='toggleSteps' alt="<%= item.steps.length %> steps">Hide <%= item.steps.length %> steps</a>]
43
+ </div>
44
+ <% end %>
45
+ <div class="steps">
46
+ <% if item.steps && !item.steps.empty? %>
47
+ <% unique_steps(item.steps).each_with_index do |uniq_step,step_index| %>
48
+ <div class="step <%= (step_index + 1) % 2 == 0 ? 'even' : 'odd' %>">
49
+ <div>
50
+ <span class="predicate">
51
+ <%= h uniq_step.last.first.keyword %>
52
+ </span>
53
+ <span class="defined">
54
+ <%= link_transformed_step(uniq_step.last.first) %>
55
+ </span>
56
+ </div>
57
+ <% uniq_step.last.each do |step| %>
58
+ <a class="definition" style="clear: right;" href="<%= url_for step.scenario.feature %>"><%= h step.location %></a>
59
+ <% end %>
60
+ <div style="clear: both;"></div>
61
+ </div>
62
+ <% end %>
63
+ <% else %>
64
+ <div class="undefined">No steps were found to match this <%= @item_type %>.</div>
65
+ <% end%>
66
+ </div>
67
+
68
+ </div>
69
+
70
+ <div style="margin: 30px 20px; border-top: 1px dotted #AAA;"></div>
71
+
72
+ </div>
73
+
74
+ <% end %>
@@ -0,0 +1,26 @@
1
+ <div class="transformer">
2
+ <div class="steps">
3
+ <% if @undefined_steps && !@undefined_steps.empty? %>
4
+ <% @undefined_steps.each_with_index do |uniq_step,step_index| %>
5
+ <div class="step <%= (step_index + 1) % 2 == 0 ? 'even' : 'odd' %>">
6
+ <div>
7
+ <span class="predicate"><%= uniq_step.last.first.keyword %></span>
8
+ <span class="undefined">
9
+ <%= h uniq_step.last.first.value %>
10
+ </span>
11
+ </div>
12
+ <% uniq_step.last.each do |step| %>
13
+ <a class="definition" style="clear: right;" href="<%= url_for step.scenario.feature %>">
14
+ <%= h step.location %>
15
+ </a>
16
+ <% end%>
17
+ <div style="clear: both;"></div>
18
+ </div>
19
+ <% end %>
20
+ <% else %>
21
+ <div class="steps">
22
+ <div class="undefined">No undefined steps</div>
23
+ </div>
24
+ <% end%>
25
+ </div>
26
+ </div>
@@ -0,0 +1,32 @@
1
+ <% if @elements && !@elements.empty? %>
2
+ <% i = (@elements.length % 2 == 0 ? 1 : 0) %>
3
+ <table style="margin-left: 10px; width: 100%;">
4
+ <tr>
5
+ <td valign='top' width="50%">
6
+ <% @elements.each do |letter, objects| %>
7
+ <% if (i += 1) > (@elements.length / 2 + 1) %>
8
+ </td><td valign='top' width="50%">
9
+ <% i = 0 %>
10
+ <% end %>
11
+ <ul id="alpha_<%= letter %>" class="alpha">
12
+ <li class="letter"><%= letter %></li>
13
+ <ul>
14
+ <% objects.each do |obj| %>
15
+ <li>
16
+ <% if obj.is_a?(YARD::CodeObjects::Cucumber::Scenario) || obj.is_a?(YARD::CodeObjects::Cucumber::ScenarioOutline) %>
17
+ <a href="<%= url_for(obj.feature,"scenario_#{obj.path[(/.+_(\d+)$/),1]}") %>">
18
+ <%= h obj.value %>
19
+ </a>
20
+ <% else %>
21
+ <%= linkify obj, obj.value %>
22
+ <% end %>
23
+ <small>(<%= obj.file %>)</small>
24
+ </li>
25
+ <% end %>
26
+ </ul>
27
+ </ul>
28
+ <% end %>
29
+ </td>
30
+ </tr>
31
+ </table>
32
+ <% end %>
@@ -0,0 +1,27 @@
1
+ def init
2
+ super
3
+ @tag = object
4
+
5
+ sections.push :tag
6
+ end
7
+
8
+ def features
9
+ @tag.features
10
+ end
11
+
12
+ def scenarios
13
+ @tag.scenarios
14
+ end
15
+
16
+
17
+ def alpha_table(objects)
18
+ @elements = Hash.new
19
+
20
+ objects = run_verifier(objects)
21
+ objects.each {|o| (@elements[o.value.to_s[0,1].upcase] ||= []) << o }
22
+ @elements.values.each {|v| v.sort! {|a,b| b.value.to_s <=> a.value.to_s } }
23
+ @elements = @elements.sort_by {|l,o| l.to_s }
24
+
25
+ @elements.each {|letter,objects| objects.sort! {|a,b| b.value.to_s <=> a.value.to_s }}
26
+ erb(:alpha_table)
27
+ end
@@ -0,0 +1,35 @@
1
+ <div class="tag">
2
+ <div class="title">
3
+ <span class="pre">Tag:</span>
4
+ <span class="name"><%= @tag.value %></span>
5
+
6
+ </div>
7
+
8
+ <div class="meta">
9
+ <div class="file">
10
+ <%= @tag.features.size > 0 ? "#{@tag.features.size} feature#{@tag.features.size > 1 ? 's' : ''} (with #{@tag.indirect_scenarios.size} scenario#{@tag.indirect_scenarios.size > 1 ? 's' : ''})" : "" %>
11
+ <%= " and " if @tag.features.size > 0 && @tag.scenarios.size > 0 %>
12
+ <%= @tag.scenarios.size > 0 ? "#{@tag.scenarios.size} scenario#{@tag.scenarios.size > 1 ? 's' : ''}" : "" %>
13
+ </div>
14
+ </div>
15
+
16
+ <div style="margin-top: 20px;">&nbsp;</div>
17
+
18
+ <% if features && !features.empty? %>
19
+ <div id="features" style="margin-left: 40px;">
20
+ <div class="title"><span class="name">Features</span></div>
21
+ </div>
22
+ <%= alpha_table(features) %>
23
+
24
+ <% end %>
25
+
26
+ <% if scenarios && !scenarios.empty? %>
27
+ <div id="features" style="margin-left: 40px;">
28
+ <div class="title"><span class="name">Scenarios</span></div>
29
+ </div>
30
+ <%= alpha_table(scenarios) %>
31
+
32
+ <% end %>
33
+
34
+
35
+ </div>
@@ -0,0 +1,32 @@
1
+
2
+ module YARD::CodeObjects::Cucumber
3
+
4
+ module LocationHelper
5
+
6
+ def line_number
7
+ files.first.last
8
+ end
9
+
10
+ def file
11
+ files.first.first if files && !files.empty?
12
+ end
13
+
14
+ def location
15
+ "#{file}:#{line_number}"
16
+ end
17
+
18
+ end
19
+
20
+ class Base < YARD::CodeObjects::Base
21
+ include LocationHelper
22
+
23
+ def path
24
+ @value || super
25
+ end
26
+
27
+ end
28
+
29
+
30
+
31
+ end
32
+
@@ -0,0 +1,18 @@
1
+
2
+
3
+ module YARD::CodeObjects::Cucumber
4
+
5
+ class Feature < NamespaceObject
6
+
7
+ attr_accessor :background, :comments, :description, :keyword, :scenarios, :tags, :value
8
+
9
+ def initialize(namespace,name)
10
+ @comments = ""
11
+ @scenarios = []
12
+ @tags = []
13
+ super(namespace,name.to_s.strip)
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,45 @@
1
+
2
+ module YARD::CodeObjects::Cucumber
3
+
4
+ class NamespaceObject < YARD::CodeObjects::NamespaceObject
5
+ include LocationHelper
6
+ def value ; nil ; end
7
+ end
8
+
9
+ class Requirements < NamespaceObject ; end
10
+ class FeatureTags < NamespaceObject ; end
11
+ class StepTransformersObject < NamespaceObject ; end
12
+
13
+ class FeatureDirectory < YARD::CodeObjects::NamespaceObject
14
+
15
+ attr_accessor :description
16
+
17
+ def initialize(namespace,name)
18
+ super(namespace,name)
19
+ @description = ""
20
+ end
21
+
22
+ def location
23
+ files.first.first if files && !files.empty?
24
+ end
25
+
26
+ def value ; name ; end
27
+
28
+ def features
29
+ children.find_all {|d| d.is_a?(Feature) }
30
+ end
31
+
32
+ def subdirectories
33
+ subdirectories = children.find_all {|d| d.is_a?(FeatureDirectory) }
34
+ subdirectories + subdirectories.collect {|s| s.subdirectories }.flatten
35
+ end
36
+
37
+ end
38
+
39
+ CUCUMBER_NAMESPACE = Requirements.new(:root, "requirements") unless defined?(CUCUMBER_NAMESPACE)
40
+
41
+ CUCUMBER_TAG_NAMESPACE = FeatureTags.new(CUCUMBER_NAMESPACE, "tags") unless defined?(CUCUMBER_TAG_NAMESPACE)
42
+
43
+ CUCUMBER_STEPTRANSFORM_NAMESPACE = StepTransformersObject.new(CUCUMBER_NAMESPACE, "step_transformers") unless defined?(CUCUMBER_STEPTRANSFORM_NAMESPACE)
44
+
45
+ end
@@ -0,0 +1,26 @@
1
+
2
+
3
+ module YARD::CodeObjects::Cucumber
4
+
5
+ class Scenario < NamespaceObject
6
+
7
+ attr_accessor :value, :comments, :keyword, :description, :steps, :tags, :feature
8
+
9
+ def initialize(namespace,name)
10
+ super(namespace,name.to_s.strip)
11
+ @comments = @description = @keyword = @value = @feature = nil
12
+ @steps = []
13
+ @tags = []
14
+ end
15
+
16
+ def background?
17
+ @keyword == "Background"
18
+ end
19
+
20
+ def outline?
21
+ false
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,66 @@
1
+
2
+
3
+ module YARD::CodeObjects::Cucumber
4
+
5
+ class ScenarioOutline < NamespaceObject
6
+
7
+ attr_accessor :value, :comments, :keyword, :description, :steps, :tags, :feature
8
+ attr_accessor :scenarios, :examples
9
+
10
+ def initialize(namespace,name)
11
+ super(namespace,name.to_s.strip)
12
+ @comments = @description = @value = @feature = nil
13
+ @steps = []
14
+ @tags = []
15
+ @scenarios = []
16
+ @examples = {}
17
+ end
18
+
19
+ def background?
20
+ false
21
+ end
22
+
23
+ def outline?
24
+ true
25
+ end
26
+
27
+ def examples?
28
+ !@examples[:rows].nil?
29
+ end
30
+
31
+ def example_keyword
32
+ @examples[:keyword]
33
+ end
34
+
35
+ def example_headers
36
+ @examples[:rows].first
37
+ end
38
+
39
+ def example_data
40
+ return "" unless @examples[:rows]
41
+ @examples[:rows][1..-1]
42
+ end
43
+
44
+ def example_values_for_row(row)
45
+ hash = {}
46
+
47
+ example_headers.each_with_index do |header,index|
48
+ hash[header] = example_data[row][index]
49
+ end
50
+
51
+ hash
52
+ end
53
+
54
+ def example_hash
55
+ hash = {}
56
+
57
+ @examples[:rows].each_with_index do |header,index|
58
+ hash[header] = @examples[:rows].collect {|row| row[index] }
59
+ end
60
+
61
+ hash
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,35 @@
1
+
2
+
3
+ module YARD::CodeObjects::Cucumber
4
+
5
+ class Step < Base
6
+
7
+ attr_accessor :comments, :definition, :examples, :keyword, :scenario, :table, :text, :transforms, :value
8
+
9
+ def initialize(namespace,name)
10
+ super(namespace,name.to_s.strip)
11
+ @comments = @definition = @description = @keyword = @table = @text = @value = nil
12
+ @examples = {}
13
+ @transforms = []
14
+ end
15
+
16
+ def has_table?
17
+ !@table.nil?
18
+ end
19
+
20
+ def has_text?
21
+ !@text.nil?
22
+ end
23
+
24
+ def definition=(stepdef)
25
+ @definition = stepdef
26
+ stepdef.steps << self
27
+ end
28
+
29
+ def transformed?
30
+ !@transforms.empty?
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,27 @@
1
+
2
+
3
+ module YARD::CodeObjects::Cucumber
4
+
5
+ class Tag < NamespaceObject
6
+
7
+ attr_accessor :value, :owners
8
+
9
+ def features
10
+ @owners.find_all{|owner| owner.is_a?(Feature) }
11
+ end
12
+
13
+ def scenarios
14
+ @owners.find_all{|owner| owner.is_a?(Scenario) || owner.is_a?(ScenarioOutline) }
15
+ end
16
+
17
+ def indirect_scenarios
18
+ @owners.find_all{|owner| owner.is_a?(Feature) }.collect {|feature| feature.scenarios }.flatten
19
+ end
20
+
21
+ def all_scenarios
22
+ scenarios + indirect_scenarios
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,7 @@
1
+
2
+
3
+ module YARD::CodeObjects
4
+
5
+ class StepDefinitionObject < StepTransformerObject ; end
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+
3
+ module YARD::CodeObjects
4
+
5
+ class StepTransformObject < StepTransformerObject ; end
6
+
7
+ end
@@ -0,0 +1,51 @@
1
+
2
+ module YARD::CodeObjects
3
+
4
+ class StepTransformerObject < Base
5
+
6
+ include Cucumber::LocationHelper
7
+
8
+ attr_reader :constants, :keyword, :source, :value, :literal_value
9
+ attr_accessor :steps
10
+
11
+ ESCAPE_PATTERN = /#\{\s*(\w+)\s*\}/ unless defined?(ESCAPE_PATTERN)
12
+
13
+ def value=(value)
14
+ @literal_value = format_source(value)
15
+ @value = format_source(value)
16
+
17
+ until (nested = constants_from_value).empty?
18
+ nested.each {|n| @value.gsub!(value_regex(n),find_value_for_constant(n)) }
19
+ end
20
+
21
+ @steps = []
22
+ end
23
+
24
+ def regex
25
+ @regex ||= /#{strip_regex_from(@value)}/
26
+ end
27
+
28
+ def constants_from_value(data=@value)
29
+ data.scan(ESCAPE_PATTERN).flatten.collect { |value| value.strip }
30
+ end
31
+
32
+ protected
33
+
34
+ def find_value_for_constant(name)
35
+ constant = YARD::Registry.all(:constant).find{|c| c.name == name.to_sym }
36
+ log.warn "StepTransformer#find_value_for_constant : Could not find the CONSTANT [#{name}] using the string value." unless constant
37
+ constant ? strip_regex_from(constant.value) : name
38
+ end
39
+
40
+ def value_regex(value)
41
+ /#\{\s*#{value}\s*\}/
42
+ end
43
+
44
+ def strip_regex_from(value)
45
+ value.gsub(/^\/|\/$/,'')
46
+ end
47
+
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,22 @@
1
+ module YARD
2
+ module Handlers
3
+ module Cucumber
4
+
5
+ class Base < Handlers::Base
6
+ class << self
7
+ include Parser::Cucumber
8
+ def handles?(node)
9
+ handlers.any? do |a_handler|
10
+ #log.debug "YARD::Handlers::Cucumber::Base#handles?(#{node.class})"
11
+ node.class == a_handler
12
+ end
13
+ end
14
+ include Parser::Cucumber
15
+ end
16
+
17
+ end
18
+
19
+ Processor.register_handler_namespace :feature, Cucumber
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,93 @@
1
+ module YARD
2
+ module Handlers
3
+ module Cucumber
4
+ class FeatureHandler < Base
5
+
6
+ handles CodeObjects::Cucumber::Feature
7
+
8
+ @@step_definitions = nil
9
+ @@step_transforms = nil
10
+
11
+ def process
12
+
13
+ # Create a cache of all of the step definitions and the step transforms
14
+ @@step_definitions = cache(:stepdefinition) unless @@step_definitions
15
+ @@step_transforms = cache(:steptransform) unless @@step_transforms
16
+
17
+ if statement
18
+ # For the background and the scenario, find the steps that have definitions
19
+ process_scenario(statement.background) if statement.background
20
+
21
+ statement.scenarios.each do |scenario|
22
+ if scenario.outline?
23
+ #log.info "Scenario Outline: #{scenario.value}"
24
+ scenario.scenarios.each_with_index do |example,index|
25
+ #log.info " * Processing Example #{index + 1}"
26
+ process_scenario(example)
27
+ end
28
+ else
29
+ process_scenario(scenario)
30
+ end
31
+ end
32
+
33
+
34
+ else
35
+ log.warn "Empty feature file. A feature failed to process correctly or contains no feature"
36
+ end
37
+
38
+ rescue YARD::Handlers::NamespaceMissingError
39
+ rescue Exception => exception
40
+ log.error "Skipping feature because an error has occurred."
41
+ log.debug "\n#{exception}\n#{exception.backtrace.join("\n")}\n"
42
+ end
43
+
44
+ #
45
+ # Store all comparable items with their compare_value as the key and the item as the value
46
+ # - Reject any compare values that contain escapes #{} as that means they have unpacked constants
47
+ #
48
+ def cache(type)
49
+ YARD::Registry.all(type).inject({}) do |hash,item|
50
+ hash[item.regex] = item if item.regex
51
+ hash
52
+ end
53
+ end
54
+
55
+
56
+ def process_scenario(scenario)
57
+ scenario.steps.each {|step| process_step(step) }
58
+ end
59
+
60
+ def process_step(step)
61
+ match_step_to_step_definition_and_transforms(step)
62
+
63
+ end
64
+
65
+ def match_step_to_step_definition_and_transforms(step)
66
+ @@step_definitions.each_pair do |stepdef,stepdef_object|
67
+ stepdef_matches = step.value.match(stepdef)
68
+
69
+ if stepdef_matches
70
+ step.definition = stepdef_object
71
+ stepdef_matches[-1..1].each do |match|
72
+ @@step_transforms.each do |steptrans,steptransform_object|
73
+ if steptrans.match(match)
74
+ step.transforms << steptransform_object
75
+ steptransform_object.steps << step
76
+ end
77
+ end
78
+ end
79
+
80
+ # Step has been matched to step definition and step transforms
81
+ # TODO: If the step were to match again then we would be able to display ambigous step definitions
82
+ break
83
+
84
+ end
85
+
86
+ end
87
+
88
+
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,46 @@
1
+ class YARD::Handlers::Ruby::Legacy::StepDefinitionHandler < YARD::Handlers::Ruby::Legacy::Base
2
+ #TODO: This needs to become language independent.
3
+ STEP_DEFINITION_MATCH = /^((When|Given|And|Then)\s*(\/.+\/)\s+do(?:\s*\|.+\|)?\s*)$/ unless defined?(STEP_DEFINITION_MATCH)
4
+ handles STEP_DEFINITION_MATCH
5
+
6
+ @@unique_name = 0
7
+
8
+ def process
9
+ keyword = statement.tokens.to_s[STEP_DEFINITION_MATCH,2]
10
+ step_definition = statement.tokens.to_s[STEP_DEFINITION_MATCH,3]
11
+
12
+ @@unique_name = @@unique_name + 1
13
+
14
+ stepdef_instance = StepDefinitionObject.new(YARD::CodeObjects::Cucumber::CUCUMBER_STEPTRANSFORM_NAMESPACE, "definition_#{@@unique_name}") do |o|
15
+ o.source = "#{keyword} #{step_definition} do #{statement.block.to_s =~ /^\s*\|.+/ ? '' : "\n "}#{statement.block.to_s}\nend"
16
+ o.value = step_definition
17
+ o.keyword = keyword
18
+ end
19
+
20
+ obj = register stepdef_instance
21
+ parse_block :owner => obj
22
+
23
+ rescue YARD::Handlers::NamespaceMissingError
24
+ end
25
+
26
+ #
27
+ # Step Definitions can contain defined steps within them. While it is likely that they could not
28
+ # very easily be parsed because of variables that are only calculated at runtime, it would be nice
29
+ # to at least list those in use within a step definition and if you can find a match, go ahead and
30
+ # make it
31
+ #
32
+ def find_steps_defined_in_block(block)
33
+ #log.debug "#{block} #{block.class}"
34
+ block.each_with_index do |token,index|
35
+ #log.debug "Token #{token.class} #{token.text}"
36
+ if token.is_a?(YARD::Parser::Ruby::Legacy::RubyToken::TkCONSTANT) &&
37
+ token.text =~ /^(given|when|then|and)$/i &&
38
+ block[index + 2].is_a?(YARD::Parser::Ruby::Legacy::RubyToken::TkSTRING)
39
+ log.debug "Step found in Step Definition: #{block[index + 2].text} "
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ end