cucumber-in-the-yard 1.5.3 → 1.5.4

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.
data/.autotest ADDED
@@ -0,0 +1,15 @@
1
+ require 'autotest/growl'
2
+
3
+ Autotest.add_hook :initialize do |at|
4
+ #%w{ features definitions common browser jmx }.each {|exception| at.add_exception(exception)}
5
+ end
6
+
7
+ # Overrides to include the required folders to make this project autotestable
8
+ # This is because requires cannot exist within the options file
9
+ class Autotest::Rspec < Autotest
10
+ def make_test_cmd(files_to_test)
11
+ files_to_test.empty? ? '' :
12
+ "#{ruby} #{SPEC_PROGRAM} -r lib/city.rb --color --autospec #{normalize(files_to_test).keys.flatten.join(' ')} #{add_options_if_present}"
13
+ end
14
+ end
15
+
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ # /.rspec
2
+ --format d
3
+ --color
data/History.txt CHANGED
@@ -1,3 +1,14 @@
1
+ === 1.5.4 / 2010-10-28
2
+
3
+ * Optimization - Found that for a large test suite that the processing time was
4
+ approaching 2 hours (oh boy!). Reduced that time to a few minutes by optimizing
5
+ the feature handler to cache all step definitions and step transforms.
6
+
7
+ * Step Transforms will now attempt to unpack any constants found within them.
8
+ * FIX - Step Transforms were not being parsed because the regex incorrectly included
9
+ the block.
10
+ * FIX - Features and Scenarios with multiple tags were not being displayed
11
+
1
12
  === 1.5.3 / 2010-10-26
2
13
 
3
14
  * FIX - Step Definition YARD handler regex was poorly formed and raised exceptions
data/Rakefile CHANGED
@@ -1,22 +1,9 @@
1
1
  require 'rake'
2
- require 'echoe'
3
2
 
4
3
  task :default => :gendoc
5
4
 
6
5
  task :gendoc do
7
6
  `rm -rf doc`
8
- `yardoc -e lib/city.rb -p lib/templates 'example/**/*' --debug`
9
- end
10
-
11
- Echoe.new('cucumber-in-the-yard', '1.5.3') do |g|
12
- g.author = "Franklin Webber"
13
- g.email = "franklin.webber@gmail.com"
14
- g.url = "http://github.com/burtlo/Cucumber-In-The-Yard"
15
- g.description = %{
16
- Cucumber-In-The-Yard is a YARD extension that processes Cucumber Features, Scenarios, Steps,
17
- Step Definitions, Transforms, and Tags and provides a documentation interface that allows you
18
- easily view and investigate the test suite. This tools hopes to bridge the gap of being able
19
- to provide your feature descriptions to your Product Owners and Stakeholders. }
20
- g.ignore_pattern = FileList["{doc,pkg,spec,features,nbproject,autotest}/**/*"].to_a
21
- g.runtime_dependencies = [ "cucumber >=0.7.5", "yard >=0.6.1" ]
22
- end
7
+ `rm -rf .yardoc`
8
+ `yardoc -e lib/city.rb -p lib/templates 'example/**/*.*' --debug`
9
+ end
@@ -0,0 +1,3 @@
1
+ #./autotest/discover.rb
2
+
3
+ Autotest.add_discovery { "rspec2" }
data/city.gemspec ADDED
@@ -0,0 +1,66 @@
1
+ require File.dirname(__FILE__) + "/lib/city"
2
+
3
+ module CucumberInTheYARD
4
+
5
+ def self.show_version_changes(version)
6
+ date = ""
7
+ changes = []
8
+ grab_changes = false
9
+
10
+ File.open("#{File.dirname(__FILE__)}/History.txt",'r') do |file|
11
+ while (line = file.gets) do
12
+
13
+ if line =~ /^===\s*#{version.gsub('.','\.')}\s*\/\s*(.+)\s*$/
14
+ grab_changes = true
15
+ date = $1.strip
16
+ elsif line =~ /^===\s*.+$/
17
+ grab_changes = false
18
+ elsif grab_changes
19
+ changes = changes << line
20
+ end
21
+
22
+ end
23
+ end
24
+
25
+ { :date => date, :changes => changes }
26
+ end
27
+ end
28
+
29
+ Gem::Specification.new do |s|
30
+ s.name = 'cucumber-in-the-yard'
31
+ s.version = ::CucumberInTheYARD::VERSION
32
+ s.authors = ["Franklin Webber"]
33
+ s.description = %{
34
+ Cucumber-In-The-Yard is a YARD extension that processes Cucumber Features, Scenarios, Steps,
35
+ Step Definitions, Transforms, and Tags and provides a documentation interface that allows you
36
+ easily view and investigate the test suite. This tools hopes to bridge the gap of being able
37
+ to provide your feature descriptions to your Product Owners and Stakeholders. }
38
+ s.summary = "Cucumber Features in YARD"
39
+ s.email = 'franklin.webber@gmail.com'
40
+ s.homepage = "http://github.com/burtlo/Cucumber-In-The-Yard"
41
+
42
+ s.platform = Gem::Platform::RUBY
43
+
44
+ changes = CucumberInTheYARD.show_version_changes(::CucumberInTheYARD::VERSION)
45
+
46
+ s.post_install_message = %{
47
+ (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
48
+
49
+ Thank you for installing Cucumber-In-The-YARD #{::CucumberInTheYARD::VERSION} / #{changes[:date]}.
50
+
51
+ Changes:
52
+ #{changes[:changes].collect{|change| " #{change}"}.join("")}
53
+ (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
54
+
55
+ }
56
+
57
+ s.add_dependency 'gherkin', '>= 2.2.9'
58
+ s.add_dependency 'cucumber', '>= 0.7.5'
59
+ s.add_dependency 'yard', '>= 0.6.1'
60
+
61
+ s.rubygems_version = "1.3.7"
62
+ s.files = `git ls-files`.split("\n")
63
+ s.extra_rdoc_files = ["README.md", "History.txt"]
64
+ s.rdoc_options = ["--charset=UTF-8"]
65
+ s.require_path = "lib"
66
+ end
@@ -0,0 +1,19 @@
1
+ @feature @bvt
2
+ Feature: Feature File
3
+ As a product owner it is important for me to be able to view a feature file through
4
+ an interface which is easily accessible. A feature's description appears along side
5
+ the comments for the feature.
6
+
7
+ Background:
8
+ Given this first background step
9
+
10
+ @bvt
11
+ Scenario: First Scenario
12
+ Given this first scenario step
13
+ When this is parsed with Cucumber-In-The-YARD
14
+ Then I expect that each step is highlighted and matched to a step definition
15
+
16
+ Scenario: Second Scenario
17
+ Given this first scenario step
18
+ When this is parsed with Cucumber-In-The-YARD
19
+ Then I expect that this scenario is present
@@ -5,7 +5,7 @@ Feature: Customer Logout Feature
5
5
  Background:
6
6
  Given this undefined step definition
7
7
 
8
- @bvt
8
+ @bvt @param2 @param3
9
9
  Scenario: Customer that is logged in is able to log out
10
10
  Given that a customer is a valid customer
11
11
  And a customer logs in as username 'frank' with password 'default'
@@ -10,6 +10,11 @@ Transform /^the customer$/ do |customer|
10
10
  "the transformed customer"
11
11
  end
12
12
 
13
+ Transform /^#{TEDDY_BEAR}$/ do |teddy|
14
+ "the tranformed teddy bear"
15
+ end
16
+
17
+
13
18
  Transform /^((?:\d{1,2}[\/-]){2}(?:\d\d){1,2})?\s*(\w{3})?\s*(\d{1,2}:\d{2}\s*(?:AM|PM)?)$/ do |date,day,time|
14
19
  "#{date} #{day} #{time}"
15
20
  end
data/lib/city.rb CHANGED
@@ -5,6 +5,11 @@ require 'gherkin/formatter/tag_count_formatter'
5
5
 
6
6
  require 'yard'
7
7
 
8
+ module CucumberInTheYARD
9
+ VERSION = '1.5.4' unless defined?(CucumberInTheYARD::VERSION)
10
+ end
11
+
12
+
8
13
  require File.dirname(__FILE__) + "/yard/code_objects/cucumber/base.rb"
9
14
  require File.dirname(__FILE__) + "/yard/code_objects/cucumber/namespace_object.rb"
10
15
  require File.dirname(__FILE__) + "/yard/code_objects/cucumber/feature.rb"
@@ -27,7 +27,7 @@ module Cucumber
27
27
 
28
28
  tag_code_object.add_file(@file,parent.line)
29
29
 
30
- parent.tags << tag_code_object unless parent.tags.find {|tag| tag_code_object }
30
+ parent.tags << tag_code_object unless parent.tags.find {|tag| tag == tag_code_object }
31
31
  tag_code_object.owners << parent unless tag_code_object.owners.find {|owner| owner == parent}
32
32
  end
33
33
 
@@ -12,8 +12,8 @@ def stepdefinitions
12
12
  end
13
13
 
14
14
  def steptransforms
15
- @item_title = "Step Transformers"
16
- @item_type = "step transformer"
15
+ @item_title = "Step Transforms"
16
+ @item_type = "step transform"
17
17
  @items = YARD::Registry.all(:steptransform)
18
18
  erb(:transformers)
19
19
  end
@@ -5,8 +5,8 @@ module YARD::CodeObjects
5
5
  class StepDefinitionObject < Base
6
6
  include Cucumber::LocationHelper
7
7
 
8
- attr_reader :keyword, :value, :compare_value, :source
9
- attr_accessor :constants, :steps
8
+ attr_reader :constants, :keyword, :source, :value
9
+ attr_accessor :steps
10
10
 
11
11
  def value=(value)
12
12
  @value = format_source(value)
@@ -1,18 +1,38 @@
1
1
 
2
+
2
3
  module YARD::CodeObjects
3
4
 
4
5
  class StepTransformObject < Base
5
6
  include Cucumber::LocationHelper
6
7
 
7
- attr_reader :value
8
+ attr_reader :constants, :source, :value
9
+ attr_accessor :steps
8
10
 
9
11
  def value=(value)
10
12
  @value = format_source(value)
13
+ @constants = {}
11
14
  @steps = []
15
+ @compare_value = nil
12
16
  end
13
17
 
14
18
  def compare_value
15
- value.gsub(/^\/|\/$/,'')
19
+ unless @compare_value
20
+ @compare_value = value.gsub(/^\/|\/$/,'')
21
+ @constants.each do |name,value|
22
+ @compare_value.gsub!(/\#\{\s*#{name.to_s}\s*\}/,value.gsub(/^\/|\/$/,''))
23
+ end
24
+ end
25
+ @compare_value
26
+ end
27
+
28
+ def _value_constants(data=@value)
29
+ data.scan(/\#\{([^\}]+)\}/).flatten.collect { |value| value.strip }
30
+ end
31
+
32
+ def constants=(value)
33
+ value.each do |val|
34
+ @constants[val.name.to_s] = val if val.respond_to?(:name) && val.respond_to?(:value)
35
+ end
16
36
  end
17
37
 
18
38
  end
@@ -1,32 +1,38 @@
1
1
  module YARD
2
2
  module Handlers
3
3
  module Cucumber
4
-
5
4
  class FeatureHandler < Base
6
5
 
7
6
  handles CodeObjects::Cucumber::Feature
8
7
 
9
- def process
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
+
10
17
 
11
18
  if statement
12
- log.info "Processing Feature: #{statement.value}"
13
19
  # For the background and the scenario, find the steps that have definitions
14
20
  process_scenario(statement.background) if statement.background
15
21
 
16
-
17
22
  statement.scenarios.each do |scenario|
18
23
  if scenario.outline?
19
- log.info "Scenario Outline: #{scenario.value}"
24
+ #log.info "Scenario Outline: #{scenario.value}"
20
25
  scenario.scenarios.each_with_index do |example,index|
21
- log.info " * Processing Example #{index + 1}"
26
+ #log.info " * Processing Example #{index + 1}"
22
27
  process_scenario(example)
23
28
  end
24
29
  else
25
- log.info "Processing Scenario: #{scenario.value}"
30
+ #log.info "Processing Scenario: #{scenario.value}"
26
31
  process_scenario(scenario)
27
32
  end
28
33
  end
29
-
34
+
35
+
30
36
  else
31
37
  log.warn "Empty feature file. A feature failed to process correctly or contains no feature"
32
38
  end
@@ -37,64 +43,53 @@ module YARD
37
43
  log.debug "\n#{exception}\n#{exception.backtrace.join("\n")}\n"
38
44
  end
39
45
 
46
+ #
47
+ # Store all comparable items with their compare_value as the key and the item as the value
48
+ # - Reject any compare values that contain escapes #{} as that means they have unpacked constants
49
+ #
50
+ def cache(type)
51
+ YARD::Registry.all(type).inject({}) do |hash,item|
52
+ hash[%r{#{item.compare_value}}] = item unless item.compare_value =~ /.+\#\{[^\}]+\}.+/
53
+ hash
54
+ end
55
+ end
40
56
 
41
57
 
42
58
  def process_scenario(scenario)
43
- scenario.steps.each do |step|
44
- process_step(step)
45
- end
59
+ scenario.steps.each {|step| process_step(step) }
46
60
  end
47
61
 
48
-
49
62
  def process_step(step)
50
- step_definition = match_step_to_step_definition(step.value)
51
-
52
- if step_definition
53
- step.definition = step_definition
54
- find_transforms_for_step(step)
55
- end
56
- end
63
+ match_step_to_step_definition_and_transforms(step)
57
64
 
65
+ end
58
66
 
59
- def match_step_to_step_definition(step_value)
60
- YARD::Registry.all(:stepdefinition).each do |stepdef|
61
- #log.debug "Looking at step #{step_value} against #{stepdef}"
67
+ def match_step_to_step_definition_and_transforms(step)
68
+ @@step_definitions.each do |stepdef,stepdef_object|
62
69
 
63
- if stepdef.compare_value =~ /.+\#\{[^\}]+\}.+/
64
- log.warn "Step definition still has a unpacked constant #{stepdef.compare_value}"
65
- else
66
- return stepdef if %r{#{stepdef.compare_value}}.match(step_value)
67
- end
68
- end
70
+ stepdef_matches = step.value.match(stepdef)
69
71
 
70
- nil
71
- end
72
-
73
- def find_transforms_for_step(step)
74
- #log.debug "Looking at step #{step} for transforms"
75
-
76
- if step.definition
77
-
78
- step.value.match(%r{#{step.definition.compare_value}}).to_a.each do |match|
79
- YARD::Registry.all(:steptransform).each do |steptrans|
80
- #log.debug "Looking at transform #{steptrans.value}"
81
- if %r{#{steptrans.compare_value}}.match(match)
82
- #log.debug "Step #{step} is affected by the transform #{steptrans}"
83
- step.transforms << steptrans
84
- steptrans.steps << step
72
+ if stepdef_matches
73
+ step.definition = stepdef_object
74
+ stepdef_matches[-1..1].each do |match|
75
+ @@step_transforms.each do |steptrans,steptransform_object|
76
+ if steptrans.match(match)
77
+ step.transforms << steptransform_object
78
+ steptransform_object.steps << step
79
+ end
85
80
  end
86
81
  end
87
82
 
83
+ # Step has been matched to step definition and step transforms
84
+ break
85
+
88
86
  end
89
-
90
- end
91
-
92
- end
93
87
 
88
+ end
94
89
 
95
90
 
91
+ end
96
92
  end
97
-
98
93
  end
99
94
  end
100
95
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  class StepDefinitionHandler < YARD::Handlers::Ruby::Legacy::Base
4
4
  #TODO: This needs to become language independent.
5
- MATCH = /^((When|Given|And|Then)\s*(\/.+\/)\s+do(?:\s\|.+\|)?\s*)$/
6
- handles MATCH
5
+ STEP_DEFINITION_MATCH = /^((When|Given|And|Then)\s*(\/.+\/)\s+do(?:\s*\|.+\|)?\s*)$/
6
+ handles STEP_DEFINITION_MATCH
7
7
 
8
8
  @@unique_name = 0
9
9
 
10
10
  def process
11
- keyword = statement.tokens.to_s[MATCH,2]
12
- step_definition = statement.tokens.to_s[MATCH,3]
11
+ keyword = statement.tokens.to_s[STEP_DEFINITION_MATCH,2]
12
+ step_definition = statement.tokens.to_s[STEP_DEFINITION_MATCH,3]
13
13
 
14
14
  @@unique_name = @@unique_name + 1
15
15
 
@@ -19,12 +19,15 @@ class StepDefinitionHandler < YARD::Handlers::Ruby::Legacy::Base
19
19
  o.keyword = keyword
20
20
  end
21
21
 
22
- find_steps_defined_in_block(statement.block)
22
+ # TODO: Currently I have not devised a good way to declare them or show them
23
+ #find_steps_defined_in_block(statement.block)
23
24
 
24
25
  begin
26
+ @constants = YARD::Registry.all(:constant)
27
+
25
28
  # Look for all constants within the step definitions
26
29
  stepdef_instance._value_constants.each do |stepdef_constant|
27
- YARD::Registry.all(:constant).each do |constant|
30
+ @constants.each do |constant|
28
31
  if stepdef_constant.to_sym == constant.name
29
32
  #log.debug "Constant #{constant.name} was found in the step definition #{stepdef_instance.value}, attempting to replace that value"
30
33
  returned_constant = unpack_constants(constant.value)
@@ -39,17 +42,16 @@ class StepDefinitionHandler < YARD::Handlers::Ruby::Legacy::Base
39
42
  end
40
43
 
41
44
 
42
- obj = register stepdef_instance
43
-
44
-
45
+ obj = register stepdef_instance
45
46
  parse_block :owner => obj
47
+
46
48
  rescue YARD::Handlers::NamespaceMissingError
47
49
  end
48
50
 
49
51
 
50
52
  def unpack_constants(constant_value)
51
53
  constant_value.scan(/\#\{([^\}]+)\}/).flatten.collect { |value| value.strip }.each do |inner_constant|
52
- inner_constant_match = owner.constants.find {|constant| constant.name.to_s == inner_constant }
54
+ inner_constant_match = @constants.find {|constant| constant.name.to_s == inner_constant }
53
55
  if inner_constant_match
54
56
  constant_value.gsub!(/\#\{#{inner_constant}\}/,unpack_constants(inner_constant_match.value))
55
57
  end
@@ -1,23 +1,58 @@
1
1
 
2
+
2
3
  class StepTransformHandler < YARD::Handlers::Ruby::Legacy::Base
3
- MATCH = /^Transform\s*(\/.+\/)\s+do\s+\|.+\|\s*$/
4
- handles MATCH
4
+ STEP_TRANSFORM_MATCH = /^(Transform\s*(\/.+\/)\s+do(?:\s*\|.+\|)?\s*)$/
5
+ handles STEP_TRANSFORM_MATCH
5
6
 
6
7
  @@unique_name = 0
7
8
 
8
9
  def process
9
- transform = statement.tokens.to_s[MATCH,1]
10
-
10
+ transform = statement.tokens.to_s[STEP_TRANSFORM_MATCH,2]
11
11
  @@unique_name = @@unique_name + 1
12
12
 
13
- obj = register StepTransformObject.new(YARD::CodeObjects::Cucumber::CUCUMBER_STEPTRANSFORM_NAMESPACE, "transform_#{@@unique_name}") do |o|
13
+ instance = StepTransformObject.new(YARD::CodeObjects::Cucumber::CUCUMBER_STEPTRANSFORM_NAMESPACE, "transform_#{@@unique_name}") do |o|
14
14
  o.source = "Transform #{transform} do #{statement.block.to_s}\nend"
15
15
  o.value = transform
16
16
  o.keyword = "Transform"
17
17
  end
18
+
19
+ log.debug "Step Tranform: #{instance}"
18
20
 
19
- parse_block :owner => obj
21
+ begin
22
+ @constants = YARD::Registry.all(:constant)
23
+
24
+ # Look for all constants within the step transforms
25
+ instance._value_constants.each do |instance_constants|
26
+ @constants.each do |constant|
27
+ if instance_constants.to_sym == constant.name
28
+ returned_constant = unpack_constants(constant.value)
29
+ instance.constants[constant.name] = unpack_constants(constant.value)
30
+ end
31
+ end
32
+ end
20
33
 
34
+ rescue Exception => e
35
+ log.error "Failed to link step transform to constants. This will make step transform to step linking impossible if constants are present. #{e}"
36
+ end
37
+
38
+ obj = register instance
39
+ parse_block :owner => obj
40
+
21
41
  rescue YARD::Handlers::NamespaceMissingError
22
42
  end
23
- end
43
+
44
+
45
+ def unpack_constants(constant_value)
46
+ constant_value.scan(/\#\{([^\}]+)\}/).flatten.collect { |value| value.strip }.each do |inner_constant|
47
+ inner_constant_match = @constants.find {|constant| constant.name.to_s == inner_constant }
48
+ if inner_constant_match
49
+ constant_value.gsub!(/\#\{#{inner_constant}\}/,unpack_constants(inner_constant_match.value))
50
+ end
51
+ end
52
+
53
+ constant_value.gsub!(/^('|"|\/)|('|"|\/)$/,'')
54
+ constant_value
55
+ end
56
+
57
+ end
58
+