rails-footnotes 3.7.9 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|