nuker 0.0.47 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -0
  3. data/.ruby-version +1 -0
  4. data/.rvmrc +62 -0
  5. data/.rvmrc.08.13.2014-14:58:37 +1 -0
  6. data/.travis.yml +3 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +165 -0
  9. data/Rakefile +5 -0
  10. data/bin/nuker +26 -0
  11. data/config.ru +2 -0
  12. data/example-features/generic/example-with-background.feature +11 -0
  13. data/example-features/generic/example-with-data-table.feature +7 -0
  14. data/example-features/generic/example-with-scenario-outline-examples.feature +11 -0
  15. data/example-features/generic/example_with_tags.feature +8 -0
  16. data/example-features/generic/has-lots-of-tags.feature +5 -0
  17. data/example-features/generic/multiple-scenarios.feature +7 -0
  18. data/example-features/too-many-wip-tags/too-many-wip-tags.feature +21 -0
  19. data/features/counts.feature +25 -0
  20. data/features/feature_page.feature +69 -0
  21. data/features/list_tags.feature +31 -0
  22. data/features/notifications.feature +9 -0
  23. data/features/progress_bar.feature +21 -0
  24. data/features/project_home.feature +25 -0
  25. data/features/projects.feature +19 -0
  26. data/features/push_features.feature +34 -0
  27. data/features/scenario_page.feature +84 -0
  28. data/features/search_features.feature +100 -0
  29. data/features/step_definitions/feature_page_steps.rb +15 -0
  30. data/features/step_definitions/notifications_steps.rb +11 -0
  31. data/features/step_definitions/project_home_steps.rb +10 -0
  32. data/features/step_definitions/projects_steps.rb +28 -0
  33. data/features/step_definitions/push_features_steps.rb +48 -0
  34. data/features/step_definitions/scenario_page_steps.rb +29 -0
  35. data/features/step_definitions/search_features_steps.rb +24 -0
  36. data/features/step_definitions/steps.rb +35 -0
  37. data/features/step_definitions/welcome_page.rb +19 -0
  38. data/features/support/env.rb +33 -0
  39. data/features/welcome_page.feature +30 -0
  40. data/lib/nuker/application.rb +161 -0
  41. data/lib/nuker/counts_tags.rb +27 -0
  42. data/lib/nuker/feature.rb +16 -0
  43. data/lib/nuker/parses_features.rb +30 -0
  44. data/lib/nuker/project.rb +8 -0
  45. data/lib/nuker/public/bootstrap.min.css +356 -0
  46. data/lib/nuker/public/nuker-logo.png +0 -0
  47. data/lib/nuker/public/scripts/projects.js +6 -0
  48. data/lib/nuker/public/skin.css +208 -0
  49. data/lib/nuker/public/wally-logo.png +0 -0
  50. data/lib/nuker/search_features.rb +47 -0
  51. data/lib/nuker/version.rb +3 -0
  52. data/lib/nuker/views/feature.haml +19 -0
  53. data/lib/nuker/views/feature_link.haml +6 -0
  54. data/lib/nuker/views/layout.haml +53 -0
  55. data/lib/nuker/views/progress.haml +15 -0
  56. data/lib/nuker/views/project.haml +0 -0
  57. data/lib/nuker/views/scenario.haml +31 -0
  58. data/lib/nuker/views/search.haml +36 -0
  59. data/lib/nuker/views/table.haml +10 -0
  60. data/lib/nuker/views/tag_links.haml +4 -0
  61. data/lib/nuker.rb +7 -0
  62. data/nuker.gemspec +37 -0
  63. data/spec/spec_helper.rb +35 -0
  64. metadata +88 -3
@@ -0,0 +1,84 @@
1
+ Feature: Scenario Page
2
+ In order to view a scenario's intent
3
+ As a stakeholder
4
+ I want a page that displays each scenario and its steps
5
+
6
+ Scenario: Content
7
+ Given a feature file named "sample.feature" with the contents:
8
+ """
9
+ Feature: Sample Feature
10
+
11
+ @tag1 @tag2
12
+ Scenario: Sample Aidy
13
+ Given my name is "Aidy"
14
+ When I drink alcohol
15
+ Then I go nuts
16
+ """
17
+ When I visit the sample feature page
18
+ And click on a scenario header link
19
+ Then a page appears with the scenario content
20
+ And I see "tag1"
21
+ And I see "tag2"
22
+
23
+ Scenario: Background
24
+ Given a feature file named "sample.feature" with the contents:
25
+ """
26
+ Feature: Sample Feature
27
+
28
+ Background:
29
+ Given some things
30
+
31
+ Scenario: Sample Aidy
32
+ """
33
+ When I visit the sample feature page
34
+ And click on a scenario header link
35
+ Then the background is visible
36
+
37
+ Scenario: Tags
38
+ Given a feature file named "sample.feature" with the contents:
39
+ """
40
+ Feature: Sample Feature
41
+
42
+ Background:
43
+ Given some things
44
+
45
+ @work_in_progress
46
+ Scenario: Sample Aidy
47
+ """
48
+ When I visit the sample feature page
49
+ And click on a scenario header link
50
+ Then I see "work_in_progress"
51
+
52
+ Scenario: Data Table
53
+ Given a feature file named "sample.feature" with the contents:
54
+ """
55
+ Feature: Sample Feature
56
+
57
+ Scenario: Data Table
58
+ Given the following people exist:
59
+ | name | email |
60
+ | Aidy | aidy@example.com |
61
+ | Andrew | vos@example.com |
62
+ """
63
+ When I visit the sample feature page
64
+ And click on a scenario header link
65
+ Then I see the data table
66
+
67
+ Scenario: Scenario Outline
68
+ Given a feature file named "sample.feature" with the contents:
69
+ """
70
+ Feature: Sample Feature
71
+
72
+ Scenario Outline: Outline with examples
73
+ Given there are <start> cucumbers
74
+ When I eat <eat> cucumbers
75
+ Then I have <left> cucumbers
76
+
77
+ Examples:
78
+ | start | eat | left |
79
+ | 12 | 5 | 7 |
80
+ | 20 | 5 | 15 |
81
+ """
82
+ When I visit the sample feature page
83
+ And click on a scenario header link
84
+ Then I see the examples table
@@ -0,0 +1,100 @@
1
+ Feature: Search features
2
+ In order to have fast access to features and scenarios
3
+ As a stakeholder
4
+ I want to be able to search features
5
+
6
+ Scenario Outline: Search feature name
7
+ Given a feature file named "sample.feature" with the contents:
8
+ """
9
+ @QA
10
+ Feature: Sample Feature
11
+ """
12
+ And I am on the search page
13
+ When I search for "<query>"
14
+ Then I see a search result link to "<feature name>" with the url "<url>"
15
+
16
+ Examples:
17
+ | query | feature name | url |
18
+ | Sample | Sample Feature |/projects/project/features/sample-feature |
19
+ | sAmPlE | Sample Feature |/projects/project/features/sample-feature |
20
+ | @QA | Sample Feature |/projects/project/features/sample-feature |
21
+
22
+ Scenario: Search feature narrative
23
+ Given a feature file named "sample.feature" with the contents:
24
+ """
25
+ Feature: Sample Feature
26
+ In order to bla bla bla
27
+ As donkey
28
+ I want ermm I dunno.
29
+ """
30
+ And I am on the search page
31
+ When I search for "donkey"
32
+ Then I see a search result link to "Sample Feature" with the url "/projects/project/features/sample-feature"
33
+
34
+ Scenario: Search scenario name
35
+ Given a feature file named "sample.feature" with the contents:
36
+ """
37
+ Feature: Sample Feature
38
+ Scenario: Sample Scenario
39
+ """
40
+ And I am on the search page
41
+ When I search for "Sample Scenario"
42
+ Then I see a search result link to "Sample Scenario" with the url "/projects/project/features/sample-feature/scenario/sample-scenario"
43
+
44
+ Scenario: Search scenario steps
45
+ Given a feature file named "sample.feature" with the contents:
46
+ """
47
+ Feature: Sample Feature
48
+ Scenario: Sample Scenario
49
+ Given I do something
50
+ """
51
+ And I am on the search page
52
+ When I search for "I do something"
53
+ Then I see a search result link to "Sample Scenario" with the url "/projects/project/features/sample-feature/scenario/sample-scenario"
54
+
55
+ Scenario: Search suggests other searches
56
+ Given a feature file named "sample.feature" with the contents:
57
+ """
58
+ Feature: Batman
59
+ """
60
+ And I am on the search page
61
+ When I search for "btman"
62
+ Then I see "Did you mean"
63
+ And I see a search result link to "Batman" with the url "/projects/project/search?q=Batman"
64
+
65
+ Scenario: Search displays tags
66
+ Given a feature file named "sample.feature" with the contents:
67
+ """
68
+ @feature_tag
69
+ Feature: Batman
70
+
71
+ @scenario_tag
72
+ Scenario: Batman?
73
+ """
74
+ And I am on the search page
75
+ When I search for "Batman"
76
+ Then I see "feature_tag" in the search results
77
+ And I see "scenario_tag" in the search results
78
+
79
+ Scenario: Highlighted search result with multiple matches
80
+ Given a feature file named "sample1.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
+ Given I have a word
86
+ """
87
+ And I am on the search page
88
+ When I search for "word"
89
+ Then I see the html:
90
+ """
91
+ Some &lt;long <span class="search-result">WORD</span> feature <span class="search-result">word</span> name
92
+ """
93
+ And I see the html:
94
+ """
95
+ Some &lt;long <span class="search-result">WORD</span> scenario <span class="search-result">word</span> name
96
+ """
97
+ And I see the html:
98
+ """
99
+ I have a <span class="search-result">word</span>
100
+ """
@@ -0,0 +1,15 @@
1
+ Then /^I see the feature free\-form narrative$/ do
2
+ page.should have_content "In order to get some value"
3
+ page.should have_content "As a person"
4
+ page.should have_content "I want to create value"
5
+ end
6
+
7
+ Then /^I see Scenario headers as links$/ do
8
+ page.body.should have_content "Scenarios"
9
+ page.should have_link "Sample Aidy", :href => "/projects/project/features/sample-feature/scenario/sample-aidy"
10
+ page.should have_link "Sample Andrew", :href => "/projects/project/features/sample-feature/scenario/sample-andrew"
11
+ end
12
+
13
+ Then /^the scenario links are sorted$/ do
14
+ page.body.should =~ /C.*I.*N.*V/m
15
+ end
@@ -0,0 +1,11 @@
1
+ Given /^a feature file with (\d+) @wip tags$/ do |wip_tag_count|
2
+ contents = "Feature: Feature 1\n"
3
+ 1.upto(wip_tag_count.to_i) do |number|
4
+ contents += "@wip\nScenario: Scenario #{number}\n"
5
+ end
6
+ create_feature("project", "sample1.feature", contents)
7
+ end
8
+
9
+ Then /^I see a notification that says "([^"]*)"$/ do |text|
10
+ page.should have_content text
11
+ end
@@ -0,0 +1,10 @@
1
+ Then /^I see a link to my sample features$/ do
2
+ page.should have_link "Kate Moss", :href => "/projects/project/features/kate-moss"
3
+ page.should have_link "Katie Price", :href => "/projects/project/features/katie-price"
4
+ page.should have_link "Jessica-Jane Clement", :href => "/projects/project/features/jessica-jane-clement"
5
+ page.should have_link "Elle Macpherson", :href => "/projects/project/features/elle-macpherson"
6
+ end
7
+
8
+ Then /^the features are ordered alphabetically$/ do
9
+ page.body.should =~ /Elle Macpherson.*Jessica-Jane Clement.*Kate Moss.*Katie Price/m
10
+ end
@@ -0,0 +1,28 @@
1
+ Given /^a feature file on the project "([^"]*)" with the contents:$/ do |project, contents|
2
+ create_feature(project, "feature1.feature", contents)
3
+ end
4
+
5
+ Given /^I visit the project page for "([^"]*)"$/ do |project|
6
+ visit "/projects/#{project}"
7
+ end
8
+
9
+ Given /^(\d+) projects exist$/ do |number_of_projects|
10
+ number_of_projects.to_i.times do |project_number|
11
+ project(project_number + 1)
12
+ end
13
+ end
14
+
15
+ Then /^I see a link to the feature "([^"]*)"$/ do |feature|
16
+ page.should have_link feature
17
+ end
18
+
19
+ Then /^I can switch to the (\d).+ project$/ do |project_number|
20
+ select project_number, :from => 'projects'
21
+
22
+ #This is needed because there seems to be a bug in the chrome driver.
23
+ #The first time this is called, we get the old url, and the second time we get the new url.
24
+ page.current_url
25
+
26
+ page.current_url.end_with?(project_number).should be_true
27
+ end
28
+
@@ -0,0 +1,48 @@
1
+ After do
2
+ File.delete ".nuker" if File.exist? ".wally"
3
+ end
4
+
5
+ Given /^I don't have a \.nuker authorisation file$/ do
6
+ end
7
+
8
+ Given /^I have a \.nuker authentication file$/ do
9
+ @authentication_code = "authCodE!!2322"
10
+ File.open(".nuker", "w") do |file|
11
+ file.write @authentication_code
12
+ end
13
+ end
14
+
15
+ Then /^I get a (\d+) http status$/ do |status|
16
+ page.driver.status_code.should eql status.to_i
17
+ end
18
+
19
+ Then /^I see the uploaded feature$/ do
20
+ page.body.should have_content "Feature Name"
21
+ end
22
+
23
+ When /^I put data to \/my_project_name\/features with the authentication code$/ do
24
+ gherkin = Nuker::ParsesFeatures.new.parse("Feature: Feature Name")
25
+ data = [{:path => "feature-name.feature", :gherkin => gherkin}].to_json
26
+ page.driver.put "/projects/my_project_name/features?authentication_code=#{@authentication_code}", data
27
+ end
28
+
29
+ Given /^I create a project called "([^"]*)"$/ do |project_name|
30
+ project project_name
31
+ Nuker::Project.first(:name => project_name).class.should equal Nuker::Project
32
+ end
33
+
34
+ When /^I send DELETE to "([^"]*)"$/ do |project_path|
35
+ page.driver.delete "#{project_path}?authentication_code=#{@authentication_code}"
36
+ end
37
+
38
+ Then /^"([^"]*)" should exist$/ do |project_name|
39
+ Nuker::Project.first(:name => project_name).class.should equal Nuker::Project
40
+ end
41
+
42
+ Then /^"([^"]*)" should not exist$/ do |project_name|
43
+ Nuker::Project.first(:name => project_name).class.should_not equal Nuker::Project
44
+ end
45
+
46
+ When /^I visit "([^"]*)" page$/ do |project_name|
47
+ visit "/projects/#{project_name}"
48
+ end
@@ -0,0 +1,29 @@
1
+ When /^click on a scenario header link$/ do
2
+ find('.scenarios a').click
3
+ end
4
+
5
+ Then /^a page appears with the scenario content$/ do
6
+ page.body.should have_content "Sample Aidy"
7
+ page.body.should have_content "Given my name is \"Aidy\""
8
+ page.body.should have_content "When I drink alcohol"
9
+ page.body.should have_content "Then I go nuts"
10
+ end
11
+
12
+ Then /^the background is visible$/ do
13
+ page.body.should have_content "Background:"
14
+ page.body.should have_content "Given some things"
15
+ end
16
+
17
+ Then /^I see the data table$/ do
18
+ text_for_all('th').should == ['name', 'email']
19
+ text_for_all('td').should == ['Aidy', 'aidy@example.com', 'Andrew', 'vos@example.com']
20
+ end
21
+
22
+ Then /^I see the examples table$/ do
23
+ text_for_all('th').should == ['start', 'eat', 'left']
24
+ text_for_all('td').should == ['12', '5', '7', '20', '5', '15']
25
+ end
26
+
27
+ def text_for_all tag
28
+ page.all(tag).collect { |heading| heading.text.strip }
29
+ end
@@ -0,0 +1,24 @@
1
+ Given /^I am on the search page$/ do
2
+ visit "/projects/project/search"
3
+ end
4
+
5
+ When /^I search for "([^"]*)"$/ do |text|
6
+ fill_in 'q', :with => text
7
+ click_button 'Search'
8
+ end
9
+
10
+ Then /^I see a search result link to "([^"]*)" with the url "([^"]*)"$/ do |text, url|
11
+ within ".content" do
12
+ page.should have_link text, :href => url
13
+ end
14
+ end
15
+
16
+ Then /^I see "([^"]*)" in the search results$/ do |text|
17
+ within ".content" do
18
+ page.should have_content text
19
+ end
20
+ end
21
+
22
+ Then /^I see the html:$/ do |html|
23
+ page.body.should include html
24
+ end
@@ -0,0 +1,35 @@
1
+ Given /^a feature file named "([^"]*)" with the contents:$/ do |filename, contents|
2
+ @contents = contents
3
+ create_feature("project", filename, @contents)
4
+ end
5
+
6
+ When /^I visit the project page$/ do
7
+ visit "/projects/project"
8
+ end
9
+
10
+ When /^I visit the sample feature page$/ do
11
+ visit "/projects/project/features/sample-feature"
12
+ end
13
+
14
+ When /^I select "([^"]*)"$/ do |text|
15
+ click_link text
16
+ end
17
+
18
+ Then /^I see a link to "([^"]*)" with the url "([^"]*)"$/ do |text, url|
19
+ page.should have_link text, :href => url
20
+ end
21
+
22
+ Then /^I see "([^"]*)"$/ do |text|
23
+ page.should have_content(text)
24
+ end
25
+
26
+ Then /^the total tag count is displayed$/ do
27
+ save_and_open_page
28
+ end
29
+
30
+ Then /^I see each tag has an individual colour$/ do
31
+ find('a.tag-tag1').should be_visible
32
+ find('a.tag-tag2').should be_visible
33
+ find('a.tag-tag3').should be_visible
34
+ end
35
+
@@ -0,0 +1,19 @@
1
+ Given /^there aren't any projects$/ do
2
+ end
3
+
4
+ When /^I view the welcome page$/ do
5
+ visit "/"
6
+ end
7
+
8
+ Then /^I am redirected to the "([^"]*)" project page$/ do |project|
9
+ sleep 1
10
+ page.current_path.should include "/projects/#{project}"
11
+ end
12
+
13
+ When /^I select the project "([^"]*)"$/ do |project|
14
+ select(project, :from => "projects")
15
+ end
16
+
17
+ Then /^I see the nuker README$/ do
18
+ page.should have_content "Nuker is a web-based Cucumber viewer and navigator"
19
+ end
@@ -0,0 +1,33 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), "../../lib"))
2
+ ENV['RACK_ENV'] = 'test'
3
+ require "nuker"
4
+ require "fileutils"
5
+ require "capybara/cucumber"
6
+ require "rspec"
7
+ require "fakefs/spec_helpers"
8
+
9
+ Capybara.app = Sinatra::Application
10
+
11
+ After do
12
+ Nuker::Project.delete_all
13
+ end
14
+
15
+ Capybara.register_driver :selenium_chrome do |app|
16
+ Capybara::Selenium::Driver.new(app, :browser => :chrome)
17
+ end
18
+ Capybara.javascript_driver = :selenium_chrome
19
+
20
+ def project name
21
+ project = Nuker::Project.first(:name => name)
22
+ unless project
23
+ project = Nuker::Project.create(:name => name)
24
+ end
25
+ project
26
+ end
27
+
28
+ def create_feature project, path, content
29
+ project = project(project)
30
+ feature = Nuker::Feature.new(:path => path, :gherkin => Nuker::ParsesFeatures.new.parse(content))
31
+ project.features << feature
32
+ project.save
33
+ end
@@ -0,0 +1,30 @@
1
+ Feature: Welcome Page
2
+ As a stakeholder
3
+ I want a welcome page
4
+
5
+ Scenario: No projects
6
+ Given there aren't any projects
7
+ When I view the welcome page
8
+ Then I see the nuker README
9
+
10
+ @javascript
11
+ Scenario: Project links on home page
12
+ Given a feature file on the project "sample1" with the contents:
13
+ """
14
+ Feature: Sample1
15
+ """
16
+ And a feature file on the project "sample2" with the contents:
17
+ """
18
+ Feature: Sample2
19
+ """
20
+ When I view the welcome page
21
+ And I select the project "sample2"
22
+ Then I am redirected to the "sample2" project page
23
+
24
+ Scenario: Redirect to first project
25
+ Given a feature file on the project "sample1" with the contents:
26
+ """
27
+ Feature: Sample1
28
+ """
29
+ When I view the welcome page
30
+ Then I am redirected to the "sample1" project page
@@ -0,0 +1,161 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__)))
2
+ require "sinatra"
3
+ require "haml"
4
+ require "rdiscount"
5
+ require "mongo_mapper"
6
+ require "nuker/feature"
7
+ require "nuker/project"
8
+ require "nuker/search_features"
9
+ require "nuker/counts_tags"
10
+ require "nuker/parses_features"
11
+ require "cgi"
12
+
13
+ configure do
14
+ set :haml, { :ugly=>true }
15
+ end
16
+
17
+ if ENV['MONGOHQ_URL']
18
+ uri = URI.parse(ENV['MONGOHQ_URL'])
19
+ MongoMapper.connection = Mongo::Connection.from_uri(ENV['MONGOHQ_URL'])
20
+ MongoMapper.database = uri.path.gsub(/^\//, '')
21
+ else
22
+ MongoMapper.connection = Mongo::Connection.new('localhost')
23
+ MongoMapper.database = "nuker"
24
+ end
25
+
26
+ def current_project
27
+ @current_project ||= Nuker::Project.first(:name => params[:project])
28
+ end
29
+
30
+ def tag_count
31
+ return {} if current_project.nil?
32
+ @tag_count ||= Nuker::CountsTags.new(current_project).count_tags
33
+ end
34
+
35
+ def excessive_wip_tags
36
+ tag_count["@wip"] >= 10 if tag_count["@wip"]
37
+ end
38
+
39
+ def scenario_count
40
+ current_project.features.inject(0) do |count, feature|
41
+ if feature.gherkin["elements"]
42
+ count += feature.gherkin["elements"].select { |e| e["type"] == "scenario" }.size
43
+ end
44
+ if feature.gherkin["elements"]
45
+ count += feature.gherkin["elements"].select { |e| e["type"] == "scenario_outline" }.size
46
+ end
47
+ count
48
+ end
49
+ end
50
+
51
+ def highlighted_search_result_blurb search_result
52
+ offset = 0
53
+ highlighted = search_result.object.text.dup
54
+ span_start = "!!SPAN_START!!"
55
+ span_end = "!!SPAN_END!!"
56
+ search_result.matches.each do |match|
57
+ highlighted.insert(match.index + offset, span_start)
58
+ offset += span_start.length
59
+ highlighted.insert(match.index + match.text.length + offset, span_end)
60
+ offset += span_end.length
61
+ end
62
+ highlighted = CGI::escapeHTML(highlighted)
63
+ highlighted.gsub!(span_start, "<span class=\"search-result\">")
64
+ highlighted.gsub!(span_end, "</span>")
65
+ highlighted
66
+ end
67
+
68
+ def authenticated?
69
+ File.exist?(".nuker") && params[:authentication_code] == File.read(".nuker").strip
70
+ end
71
+
72
+ def get_scenario_url(scenario)
73
+ url = "/projects/#{current_project.name}/features/#{scenario["id"].gsub(";", "/scenario/")}"
74
+ end
75
+
76
+ def get_sorted_scenarios(feature)
77
+ scenarios = []
78
+
79
+ if feature.gherkin["elements"]
80
+ feature.gherkin["elements"].each do |element|
81
+ if element["type"] == "scenario" || element["type"] == "scenario_outline"
82
+ scenarios << element
83
+ end
84
+ end
85
+ end
86
+ scenarios.sort! { |a, b| a["name"] <=> b["name"] }
87
+ scenarios
88
+ end
89
+
90
+ put '/projects/:project/features/?' do
91
+ error 403 unless authenticated?
92
+
93
+ current_project.delete if current_project
94
+ project = Nuker::Project.create(:name => params[:project])
95
+
96
+ JSON.parse(request.body.read).each do |json|
97
+ project.features << Nuker::Feature.new(:path => json["path"], :gherkin => json["gherkin"])
98
+ end
99
+ project.save
100
+ halt 201
101
+ end
102
+
103
+ get '/?' do
104
+ first_project = Nuker::Project.first
105
+ if first_project
106
+ redirect "/projects/#{first_project.name}"
107
+ else
108
+ readme_path = File.expand_path(File.join(File.dirname(__FILE__), "../../README.md"))
109
+ markdown File.read(readme_path), :layout => false
110
+ end
111
+ end
112
+
113
+ get '/robots.txt' do
114
+ "User-agent: *\nDisallow: /"
115
+ end
116
+
117
+ get '/projects/:project/?' do
118
+ haml :project
119
+ end
120
+
121
+ delete '/projects/:project' do
122
+ error 403 unless authenticated?
123
+ project = Nuker::Project.first(:name => params[:project])
124
+ project.destroy
125
+ halt 201
126
+ end
127
+
128
+ get '/projects/:project/features/:feature/?' do
129
+ current_project.features.each do |feature|
130
+ @feature = feature if feature.gherkin["id"] == params[:feature]
131
+ end
132
+ haml :feature
133
+ end
134
+
135
+ get '/projects/:project/progress/?' do
136
+ haml :progress
137
+ end
138
+
139
+ get '/projects/:project/search/?' do
140
+ if params[:q]
141
+ @search_results = Nuker::SearchFeatures.new(current_project).find(:query => params[:q])
142
+ end
143
+ haml :search
144
+ end
145
+
146
+ get '/projects/:project/features/:feature/scenario/:scenario/?' do
147
+ current_project.features.each do |feature|
148
+ if feature.gherkin["id"] == params[:feature]
149
+ @feature = feature
150
+ feature.gherkin["elements"].each do |element|
151
+ if element["type"] == "background"
152
+ @background = element
153
+ end
154
+ if (element["type"] == "scenario" || element["type"] == "scenario_outline") && element["id"] == "#{params[:feature]};#{params[:scenario]}"
155
+ @scenario = element
156
+ end
157
+ end
158
+ end
159
+ end
160
+ haml :scenario
161
+ end
@@ -0,0 +1,27 @@
1
+ module Nuker
2
+ class CountsTags
3
+ def initialize project
4
+ @project = project
5
+ end
6
+
7
+ def count_tags
8
+ @project.features.inject(Hash.new(0)) do |tag_count, feature|
9
+ if feature.gherkin["tags"]
10
+ feature.gherkin["tags"].each do |tag|
11
+ tag_count[tag["name"].downcase] += 1
12
+ end
13
+ end
14
+ if feature.gherkin["elements"]
15
+ feature.gherkin["elements"].each do |element|
16
+ if element["tags"]
17
+ element["tags"].each do |tag|
18
+ tag_count[tag["name"].downcase] += 1
19
+ end
20
+ end
21
+ end
22
+ end
23
+ tag_count
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ module Nuker
2
+ class Feature
3
+ include MongoMapper::EmbeddedDocument
4
+
5
+ key :path, String
6
+ key :gherkin, Hash
7
+ key :name, String
8
+
9
+ before_save :save_feature_name
10
+
11
+ private
12
+ def save_feature_name
13
+ @name = gherkin["name"]
14
+ end
15
+ end
16
+ end