yard-cucumber2 2.3.3

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 (93) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.rspec +3 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +5 -0
  7. data/Gemfile.lock +37 -0
  8. data/History.txt +274 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +188 -0
  11. data/Rakefile +25 -0
  12. data/example/README.md +8 -0
  13. data/example/child_feature/README.md +21 -0
  14. data/example/child_feature/child.feature +11 -0
  15. data/example/child_feature/grandchild_feature/grandchild.feature +12 -0
  16. data/example/empty.feature +2 -0
  17. data/example/french.feature +18 -0
  18. data/example/scenario.feature +63 -0
  19. data/example/scenario_outline.feature +94 -0
  20. data/example/scenario_outline_multi.feature +15 -0
  21. data/example/step_definitions/example.step.rb +109 -0
  22. data/example/step_definitions/first.step.rb +21 -0
  23. data/example/step_definitions/french_steps.rb +32 -0
  24. data/example/step_definitions/struct.rb +11 -0
  25. data/example/step_definitions/support/env.rb +7 -0
  26. data/example/step_definitions/support/env_support.rb +12 -0
  27. data/example/step_definitions/support/support.rb +6 -0
  28. data/example/tags.feature +18 -0
  29. data/example/transform.feature +13 -0
  30. data/lib/cucumber/city_builder.rb +331 -0
  31. data/lib/docserver/default/fulldoc/html/js/cucumber.js +85 -0
  32. data/lib/docserver/default/layout/html/headers.erb +14 -0
  33. data/lib/docserver/doc_server/full_list/html/full_list.erb +39 -0
  34. data/lib/docserver/doc_server/full_list/html/setup.rb +18 -0
  35. data/lib/templates/default/feature/html/feature.erb +39 -0
  36. data/lib/templates/default/feature/html/no_steps_defined.erb +1 -0
  37. data/lib/templates/default/feature/html/outline.erb +56 -0
  38. data/lib/templates/default/feature/html/pystring.erb +3 -0
  39. data/lib/templates/default/feature/html/scenario.erb +55 -0
  40. data/lib/templates/default/feature/html/setup.rb +55 -0
  41. data/lib/templates/default/feature/html/steps.erb +39 -0
  42. data/lib/templates/default/feature/html/table.erb +20 -0
  43. data/lib/templates/default/featuredirectory/html/alpha_table.erb +30 -0
  44. data/lib/templates/default/featuredirectory/html/directory.erb +32 -0
  45. data/lib/templates/default/featuredirectory/html/setup.rb +41 -0
  46. data/lib/templates/default/featuretags/html/namespace.erb +131 -0
  47. data/lib/templates/default/featuretags/html/setup.rb +34 -0
  48. data/lib/templates/default/fulldoc/html/css/cucumber.css +227 -0
  49. data/lib/templates/default/fulldoc/html/directories.erb +53 -0
  50. data/lib/templates/default/fulldoc/html/full_list_featuredirectories.erb +11 -0
  51. data/lib/templates/default/fulldoc/html/full_list_features.erb +29 -0
  52. data/lib/templates/default/fulldoc/html/full_list_stepdefinitions.erb +16 -0
  53. data/lib/templates/default/fulldoc/html/full_list_steps.erb +17 -0
  54. data/lib/templates/default/fulldoc/html/full_list_tags.erb +12 -0
  55. data/lib/templates/default/fulldoc/html/js/cucumber.js +305 -0
  56. data/lib/templates/default/fulldoc/html/setup.rb +175 -0
  57. data/lib/templates/default/layout/html/setup.rb +56 -0
  58. data/lib/templates/default/requirements/html/alpha_table.erb +26 -0
  59. data/lib/templates/default/requirements/html/requirements.erb +50 -0
  60. data/lib/templates/default/requirements/html/setup.rb +51 -0
  61. data/lib/templates/default/steptransformers/html/header.erb +12 -0
  62. data/lib/templates/default/steptransformers/html/index.erb +10 -0
  63. data/lib/templates/default/steptransformers/html/setup.rb +94 -0
  64. data/lib/templates/default/steptransformers/html/transformers.erb +79 -0
  65. data/lib/templates/default/steptransformers/html/undefinedsteps.erb +26 -0
  66. data/lib/templates/default/tag/html/alpha_table.erb +32 -0
  67. data/lib/templates/default/tag/html/setup.rb +27 -0
  68. data/lib/templates/default/tag/html/tag.erb +35 -0
  69. data/lib/yard-cucumber.rb +47 -0
  70. data/lib/yard-cucumber/version.rb +3 -0
  71. data/lib/yard/code_objects/cucumber/base.rb +32 -0
  72. data/lib/yard/code_objects/cucumber/feature.rb +18 -0
  73. data/lib/yard/code_objects/cucumber/namespace_object.rb +49 -0
  74. data/lib/yard/code_objects/cucumber/scenario.rb +26 -0
  75. data/lib/yard/code_objects/cucumber/scenario_outline.rb +75 -0
  76. data/lib/yard/code_objects/cucumber/step.rb +38 -0
  77. data/lib/yard/code_objects/cucumber/tag.rb +27 -0
  78. data/lib/yard/code_objects/step_definition.rb +7 -0
  79. data/lib/yard/code_objects/step_transform.rb +7 -0
  80. data/lib/yard/code_objects/step_transformer.rb +97 -0
  81. data/lib/yard/handlers/cucumber/base.rb +21 -0
  82. data/lib/yard/handlers/cucumber/feature_handler.rb +131 -0
  83. data/lib/yard/handlers/legacy/step_definition_handler.rb +45 -0
  84. data/lib/yard/handlers/legacy/step_transform_handler.rb +24 -0
  85. data/lib/yard/handlers/step_definition_handler.rb +86 -0
  86. data/lib/yard/handlers/step_transform_handler.rb +31 -0
  87. data/lib/yard/parser/cucumber/feature.rb +73 -0
  88. data/lib/yard/server/adapter.rb +43 -0
  89. data/lib/yard/server/commands/list_command.rb +31 -0
  90. data/lib/yard/server/router.rb +32 -0
  91. data/lib/yard/templates/helpers/base_helper.rb +26 -0
  92. data/yard-cucumber.gemspec +65 -0
  93. metadata +199 -0
@@ -0,0 +1,21 @@
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
+ end
17
+
18
+ Processor.register_handler_namespace :feature, Cucumber
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,131 @@
1
+ module YARD
2
+ module Handlers
3
+ module Cucumber
4
+ class FeatureHandler < Base
5
+
6
+ handles CodeObjects::Cucumber::Feature
7
+
8
+ def process
9
+ #
10
+ # Features have already been created when they were parsed. So there
11
+ # is no need to process the feature further. Previously this is where
12
+ # feature steps were matched to step definitions and step definitions
13
+ # were matched to step transforms. This only worked if the feature
14
+ # files were were assured to be processed last which was accomplished
15
+ # by overriding YARD::SourceParser to make it load file in a similar
16
+ # order as Cucumber.
17
+ #
18
+ # As of YARD 0.7.0 this is no longer necessary as there are callbacks
19
+ # that can be registered after all the files have been loaded. That
20
+ # callback _after_parse_list_ is defined below and performs the
21
+ # functionality described above.
22
+ #
23
+ end
24
+
25
+ #
26
+ # Register, once, when that when all files are finished to perform
27
+ # the final matching of feature steps to step definitions and step
28
+ # definitions to step transforms.
29
+ #
30
+ YARD::Parser::SourceParser.after_parse_list do |files,globals|
31
+ # For every feature found in the Registry, find their steps and step
32
+ # definitions...
33
+ YARD::Registry.all(:feature).each do |feature|
34
+ log.debug "Finding #{feature.file} - steps, step definitions, and step transforms"
35
+ FeatureHandler.match_steps_to_step_definitions(feature)
36
+ end
37
+
38
+ end
39
+
40
+ class << self
41
+
42
+ @@step_definitions = nil
43
+ @@step_transforms = nil
44
+
45
+ def match_steps_to_step_definitions(statement)
46
+ # Create a cache of all of the step definitions and the step transforms
47
+ @@step_definitions = cache(:stepdefinition) unless @@step_definitions
48
+ @@step_transforms = cache(:steptransform) unless @@step_transforms
49
+
50
+ if statement
51
+ # For the background and the scenario, find the steps that have definitions
52
+ process_scenario(statement.background) if statement.background
53
+
54
+ statement.scenarios.each do |scenario|
55
+ if scenario.outline?
56
+ #log.info "Scenario Outline: #{scenario.value}"
57
+ scenario.scenarios.each_with_index do |example,index|
58
+ #log.info " * Processing Example #{index + 1}"
59
+ process_scenario(example)
60
+ end
61
+ else
62
+ process_scenario(scenario)
63
+ end
64
+ end
65
+
66
+
67
+ else
68
+ log.warn "Empty feature file. A feature failed to process correctly or contains no feature"
69
+ end
70
+
71
+ rescue YARD::Handlers::NamespaceMissingError
72
+ rescue Exception => exception
73
+ log.error "Skipping feature because an error has occurred."
74
+ log.debug "\n#{exception}\n#{exception.backtrace.join("\n")}\n"
75
+ end
76
+
77
+ #
78
+ # Store all comparable items with their compare_value as the key and the item as the value
79
+ # - Reject any compare values that contain escapes #{} as that means they have unpacked constants
80
+ #
81
+ def cache(type)
82
+ YARD::Registry.all(type).inject({}) do |hash,item|
83
+ hash[item.regex] = item if item.regex
84
+ hash
85
+ end
86
+ end
87
+
88
+ # process a scenario
89
+ def process_scenario(scenario)
90
+ scenario.steps.each {|step| process_step(step) }
91
+ end
92
+
93
+ # process a step
94
+ def process_step(step)
95
+ match_step_to_step_definition_and_transforms(step)
96
+ end
97
+
98
+ #
99
+ # Given a step object, attempt to match that step to a step
100
+ # transformation
101
+ #
102
+ def match_step_to_step_definition_and_transforms(step)
103
+ @@step_definitions.each_pair do |stepdef,stepdef_object|
104
+ stepdef_matches = step.value.match(stepdef)
105
+
106
+ if stepdef_matches
107
+ step.definition = stepdef_object
108
+ stepdef_matches[-1..1].each do |match|
109
+ @@step_transforms.each do |steptrans,steptransform_object|
110
+ if steptrans.match(match)
111
+ step.transforms << steptransform_object
112
+ steptransform_object.steps << step
113
+ end
114
+ end
115
+ end
116
+
117
+ # Step has been matched to step definition and step transforms
118
+ # TODO: If the step were to match again then we would be able to display ambigous step definitions
119
+ break
120
+
121
+ end
122
+
123
+ end
124
+
125
+ end
126
+
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,45 @@
1
+ class YARD::Handlers::Ruby::Legacy::StepDefinitionHandler < YARD::Handlers::Ruby::Legacy::Base
2
+ STEP_DEFINITION_MATCH = /^((When|Given|And|Then)\s*(\/.+\/)\s+do(?:\s*\|.+\|)?\s*)$/ unless defined?(STEP_DEFINITION_MATCH)
3
+ handles STEP_DEFINITION_MATCH
4
+
5
+ @@unique_name = 0
6
+
7
+ def process
8
+ keyword = statement.tokens.to_s[STEP_DEFINITION_MATCH,2]
9
+ step_definition = statement.tokens.to_s[STEP_DEFINITION_MATCH,3]
10
+
11
+ @@unique_name = @@unique_name + 1
12
+
13
+ stepdef_instance = StepDefinitionObject.new(YARD::CodeObjects::Cucumber::CUCUMBER_STEPTRANSFORM_NAMESPACE, "definition_#{@@unique_name}") do |o|
14
+ o.source = "#{keyword} #{step_definition} do #{statement.block.to_s =~ /^\s*\|.+/ ? '' : "\n "}#{statement.block.to_s}\nend"
15
+ o.value = step_definition
16
+ o.keyword = keyword
17
+ end
18
+
19
+ obj = register stepdef_instance
20
+ parse_block :owner => obj
21
+
22
+ rescue YARD::Handlers::NamespaceMissingError
23
+ end
24
+
25
+ #
26
+ # Step Definitions can contain defined steps within them. While it is likely that they could not
27
+ # very easily be parsed because of variables that are only calculated at runtime, it would be nice
28
+ # to at least list those in use within a step definition and if you can find a match, go ahead and
29
+ # make it
30
+ #
31
+ def find_steps_defined_in_block(block)
32
+ #log.debug "#{block} #{block.class}"
33
+ block.each_with_index do |token,index|
34
+ #log.debug "Token #{token.class} #{token.text}"
35
+ if token.is_a?(YARD::Parser::Ruby::Legacy::RubyToken::TkCONSTANT) &&
36
+ token.text =~ /^(given|when|then|and)$/i &&
37
+ block[index + 2].is_a?(YARD::Parser::Ruby::Legacy::RubyToken::TkSTRING)
38
+ log.debug "Step found in Step Definition: #{block[index + 2].text} "
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,24 @@
1
+ class YARD::Handlers::Ruby::Legacy::StepTransformHandler < YARD::Handlers::Ruby::Legacy::Base
2
+ STEP_TRANSFORM_MATCH = /^(Transform\s*(\/.+\/)\s+do(?:\s*\|.+\|)?\s*)$/ unless defined?(STEP_TRANSFORM_MATCH)
3
+ handles STEP_TRANSFORM_MATCH
4
+
5
+ @@unique_name = 0
6
+
7
+ def process
8
+ transform = statement.tokens.to_s[STEP_TRANSFORM_MATCH,2]
9
+ @@unique_name = @@unique_name + 1
10
+
11
+ instance = StepTransformObject.new(YARD::CodeObjects::Cucumber::CUCUMBER_STEPTRANSFORM_NAMESPACE, "transform_#{@@unique_name}") do |o|
12
+ o.source = "Transform #{transform} do #{statement.block.to_s}\nend"
13
+ o.value = transform
14
+ o.keyword = "Transform"
15
+ end
16
+
17
+ obj = register instance
18
+ parse_block :owner => obj
19
+
20
+ rescue YARD::Handlers::NamespaceMissingError
21
+ end
22
+
23
+ end
24
+
@@ -0,0 +1,86 @@
1
+ #
2
+ # Finds and processes all the step definitions defined in the ruby source
3
+ # code. By default the english gherkin language will be parsed.
4
+ #
5
+ # To override the language you can define the step definitions in the YARD
6
+ # configuration file `~./yard/config`:
7
+ #
8
+ # @example `~/.yard/config` with LOLCatz step definitions
9
+ #
10
+ # :"yard-cucumber":
11
+ # language:
12
+ # step_definitions: [ 'WEN', 'I CAN HAZ', 'AN', 'DEN' ]
13
+ #
14
+ # @example `~/.yard/config` with French step definitions
15
+ #
16
+ # :"yard-cucumber":
17
+ # language:
18
+ # step_definitions: [ 'Soit', 'Etantdonné', 'Lorsque', 'Lorsqu', 'Alors', 'Et' ]
19
+ #
20
+ class YARD::Handlers::Ruby::StepDefinitionHandler < YARD::Handlers::Ruby::Base
21
+
22
+ def self.default_step_definitions
23
+ [ "When", "Given", "And", "Then" ]
24
+ end
25
+
26
+ def self.custom_step_definitions
27
+ YARD::Config.options["yard-cucumber"]["language"]["step_definitions"]
28
+ end
29
+
30
+ def self.custom_step_definitions_defined?
31
+ YARD::Config.options["yard-cucumber"] and
32
+ YARD::Config.options["yard-cucumber"]["language"] and
33
+ YARD::Config.options["yard-cucumber"]["language"]["step_definitions"]
34
+ end
35
+
36
+ def self.step_definitions
37
+ if custom_step_definitions_defined?
38
+ custom_step_definitions
39
+ else
40
+ default_step_definitions
41
+ end
42
+ end
43
+
44
+ step_definitions.each { |step_def| handles method_call(step_def) }
45
+
46
+ process do
47
+
48
+ instance = YARD::CodeObjects::StepDefinitionObject.new(step_transform_namespace,step_definition_name) do |o|
49
+ o.source = statement.source
50
+ o.comments = statement.comments
51
+ o.keyword = statement.method_name.source
52
+ o.value = statement.parameters.source
53
+ o.pending = pending_keyword_used?(statement.block)
54
+ end
55
+
56
+ obj = register instance
57
+ parse_block(statement[2],:owner => obj)
58
+
59
+ end
60
+
61
+ def pending_keyword
62
+ "pending"
63
+ end
64
+
65
+ def pending_command_statement?(line)
66
+ (line.type == :command || line.type == :vcall) && line.first.source == pending_keyword
67
+ end
68
+
69
+ def pending_keyword_used?(block)
70
+ code_in_block = block.last
71
+ code_in_block.find { |line| pending_command_statement?(line) }
72
+ end
73
+
74
+ def step_transform_namespace
75
+ YARD::CodeObjects::Cucumber::CUCUMBER_STEPTRANSFORM_NAMESPACE
76
+ end
77
+
78
+ def step_definition_name
79
+ "step_definition#{self.class.generate_unique_id}"
80
+ end
81
+
82
+ def self.generate_unique_id
83
+ @step_definition_count = @step_definition_count.to_i + 1
84
+ end
85
+
86
+ end
@@ -0,0 +1,31 @@
1
+
2
+ class YARD::Handlers::Ruby::StepTransformHandler < YARD::Handlers::Ruby::Base
3
+ handles method_call(:Transform)
4
+
5
+ process do
6
+
7
+ instance = YARD::CodeObjects::StepTransformObject.new(step_transform_namespace,step_transformer_name) do |o|
8
+ o.source = statement.source
9
+ o.comments = statement.comments
10
+ o.keyword = statement[0].source
11
+ o.value = statement[1].source
12
+ end
13
+
14
+ obj = register instance
15
+ parse_block(statement[2],:owner => obj)
16
+
17
+ end
18
+
19
+ def step_transform_namespace
20
+ YARD::CodeObjects::Cucumber::CUCUMBER_STEPTRANSFORM_NAMESPACE
21
+ end
22
+
23
+ def step_transformer_name
24
+ "step_transform#{self.class.generate_unique_id}"
25
+ end
26
+
27
+ def self.generate_unique_id
28
+ @step_transformer_count = @step_transformer_count.to_i + 1
29
+ end
30
+
31
+ end
@@ -0,0 +1,73 @@
1
+ module YARD::Parser::Cucumber
2
+
3
+ class FeatureParser < YARD::Parser::Base
4
+
5
+ #
6
+ # Each found feature found is creates a new FeatureParser
7
+ #
8
+ # This logic was copied from the logic found in Cucumber to create the builder
9
+ # and then set up the formatter and parser. The difference is really the
10
+ # custom Cucumber::Parser::CityBuilder that is being used to parse the elements
11
+ # of the feature into YARD::CodeObjects.
12
+ #
13
+ # @param [<String>] source containing the string conents of the feauture file
14
+ # @param [<String>] file the filename that contains the source
15
+ #
16
+ def initialize(source, file = '(stdin)')
17
+
18
+ @builder = Cucumber::Parser::CityBuilder.new(file)
19
+ @tag_counts = {}
20
+ @tag_formatter = Gherkin::Formatter::TagCountFormatter.new(@builder, @tag_counts)
21
+ @parser = Gherkin::Parser::Parser.new(@tag_formatter, true, "root", false)
22
+
23
+ @source = source
24
+ @file = file
25
+
26
+ @feature = nil
27
+ end
28
+
29
+ #
30
+ # When parse is called, the gherkin parser is executed and all the feature
31
+ # elements that are found are sent to the various methods in the
32
+ # Cucumber::Parser::CityBuilder. The result of which is the feature element
33
+ # that contains all the scenarios, steps, etc. associated with that feature.
34
+ #
35
+ # @see Cucumber::Parser::CityBuilder
36
+ def parse
37
+ begin
38
+ @parser.parse(@source, @file, 0)
39
+ @feature = @builder.ast
40
+ return nil if @feature.nil? # Nothing matched
41
+
42
+ # The parser used the following keywords when parsing the feature
43
+ # @feature.language = @parser.i18n_language.get_code_keywords.map {|word| word }
44
+
45
+ rescue Gherkin::Lexer::LexingError, Gherkin::Parser::ParseError => e
46
+ e.message.insert(0, "#{@file}: ")
47
+ raise e
48
+ end
49
+
50
+ self
51
+ end
52
+
53
+ #
54
+ # This is not used as all the work is done in the parse method
55
+ #
56
+ def tokenize
57
+
58
+ end
59
+
60
+ #
61
+ # The only enumeration that can be done here is returning the feature itself
62
+ #
63
+ def enumerator
64
+ [@feature]
65
+ end
66
+
67
+ end
68
+
69
+ #
70
+ # Register all feature files (.feature) to be processed with the above FeatureParser
71
+ YARD::Parser::SourceParser.register_parser_type :feature, FeatureParser, 'feature'
72
+
73
+ end
@@ -0,0 +1,43 @@
1
+ module YARD
2
+ module Server
3
+
4
+ class Adapter
5
+
6
+ class << self
7
+
8
+ alias_method :yard_setup, :setup
9
+
10
+ #
11
+ # To provide the templates necessary for `yard-cucumber` to integrate
12
+ # with YARD the adapter has to around-alias the setup method to place
13
+ # the `yard-cucumber` server templates as the last template in the list.
14
+ #
15
+ # When they are normally loaded with the plugin they cause an error with
16
+ # the `yardoc` command. They are also not used because the YARD server
17
+ # templates are placed after all plugin templates.
18
+ #
19
+ def setup
20
+ yard_setup
21
+ YARD::Templates::Engine.template_paths +=
22
+ [File.dirname(__FILE__) + '/../../templates',File.dirname(__FILE__) + '/../../docserver']
23
+ end
24
+
25
+ alias_method :yard_shutdown, :shutdown
26
+
27
+ #
28
+ # Similar to the addition, it is good business to tear down the templates
29
+ # that were added by again around-aliasing the shutdown method.
30
+ #
31
+ def shutdown
32
+ yard_shutdown
33
+ YARD::Templates::Engine.template_paths -=
34
+ [File.dirname(__FILE__) + '/../../templates',File.dirname(__FILE__) + '/../../docserver']
35
+ end
36
+
37
+ end
38
+
39
+
40
+ end
41
+
42
+ end
43
+ end