nuker 0.0.47 → 1.0.0

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 (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