rack-usermanual 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTU5Mzg1NWM1NzFkMzA5Y2RiMDc2OWNhYjBlMzRjZjNjNmM1YzU0MQ==
5
+ data.tar.gz: !binary |-
6
+ MDE4NDA4NzI1MTcxNDM1Y2IxMTc0NmM2NTYwYjNkZjdkOTgyMTZhZA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MjVmNDQ2ZmJmNDFlMGQ4NmVlYmRiZWUwYWY5MzA0N2IyNzhkYmYwNzU2OGU4
10
+ MTRhYzBlZDVlYTMwODIwMWUyYzVjYTBlMTBiNjBiYTY2YjYzMWJjOTQ1OWM0
11
+ YTI3MDA3ZTc3MjAxYmU2OTkyY2VlYjZlM2ZiY2ZmMDRhYTExM2I=
12
+ data.tar.gz: !binary |-
13
+ ZWI2MTI3NDBhODVkM2FiY2E0YjAwMDBjYTU3MDJiYmYzZTU3MzA0OThlN2Iz
14
+ Y2YyOTQ4ZWMxN2I5ZjliNDlkMzBhNmI0MDQ1YzlkYWE5YmNiNzkxYWNkNmEy
15
+ OGYwZmFjZjdlOTc3MjBjNWRjYmViMzg5N2IxMWNhYTBhZmFkYWY=
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Chris Parsons
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.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ Rack::Usermanual
2
+ ================
3
+
4
+ This little piece of middleware helps you expose your cucumber features in a readable 'manual-like' style for your users to consume.
5
+
6
+ To use, add the following to your Rack app:
7
+
8
+ ```
9
+ # Choose whatever url endpoint you like.
10
+ map "/help" do
11
+ use Rack::Usermanual,
12
+ # `sections`: Sections of the manual: human readable name together
13
+ # with a path to a folder containing the features.
14
+ :sections => {
15
+ "Game manual" => 'features/docs/game-manual',
16
+ "API documentation" => 'features/docs/api-documentation'
17
+ },
18
+ # `index`: Markdown to display on the index page of the help.
19
+ :index => 'features/docs/README.md',
20
+ # `views`: Look in here for the layout: layout.erb, layout.haml etc.
21
+ :views => File.join(Dir.pwd, 'views')
22
+ end
23
+ ```
24
+
25
+ Then start your app and point your browser to `/help` and your features should be displayed for you!
26
+
27
+ The app will use the layout that you have in layout.{erb,haml} in whichever folder you specify. The CSS in the views is based on bootstrap: you might need to style your features slightly differently to get them to work in the way that you want. In the future it may be possible to completely override the views with your own.
28
+
29
+ ## Contributing
30
+
31
+ We work on pull requests. If you have an idea for something you'd like to contribute, here's how to do it:
32
+
33
+ * Fork the project.
34
+ * Make your feature addition or bug fix.
35
+ * Add tests for it. This is important so I don't break it in a
36
+ future version unintentionally.
37
+ * Commit, do not mess with rakefile, version, or history.
38
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
39
+ * Send me a pull request. Bonus points for topic branches.
@@ -0,0 +1,73 @@
1
+ require 'gherkin'
2
+ require 'gherkin/formatter/json_formatter'
3
+ require 'stringio'
4
+ require 'json'
5
+ require 'sinatra'
6
+ require 'kramdown'
7
+
8
+ module Rack
9
+ class Usermanual < Sinatra::Base
10
+ VERSION = "0.1.0"
11
+
12
+ def initialize(app, options)
13
+ super(app)
14
+ @sections = options[:sections]
15
+ @index = options[:index]
16
+ @main_views = options[:views]
17
+ end
18
+
19
+ helpers do
20
+ def find_template(views, name, engine, &block)
21
+ new_views = [
22
+ ::File.expand_path(::File.join(::File.dirname(__FILE__), '..', '..', '..', 'views')),
23
+ @main_views
24
+ ].flatten.compact
25
+ Array(new_views).each { |v| super(v, name, engine, &block) }
26
+ end
27
+
28
+ def h(text)
29
+ Rack::Utils.escape_html(text)
30
+ end
31
+
32
+ def replace_start(sentence)
33
+ {
34
+ /^given / => 'Assume ',
35
+ /^but / => 'However, ',
36
+ /^and / => ''
37
+ }.each do |find, replace|
38
+ sentence.sub!(find, replace)
39
+ end
40
+ sentence
41
+ end
42
+ end
43
+
44
+ get '/?' do
45
+ haml :index
46
+ end
47
+
48
+ def get_feature(path, page)
49
+ sio = StringIO.new
50
+ json_formatter = Gherkin::Formatter::JSONFormatter.new(sio)
51
+ parser = Gherkin::Parser::Parser.new(json_formatter)
52
+ raw = ::File.read("#{path}/#{page}.feature")
53
+ parser.parse(raw, uri, 0)
54
+ json_formatter.done
55
+ [raw, JSON.parse(sio.string)]
56
+ end
57
+
58
+ get %r{/([\w-]+)/([\w-]+)/?$} do
59
+ section_uri, @page = params[:captures]
60
+
61
+ section = @sections.select do |human_name, path|
62
+ ::File.basename(path) == section_uri
63
+ end
64
+ halt 404 unless section
65
+ @human_name = section.keys.first
66
+ path = section.values.first
67
+
68
+ @raw, @json = get_feature(path, @page)
69
+
70
+ haml :page
71
+ end
72
+ end
73
+ end
@@ -0,0 +1 @@
1
+ require 'rack/usermanual/app'
@@ -0,0 +1 @@
1
+ require 'rack/usermanual'
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rack/usermanual"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rack-usermanual"
7
+ s.version = Rack::Usermanual::VERSION
8
+ s.authors = ["Chris Parsons"]
9
+ s.email = ["chris.p@rsons.org"]
10
+ s.homepage = "http://github.com/chrismdp/rack-usermanual"
11
+ s.summary = %q{Rack endpoint to serve your cucumber features as a user manual}
12
+ s.description = %q{}
13
+
14
+ s.rubyforge_project = "rack-usermanual"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
18
+ s.require_paths = ['lib']
19
+
20
+ s.add_dependency 'sinatra'
21
+ s.add_dependency 'haml'
22
+ s.add_dependency 'kramdown'
23
+ s.add_dependency 'gherkin'
24
+ s.add_dependency 'rack'
25
+ s.add_development_dependency 'rspec'
26
+ s.add_development_dependency 'rack-test'
27
+ end
@@ -0,0 +1,8 @@
1
+ Feature: test feature
2
+ This is the preamble
3
+
4
+ Scenario: First
5
+ Given something is true
6
+ When this happens
7
+ Then that happens
8
+
@@ -0,0 +1,7 @@
1
+ require 'sinatra'
2
+
3
+ Sinatra::Application.environment = :test
4
+ Bundler.require :default, :test
5
+
6
+ require_relative '../lib/rack-usermanual'
7
+
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'rack/test'
3
+
4
+ describe Rack::Usermanual do
5
+ include Rack::Test::Methods
6
+
7
+ def app
8
+ Rack::Usermanual.new(nil, :sections => {'My section' => 'spec/fixtures/features/my-section'})
9
+ end
10
+
11
+ it "grabs a file from the features folder" do
12
+ get '/help/my-section/test'
13
+ last_response.should be_ok
14
+ last_response.body.should include("This is the preamble")
15
+ end
16
+
17
+ it "accepts trailing slashes" do
18
+ get '/help/my-section/test/'
19
+ last_response.should be_ok
20
+ last_response.body.should include("This is the preamble")
21
+ end
22
+
23
+ it "formats that file correctly" do
24
+ get '/help/my-section/test'
25
+ last_response.body.should include("Assume something is true")
26
+ end
27
+
28
+ it "does not allow you to get a random filesystem file" do
29
+ get '/help/../../lib/solweb.rb'
30
+ last_response.should_not be_ok
31
+ get '/help/../docs/game-manual/combat.feature'
32
+ last_response.should_not be_ok
33
+ end
34
+
35
+ it "returns 404 if the file doesn't exist" do
36
+ get '/help/game-manual/cimbat'
37
+ last_response.should_not be_ok
38
+ end
39
+ end
data/views/_menu.haml ADDED
@@ -0,0 +1,10 @@
1
+ %nav.span3.pull-right
2
+ %ul.nav.nav-list.affix-top{:'data-offset-top' => 100, :'data-spy' => 'affix'}
3
+ - @sections.each do |human_name, path|
4
+ %li.nav-header= human_name
5
+ - if (features = Dir.glob(path + '/*.feature').sort).empty?
6
+ %small.muted No docs yet.
7
+ - features.each do |fn|
8
+ - name = ::File.basename(fn, '.feature')
9
+ %li
10
+ %a{:href => "/help/#{::File.basename(path)}/#{name}"}= name.capitalize.gsub(/[-_]/, ' ')
@@ -0,0 +1,4 @@
1
+ - if element['tags'] && element['tags'].any? {|t| t['name'] == '@pending' }
2
+ .alert.alert-info
3
+ %strong Please note:
4
+ This #{element['keyword'].downcase} does not yet exist, but is planned for some point in the future.
data/views/index.haml ADDED
@@ -0,0 +1,7 @@
1
+ %h4.page-header Help &amp; support
2
+
3
+ .container
4
+ .row
5
+ = haml :_menu
6
+ %article.span9
7
+ = ::Kramdown::Document.new(h(::File.read(@index))).to_html
data/views/page.haml ADDED
@@ -0,0 +1,45 @@
1
+ %h4.page-header
2
+ %a{:href => '/help'} Help &amp; support
3
+ == &raquo; #{@human_name} &raquo; #{@page.capitalize}
4
+
5
+ .container
6
+ .row
7
+ = haml :_menu
8
+ %article.span9.help-text
9
+ %h1= @json.first['name']
10
+ = haml :_pending, :locals => { :element => @json.first }
11
+ = ::Kramdown::Document.new(h(@json.first['description'])).to_html
12
+
13
+ - elements = @json.first['elements']
14
+ - if elements
15
+ %h4 Some examples:
16
+ .examples
17
+ - elements = @json.first['elements']
18
+ - if elements.first['keyword'] == 'Background'
19
+ .well.well-small
20
+ %strong Note:
21
+ The following examples assume
22
+ = elements.first['steps'].map{|s| 'that ' + s['name']}.to_sentence + '.'
23
+ - elements.select { |e| e['keyword'] == 'Scenario' }.each do |example|
24
+ %h5.example== Example: #{example['name'].downcase}
25
+ = haml :_pending, :locals => { :element => example }
26
+ %p
27
+ %em
28
+ - if example['steps']
29
+ - example['steps'].slice_before {|step| step['keyword'] =~ /When|But/ }.each do |chunk|
30
+ = replace_start(chunk.map { |step| step['keyword'].downcase + step['name'] }.join(', ')).tap {|s| s.sub!(/./, &:upcase) } + '.'
31
+ - else
32
+ %span.muted This example hasn't yet been detailed.
33
+ %hr
34
+ %footer.muted
35
+ %small
36
+ Generated automatically from this project's
37
+ %a{:href => "http://github.com/cucumber/cucumber"} Cucumber
38
+ features.
39
+ View the
40
+ %a{:href => 'javascript:false', :'data-toggle' => 'collapse', :'data-target' => '#source'} source.
41
+ %br
42
+ %br
43
+ #source.collapse
44
+ %pre
45
+ %code= @raw
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-usermanual
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Parsons
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sinatra
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: haml
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: kramdown
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: gherkin
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rack-test
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: ''
112
+ email:
113
+ - chris.p@rsons.org
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .rspec
120
+ - Gemfile
121
+ - LICENSE
122
+ - README.md
123
+ - lib/rack-usermanual.rb
124
+ - lib/rack/usermanual.rb
125
+ - lib/rack/usermanual/app.rb
126
+ - rack-usermanual.gemspec
127
+ - spec/fixtures/features/my-section/test.feature
128
+ - spec/spec_helper.rb
129
+ - spec/usermanual_spec.rb
130
+ - views/_menu.haml
131
+ - views/_pending.haml
132
+ - views/index.haml
133
+ - views/page.haml
134
+ homepage: http://github.com/chrismdp/rack-usermanual
135
+ licenses: []
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ! '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ! '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project: rack-usermanual
153
+ rubygems_version: 2.0.3
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: Rack endpoint to serve your cucumber features as a user manual
157
+ test_files:
158
+ - spec/fixtures/features/my-section/test.feature
159
+ - spec/spec_helper.rb
160
+ - spec/usermanual_spec.rb
161
+ has_rdoc: