rails-footnotes 3.7.9 → 4.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.
- data/.gitignore +4 -3
- data/.travis.yml +10 -6
- data/CHANGELOG +13 -0
- data/README.rdoc +33 -46
- data/Rakefile +2 -2
- data/gemfiles/Gemfile.rails-3.2.x +5 -0
- data/gemfiles/Gemfile.rails-4.0.x +6 -0
- data/gemfiles/Gemfile.rails-4.1.x +5 -0
- data/gemfiles/Gemfile.rails-edge +5 -0
- data/lib/generators/rails_footnotes/install_generator.rb +1 -4
- data/lib/generators/templates/rails_footnotes.rb +19 -3
- data/lib/rails-footnotes.rb +41 -13
- data/lib/rails-footnotes/extension.rb +22 -3
- data/lib/rails-footnotes/filter.rb +9 -18
- data/lib/rails-footnotes/notes/log_note.rb +18 -25
- data/lib/rails-footnotes/notes/log_note/note_logger.rb +59 -0
- data/lib/rails-footnotes/notes/partials_note.rb +20 -38
- data/lib/rails-footnotes/notes/queries_note.rb +1 -1
- data/lib/rails-footnotes/notes/routes_note.rb +13 -14
- data/lib/rails-footnotes/version.rb +1 -1
- data/rails-footnotes.gemspec +5 -6
- data/spec/abstract_note_spec.rb +5 -0
- data/spec/controllers/footnotes_controller_spec.rb +113 -0
- data/spec/controllers/log_note_controller_spec.rb +45 -0
- data/spec/controllers/partials_note_controller_spec.rb +29 -0
- data/spec/fixtures/html_download.html +5 -0
- data/spec/footnotes_spec.rb +5 -8
- data/spec/notes/assigns_note_spec.rb +1 -1
- data/spec/notes/controller_note_spec.rb +1 -1
- data/spec/notes/files_note_spec.rb +1 -1
- data/spec/notes/javascripts_note_spec.rb +1 -1
- data/spec/notes/stylesheets_note_spec.rb +1 -1
- data/spec/spec_helper.rb +23 -12
- data/spec/views/partials/_foo.html.erb +1 -0
- data/spec/views/partials/index.html.erb +1 -0
- metadata +31 -22
- data/.watchr.example +0 -13
- data/lib/generators/templates/rails_footnotes +0 -3
- data/lib/rails-footnotes/after_filter.rb +0 -10
- data/lib/rails-footnotes/backtracer.rb +0 -32
- data/lib/rails-footnotes/before_filter.rb +0 -9
- data/lib/rails-footnotes/footnotes.rb +0 -7
- data/lib/rails-footnotes/notes/general_note.rb +0 -17
- data/spec/notes/partials_notes_spec.rb +0 -9
@@ -1,14 +1,21 @@
|
|
1
1
|
module Footnotes
|
2
2
|
module Notes
|
3
3
|
class LogNote < AbstractNote
|
4
|
-
@@log = []
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
autoload :NoteLogger, 'rails-footnotes/notes/log_note/note_logger'
|
6
|
+
|
7
|
+
cattr_accessor :logs
|
8
|
+
cattr_accessor :original_logger
|
9
9
|
|
10
|
-
def
|
11
|
-
|
10
|
+
def self.start!(controller)
|
11
|
+
self.logs = []
|
12
|
+
self.original_logger = Rails.logger
|
13
|
+
note_logger = NoteLogger.new(self.logs)
|
14
|
+
note_logger.level = self.original_logger.level
|
15
|
+
note_logger.formatter = self.original_logger.kind_of?(Logger) ? self.original_logger.formatter : Logger::SimpleFormatter.new
|
16
|
+
# Rails 3 don't have ActiveSupport::Logger#broadcast so we backported it
|
17
|
+
extend_module = defined?(ActiveSupport::Logger) ? ActiveSupport::Logger.broadcast(note_logger) : NoteLogger.broadcast(note_logger)
|
18
|
+
Rails.logger = self.original_logger.dup.extend(extend_module)
|
12
19
|
end
|
13
20
|
|
14
21
|
def title
|
@@ -16,30 +23,16 @@ module Footnotes
|
|
16
23
|
end
|
17
24
|
|
18
25
|
def content
|
19
|
-
escape(log.gsub(/\e\[.+?m/, '')).gsub("\n", '<br />')
|
26
|
+
result = escape(log.gsub(/\e\[.+?m/, '')).gsub("\n", '<br />')
|
27
|
+
# Restore formatter
|
28
|
+
Rails.logger = self.class.original_logger
|
29
|
+
result
|
20
30
|
end
|
21
31
|
|
22
32
|
def log
|
23
|
-
|
24
|
-
@log = @@log.join('')
|
25
|
-
@@log = []
|
26
|
-
if rindex = @log.rindex('Processing '+@controller.class.name+'#'+@controller.action_name)
|
27
|
-
@log = @log[rindex..-1]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
@log
|
33
|
+
self.class.logs.join("\n")
|
31
34
|
end
|
32
35
|
|
33
|
-
module LoggingExtensions
|
34
|
-
def add(*args, &block)
|
35
|
-
logged_message = super
|
36
|
-
Footnotes::Notes::LogNote.log(logged_message)
|
37
|
-
logged_message
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
Rails.logger.extend LoggingExtensions
|
42
36
|
end
|
43
37
|
end
|
44
38
|
end
|
45
|
-
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Footnotes
|
2
|
+
module Notes
|
3
|
+
class LogNote
|
4
|
+
class NoteLogger < Logger
|
5
|
+
|
6
|
+
def initialize(logs)
|
7
|
+
@logs = logs
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(severity, message = nil, progname = nil, &block)
|
11
|
+
severity ||= UNKNOWN
|
12
|
+
if severity < level
|
13
|
+
return true
|
14
|
+
end
|
15
|
+
formatter = @formatter || Logger::Formatter.new
|
16
|
+
@logs << formatter.call(format_severity(severity), Time.now, message, progname)
|
17
|
+
end
|
18
|
+
|
19
|
+
## Backport from rails 4 for handling logging broadcast, should be removed when rails 3 is deprecated :
|
20
|
+
|
21
|
+
# Broadcasts logs to multiple loggers.
|
22
|
+
def self.broadcast(logger) # :nodoc:
|
23
|
+
Module.new do
|
24
|
+
define_method(:add) do |*args, &block|
|
25
|
+
logger.add(*args, &block)
|
26
|
+
super(*args, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
define_method(:<<) do |x|
|
30
|
+
logger << x
|
31
|
+
super(x)
|
32
|
+
end
|
33
|
+
|
34
|
+
define_method(:close) do
|
35
|
+
logger.close
|
36
|
+
super()
|
37
|
+
end
|
38
|
+
|
39
|
+
define_method(:progname=) do |name|
|
40
|
+
logger.progname = name
|
41
|
+
super(name)
|
42
|
+
end
|
43
|
+
|
44
|
+
define_method(:formatter=) do |formatter|
|
45
|
+
logger.formatter = formatter
|
46
|
+
super(formatter)
|
47
|
+
end
|
48
|
+
|
49
|
+
define_method(:level=) do |level|
|
50
|
+
logger.level = level
|
51
|
+
super(level)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -1,56 +1,38 @@
|
|
1
|
-
require 'rails-footnotes/notes/log_note'
|
2
|
-
|
3
1
|
module Footnotes
|
4
2
|
module Notes
|
5
|
-
class PartialsNote <
|
3
|
+
class PartialsNote < AbstractNote
|
4
|
+
|
5
|
+
cattr_accessor :partials
|
6
|
+
|
7
|
+
def self.start!(controller)
|
8
|
+
self.partials = []
|
9
|
+
@subscriber ||= ActiveSupport::Notifications.subscribe('render_partial.action_view') do |*args|
|
10
|
+
event = ActiveSupport::Notifications::Event.new *args
|
11
|
+
self.partials << {:file => event.payload[:identifier], :duration => event.duration}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
6
15
|
def initialize(controller)
|
7
|
-
super
|
8
16
|
@controller = controller
|
9
17
|
end
|
18
|
+
|
10
19
|
def row
|
11
20
|
:edit
|
12
21
|
end
|
22
|
+
|
13
23
|
def title
|
14
24
|
"Partials (#{partials.size})"
|
15
25
|
end
|
26
|
+
|
16
27
|
def content
|
17
|
-
rows = partials.map do |
|
18
|
-
href = Footnotes::Filter.prefix(
|
19
|
-
shortened_name=
|
20
|
-
[%{<a href="#{href}">#{shortened_name}</a>},"#{
|
28
|
+
rows = self.class.partials.map do |partial|
|
29
|
+
href = Footnotes::Filter.prefix(partial[:file],1,1)
|
30
|
+
shortened_name = partial[:file].gsub(File.join(Rails.root,"app/views/"),"")
|
31
|
+
[%{<a href="#{href}">#{shortened_name}</a>},"#{partial[:duration]}ms"]
|
21
32
|
end
|
22
|
-
mount_table(rows.unshift(%w(Partial Time
|
33
|
+
mount_table(rows.unshift(%w(Partial Time)), :summary => "Partials for #{title}")
|
23
34
|
end
|
24
35
|
|
25
|
-
protected
|
26
|
-
#Generate a list of partials that were rendered, also build up render times and counts.
|
27
|
-
#This is memoized so we can use its information in the title easily.
|
28
|
-
def partials
|
29
|
-
@partials ||= begin
|
30
|
-
partials = []
|
31
|
-
@partial_counts = {}
|
32
|
-
@partial_times = {}
|
33
|
-
log_lines = log
|
34
|
-
log_lines.split("\n").each do |line|
|
35
|
-
if line =~ /Rendered (\S*) \(([\d\.]+)\S*?\)/
|
36
|
-
partial = $1
|
37
|
-
@controller.view_paths.each do |view_path|
|
38
|
-
path = File.join(view_path.to_s, "#{partial}*")
|
39
|
-
files = Dir.glob(path)
|
40
|
-
for file in files
|
41
|
-
#TODO figure out what format got rendered if theres multiple
|
42
|
-
@partial_times[file] ||= []
|
43
|
-
@partial_times[file] << $2.to_f
|
44
|
-
@partial_counts[file] ||= 0
|
45
|
-
@partial_counts[file] += 1
|
46
|
-
partials << file unless partials.include?(file)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
partials.reverse
|
52
|
-
end
|
53
|
-
end
|
54
36
|
end
|
55
37
|
end
|
56
38
|
end
|
@@ -6,7 +6,7 @@ module Footnotes
|
|
6
6
|
@@alert_sql_number = 8
|
7
7
|
@@query_subscriber = nil
|
8
8
|
@@orm = [:active_record, :data_mapper]
|
9
|
-
@@ignored_regexps = [%r{(pg_table|pg_attribute|show\stables|pragma|sqlite_master)}i]
|
9
|
+
@@ignored_regexps = [%r{(pg_table|pg_attribute|pg_namespace|show\stables|pragma|sqlite_master)}i]
|
10
10
|
|
11
11
|
def self.start!(controller)
|
12
12
|
self.query_subscriber.reset!
|
@@ -24,17 +24,8 @@ module Footnotes
|
|
24
24
|
name = i ? routes_with_name[i-1].to_s : ''
|
25
25
|
|
26
26
|
# Catch segments requirements
|
27
|
-
req =
|
28
|
-
|
29
|
-
route.segments.each do |segment|
|
30
|
-
next unless segment.is_a?(ActionController::Routing::DynamicSegment) && segment.regexp
|
31
|
-
req[segment.key.to_sym] = segment.regexp
|
32
|
-
end
|
33
|
-
[escape(name), route.segments.join, route.requirements.reject{|key,value| key == :controller}.inspect, req.inspect]
|
34
|
-
else
|
35
|
-
req = route.conditions
|
36
|
-
[escape(name), route.conditions.keys.join, route.requirements.reject{|key,value| key == :controller}.inspect, req.inspect]
|
37
|
-
end
|
27
|
+
req = route.conditions
|
28
|
+
[escape(name), route.conditions.keys.join, route.requirements.reject{|key,value| key == :controller}.inspect, req.inspect]
|
38
29
|
end
|
39
30
|
end
|
40
31
|
end
|
@@ -42,13 +33,21 @@ module Footnotes
|
|
42
33
|
|
43
34
|
module Extensions
|
44
35
|
module Routes
|
36
|
+
|
37
|
+
def __hash_diff(hash_self, other)
|
38
|
+
# ActiveSupport::Deprecation.warn "Hash#diff is no longer used inside of Rails,
|
39
|
+
# and is being deprecated with no replacement. If you're using it to compare hashes for the purpose of testing, please use MiniTest's diff instead."
|
40
|
+
hash_self.dup.delete_if { |k, v| other[k] == v }.merge!(other.dup.delete_if { |k, v| hash_self.has_key?(k) })
|
41
|
+
end
|
42
|
+
|
45
43
|
# Filter routes according to the filter sent
|
46
44
|
#
|
47
45
|
def filtered_routes(filter = {})
|
48
46
|
return [] unless filter.is_a?(Hash)
|
49
47
|
return routes.reject do |r|
|
50
|
-
filter_diff = filter
|
51
|
-
route_diff = r.requirements
|
48
|
+
filter_diff = __hash_diff(filter, r.requirements)
|
49
|
+
route_diff = __hash_diff(r.requirements, filter)
|
50
|
+
|
52
51
|
(filter_diff == filter) || (filter_diff != route_diff)
|
53
52
|
end
|
54
53
|
end
|
@@ -57,5 +56,5 @@ module Footnotes
|
|
57
56
|
end
|
58
57
|
|
59
58
|
if Footnotes::Notes::RoutesNote.included?
|
60
|
-
|
59
|
+
ActionDispatch::Routing::RouteSet.send :include, Footnotes::Extensions::Routes
|
61
60
|
end
|
data/rails-footnotes.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = "rails-footnotes"
|
7
7
|
s.version = Footnotes::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["Roman V. Babenko", "José Valim", "Keenan Brock", "Duane Johnson"]
|
9
|
+
s.authors = ["Roman V. Babenko", "José Valim", "Keenan Brock", "Duane Johnson", "Adrien Siami"]
|
10
10
|
s.email = ["romanvbabenko@gmail.com"]
|
11
11
|
s.homepage = "http://github.com/josevalim/rails-footnotes"
|
12
12
|
s.summary = %q{Every Rails page has footnotes that gives information about your application and links back to your editor.}
|
@@ -14,14 +14,13 @@ Gem::Specification.new do |s|
|
|
14
14
|
|
15
15
|
s.rubyforge_project = "rails-footnotes"
|
16
16
|
|
17
|
-
s.add_dependency "rails", ">= 3.
|
17
|
+
s.add_dependency "rails", ">= 3.2"
|
18
18
|
|
19
|
-
s.add_development_dependency "rails"
|
20
|
-
s.add_development_dependency "
|
19
|
+
s.add_development_dependency "rspec-rails"
|
20
|
+
s.add_development_dependency "capybara"
|
21
21
|
|
22
22
|
s.files = `git ls-files`.split("\n")
|
23
23
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
25
25
|
s.require_paths = ["lib"]
|
26
26
|
end
|
27
|
-
|
data/spec/abstract_note_spec.rb
CHANGED
@@ -3,9 +3,14 @@ require "spec_helper"
|
|
3
3
|
describe Footnotes::Notes::AbstractNote do
|
4
4
|
before do
|
5
5
|
@note = Footnotes::Notes::AbstractNote.new
|
6
|
+
@notes = Footnotes::Filter.notes
|
6
7
|
Footnotes::Filter.notes = [:abstract]
|
7
8
|
end
|
8
9
|
|
10
|
+
after do
|
11
|
+
Footnotes::Filter.notes = @notes
|
12
|
+
end
|
13
|
+
|
9
14
|
it {described_class.should respond_to :start!}
|
10
15
|
it {described_class.should respond_to :close!}
|
11
16
|
it {described_class.should respond_to :title}
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class FootnotesController < ActionController::Base
|
4
|
+
|
5
|
+
def foo
|
6
|
+
render :text => HTML_DOCUMENT, :content_type => 'text/html'
|
7
|
+
end
|
8
|
+
|
9
|
+
def foo_holder
|
10
|
+
render :text => '<html><body><div id="footnotes_holder"></div></body></html>'
|
11
|
+
end
|
12
|
+
|
13
|
+
def foo_js
|
14
|
+
render :text => '<script></script>', :content_type => 'text/javascript'
|
15
|
+
end
|
16
|
+
|
17
|
+
def foo_download
|
18
|
+
send_file Rails.root.join('spec', 'fixtures', 'html_download.html'), :disposition => 'attachment'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe FootnotesController do
|
24
|
+
|
25
|
+
def page
|
26
|
+
Capybara::Node::Simple.new(response.body)
|
27
|
+
end
|
28
|
+
|
29
|
+
shared_examples 'has_footnotes' do
|
30
|
+
it 'includes footnotes' do
|
31
|
+
get :foo
|
32
|
+
response.body.should have_selector('#footnotes_debug')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
shared_examples 'has_no_footnotes' do
|
37
|
+
it 'does not include footnotes' do
|
38
|
+
response.body.should_not have_selector('#footnotes_debug')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'does not alter the page by default' do
|
43
|
+
get :foo
|
44
|
+
response.body.should == HTML_DOCUMENT
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with footnotes' do
|
48
|
+
|
49
|
+
before :all do
|
50
|
+
Footnotes.enabled = true
|
51
|
+
end
|
52
|
+
|
53
|
+
after :all do
|
54
|
+
Footnotes.enabled = false
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'by default' do
|
58
|
+
include_context 'has_footnotes'
|
59
|
+
|
60
|
+
before do
|
61
|
+
get :foo
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'includes footnotes in the last div in body' do
|
65
|
+
all('body > :last-child')[0][:id].should == 'footnotes_debug'
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'includes footnotes in the footnoted_holder div if present' do
|
69
|
+
get :foo_holder
|
70
|
+
response.body.should have_selector('#footnotes_holder > #footnotes_debug')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'does not alter a html file download' do
|
74
|
+
get :foo_download
|
75
|
+
response.body.should == File.open(Rails.root.join('spec', 'fixtures', 'html_download.html')).read
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'when request is xhr' do
|
80
|
+
include_context 'has_no_footnotes'
|
81
|
+
before do
|
82
|
+
xhr :get, :foo
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe 'when content type is javascript' do
|
87
|
+
include_context 'has_no_footnotes'
|
88
|
+
before do
|
89
|
+
get :foo_js
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
HTML_DOCUMENT = <<EOF
|
99
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
100
|
+
<html>
|
101
|
+
<head>
|
102
|
+
<title>HTML to XHTML Example: HTML page</title>
|
103
|
+
<link rel="Stylesheet" href="htmltohxhtml.css" type="text/css" media="screen">
|
104
|
+
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
105
|
+
</head>
|
106
|
+
<body>
|
107
|
+
<p>This is the HTML page. It works and is encoded just like any HTML page you
|
108
|
+
have previously done. View <a href="htmltoxhtml2.htm">the XHTML version</a> of
|
109
|
+
this page to view the difference between HTML and XHTML.</p>
|
110
|
+
<p>You will be glad to know that no changes need to be made to any of your CSS files.</p>
|
111
|
+
</body>
|
112
|
+
</html>
|
113
|
+
EOF
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
describe 'log note' do
|
5
|
+
|
6
|
+
class ApplicationController < ActionController::Base
|
7
|
+
end
|
8
|
+
|
9
|
+
controller do
|
10
|
+
def index
|
11
|
+
Rails.logger.error 'foo'
|
12
|
+
Rails.logger.warn 'bar'
|
13
|
+
render :text => '<html><head></head><body></body></html>', :content_type => 'text/html'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def page
|
18
|
+
Capybara::Node::Simple.new(response.body)
|
19
|
+
end
|
20
|
+
|
21
|
+
before :all do
|
22
|
+
Footnotes.enabled = true
|
23
|
+
end
|
24
|
+
|
25
|
+
after :all do
|
26
|
+
Footnotes.enabled = false
|
27
|
+
end
|
28
|
+
|
29
|
+
before do
|
30
|
+
@original_logger = Rails.logger
|
31
|
+
Rails.logger = Logger.new(StringIO.new)
|
32
|
+
end
|
33
|
+
|
34
|
+
after do
|
35
|
+
Rails.logger = @original_logger
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'Includes the log in the response' do
|
39
|
+
get :index
|
40
|
+
log_debug = first('fieldset#log_debug_info div', :visible => false)
|
41
|
+
log_debug.should have_content('foo')
|
42
|
+
log_debug.should have_content('bar')
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|