sinatra-footnotes 0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 214783285ead66416d306c66355500bcb314603c
4
+ data.tar.gz: fa8c328067f09b58e3384d0aba746716dfb692d2
5
+ SHA512:
6
+ metadata.gz: a6eb18d3a39196bf28a0fadda858bb747d99017672365c9a8004f708bf729a05ee850f35d8943994774063feaa0832325fd4fc1a8da429a00738eb81666e41b5
7
+ data.tar.gz: dc2f36b6771f77c80eba9fae45675a1e7adb57fed47909c62073735831c582922976ea35d42e794fd3a17ab8a08cece290819819e9679a00a34be934cbffcb49
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sinatra-footnotes.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Daniel Stutzman
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # Sinatra Footnotes
2
+
3
+ Every page has footnotes that give information about your application. Based on Rails Footnotes by José Valim (https://github.com/josevalim/rails-footnotes)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'sinatra-footnotes'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install sinatra-footnotes
18
+
19
+ ## Usage
20
+
21
+ Add this line to your Sinatra application file:
22
+
23
+ require 'sinatra-footnotes'
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,98 @@
1
+ require 'sinatra-footnotes/version'
2
+ require 'sinatra/base'
3
+ require 'active_support/core_ext'
4
+
5
+ dir = File.dirname(__FILE__)
6
+ %w[session cookies params sinatra_routes env assigns].each do |prefix|
7
+ require File.join(dir, 'sinatra-footnotes', 'notes', "#{prefix}_note.rb")
8
+ end
9
+
10
+ module Sinatra
11
+ module Footnotes
12
+ module Helpers
13
+ # Process notes to get javascript code to close them.
14
+ #
15
+ def close_helper(note)
16
+ "Footnotes.hide(document.getElementById('#{note.to_sym}_debug_info'));\n"
17
+ end
18
+
19
+ # Helper that creates the link and javascript code when note is clicked
20
+ #
21
+ def link_helper(note)
22
+ onclick = note.onclick
23
+ unless href = note.link
24
+ href = '#'
25
+ onclick ||= "Footnotes.hideAllAndToggle('#{note.to_sym}_debug_info');return false;" if note.has_fieldset?
26
+ end
27
+
28
+ "<a href=\"#{href}\" onclick=\"#{onclick}\">#{note.title}</a>"
29
+ end
30
+
31
+ def each_with_rescue(notes)
32
+ notes.each do |note|
33
+ begin
34
+ yield note
35
+ rescue Exception => e
36
+ STDERR.puts "FootNotes #{note.to_s.camelize}NoteException"
37
+ STDERR.puts e
38
+ end
39
+ end
40
+ end
41
+
42
+ def fieldsets(notes)
43
+ content = ''
44
+ each_with_rescue(notes) do |note|
45
+ next unless note.has_fieldset?
46
+ content << <<-HTML
47
+ <fieldset id="#{note.to_sym}_debug_info" style="display: none">
48
+ <legend>#{note.legend}</legend>
49
+ <div>#{note.content}</div>
50
+ </fieldset>
51
+ HTML
52
+ end
53
+ content
54
+ end
55
+ end
56
+
57
+ def self.registered(app)
58
+ app.helpers Footnotes::Helpers
59
+
60
+ app.after do
61
+ style_path = File.join(
62
+ File.dirname(__FILE__), 'sinatra-footnotes', 'style.html')
63
+ response.body.push File.read(style_path)
64
+
65
+ response.body.push '<!-- Footnotes -->'
66
+ response.body.push '<div style="clear:both"></div>'
67
+ response.body.push '<div id="footnotes_debug">'
68
+ response.body.push 'Show:'
69
+
70
+ notes = []
71
+ notes.push ::Footnotes::Notes::SessionNote.new(self)
72
+ notes.push ::Footnotes::Notes::CookiesNote.new(self.request)
73
+ notes.push ::Footnotes::Notes::ParamsNote.new(self)
74
+ notes.push ::Footnotes::Notes::SinatraRoutesNote.new(app)
75
+ notes.push ::Footnotes::Notes::EnvNote.new(self)
76
+ notes.push(::Footnotes::Notes::AssignsNote.new(self).tap do |note|
77
+ note.ignored_assigns = [:@default_layout, :@app, :@template_cache,
78
+ :@env, :@request, :@response, :@params,
79
+ :@preferred_extension, :@_out_buf]
80
+ end)
81
+
82
+ response.body.push notes.map { |note| link_helper(note) }.join(' | ')
83
+ response.body.push '<br />'
84
+
85
+ response.body.push fieldsets(notes)
86
+
87
+ script_path = File.join(
88
+ File.dirname(__FILE__), 'sinatra-footnotes', 'script.html')
89
+ response.body.push(File.read(script_path))
90
+
91
+ response.body.push '</div>'
92
+ response.body.push '<!-- End Footnotes -->'
93
+ end
94
+ end
95
+ end
96
+
97
+ register Footnotes
98
+ end
@@ -0,0 +1,179 @@
1
+ module Footnotes
2
+ module Notes
3
+ # This is the abstract class for notes.
4
+ # You can overwrite all instance public methods to create your notes.
5
+ #
6
+ class AbstractNote
7
+
8
+ # Class methods. Do NOT overwrite them.
9
+ #
10
+ class << self
11
+ # Returns the symbol that represents this note.
12
+ # It's the name of the class, underscored and without _note.
13
+ #
14
+ # For example, for ControllerNote it will return :controller.
15
+ #
16
+ def to_sym
17
+ @note_sym ||= self.title.underscore.to_sym
18
+ end
19
+
20
+ # Returns the title that represents this note.
21
+ # It's the name of the class without Note.
22
+ #
23
+ # For example, for ControllerNote it will return Controller.
24
+ #
25
+ def title
26
+ @note_title ||= self.name.match(/^Footnotes::Notes::(\w+)Note$/)[1]
27
+ end
28
+
29
+ # Return true if Note is included in notes array.
30
+ #
31
+ def included?
32
+ Footnotes::Filter.notes.include?(self.to_sym)
33
+ end
34
+
35
+ # Action to be called to start the Note.
36
+ # This is applied as a before_filter.
37
+ #
38
+ def start!(controller = nil)
39
+ end
40
+
41
+ # Action to be called after the Note was used.
42
+ # This is applied as an after_filter.
43
+ #
44
+ def close!(controller = nil)
45
+ end
46
+ end
47
+
48
+ # Initialize notes.
49
+ # Always receives a controller.
50
+ #
51
+ def initialize(controller = nil)
52
+ end
53
+
54
+ # Returns the symbol that represents this note.
55
+ #
56
+ def to_sym
57
+ self.class.to_sym
58
+ end
59
+
60
+ # Specifies in which row should appear the title.
61
+ # The default is :show.
62
+ #
63
+ def row
64
+ :show
65
+ end
66
+
67
+ # Returns the title to be used as link.
68
+ # The default is the note title.
69
+ #
70
+ def title
71
+ self.class.title
72
+ end
73
+
74
+ # If has_fieldset? is true, create a fieldset with the value returned as legend.
75
+ # By default, returns the title of the class (defined above).
76
+ #
77
+ def legend
78
+ self.class.title
79
+ end
80
+
81
+ # If content is defined, has_fieldset? returns true and the value of content
82
+ # is displayed when the Note is clicked. See has_fieldset? below for more info.
83
+ #
84
+ # def content
85
+ # end
86
+
87
+ # Set href field for Footnotes links.
88
+ # If it's nil, Footnotes will use '#'.
89
+ #
90
+ def link
91
+ end
92
+
93
+ # Set onclick field for Footnotes links.
94
+ # If it's nil, Footnotes will make it open the fieldset.
95
+ #
96
+ def onclick
97
+ end
98
+
99
+ # Insert here any additional stylesheet.
100
+ # This is directly inserted into a <style> tag.
101
+ #
102
+ def stylesheet
103
+ end
104
+
105
+ # Insert here any additional javascript.
106
+ # This is directly inserted into a <script> tag.
107
+ #
108
+ def javascript
109
+ end
110
+
111
+ # Specifies when should create a note for it.
112
+ # By default, it's valid.
113
+ #
114
+ def valid?
115
+ true
116
+ end
117
+
118
+ # Specifies when should create a fieldset for it, considering it's valid.
119
+ #
120
+ def has_fieldset?
121
+ self.respond_to?(:content)
122
+ end
123
+
124
+ # Some helpers to generate notes.
125
+ #
126
+ protected
127
+ # Return if Footnotes::Filter.prefix exists or not.
128
+ # Some notes only work with prefix set.
129
+ #
130
+ def prefix?
131
+ !Footnotes::Filter.prefix.blank?
132
+ end
133
+
134
+ # Escape HTML special characters.
135
+ #
136
+ def escape(text)
137
+ text.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;')
138
+ end
139
+
140
+ # Gets a bidimensional array and create a table.
141
+ # The first array is used as label.
142
+ #
143
+ def mount_table(array, options = {})
144
+ header = array.shift
145
+ return '' if array.empty?
146
+
147
+ header = header.collect{|i| escape(i.to_s.humanize) }
148
+ # array = array.collect { |a| a.collect { |b| c = b.to_s; escape(c) unless c == ""}}
149
+ rows = array.collect{|i| "<tr><td>#{i.join('</td><td>')}</td></tr>" }
150
+
151
+ <<-TABLE
152
+ <table #{hash_to_xml_attributes(options)}>
153
+ <thead><tr><th>#{header.join('</th><th>')}</th></tr></thead>
154
+ <tbody>#{rows.join}</tbody>
155
+ </table>
156
+ TABLE
157
+ end
158
+
159
+ # Mount table for hash, using name and value and adding a name_value class
160
+ # to the generated table.
161
+ #
162
+ def mount_table_for_hash(hash, options={})
163
+ rows = []
164
+ hash.each do |key, value|
165
+ rows << [ key.to_sym.inspect, escape(value.inspect) ]
166
+ end
167
+ mount_table(rows.unshift(['Name', 'Value']), {:class => 'name_value'}.merge(options))
168
+ end
169
+
170
+ def hash_to_xml_attributes(hash)
171
+ newstring = ""
172
+ hash.each do |key, value|
173
+ newstring << "#{key.to_s}=\"#{value.gsub('"','\"')}\" "
174
+ end
175
+ return newstring
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,60 @@
1
+ require "#{File.dirname(__FILE__)}/abstract_note"
2
+
3
+ module Footnotes
4
+ module Notes
5
+ class AssignsNote < AbstractNote
6
+ @@ignored_assigns = [
7
+ :@real_format,
8
+ :@before_filter_chain_aborted,
9
+ :@performed_redirect,
10
+ :@performed_render,
11
+ :@_params,
12
+ :@_response,
13
+ :@url,
14
+ :@template,
15
+ :@_request,
16
+ :@db_rt_before_render,
17
+ :@db_rt_after_render,
18
+ :@view_runtime
19
+ ]
20
+ cattr_accessor :ignored_assigns, :instance_writter => false
21
+
22
+ def initialize(controller)
23
+ @controller = controller
24
+ end
25
+
26
+ def title
27
+ "Assigns (#{assigns.size})"
28
+ end
29
+
30
+ def valid?
31
+ assigns
32
+ end
33
+
34
+ def content
35
+ rows = []
36
+ assigns.each do |key|
37
+ rows << [ key, escape(assigned_value(key)) ]
38
+ end
39
+ mount_table(rows.unshift(['Name', 'Value']), :class => 'name_values', :summary => "Debug information for #{title}")
40
+ end
41
+
42
+ protected
43
+
44
+ def assigns
45
+ assign = []
46
+ ignored = @@ignored_assigns
47
+
48
+ @controller.instance_variables.each {|x| assign << x.intern }
49
+ @controller.protected_instance_variables.each {|x| ignored << x.intern } if @controller.respond_to? :protected_instance_variables
50
+
51
+ assign -= ignored
52
+ return assign
53
+ end
54
+
55
+ def assigned_value(key)
56
+ @controller.instance_variable_get(key).inspect
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,19 @@
1
+ require "#{File.dirname(__FILE__)}/abstract_note"
2
+
3
+ module Footnotes
4
+ module Notes
5
+ class CookiesNote < AbstractNote
6
+ def initialize(controller)
7
+ @cookies = (controller.__send__(:cookies) || {}).symbolize_keys
8
+ end
9
+
10
+ def title
11
+ "Cookies (#{@cookies.length})"
12
+ end
13
+
14
+ def content
15
+ mount_table_for_hash(@cookies, :summary => "Debug information for #{title}")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ require "#{File.dirname(__FILE__)}/abstract_note"
2
+
3
+ module Footnotes
4
+ module Notes
5
+ class EnvNote < AbstractNote
6
+ def initialize(controller)
7
+ @env = controller.request.env.dup
8
+ end
9
+
10
+ def content
11
+ env_data = @env.to_a.sort.unshift([:key, :value]).map do |k,v|
12
+ case k
13
+ when 'HTTP_COOKIE'
14
+ # Replace HTTP_COOKIE for a link
15
+ [k, '<a href="#" style="color:#009" onclick="Footnotes.hideAllAndToggle(\'cookies_debug_info\');return false;">See cookies on its tab</a>']
16
+ else
17
+ [k, escape(v.to_s)]
18
+ end
19
+ end
20
+
21
+ # Create the env table
22
+ mount_table(env_data)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ require "#{File.dirname(__FILE__)}/abstract_note"
2
+
3
+ module Footnotes
4
+ module Notes
5
+ class ParamsNote < AbstractNote
6
+ def initialize(controller)
7
+ @params = controller.params.symbolize_keys
8
+ end
9
+
10
+ def title
11
+ "Params (#{@params.length})"
12
+ end
13
+
14
+ def content
15
+ mount_table_for_hash(@params, :summary => "Debug information for #{title}")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ require "#{File.dirname(__FILE__)}/abstract_note"
2
+
3
+ module Footnotes
4
+ module Notes
5
+ class SessionNote < AbstractNote
6
+ def initialize(controller)
7
+ session = controller.session
8
+ if session
9
+ if session.respond_to? :to_hash
10
+ # rails >= 2.3
11
+ session = session.to_hash
12
+ else
13
+ #rails < 2.3
14
+ session = session.data
15
+ end
16
+ end
17
+ @session = (session || {}).symbolize_keys
18
+ end
19
+
20
+ def title
21
+ "Session (#{@session.length})"
22
+ end
23
+
24
+ def content
25
+ mount_table_for_hash(@session, :summary => "Debug information for #{title}")
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,52 @@
1
+ require "#{File.dirname(__FILE__)}/abstract_note"
2
+
3
+ module Footnotes
4
+ module Notes
5
+ class SinatraRoutesNote < AbstractNote
6
+ def initialize(controller)
7
+ @controller = controller
8
+ @parsed_routes = parse_routes(controller)
9
+ end
10
+
11
+ def title
12
+ "Routes (#{@parsed_routes.size})" # don't show 'SinatraRoutes'
13
+ end
14
+
15
+ def legend
16
+ 'Routes'
17
+ end
18
+
19
+ def content
20
+ #mount_table(@parsed_routes.unshift([:path, :name, :options, :requirements]), :summary => "Debug information for #{title}")
21
+ mount_table(@parsed_routes.unshift([:method, :path]), :summary => "Debug information for #{title}")
22
+ end
23
+
24
+ protected
25
+ def parse_routes(controller)
26
+ # thanks to cldwalker's tux gem for this code to interpret Sinatra routes
27
+ routes = controller.routes.inject([]) {|arr, (k,v)|
28
+ arr += v.map {|regex,params,*|
29
+ path = params.empty? ? regex.inspect :
30
+ params.inject(regex.inspect) {|s,e| s.sub(/\([^()]+\)/, ":#{e}") }
31
+ [k, (str = path[%r{/\^(.*)\$/}, 1]) ? str.tr('\\', '') : path]
32
+ }
33
+ }
34
+
35
+ # still need to pull the regex syntax out
36
+ routes = routes.map do |method_and_path|
37
+ method, path = method_and_path
38
+ path =
39
+ path.to_s.gsub("\\/", "/").gsub(%r[^/\\A], "").gsub(%r[\\z/$], "")
40
+ [method, path]
41
+ end
42
+
43
+ # don't show HEAD requests
44
+ routes = routes.reject! do |method_and_path|
45
+ method_and_path[0] == 'HEAD'
46
+ end
47
+
48
+ routes
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ <script type="text/javascript">
2
+ var Footnotes = function() {
3
+
4
+ function hideAll(){
5
+ Footnotes.hide(document.getElementById('assigns_debug_info'));
6
+ Footnotes.hide(document.getElementById('params_debug_info'));
7
+ Footnotes.hide(document.getElementById('sinatra_routes_debug_info'));
8
+ Footnotes.hide(document.getElementById('session_debug_info'));
9
+ Footnotes.hide(document.getElementById('cookies_debug_info'));
10
+ Footnotes.hide(document.getElementById('env_debug_info'));
11
+ }
12
+
13
+ function hideAllAndToggle(id) {
14
+ hideAll();
15
+ toggle(id)
16
+
17
+ location.href = '#footnotes_debug';
18
+ }
19
+
20
+ function toggle(id){
21
+ var el = document.getElementById(id);
22
+ if (el.style.display == 'none') {
23
+ Footnotes.show(el);
24
+ } else {
25
+ Footnotes.hide(el);
26
+ }
27
+ }
28
+
29
+ function show(element) {
30
+ element.style.display = 'block'
31
+ }
32
+
33
+ function hide(element) {
34
+ element.style.display = 'none'
35
+ }
36
+
37
+ return {
38
+ show: show,
39
+ hide: hide,
40
+ toggle: toggle,
41
+ hideAllAndToggle: hideAllAndToggle
42
+ }
43
+ }();
44
+ /* Additional Javascript */
45
+ </script>
@@ -0,0 +1,15 @@
1
+ <!-- Footnotes Style -->
2
+ <style type="text/css">
3
+ #footnotes_debug {font-size: 11px; font-weight: normal; margin: 2em 0 1em 0; text-align: center; color: #444; line-height: 16px;}
4
+ #footnotes_debug th, #footnotes_debug td {color: #444; line-height: 18px;}
5
+ #footnotes_debug a {color: #9b1b1b; font-weight: inherit; text-decoration: none; line-height: 18px;}
6
+ #footnotes_debug table {text-align: center;}
7
+ #footnotes_debug table td {padding: 0 5px;}
8
+ #footnotes_debug tbody {text-align: left;}
9
+ #footnotes_debug .name_values td {vertical-align: top;}
10
+ #footnotes_debug legend {background-color: #fff;}
11
+ #footnotes_debug fieldset {text-align: left; border: 1px dashed #aaa; padding: 0.5em 1em 1em 1em; margin: 1em 2em; color: #444; background-color: #FFF;}
12
+ /* Aditional Stylesheets */
13
+
14
+ </style>
15
+ <!-- End Footnotes Style -->
@@ -0,0 +1,5 @@
1
+ module Sinatra
2
+ module Footnotes
3
+ VERSION = "0.1"
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sinatra-footnotes/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "sinatra-footnotes"
8
+ gem.version = Sinatra::Footnotes::VERSION
9
+ gem.authors = ["Daniel Stutzman"]
10
+ gem.email = ["dtstutz@gmail.com"]
11
+ gem.description = "Every page has footnotes that give information about your application."
12
+ gem.summary = "Every page has footnotes that give information about your application."
13
+ gem.homepage = "https://github.com/danielstutzman/sinatra-footnotes"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "sinatra"
21
+ gem.add_dependency "activesupport"
22
+ gem.add_dependency "i18n" # needed for active_support
23
+ end
@@ -0,0 +1,8 @@
1
+ require 'sinatra'
2
+
3
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)) + "/lib")
4
+ require 'sinatra-footnotes'
5
+
6
+ get "/" do
7
+ @a = 1
8
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-footnotes
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Stutzman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-07 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: activesupport
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: i18n
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
+ description: Every page has footnotes that give information about your application.
56
+ email:
57
+ - dtstutz@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/sinatra-footnotes.rb
68
+ - lib/sinatra-footnotes/notes/abstract_note.rb
69
+ - lib/sinatra-footnotes/notes/assigns_note.rb
70
+ - lib/sinatra-footnotes/notes/cookies_note.rb
71
+ - lib/sinatra-footnotes/notes/env_note.rb
72
+ - lib/sinatra-footnotes/notes/params_note.rb
73
+ - lib/sinatra-footnotes/notes/session_note.rb
74
+ - lib/sinatra-footnotes/notes/sinatra_routes_note.rb
75
+ - lib/sinatra-footnotes/script.html
76
+ - lib/sinatra-footnotes/style.html
77
+ - lib/sinatra-footnotes/version.rb
78
+ - sinatra-footnotes.gemspec
79
+ - test_sinatra_app.rb
80
+ homepage: https://github.com/danielstutzman/sinatra-footnotes
81
+ licenses: []
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.0.3
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Every page has footnotes that give information about your application.
103
+ test_files: []
104
+ has_rdoc: