cucumber_fm-core 0.1

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 (74) hide show
  1. data/LICENCE +20 -0
  2. data/lib/cucumber_f_m/aggregator.rb +65 -0
  3. data/lib/cucumber_f_m/comment_module/comment.rb +7 -0
  4. data/lib/cucumber_f_m/config.rb +37 -0
  5. data/lib/cucumber_f_m/cvs/git.rb +7 -0
  6. data/lib/cucumber_f_m/feature.rb +141 -0
  7. data/lib/cucumber_f_m/feature_element/background.rb +10 -0
  8. data/lib/cucumber_f_m/feature_element/comment.rb +13 -0
  9. data/lib/cucumber_f_m/feature_element/component/comments.rb +21 -0
  10. data/lib/cucumber_f_m/feature_element/component/information/component.rb +16 -0
  11. data/lib/cucumber_f_m/feature_element/component/tags.rb +108 -0
  12. data/lib/cucumber_f_m/feature_element/component/title.rb +26 -0
  13. data/lib/cucumber_f_m/feature_element/component/total_estimation.rb +42 -0
  14. data/lib/cucumber_f_m/feature_element/example.rb +7 -0
  15. data/lib/cucumber_f_m/feature_element/info.rb +13 -0
  16. data/lib/cucumber_f_m/feature_element/narrative.rb +7 -0
  17. data/lib/cucumber_f_m/feature_element/scenario.rb +15 -0
  18. data/lib/cucumber_f_m/feature_element/scenario_outline.rb +23 -0
  19. data/lib/cucumber_f_m/feature_element/step.rb +7 -0
  20. data/lib/cucumber_f_m/statistic.rb +31 -0
  21. data/lib/cucumber_f_m/tag_filter.rb +85 -0
  22. data/lib/cucumber_feature_manager.rb +164 -0
  23. data/lib/grit/lib/grit.rb +75 -0
  24. data/lib/grit/lib/grit/actor.rb +36 -0
  25. data/lib/grit/lib/grit/blame.rb +61 -0
  26. data/lib/grit/lib/grit/blob.rb +126 -0
  27. data/lib/grit/lib/grit/commit.rb +247 -0
  28. data/lib/grit/lib/grit/commit_stats.rb +128 -0
  29. data/lib/grit/lib/grit/config.rb +44 -0
  30. data/lib/grit/lib/grit/diff.rb +70 -0
  31. data/lib/grit/lib/grit/errors.rb +7 -0
  32. data/lib/grit/lib/grit/git-ruby.rb +267 -0
  33. data/lib/grit/lib/grit/git-ruby/commit_db.rb +52 -0
  34. data/lib/grit/lib/grit/git-ruby/file_index.rb +193 -0
  35. data/lib/grit/lib/grit/git-ruby/git_object.rb +350 -0
  36. data/lib/grit/lib/grit/git-ruby/internal/file_window.rb +58 -0
  37. data/lib/grit/lib/grit/git-ruby/internal/loose.rb +137 -0
  38. data/lib/grit/lib/grit/git-ruby/internal/pack.rb +384 -0
  39. data/lib/grit/lib/grit/git-ruby/internal/raw_object.rb +37 -0
  40. data/lib/grit/lib/grit/git-ruby/object.rb +325 -0
  41. data/lib/grit/lib/grit/git-ruby/repository.rb +767 -0
  42. data/lib/grit/lib/grit/git.rb +323 -0
  43. data/lib/grit/lib/grit/index.rb +122 -0
  44. data/lib/grit/lib/grit/lazy.rb +33 -0
  45. data/lib/grit/lib/grit/merge.rb +45 -0
  46. data/lib/grit/lib/grit/ref.rb +74 -0
  47. data/lib/grit/lib/grit/repo.rb +482 -0
  48. data/lib/grit/lib/grit/ruby1.9.rb +7 -0
  49. data/lib/grit/lib/grit/status.rb +151 -0
  50. data/lib/grit/lib/grit/submodule.rb +88 -0
  51. data/lib/grit/lib/grit/tag.rb +16 -0
  52. data/lib/grit/lib/grit/tree.rb +123 -0
  53. data/lib/grit/lib/open3_detach.rb +46 -0
  54. data/spec/cucumber_f_m/aggregator_spec.rb +210 -0
  55. data/spec/cucumber_f_m/comment_module/comment_spec.rb +4 -0
  56. data/spec/cucumber_f_m/config_spec.rb +27 -0
  57. data/spec/cucumber_f_m/cvs/git_spec.rb +40 -0
  58. data/spec/cucumber_f_m/feature_all_tags_to_scenario_spec.rb +7 -0
  59. data/spec/cucumber_f_m/feature_file_manipulation_spec.rb +29 -0
  60. data/spec/cucumber_f_m/feature_module/background_spec.rb +30 -0
  61. data/spec/cucumber_f_m/feature_module/comment_spec.rb +23 -0
  62. data/spec/cucumber_f_m/feature_module/example_spec.rb +5 -0
  63. data/spec/cucumber_f_m/feature_module/info_spec.rb +30 -0
  64. data/spec/cucumber_f_m/feature_module/narrative_spec.rb +7 -0
  65. data/spec/cucumber_f_m/feature_module/scenario_outline_spec.rb +39 -0
  66. data/spec/cucumber_f_m/feature_module/scenario_spec.rb +33 -0
  67. data/spec/cucumber_f_m/feature_module/step_spec.rb +7 -0
  68. data/spec/cucumber_f_m/feature_module/tag_spec.rb +96 -0
  69. data/spec/cucumber_f_m/feature_spec.rb +229 -0
  70. data/spec/cucumber_f_m/tag_filter_spec.rb +191 -0
  71. data/spec/cucumber_feature_manager_spec.rb +59 -0
  72. data/spec/data/feature_manager/some_ruby_file.rb +0 -0
  73. data/spec/spec_helper.rb +1 -0
  74. metadata +141 -0
data/LICENCE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010..2011 Michał Czyż @cs3b <michalczyz@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,65 @@
1
+ module CucumberFM
2
+ class Aggregator
3
+ def initialize(cfm, aggregator, multiple = false)
4
+ if multiple
5
+ @collection = Collection.nested_hash(0)
6
+ multiple.each do |tag|
7
+ cfm.scenarios.each do |scenario|
8
+ @collection[tag].push scenario if scenario.tags.include?(tag)
9
+ end
10
+ end
11
+ else
12
+ @collection = Collection.nested_hash(aggregator.size)
13
+ if aggregator.size == 2
14
+ cfm.scenarios.each do |scenario|
15
+ @collection[label(aggregator.first, scenario.tags_without_technical)][label(aggregator.last, scenario.tags_without_technical)][scenario.feature].push scenario
16
+ end
17
+ else
18
+ @collection = Collection.nested_hash(1)
19
+ cfm.scenarios.each do |scenario|
20
+ @collection[label(aggregator.first, scenario.tags_without_technical)][scenario.feature].push scenario
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ def collection
27
+ @collection
28
+ end
29
+
30
+ private
31
+
32
+ def label(aggregate, tags)
33
+ tags.find { |tag| tag =~ aggregate } || '_undefined_'
34
+ end
35
+
36
+ class Collection < Hash
37
+
38
+ include CucumberFM::FeatureElement::Component::TotalEstimation
39
+
40
+ def features
41
+ keys.collect { |key|
42
+ self[key].is_a?(Array) ? key : self[key].features
43
+ }.flatten.uniq
44
+ end
45
+
46
+ def scenarios
47
+ values.collect { |value|
48
+ value.is_a?(Array) ? value : value.scenarios
49
+ }.flatten
50
+ end
51
+
52
+ def Collection.nested_hash (level=1)
53
+ new do |hash, key|
54
+ hash[key]= (level > 0 ? nested_hash(level-1) : ScenarioCollection.new)
55
+ end
56
+ end
57
+ end
58
+ class ScenarioCollection < Array
59
+
60
+ include CucumberFM::FeatureElement::Component::TotalEstimation
61
+
62
+ alias_method :scenarios, :entries
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,7 @@
1
+ module CucumberFM
2
+ module CommentModule
3
+ class Comment
4
+ #Code here
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ module CucumberFM
2
+ class Config
3
+ attr_accessor :dir, :tags, :aggregate, :sort, :display_as, :cvs_commit, :cvs_push
4
+
5
+ def initialize(params={})
6
+ set_default_values
7
+ update(params)
8
+ end
9
+
10
+ def aggregate_options
11
+ [''] + CucumberFM::FeatureElement::Component::Tags::PATTERN.keys.map(& :to_s).sort
12
+ end
13
+
14
+ private
15
+
16
+ def set_default_values
17
+ update(
18
+ {
19
+ :dir => '',
20
+ :tags => '',
21
+ :aggregate => [],
22
+ :sort => '',
23
+ :display_as => 'list',
24
+ :cvs_commit => '0',
25
+ :cvs_push => '0'
26
+ })
27
+
28
+ end
29
+
30
+ def update(params)
31
+ params.each_pair do |attribute, value|
32
+ setter_method_name = "#{attribute}="
33
+ send(setter_method_name, value) if respond_to? setter_method_name
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,7 @@
1
+ module CucumberFM
2
+ module Cvs
3
+ class Git
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,141 @@
1
+ module CucumberFM
2
+ class Feature < Struct.new(:path, :cfm)
3
+
4
+ include FeatureElement::Component::TotalEstimation
5
+
6
+ def id
7
+ Base64.encode64(relative_path)
8
+ end
9
+
10
+ def relative_path
11
+ path.gsub(/^#{cfm.path}\//, '')
12
+ end
13
+
14
+ def raw
15
+ @raw ||= read_content_from_file
16
+ end
17
+
18
+ def raw= content
19
+ @raw = content
20
+ end
21
+
22
+ def info
23
+ @info ||= FeatureElement::Info.new(self, scan_for_feature_info_from_raw)
24
+ end
25
+
26
+ def background
27
+ @background ||= FeatureElement::Background.new(self, scan_for_background_from_raw)
28
+ end
29
+
30
+ def scenarios
31
+ @scenarios ||= fetch_scenarios
32
+ end
33
+
34
+ def tags
35
+ info.tags
36
+ end
37
+
38
+ def tags_all
39
+ scenarios.collect{|scenario| scenario.tags }.flatten.uniq
40
+ end
41
+
42
+ def save
43
+ write_content_to_file
44
+ commit
45
+ push
46
+ true
47
+ end
48
+
49
+ def destroy
50
+ File.delete(path)
51
+ remove_file_from_repo
52
+ push
53
+ end
54
+
55
+ def filename
56
+ File.basename(path)
57
+ end
58
+
59
+ def filename_without_extension
60
+ File.basename(path, '.feature')
61
+ end
62
+
63
+ def <=>(_f)
64
+ info.title <=> _f.info.title
65
+ end
66
+
67
+ private
68
+
69
+ def read_content_from_file
70
+ File.open(path, 'r') { |stream| stream.read }
71
+ end
72
+
73
+ def write_content_to_file
74
+ File.open(path, 'w') { |stream| stream.write raw }
75
+ end
76
+
77
+
78
+ # TODO we need to detect it in more clever way
79
+ def commit
80
+ cfm.commit_change_on(self) if do_commit?
81
+ end
82
+
83
+ # TODO we need to detect it in more clever way
84
+ def push
85
+ cfm.send_to_remote if do_push?
86
+ end
87
+
88
+ def remove_file_from_repo
89
+ cfm.remove_file_from_repo(relative_path) if do_commit?
90
+ end
91
+
92
+ def do_push?
93
+ cfm && cfm.respond_to?(:send_to_remote) && cfm.config.cvs_commit=='1' && cfm.config.cvs_push=='1'
94
+ end
95
+
96
+ def do_commit?
97
+ cfm && cfm.respond_to?(:commit_change_on) && cfm.config.cvs_commit=='1'
98
+ end
99
+
100
+ def fetch_scenarios
101
+ scenarios = []
102
+ text = raw
103
+ while match = scan_for_scenarios_and_scenario_outline_from(text)
104
+ scenario = case match[0]
105
+ when FeatureElement::Scenario::PATTERN
106
+ FeatureElement::Scenario.new(self, match[0])
107
+ when FeatureElement::ScenarioOutline::PATTERN
108
+ FeatureElement::ScenarioOutline.new(self, match[0])
109
+ end
110
+ scenarios.push(scenario) if cfm.filter.pass?(scenario.tags)
111
+ text = match.post_match
112
+ end
113
+ scenarios
114
+ end
115
+
116
+ def scan_for_feature_info_from_raw
117
+ if match = FeatureElement::Info::PATTERN.match(raw)
118
+ match[0]
119
+ else
120
+ ''
121
+ end
122
+ end
123
+
124
+ def scan_for_background_from_raw
125
+ if match = FeatureElement::Background::PATTERN.match(raw)
126
+ match[0]
127
+ else
128
+ ''
129
+ end
130
+ end
131
+
132
+ def scan_for_scenarios_and_scenario_outline_from(string)
133
+ scenario_or_scenario_outline.match(string)
134
+ end
135
+
136
+ def scenario_or_scenario_outline
137
+ Regexp.union(FeatureElement::Scenario::PATTERN,
138
+ FeatureElement::ScenarioOutline::PATTERN)
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,10 @@
1
+ module CucumberFM
2
+ module FeatureElement
3
+ class Background < Struct.new(:feature, :raw)
4
+ PATTERN = /((^.*#+.*\n)+\n?)?^[ \t]*Background:.*\n?(^.*\S+.*\n?)*/
5
+
6
+ include CucumberFM::FeatureElement::Component::Title
7
+ include CucumberFM::FeatureElement::Component::Comments
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module CucumberFM
2
+ module FeatureElement
3
+ class Comment < Struct.new(:ancestors, :raw)
4
+
5
+
6
+ private
7
+
8
+ def is_it_link
9
+ raw =~ /^#:::[^:]+:::/
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module CucumberFM
2
+ module FeatureElement
3
+ module Component
4
+ module Comments
5
+ LINE_PATTERN = /^\s*#+.*$/
6
+
7
+ def comments
8
+ @comments ||= fetch_comments
9
+ end
10
+
11
+ private
12
+
13
+ def fetch_comments
14
+ raw.scan(LINE_PATTERN).collect do |comment_raw|
15
+ CucumberFM::FeatureElement::Comment.new(self, comment_raw)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ module CucumberFM
2
+ module FeatureElement
3
+ module Component
4
+ module Information
5
+ module Component
6
+ COMPONENT_PATTERN = /@[a-z]\S{3,}\z/
7
+ PATTERN[:component] = COMPONENT_PATTERN
8
+
9
+ def component
10
+
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,108 @@
1
+ module CucumberFM
2
+ module FeatureElement
3
+ module Component
4
+ module Tags
5
+ LINE_PATTERN = /^\s*@\S.*$/
6
+ TAG_PATTERN = /@[^,\s]+/
7
+
8
+ PATTERN = {
9
+ :component => /@[a-z]\S{3,}\z/,
10
+ :milestone => /@m\d.?\z/,
11
+ :iteration => /@i\d+\z/,
12
+ :priority => /@p\d+\z/,
13
+ :status => /@_[a-z]\S+\z/,
14
+ :developer => /@[a-z]{2,3}\z/,
15
+ :bucket => /@__[^\s\d]+/,
16
+ :effort => /@\d/,
17
+ :benefit => /@_\d/,
18
+ :something_todo => /@:::[a-z]{2,3}\z/,
19
+ :role => /@\$_[a-z_]+/
20
+ }
21
+
22
+ TECHNICAL = [
23
+ '@javascript',
24
+ '@selenium',
25
+ '@sellenium',
26
+ '@celerity',
27
+ '@culerity',
28
+ '@mongo',
29
+ '@allow-rescue',
30
+ '@needs_wireframe',
31
+ '@tested_elsewhere',
32
+ '@added',
33
+ '@nontestable',
34
+ '@additional-test'
35
+ ]
36
+
37
+ STATUS_COMPLETE = %w(@_done @_qa @_tested @_accepted)
38
+
39
+ def tags
40
+ @tags ||= fetch_tags
41
+ end
42
+
43
+ def tags= tags
44
+ @tags = tags
45
+ end
46
+
47
+ def tags_without_technical
48
+ tags - TECHNICAL
49
+ end
50
+
51
+ def done?
52
+ STATUS_COMPLETE.include?(status)
53
+ end
54
+
55
+
56
+ def estimation
57
+ effort ? effort.gsub('@', '').to_f : 0.0
58
+ end
59
+
60
+ def value
61
+ benefit ? benefit.gsub('@_', '').to_i : 0
62
+ end
63
+
64
+ private
65
+
66
+ def fetch_tags
67
+ this_tags + parent_tags_without_duplicates
68
+ end
69
+
70
+ def this_tags
71
+ if tag_line = LINE_PATTERN.match(raw)
72
+ tag_line[0].scan(TAG_PATTERN)
73
+ else
74
+ []
75
+ end
76
+ end
77
+
78
+ def parent_tags
79
+ respond_to?(:second_tags_source) ? second_tags_source.tags : []
80
+ end
81
+
82
+ def parent_tags_without_duplicates
83
+ parent_tags.collect { |p_tag| (type = detect_type(p_tag) and find(type, this_tags)) ? nil : p_tag }.compact
84
+ end
85
+
86
+ def find type, collection = tags
87
+ collection.detect do |tag|
88
+ !TECHNICAL.include?(tag) and tag =~ PATTERN[type]
89
+ end
90
+ end
91
+
92
+ def detect_type tag
93
+ PATTERN.invert.each_pair do |pattern, type|
94
+ return(type) if tag =~ pattern
95
+ end
96
+ end
97
+
98
+ def method_missing(m, *args, &block)
99
+ if PATTERN.has_key?(m.to_sym)
100
+ find(m.to_sym)
101
+ else
102
+ super
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end