wally 0.0.22 → 0.0.24
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.md +25 -12
- data/features/feature_page.feature +61 -0
- data/features/home_page.feature +0 -10
- data/features/search_features.feature +18 -0
- data/features/step_definitions/search_features_steps.rb +4 -0
- data/lib/wally/application.rb +14 -0
- data/lib/wally/public/skin.css +4 -0
- data/lib/wally/version.rb +1 -1
- data/lib/wally/views/progress.haml +3 -3
- data/lib/wally/views/search.haml +17 -14
- data/spec/wally/search_features_spec.rb +6 -6
- data/wally.gemspec +1 -0
- metadata +39 -26
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,18 +1,31 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# Wally
|
2
|
+
Wally is a web-based Cucumber viewer and navigator.
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
## About
|
5
|
+
The first cut of a feature is collabatively written; but it then seems to become the property of developers, who commit it to a version control system.
|
6
6
|
|
7
|
-
|
8
|
-
-------------------------
|
7
|
+
The product owner or business analyst usually does not want to use an IDE or VCS client to view requiements. They also want to search or group features and scenarios.
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
* Tags can be made more useful - Eg, cuts of all tags marked '@touch'
|
13
|
-
* I can't hyperlink my step definitions
|
9
|
+
## What's wrong with Relish?
|
10
|
+
Many of the ideas have been borrowed from Matt Wynne's Relish product, but we;
|
14
11
|
|
15
|
-
|
16
|
-
|
12
|
+
### Didn't want
|
13
|
+
* To sign-in
|
17
14
|
|
15
|
+
### Wanted to
|
16
|
+
* Use it through mobile devices
|
17
|
+
* Easily group features and scenarios by tags
|
18
|
+
* Count features and tags
|
19
|
+
* Include a project progress bar (based on tags)
|
20
|
+
|
21
|
+
### Installation
|
22
|
+
* Install [mongodb](http://www.mongodb.org/display/DOCS/Quickstart "mongodb") (> v. 2.0.0) and ensure it is running
|
23
|
+
* gem install wally
|
24
|
+
* wally server
|
25
|
+
* http://localhost:4567/
|
26
|
+
* create a '.wally' file and enter any authentication text you like
|
27
|
+
* wally push http://localhost:4567/ feature_dir
|
28
|
+
|
29
|
+
|
30
|
+
## Wally?
|
18
31
|
If you walk in to a British fish shop and ask for a wally you'll receive a [pickled gherkin](https://github.com/cucumber/cucumber/wiki/Gherkin).
|
@@ -0,0 +1,61 @@
|
|
1
|
+
Feature: Feature Page
|
2
|
+
In order to view a feature and its intent
|
3
|
+
As a stakeholder
|
4
|
+
I want a page that displays the feature's name,
|
5
|
+
free-form narrative and scenario titles
|
6
|
+
|
7
|
+
Scenario: Feature Content
|
8
|
+
Given a feature file named "sample.feature" with the contents:
|
9
|
+
"""
|
10
|
+
Feature: Sample Feature
|
11
|
+
In order to get some value
|
12
|
+
As a person
|
13
|
+
I want to create value
|
14
|
+
"""
|
15
|
+
When I visit the sample feature page
|
16
|
+
Then I should see the feature free-form narrative
|
17
|
+
|
18
|
+
Scenario: View Scenario Links
|
19
|
+
Given a feature file named "sample.feature" with the contents:
|
20
|
+
"""
|
21
|
+
Feature: Sample Feature
|
22
|
+
In order to get some value
|
23
|
+
As a person
|
24
|
+
I want to create value
|
25
|
+
|
26
|
+
Scenario: Sample Aidy
|
27
|
+
Given my name is "Aidy"
|
28
|
+
When I drink alcohol
|
29
|
+
Then I go nuts
|
30
|
+
|
31
|
+
Scenario: Sample Andrew
|
32
|
+
Given my name is 'Andrew'
|
33
|
+
When I drink alcohol
|
34
|
+
Then I go happy
|
35
|
+
"""
|
36
|
+
When I visit the sample feature page
|
37
|
+
Then I should see Scenario headers as links
|
38
|
+
|
39
|
+
Scenario: Sort Scenario Links in Alphabetical Order
|
40
|
+
Given a feature file named "sample.feature" with the contents:
|
41
|
+
"""
|
42
|
+
Feature: Sample Feature
|
43
|
+
Scenario: V
|
44
|
+
Scenario: C
|
45
|
+
Scenario: I
|
46
|
+
Scenario: N
|
47
|
+
"""
|
48
|
+
When I visit the sample feature page
|
49
|
+
Then the scenario links are sorted
|
50
|
+
|
51
|
+
Scenario: View Scenario Tags - Feature Page
|
52
|
+
Given a feature file named "sample.feature" with the contents:
|
53
|
+
"""
|
54
|
+
Feature: Sample Feature
|
55
|
+
|
56
|
+
@tag1 @tag2
|
57
|
+
Scenario: Sample Aidy
|
58
|
+
"""
|
59
|
+
When I visit the sample feature page
|
60
|
+
Then I should see "tag1"
|
61
|
+
And I should see "tag2"
|
data/features/home_page.feature
CHANGED
@@ -34,15 +34,5 @@ Feature: Home Page
|
|
34
34
|
When I visit the sample feature page
|
35
35
|
Then I should see "sample_tag"
|
36
36
|
|
37
|
-
Scenario: Feature Content
|
38
|
-
Given a feature file named "sample.feature" with the contents:
|
39
|
-
"""
|
40
|
-
Feature: Sample Feature
|
41
|
-
In order to get some value
|
42
|
-
As a person
|
43
|
-
I want to create value
|
44
|
-
"""
|
45
|
-
When I visit the sample feature page
|
46
|
-
Then I should see the feature free-form narrative
|
47
37
|
|
48
38
|
|
@@ -75,3 +75,21 @@ Feature: Search features
|
|
75
75
|
When I search for "Batman"
|
76
76
|
Then I should see "feature_tag" in the search results
|
77
77
|
And I should see "scenario_tag" in the search results
|
78
|
+
|
79
|
+
Scenario: Higlighted search result
|
80
|
+
Given a feature file named "sample.feature" with the contents:
|
81
|
+
"""
|
82
|
+
@feature_tag
|
83
|
+
Feature: Some long WORD feature word name
|
84
|
+
Scenario: Some long WORD scenario word name
|
85
|
+
"""
|
86
|
+
And I am on the search page
|
87
|
+
When I search for "word"
|
88
|
+
Then I should see the html:
|
89
|
+
"""
|
90
|
+
Some long <span class="search-result">WORD</span> feature <span class="search-result">word</span> name
|
91
|
+
"""
|
92
|
+
And I should see the html:
|
93
|
+
"""
|
94
|
+
Some long <span class="search-result">WORD</span> scenario <span class="search-result">word</span> name
|
95
|
+
"""
|
data/lib/wally/application.rb
CHANGED
@@ -34,6 +34,20 @@ def scenario_count
|
|
34
34
|
lists_features.features.to_s.scan(/scenario/).length
|
35
35
|
end
|
36
36
|
|
37
|
+
def highlighted_search_result_blurb search_result
|
38
|
+
offset = 0
|
39
|
+
highlighted = search_result.object.text
|
40
|
+
span_start = "<span class=\"search-result\">"
|
41
|
+
span_end = "</span>"
|
42
|
+
search_result.matches.each do |match|
|
43
|
+
highlighted.insert(match.index + offset, span_start)
|
44
|
+
offset += span_start.length
|
45
|
+
highlighted.insert(match.index + match.text.length + offset, span_end)
|
46
|
+
offset += span_end.length
|
47
|
+
end
|
48
|
+
highlighted
|
49
|
+
end
|
50
|
+
|
37
51
|
put '/features/?' do
|
38
52
|
if File.exist?(".wally") && params[:authentication_code] == File.read(".wally").strip
|
39
53
|
Wally::Feature.delete_all
|
data/lib/wally/public/skin.css
CHANGED
data/lib/wally/version.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
%h2
|
2
2
|
Progress
|
3
3
|
- #{@scenario_count}
|
4
|
-
- if
|
4
|
+
- if tag_count
|
5
5
|
%p
|
6
6
|
This project has #{@scenario_count} scenarios, of which :-
|
7
7
|
%ul{:class => 'chartlist'}
|
8
|
-
-
|
8
|
+
- tag_count.each do |tag, count|
|
9
9
|
- ratio = (count.to_f / @scenario_count) * 100
|
10
10
|
%li
|
11
11
|
%a{:href => "/search?q=#{tag}"}
|
@@ -13,4 +13,4 @@
|
|
13
13
|
%span{:class => "count #{tag}"}
|
14
14
|
= ratio.ceil
|
15
15
|
%span{:class => 'index', :style => "width: #{ratio.ceil}%"}
|
16
|
-
= ratio
|
16
|
+
= ratio
|
data/lib/wally/views/search.haml
CHANGED
@@ -8,23 +8,26 @@
|
|
8
8
|
%a{:href => "/search?q=#{@search_results.suggestion}"}
|
9
9
|
= @search_results.suggestion
|
10
10
|
%ul
|
11
|
-
- @search_results.items.map {|i| i.feature["id"] }.uniq.each do |current_feature_id|
|
12
|
-
- root_search_result = @search_results.items.find { |r| r.feature["id"] == current_feature_id }
|
11
|
+
- @search_results.items.map {|i| i.object.feature["id"] }.uniq.each do |current_feature_id|
|
12
|
+
- root_search_result = @search_results.items.find { |r| r.object.feature["id"] == current_feature_id }
|
13
13
|
%li
|
14
|
-
%a{:href => "/features/#{root_search_result.feature["id"]}"}
|
15
|
-
= root_search_result.feature["name"]
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
%a{:href => "/features/#{root_search_result.object.feature["id"]}"}
|
15
|
+
= root_search_result.object.feature["name"]
|
16
|
+
%p
|
17
|
+
!= highlighted_search_result_blurb root_search_result
|
18
|
+
- if root_search_result.object.feature["tags"]
|
19
|
+
= haml :tag_links, {:locals => {:tags => root_search_result.object.feature["tags"]}, :layout => false}
|
19
20
|
%ul
|
20
|
-
- @search_results.items.select { |r| r.feature["id"] == current_feature_id }.each do |search_result|
|
21
|
-
- if search_result.scenario && search_result.scenario["id"]
|
21
|
+
- @search_results.items.select { |r| r.object.feature["id"] == current_feature_id }.each do |search_result|
|
22
|
+
- if search_result.object.scenario && search_result.object.scenario["id"]
|
22
23
|
%li
|
23
|
-
%a{:href => "/features/#{search_result.scenario["id"].gsub(";", "/scenario/")}"}
|
24
|
-
= search_result.scenario["name"]
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
%a{:href => "/features/#{search_result.object.scenario["id"].gsub(";", "/scenario/")}"}
|
25
|
+
= search_result.object.scenario["name"]
|
26
|
+
%p
|
27
|
+
!= highlighted_search_result_blurb(search_result)
|
28
|
+
- if search_result.object.scenario["tags"]
|
29
|
+
= haml :tag_links, {:locals => {:tags => search_result.object.scenario["tags"]}, :layout => false}
|
30
|
+
- if @search_results.items.empty?
|
28
31
|
%p{:class => 'alert-message error'}
|
29
32
|
Where's Wally? This search returned no results.
|
30
33
|
|
@@ -23,14 +23,14 @@ module Wally
|
|
23
23
|
|
24
24
|
results = SearchFeatures.new(lists_features).find(:query => "Meh")
|
25
25
|
results.items.size.should == 1
|
26
|
-
results.items.first.feature["name"].should == "Meh"
|
26
|
+
results.items.first.object.feature["name"].should == "Meh"
|
27
27
|
end
|
28
28
|
|
29
29
|
it "finds features by narrative" do
|
30
30
|
create_feature("sample1.feature", "Feature: bla\nIn order to bananas")
|
31
31
|
results = SearchFeatures.new(lists_features).find(:query => "bananas")
|
32
32
|
results.items.size.should == 1
|
33
|
-
results.items.first.feature["name"].should == "bla"
|
33
|
+
results.items.first.object.feature["name"].should == "bla"
|
34
34
|
end
|
35
35
|
|
36
36
|
it "has a suggestion" do
|
@@ -61,13 +61,13 @@ module Wally
|
|
61
61
|
it "finds scenarios containing text" do
|
62
62
|
results = SearchFeatures.new(lists_features).find(:query => "MATCHED")
|
63
63
|
results.items.size.should == 1
|
64
|
-
results.items.first.scenario["name"].should == "Matched Scenario"
|
64
|
+
results.items.first.object.scenario["name"].should == "Matched Scenario"
|
65
65
|
end
|
66
66
|
|
67
67
|
it "finds scenario steps" do
|
68
68
|
results = SearchFeatures.new(lists_features).find(:query => "DOUGHNUTS")
|
69
69
|
results.items.size.should == 1
|
70
|
-
results.items.first.scenario["name"].should == "Matched Scenario"
|
70
|
+
results.items.first.object.scenario["name"].should == "Matched Scenario"
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
@@ -75,13 +75,13 @@ module Wally
|
|
75
75
|
it "finds features by tag" do
|
76
76
|
create_feature("example-feature.feature", "@tag_name\nFeature: Example Feature")
|
77
77
|
results = SearchFeatures.new(lists_features).find(:query => "@tag_NAME")
|
78
|
-
results.items.first.feature["name"].should == "Example Feature"
|
78
|
+
results.items.first.object.feature["name"].should == "Example Feature"
|
79
79
|
end
|
80
80
|
|
81
81
|
it "finds scenarios by tag" do
|
82
82
|
create_feature("example-feature.feature", "Feature: Example Feature\n@scenario_tag\nScenario: Example Scenario")
|
83
83
|
results = SearchFeatures.new(lists_features).find(:query => "@scenario_TAG")
|
84
|
-
results.items.first.scenario["name"].should == "Example Scenario"
|
84
|
+
results.items.first.object.scenario["name"].should == "Example Scenario"
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
data/wally.gemspec
CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_runtime_dependency "komainu"
|
26
26
|
s.add_runtime_dependency "mongoid"
|
27
27
|
s.add_runtime_dependency "bson_ext"
|
28
|
+
s.add_runtime_dependency "rest-client"
|
28
29
|
|
29
30
|
s.add_development_dependency "cucumber"
|
30
31
|
s.add_development_dependency "capybara"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wally
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.24
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-12-02 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|
16
|
-
requirement: &
|
16
|
+
requirement: &70108116103100 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70108116103100
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: haml
|
27
|
-
requirement: &
|
27
|
+
requirement: &70108116102080 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70108116102080
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rdiscount
|
38
|
-
requirement: &
|
38
|
+
requirement: &70108116101440 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70108116101440
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: gherkin
|
49
|
-
requirement: &
|
49
|
+
requirement: &70108116100100 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70108116100100
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: komainu
|
60
|
-
requirement: &
|
60
|
+
requirement: &70108116098780 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70108116098780
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: mongoid
|
71
|
-
requirement: &
|
71
|
+
requirement: &70108116096040 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70108116096040
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: bson_ext
|
82
|
-
requirement: &
|
82
|
+
requirement: &70108116095560 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,21 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70108116095560
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: rest-client
|
93
|
+
requirement: &70108116095100 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :runtime
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70108116095100
|
91
102
|
- !ruby/object:Gem::Dependency
|
92
103
|
name: cucumber
|
93
|
-
requirement: &
|
104
|
+
requirement: &70108116094600 !ruby/object:Gem::Requirement
|
94
105
|
none: false
|
95
106
|
requirements:
|
96
107
|
- - ! '>='
|
@@ -98,10 +109,10 @@ dependencies:
|
|
98
109
|
version: '0'
|
99
110
|
type: :development
|
100
111
|
prerelease: false
|
101
|
-
version_requirements: *
|
112
|
+
version_requirements: *70108116094600
|
102
113
|
- !ruby/object:Gem::Dependency
|
103
114
|
name: capybara
|
104
|
-
requirement: &
|
115
|
+
requirement: &70108116093920 !ruby/object:Gem::Requirement
|
105
116
|
none: false
|
106
117
|
requirements:
|
107
118
|
- - ! '>='
|
@@ -109,10 +120,10 @@ dependencies:
|
|
109
120
|
version: '0'
|
110
121
|
type: :development
|
111
122
|
prerelease: false
|
112
|
-
version_requirements: *
|
123
|
+
version_requirements: *70108116093920
|
113
124
|
- !ruby/object:Gem::Dependency
|
114
125
|
name: rspec
|
115
|
-
requirement: &
|
126
|
+
requirement: &70108116093320 !ruby/object:Gem::Requirement
|
116
127
|
none: false
|
117
128
|
requirements:
|
118
129
|
- - ! '>='
|
@@ -120,10 +131,10 @@ dependencies:
|
|
120
131
|
version: '0'
|
121
132
|
type: :development
|
122
133
|
prerelease: false
|
123
|
-
version_requirements: *
|
134
|
+
version_requirements: *70108116093320
|
124
135
|
- !ruby/object:Gem::Dependency
|
125
136
|
name: fakefs
|
126
|
-
requirement: &
|
137
|
+
requirement: &70108116086420 !ruby/object:Gem::Requirement
|
127
138
|
none: false
|
128
139
|
requirements:
|
129
140
|
- - ! '>='
|
@@ -131,10 +142,10 @@ dependencies:
|
|
131
142
|
version: '0'
|
132
143
|
type: :development
|
133
144
|
prerelease: false
|
134
|
-
version_requirements: *
|
145
|
+
version_requirements: *70108116086420
|
135
146
|
- !ruby/object:Gem::Dependency
|
136
147
|
name: launchy
|
137
|
-
requirement: &
|
148
|
+
requirement: &70108116085900 !ruby/object:Gem::Requirement
|
138
149
|
none: false
|
139
150
|
requirements:
|
140
151
|
- - ! '>='
|
@@ -142,7 +153,7 @@ dependencies:
|
|
142
153
|
version: '0'
|
143
154
|
type: :development
|
144
155
|
prerelease: false
|
145
|
-
version_requirements: *
|
156
|
+
version_requirements: *70108116085900
|
146
157
|
description: ''
|
147
158
|
email:
|
148
159
|
- andrew.vos@gmail.com
|
@@ -164,6 +175,7 @@ files:
|
|
164
175
|
- example-features/generic/multiple-scenarios.feature
|
165
176
|
- example-features/too-many-wip-tags/too-many-wip-tags.feature
|
166
177
|
- features/counts.feature
|
178
|
+
- features/feature_page.feature
|
167
179
|
- features/home_page.feature
|
168
180
|
- features/list_tags.feature
|
169
181
|
- features/notifications.feature
|
@@ -226,6 +238,7 @@ specification_version: 3
|
|
226
238
|
summary: ''
|
227
239
|
test_files:
|
228
240
|
- features/counts.feature
|
241
|
+
- features/feature_page.feature
|
229
242
|
- features/home_page.feature
|
230
243
|
- features/list_tags.feature
|
231
244
|
- features/notifications.feature
|