rails6-footnotes 5.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 (68) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +25 -0
  3. data/.gitignore +15 -0
  4. data/.rspec.example +1 -0
  5. data/CHANGELOG +129 -0
  6. data/Gemfile +10 -0
  7. data/Gemfile.lock +187 -0
  8. data/MIT-LICENSE +21 -0
  9. data/README.rdoc +188 -0
  10. data/Rakefile +18 -0
  11. data/bin/rake +29 -0
  12. data/bin/rspec +29 -0
  13. data/gemfiles/Gemfile.rails-3.2.22 +5 -0
  14. data/gemfiles/Gemfile.rails-4.0.x +6 -0
  15. data/gemfiles/Gemfile.rails-4.1.x +5 -0
  16. data/gemfiles/Gemfile.rails-4.2.x +5 -0
  17. data/gemfiles/Gemfile.rails-edge +5 -0
  18. data/lib/generators/rails_footnotes/install_generator.rb +14 -0
  19. data/lib/generators/templates/rails_footnotes.rb +26 -0
  20. data/lib/rails-footnotes.rb +68 -0
  21. data/lib/rails-footnotes/abstract_note.rb +178 -0
  22. data/lib/rails-footnotes/each_with_rescue.rb +36 -0
  23. data/lib/rails-footnotes/extension.rb +24 -0
  24. data/lib/rails-footnotes/filter.rb +359 -0
  25. data/lib/rails-footnotes/notes/all.rb +1 -0
  26. data/lib/rails-footnotes/notes/assigns_note.rb +60 -0
  27. data/lib/rails-footnotes/notes/controller_note.rb +55 -0
  28. data/lib/rails-footnotes/notes/cookies_note.rb +17 -0
  29. data/lib/rails-footnotes/notes/env_note.rb +24 -0
  30. data/lib/rails-footnotes/notes/files_note.rb +49 -0
  31. data/lib/rails-footnotes/notes/filters_note.rb +51 -0
  32. data/lib/rails-footnotes/notes/javascripts_note.rb +16 -0
  33. data/lib/rails-footnotes/notes/layout_note.rb +26 -0
  34. data/lib/rails-footnotes/notes/log_note.rb +47 -0
  35. data/lib/rails-footnotes/notes/log_note/note_logger.rb +59 -0
  36. data/lib/rails-footnotes/notes/params_note.rb +21 -0
  37. data/lib/rails-footnotes/notes/partials_note.rb +38 -0
  38. data/lib/rails-footnotes/notes/queries_note.rb +121 -0
  39. data/lib/rails-footnotes/notes/routes_note.rb +60 -0
  40. data/lib/rails-footnotes/notes/session_note.rb +27 -0
  41. data/lib/rails-footnotes/notes/stylesheets_note.rb +16 -0
  42. data/lib/rails-footnotes/notes/view_note.rb +41 -0
  43. data/lib/rails-footnotes/version.rb +3 -0
  44. data/lib/rails6-footnotes.rb +1 -0
  45. data/rails-footnotes.gemspec +22 -0
  46. data/spec/abstract_note_spec.rb +89 -0
  47. data/spec/app/assets/config/manifest.js +2 -0
  48. data/spec/app/assets/javascripts/foobar.js +1 -0
  49. data/spec/app/assets/stylesheets/foobar.css +0 -0
  50. data/spec/app/views/files/index.html.erb +1 -0
  51. data/spec/app/views/layouts/application.html.erb +12 -0
  52. data/spec/app/views/partials/_foo.html.erb +1 -0
  53. data/spec/app/views/partials/index.html.erb +1 -0
  54. data/spec/controllers/files_note_controller_spec.rb +38 -0
  55. data/spec/controllers/footnotes_controller_spec.rb +128 -0
  56. data/spec/controllers/log_note_controller_spec.rb +32 -0
  57. data/spec/controllers/partials_note_controller_spec.rb +28 -0
  58. data/spec/env_note_spec.rb +73 -0
  59. data/spec/fixtures/html_download.html +5 -0
  60. data/spec/footnotes_spec.rb +234 -0
  61. data/spec/notes/assigns_note_spec.rb +50 -0
  62. data/spec/notes/controller_note_spec.rb +12 -0
  63. data/spec/notes/files_note_spec.rb +26 -0
  64. data/spec/notes/javascripts_note_spec.rb +18 -0
  65. data/spec/notes/stylesheets_note_spec.rb +19 -0
  66. data/spec/notes/view_note_spec.rb +12 -0
  67. data/spec/spec_helper.rb +68 -0
  68. metadata +153 -0
@@ -0,0 +1,60 @@
1
+ module Footnotes
2
+ module Notes
3
+ class RoutesNote < AbstractNote
4
+ def initialize(controller)
5
+ @controller = controller
6
+ @parsed_routes = parse_routes
7
+ end
8
+
9
+ def legend
10
+ "Routes for #{@controller.class.to_s}"
11
+ end
12
+
13
+ def content
14
+ mount_table(@parsed_routes.unshift([:path, :name, :options, :requirements]), :summary => "Debug information for #{title}")
15
+ end
16
+
17
+ protected
18
+ def parse_routes
19
+ routes_with_name = Rails.application.routes.named_routes.to_a.flatten
20
+
21
+ return Rails.application.routes.filtered_routes(:controller => @controller.controller_path).collect do |route|
22
+ # Catch routes name if exists
23
+ i = routes_with_name.index(route)
24
+ name = i ? routes_with_name[i-1].to_s : ''
25
+
26
+ # Catch segments requirements
27
+ req = route.conditions
28
+ [escape(name), route.conditions.keys.join, route.requirements.reject{|key,value| key == :controller}.inspect, req.inspect]
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ module Extensions
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
+
43
+ # Filter routes according to the filter sent
44
+ #
45
+ def filtered_routes(filter = {})
46
+ return [] unless filter.is_a?(Hash)
47
+ return routes.reject do |r|
48
+ filter_diff = __hash_diff(filter, r.requirements)
49
+ route_diff = __hash_diff(r.requirements, filter)
50
+
51
+ (filter_diff == filter) || (filter_diff != route_diff)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ if Footnotes::Notes::RoutesNote.included?
59
+ ActionDispatch::Routing::RouteSet.send :include, Footnotes::Extensions::Routes
60
+ end
@@ -0,0 +1,27 @@
1
+ module Footnotes
2
+ module Notes
3
+ class SessionNote < AbstractNote
4
+ def initialize(controller)
5
+ session = controller.session
6
+ if session
7
+ if session.respond_to? :to_hash
8
+ # rails >= 2.3
9
+ session = session.to_hash
10
+ else
11
+ #rails < 2.3
12
+ session = session.data
13
+ end
14
+ end
15
+ @session = (session || {}).symbolize_keys
16
+ end
17
+
18
+ def title
19
+ "Session (#{@session.length})"
20
+ end
21
+
22
+ def content
23
+ mount_table_for_hash(@session, :summary => "Debug information for #{title}")
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ require "rails-footnotes/notes/files_note"
2
+
3
+ module Footnotes
4
+ module Notes
5
+ class StylesheetsNote < FilesNote
6
+ def title
7
+ "Stylesheets (#{@files.length})"
8
+ end
9
+
10
+ protected
11
+ def scan_text(text)
12
+ text.scan(/<link[^>]+href\s*=\s*['"]([^>?'"]+\.css)/im).flatten
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,41 @@
1
+ module Footnotes
2
+ module Notes
3
+ class ViewNote < AbstractNote
4
+ cattr_accessor :template
5
+
6
+ def self.start!(controller)
7
+ @subscriber ||= ActiveSupport::Notifications.subscribe('render_template.action_view') do |*args|
8
+ event = ActiveSupport::Notifications::Event.new *args
9
+ self.template = {:file => event.payload[:identifier], :duration => event.duration}
10
+ end
11
+ end
12
+
13
+ def initialize(controller)
14
+ @controller = controller
15
+ end
16
+
17
+ def row
18
+ :edit
19
+ end
20
+
21
+ def title
22
+ "View (#{"%.3f" % self.template[:duration]}ms)"
23
+ end
24
+
25
+ def link
26
+ escape(Footnotes::Filter.prefix(filename, 1, 1))
27
+ end
28
+
29
+ def valid?
30
+ prefix? && filename && File.exists?(filename)
31
+ end
32
+
33
+ protected
34
+
35
+ def filename
36
+ @filename ||= self.class.template[:file]
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module Footnotes
2
+ VERSION = "5.0.0"
3
+ end
@@ -0,0 +1 @@
1
+ require_relative "./rails-footnotes"
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rails-footnotes/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rails6-footnotes"
7
+ s.version = Footnotes::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Roman V. Babenko", "José Valim", "Keenan Brock", "Duane Johnson", "Adrien Siami", "André Arko"]
10
+ s.email = ["andre@arko.net"]
11
+ s.homepage = "http://github.com/indirect/rails-footnotes"
12
+ s.summary = %q{Every Rails page has footnotes that gives information about your application and links back to your editor.}
13
+ s.description = %q{Every Rails page has footnotes that gives information about your application and links back to your editor.}
14
+
15
+ s.add_dependency "rails", "~> 6.0"
16
+ s.required_ruby_version = "~> 3.0"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,89 @@
1
+ require "spec_helper"
2
+
3
+ describe Footnotes::Notes::AbstractNote do
4
+ before do
5
+ @note = Footnotes::Notes::AbstractNote.new
6
+ @notes = Footnotes::Filter.notes
7
+ Footnotes::Filter.notes = [:abstract]
8
+ end
9
+
10
+ after do
11
+ Footnotes::Filter.notes = @notes
12
+ end
13
+
14
+ it {expect(described_class).to respond_to :start!}
15
+ it {expect(described_class).to respond_to :close!}
16
+ it {expect(described_class).to respond_to :title}
17
+
18
+ it {should respond_to :to_sym}
19
+
20
+ describe '#to_sym' do
21
+ subject { super().to_sym }
22
+ it {should eql :abstract}
23
+ end
24
+
25
+ it { expect(described_class).to be_included }
26
+ specify do
27
+ Footnotes::Filter.notes = []
28
+ expect(described_class).not_to be_included
29
+ end
30
+
31
+ it { should respond_to :row }
32
+ it { should respond_to :legend }
33
+ it { should respond_to :link }
34
+ it { should respond_to :onclick }
35
+ it { should respond_to :stylesheet }
36
+ it { should respond_to :javascript }
37
+
38
+ it { should respond_to :valid? }
39
+ it { should be_valid }
40
+
41
+ it { should respond_to :has_fieldset? }
42
+ it { should_not have_fieldset }
43
+
44
+ specify { Footnotes::Filter.prefix = ''; should_not be_prefix }
45
+ specify do
46
+ Footnotes::Filter.prefix = 'txmt://open?url=file://%s&amp;line=%d&amp;column=%d'
47
+ should be_prefix
48
+ end
49
+
50
+ #TODO should be moved to builder
51
+ #helpers
52
+ specify { expect(subject.escape('<')).to eql '&lt;' }
53
+ specify { expect(subject.escape('&')).to eql '&amp;' }
54
+ specify { expect(subject.escape('>')).to eql '&gt;' }
55
+
56
+ specify { expect(subject.mount_table([])).to be_blank }
57
+ specify { expect(subject.mount_table([['h1', 'h2', 'h3']], :class => 'table')).to be_blank }
58
+
59
+ specify {
60
+ tab = <<-TABLE
61
+ <table class="table" >
62
+ <thead><tr><th>H1</th></tr></thead>
63
+ <tbody><tr><td>r1c1</td></tr></tbody>
64
+ </table>
65
+ TABLE
66
+
67
+ expect(subject.mount_table([['h1'],['r1c1']], :class => 'table')).to eql tab
68
+ }
69
+
70
+ specify {
71
+ tab = <<-TABLE
72
+ <table >
73
+ <thead><tr><th>H1</th><th>H2</th><th>H3</th></tr></thead>
74
+ <tbody><tr><td>r1c1</td><td>r1c2</td><td>r1c3</td></tr></tbody>
75
+ </table>
76
+ TABLE
77
+ expect(subject.mount_table([['h1', 'h2', 'h3'],['r1c1', 'r1c2', 'r1c3']])).to eql tab
78
+ }
79
+
80
+ specify {
81
+ tab = <<-TABLE
82
+ <table >
83
+ <thead><tr><th>H1</th><th>H2</th><th>H3</th></tr></thead>
84
+ <tbody><tr><td>r1c1</td><td>r1c2</td><td>r1c3</td></tr><tr><td>r2c1</td><td>r2c2</td><td>r2c3</td></tr></tbody>
85
+ </table>
86
+ TABLE
87
+ subject.mount_table([['h1', 'h2', 'h3'], ['r1c1', 'r1c2', 'r1c3'], ['r2c1', 'r2c2', 'r2c3']])
88
+ }
89
+ end
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts .js
2
+ //= link_directory ../stylesheets .css
@@ -0,0 +1 @@
1
+ // Foobar
File without changes
@@ -0,0 +1 @@
1
+ FILES INDEX
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <%= javascript_include_tag 'foobar' %>
5
+ <%= javascript_include_tag 'http://google.com/whatever.js' %>
6
+ <%= stylesheet_link_tag 'foobar' %>
7
+ <%= stylesheet_link_tag 'http://google.com/whatever.css' %>
8
+ </head>
9
+ <body>
10
+ <%= yield %>
11
+ </body>
12
+ </html>
@@ -0,0 +1 @@
1
+ bar
@@ -0,0 +1 @@
1
+ <%= render 'foo' %>
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ class FilesController < ApplicationController
4
+ def index
5
+ end
6
+ end
7
+
8
+ describe FilesController, type: :controller do
9
+ render_views
10
+
11
+ before :all do
12
+ Footnotes.enabled = true
13
+ end
14
+
15
+ after :all do
16
+ Footnotes.enabled = false
17
+ end
18
+
19
+ it 'includes stylesheets assets in the response' do
20
+ get :index
21
+ expect(response.body).to include("FILES INDEX")
22
+ js_debug = first('fieldset#javascripts_debug_info div', visible: false)
23
+ expect(js_debug).to have_selector('li a', visible: false, count: 1)
24
+ expect(js_debug).to have_selector('li a', text: /foobar\.js/, visible: false)
25
+ link = js_debug.first('a', visible: false)
26
+ expect(link['href']).to eq("txmt://open?url=file://#{Rails.root.join('app', 'assets', 'javascripts', 'foobar.js')}&line=1&column=1")
27
+ end
28
+
29
+ it 'includes css assets in the response' do
30
+ get :index
31
+ css_debug = first('fieldset#stylesheets_debug_info div', visible: false)
32
+ expect(css_debug).to have_selector('li a', visible: false, count: 1)
33
+ expect(css_debug).to have_selector('li a', text: /foobar\.css/, visible: false)
34
+ link = css_debug.first('a', visible: false)
35
+ expect(link['href']).to eq("txmt://open?url=file://#{Rails.root.join('app', 'assets', 'stylesheets', 'foobar.css')}&line=1&column=1")
36
+ end
37
+
38
+ end
@@ -0,0 +1,128 @@
1
+ require 'spec_helper'
2
+
3
+ class FootnotesController < ActionController::Base
4
+
5
+ def foo
6
+ render inline: HTML_DOCUMENT, content_type: 'text/html'
7
+ end
8
+
9
+ def foo_holder
10
+ render inline: '<html><body><div id="footnotes_holder"></div></body></html>'
11
+ end
12
+
13
+ def foo_js
14
+ render inline: '<script></script>', content_type: 'text/javascript'
15
+ end
16
+
17
+ def foo_download
18
+ send_file Rails.root.join('fixtures', 'html_download.html'), :disposition => 'attachment'
19
+ end
20
+
21
+ end
22
+
23
+ describe FootnotesController, type: :controller do
24
+
25
+ shared_examples 'has_footnotes' do
26
+ it 'includes footnotes' do
27
+ get :foo
28
+ expect(response.body).to have_selector('#footnotes_debug')
29
+ end
30
+ end
31
+
32
+ shared_examples 'has_no_footnotes' do
33
+ it 'does not include footnotes' do
34
+ expect(response.body).not_to have_selector('#footnotes_debug')
35
+ end
36
+ end
37
+
38
+ it 'does not alter the page by default' do
39
+ get :foo
40
+ expect(response.body).to eq(HTML_DOCUMENT)
41
+ end
42
+
43
+ context 'with footnotes' do
44
+
45
+ before :all do
46
+ Footnotes.enabled = true
47
+ end
48
+
49
+ after :all do
50
+ Footnotes.enabled = false
51
+ end
52
+
53
+ describe 'by default' do
54
+ include_context 'has_footnotes'
55
+
56
+ before do
57
+ get :foo
58
+ end
59
+
60
+ it 'includes footnotes in the last div in body' do
61
+ expect(all('body > :last-child')[0][:id]).to eq('footnotes_debug')
62
+ end
63
+
64
+ it 'includes footnotes in the footnoted_holder div if present' do
65
+ get :foo_holder
66
+ expect(response.body).to have_selector('#footnotes_holder > #footnotes_debug')
67
+ end
68
+
69
+ it 'does not alter a html file download' do
70
+ get :foo_download
71
+ expect(response.body).to eq(File.open(Rails.root.join('fixtures', 'html_download.html')).read)
72
+ end
73
+ end
74
+
75
+ describe 'when request is xhr' do
76
+ include_context 'has_no_footnotes'
77
+ before do
78
+ get :foo, xhr: true
79
+ end
80
+ end
81
+
82
+ describe 'when content type is javascript' do
83
+ include_context 'has_no_footnotes'
84
+ before do
85
+ get :foo_js
86
+ end
87
+ end
88
+
89
+ describe 'when footnotes is disabled' do
90
+ include_context 'has_no_footnotes'
91
+ before do
92
+ Footnotes.enabled = false
93
+ get :foo
94
+ end
95
+ end
96
+
97
+ describe 'with a proc' do
98
+
99
+ it 'yields the controller' do
100
+ c = nil
101
+ Footnotes.enabled = lambda { |controller| c = controller}
102
+ get :foo
103
+ expect(c).to be_kind_of(ActionController::Base)
104
+ end
105
+
106
+ context 'returning true' do
107
+ include_context 'has_footnotes'
108
+
109
+ before do
110
+ Footnotes.enabled = lambda { true }
111
+ get :foo
112
+ end
113
+ end
114
+
115
+ context 'returning false' do
116
+ include_context 'has_no_footnotes'
117
+
118
+ before do
119
+ Footnotes.enabled = lambda { false }
120
+ get :foo
121
+ end
122
+ end
123
+
124
+ end
125
+
126
+ end
127
+
128
+ end