cucumber-in-the-yard 1.5.3 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
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
+