tuttle 0.0.6 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +17 -0
  3. data/Rakefile +0 -1
  4. data/app/controllers/tuttle/active_job_controller.rb +1 -0
  5. data/app/controllers/tuttle/active_model_serializers_controller.rb +1 -0
  6. data/app/controllers/tuttle/active_support_controller.rb +1 -0
  7. data/app/controllers/tuttle/application_controller.rb +19 -2
  8. data/app/controllers/tuttle/cancancan_controller.rb +2 -0
  9. data/app/controllers/tuttle/devise_controller.rb +1 -0
  10. data/app/controllers/tuttle/execjs_controller.rb +12 -0
  11. data/app/controllers/tuttle/gems_controller.rb +3 -2
  12. data/app/controllers/tuttle/home_controller.rb +1 -0
  13. data/app/controllers/tuttle/i18n_controller.rb +27 -0
  14. data/app/controllers/tuttle/paperclip_controller.rb +1 -0
  15. data/app/controllers/tuttle/rack_attack_controller.rb +26 -0
  16. data/app/controllers/tuttle/rack_mini_profiler_controller.rb +1 -0
  17. data/app/controllers/tuttle/rails_controller.rb +19 -5
  18. data/app/controllers/tuttle/request_controller.rb +1 -0
  19. data/app/controllers/tuttle/ruby_controller.rb +15 -2
  20. data/app/helpers/tuttle/application_helper.rb +64 -2
  21. data/app/models/tuttle/configuration_registry.rb +1 -0
  22. data/app/models/tuttle/version_detector.rb +1 -0
  23. data/app/views/layouts/tuttle/application.html.erb +22 -6
  24. data/app/views/tuttle/active_support/dependencies.html.erb +7 -7
  25. data/app/views/tuttle/active_support/inflectors.html.erb +1 -1
  26. data/app/views/tuttle/cancancan/index.html.erb +1 -1
  27. data/app/views/tuttle/cancancan/rule_tester.html.erb +3 -3
  28. data/app/views/tuttle/execjs/index.html.erb +87 -0
  29. data/app/views/tuttle/gems/http_clients.html.erb +13 -12
  30. data/app/views/tuttle/gems/index.html.erb +4 -4
  31. data/app/views/tuttle/gems/json.html.erb +10 -10
  32. data/app/views/tuttle/home/index.html.erb +6 -6
  33. data/app/views/tuttle/i18n/_translation_entry.html.erb +10 -0
  34. data/app/views/tuttle/i18n/index.html.erb +111 -0
  35. data/app/views/tuttle/i18n/localize.html.erb +53 -0
  36. data/app/views/tuttle/i18n/translations.html.erb +12 -0
  37. data/app/views/tuttle/rack_attack/index.html.erb +227 -0
  38. data/app/views/tuttle/rails/assets.html.erb +4 -4
  39. data/app/views/tuttle/rails/cache.html.erb +4 -8
  40. data/app/views/tuttle/rails/controllers.html.erb +54 -7
  41. data/app/views/tuttle/rails/database.html.erb +14 -1
  42. data/app/views/tuttle/rails/engines.html.erb +1 -1
  43. data/app/views/tuttle/rails/helpers.html.erb +1 -1
  44. data/app/views/tuttle/rails/index.html.erb +72 -19
  45. data/app/views/tuttle/rails/models.html.erb +150 -73
  46. data/app/views/tuttle/rails/routes.html.erb +10 -8
  47. data/app/views/tuttle/rails/schema_cache.html.erb +2 -2
  48. data/app/views/tuttle/ruby/constants.html.erb +29 -0
  49. data/app/views/tuttle/ruby/extensions.html.erb +24 -0
  50. data/app/views/tuttle/ruby/index.html.erb +21 -15
  51. data/app/views/tuttle/ruby/tuning.html.erb +6 -9
  52. data/config/routes.rb +15 -1
  53. data/lib/tuttle.rb +1 -0
  54. data/lib/tuttle/engine.rb +3 -4
  55. data/lib/tuttle/instrumenter.rb +3 -1
  56. data/lib/tuttle/middleware/request_profiler.rb +11 -11
  57. data/lib/tuttle/presenters/action_dispatch/routing/route_wrapper.rb +34 -2
  58. data/lib/tuttle/presenters/active_record/reflection_presenter.rb +54 -0
  59. data/lib/tuttle/presenters/active_support/callbacks.rb +26 -0
  60. data/lib/tuttle/presenters/base_presenter.rb +19 -0
  61. data/lib/tuttle/presenters/rack_mini_profiler/client_settings.rb +1 -0
  62. data/lib/tuttle/ruby_prof/fast_call_stack_printer.rb +2 -1
  63. data/lib/tuttle/version.rb +2 -1
  64. metadata +27 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 49cad804b33f2b81f6a9bc6a2e6504e4cf37c962
4
- data.tar.gz: e8e15e4dee3836b696168ad3a89b102b4f4af856
2
+ SHA256:
3
+ metadata.gz: 9a62a3da7ea3c2565f1f91d6b9a446b95a951dbc2b3ac140102f27fc7f49c1bb
4
+ data.tar.gz: bcad3944fdbf4fc00790142e0de00318a8bbc52fae9bf3e8ad1811cfdace59e5
5
5
  SHA512:
6
- metadata.gz: a03f4de6b82666e963e1b6c1b5b4347389e8a2cd5ae00a2ece02953954a84d17fb37668adf43e88a473263cd15780e59afb8adbc66b11e2e1472f89ebb3d54a3
7
- data.tar.gz: a8b9074ed5bbcfeae270e7b2ab875710acd826b383e76f3e2169945f23df06c20f542cad4f35821bbcfe88fb902db747110b4da6439fc40e22956365be0a3bf0
6
+ metadata.gz: 7e0f1e91acf1a8775c379136e09b84749b6e29af8a1728209236867764ed78c07c606ab059d6781137961070771b6ec343df5e8fbb6de513e8d1d9876b846961
7
+ data.tar.gz: 56aa10ea1db3241284ca712a867c8752554fcfeb34e1a23c15f664fedfed1d9e796cf2b79010a5004a31b4479a10f4109008bff9be708a4cd02d10c0b71b8ff2
@@ -1,3 +1,20 @@
1
+ ### 0.0.8
2
+
3
+ * Features
4
+ * New ExecJS inspector
5
+ * New Rack::Attack inspector
6
+ * Improved ActiveRecord models inspector with associations and validations
7
+ * Improved Rails Controllers link to matched routes (excluding wildcards and implicit renders)
8
+
9
+ ### 0.0.7
10
+
11
+ * Features
12
+ * Rails 5.1 support (drops Rails 4.0)
13
+ * New I18n inspector
14
+ * New Constants and Object extensions inspector
15
+ * Improved Rails routes inspector to show route validity
16
+ * Improved listing display formatting
17
+
1
18
  ### 0.0.6
2
19
 
3
20
  * Features
data/Rakefile CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env rake
2
1
  begin
3
2
  require 'bundler/setup'
4
3
  rescue LoadError
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_dependency 'tuttle/application_controller'
2
3
 
3
4
  module Tuttle
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_dependency 'tuttle/application_controller'
2
3
 
3
4
  module Tuttle
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_dependency 'tuttle/application_controller'
2
3
 
3
4
  module Tuttle
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  module Tuttle
2
3
  class ApplicationController < ActionController::Base
3
4
  abstract!
4
5
  protect_from_forgery with: :exception
5
6
 
6
7
  before_action :check_reload_status
8
+ around_action :set_locale
7
9
 
8
10
  private
9
11
 
@@ -11,8 +13,23 @@ module Tuttle
11
13
  return unless Tuttle::Engine.reload_needed && !Rails.configuration.eager_load
12
14
  Tuttle::Engine.logger.warn('Eager-loading application')
13
15
  ActiveSupport::Notifications.instrument 'tuttle.perform_eager_load' do
14
- Rails.application.eager_load!
15
- Tuttle::Engine.reload_needed = false
16
+ begin
17
+ Rails.application.eager_load!
18
+ rescue
19
+ Tuttle::Engine.logger.warn('Failed to eager-load application')
20
+ ensure
21
+ Tuttle::Engine.reload_needed = false
22
+ end
23
+ end
24
+ end
25
+
26
+ def set_locale
27
+ if params[:hl] && I18n.locale_available?(params[:hl])
28
+ I18n.with_locale(params[:hl]) do
29
+ yield
30
+ end
31
+ else
32
+ yield
16
33
  end
17
34
  end
18
35
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_dependency 'tuttle/application_controller'
2
3
 
3
4
  module Tuttle
@@ -6,6 +7,7 @@ module Tuttle
6
7
  def index
7
8
  @cancan_user = current_user || User.new
8
9
  @ability = Ability.new(@cancan_user)
10
+ @rules = @ability.instance_variable_get('@rules')
9
11
  end
10
12
 
11
13
  def rule_tester
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_dependency 'tuttle/application_controller'
2
3
  require 'devise/version' if defined?(Devise)
3
4
 
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ require_dependency 'tuttle/application_controller'
3
+ require 'execjs/version' if defined?(::ExecJS)
4
+
5
+ module Tuttle
6
+ class ExecjsController < ApplicationController
7
+
8
+ def index
9
+ end
10
+
11
+ end
12
+ end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  require_dependency 'tuttle/application_controller'
2
3
 
3
4
  module Tuttle
4
5
  class GemsController < ApplicationController
5
6
 
6
7
  def index
8
+ @gemspecs = Bundler.rubygems.all_specs.sort_by(&:name)
7
9
  end
8
10
 
9
11
  def http_clients
@@ -12,8 +14,7 @@ module Tuttle
12
14
  def json
13
15
  end
14
16
 
15
- # rubocop:disable Style/AccessorMethodName
16
- def get_process_mem
17
+ def get_process_mem # rubocop:disable Naming/AccessorMethodName
17
18
  require 'get_process_mem'
18
19
  require 'get_process_mem/version'
19
20
  @memory_self = GetProcessMem.new
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_dependency 'tuttle/application_controller'
2
3
  require 'tuttle/version'
3
4
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require_dependency 'tuttle/application_controller'
3
+
4
+ module Tuttle
5
+ class I18nController < ApplicationController
6
+
7
+ before_action :set_sorted_locales
8
+
9
+ def index
10
+ end
11
+
12
+ def localize
13
+ end
14
+
15
+ def translations
16
+ @translations = I18n.backend.send(:translations)
17
+ end
18
+
19
+ private
20
+
21
+ def set_sorted_locales
22
+ @sorted_locales = [I18n.default_locale] +
23
+ (I18n.available_locales.map(&:to_s).sort.map(&:to_sym) - [I18n.default_locale])
24
+ end
25
+
26
+ end
27
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_dependency 'tuttle/application_controller'
2
3
  require 'paperclip/version' if defined?(Paperclip)
3
4
 
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ require_dependency 'tuttle/application_controller'
3
+
4
+ module Tuttle
5
+ class RackAttackController < ApplicationController
6
+
7
+ def index
8
+ require 'rack/attack/version'
9
+ if ::Rack::Attack::VERSION < '5'
10
+ render plain: 'Tuttle Rack::Attack support requires version 5.x' && return
11
+ end
12
+
13
+ default_keys = %w[rack.attack.matched rack.attack.match_discriminator rack.attack.match_type rack.attack.match_data]
14
+ rack_attack_env_vars = request.env.select { |k, _v| k.to_s.start_with?('rack.attack') }
15
+ @rack_attack_env_settings = (rack_attack_env_vars.keys + default_keys).uniq
16
+
17
+ @throttles = Rack::Attack.throttles
18
+ @safelists = Rack::Attack.safelists
19
+ @blocklists = Rack::Attack.blocklists
20
+ @tracks = Rack::Attack.tracks
21
+
22
+ @asn_listeners = ActiveSupport::Notifications.notifier.listeners_for("rack.attack")
23
+ end
24
+
25
+ end
26
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_dependency 'tuttle/application_controller'
2
3
 
3
4
  module Tuttle
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  require 'rails/generators'
2
3
  require_dependency 'tuttle/application_controller'
3
4
  require_dependency 'tuttle/presenters/action_dispatch/routing/route_wrapper'
5
+ require_dependency 'tuttle/presenters/active_support/callbacks'
6
+ require_dependency 'tuttle/presenters/active_record/reflection_presenter'
4
7
 
5
8
  module Tuttle
6
9
  class RailsController < ApplicationController
@@ -10,12 +13,23 @@ module Tuttle
10
13
  end
11
14
 
12
15
  def controllers
13
- # TODO: Both ObjectSpace and .descendants approaches have issues with class reloading during development
16
+ @routes = Rails.application.routes.routes.collect do |route|
17
+ Tuttle::Presenters::ActionDispatch::Routing::RouteWrapper.new(route)
18
+ end
19
+
14
20
  # It seems likely that .descendants will work best when Tuttle and Rails classes are not modified
15
21
  # but both approaches also require eager_load to be true
16
22
  # @controllers = ObjectSpace.each_object(::Class).select {|klass| klass < ActionController::Base }
17
23
  @controllers = ActionController::Base.descendants
18
- @controllers.reject! {|controller| controller <= Tuttle::ApplicationController || controller.abstract?}
24
+ @controllers.reject! do |controller|
25
+ controller.abstract? || controller <= Tuttle::ApplicationController
26
+ end
27
+
28
+ # Rails 5.1 introduced Rails::ApplicationController which really should be abstract
29
+ if defined?(Rails::ApplicationController)
30
+ @controllers.reject! { |controller| controller == Rails::ApplicationController }
31
+ end
32
+
19
33
  @controllers.sort_by!(&:name)
20
34
  end
21
35
 
@@ -24,12 +38,12 @@ module Tuttle
24
38
  end
25
39
 
26
40
  def generators
27
- Rails::Generators.lookup! if 'true' == params[:load_all_generators]
41
+ Rails::Generators.lookup! if params[:load_all_generators] == 'true'
28
42
  @generators = Rails::Generators.subclasses.group_by(&:base_name)
29
43
  end
30
44
 
31
45
  def models
32
- @models = ActiveRecord::Base.descendants
46
+ @models = ActiveRecord::Base.descendants.reject { |model| model.abstract_class? || !model.table_exists? }
33
47
  @models.sort_by!(&:name)
34
48
  end
35
49
 
@@ -101,7 +115,7 @@ module Tuttle
101
115
 
102
116
  def recognize_paths(path)
103
117
  results = {}
104
- [:get, :post, :put, :delete, :patch].each {|method| results[method] = recognize_path(path, method: method)}
118
+ %i[get post put delete patch].each {|method| results[method] = recognize_path(path, method: method)}
105
119
  results
106
120
  end
107
121
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_dependency 'tuttle/application_controller'
2
3
 
3
4
  module Tuttle
@@ -1,4 +1,4 @@
1
- # frozen-string-literal: true
1
+ # frozen_string_literal: true
2
2
 
3
3
  require_dependency 'tuttle/application_controller'
4
4
 
@@ -18,7 +18,6 @@ module Tuttle
18
18
  @gc_enabled = (GC.disable ? false : GC.enable)
19
19
 
20
20
  # taken verbatim from the ruby 2.2 man page
21
- # rubocop:disable Metrics/LineLength
22
21
  @gc_params = {
23
22
  'RUBY_GC_HEAP_INIT_SLOTS' => 'Initial allocation slots. Introduced in Ruby 2.1, default: 10000.',
24
23
  'RUBY_GC_HEAP_FREE_SLOTS' => 'Prepare at least this amount of slots after GC. Allocate this number slots if there are not enough slots. Introduced in Ruby 2.1, default: 4096',
@@ -37,5 +36,19 @@ module Tuttle
37
36
  def miscellaneous
38
37
  end
39
38
 
39
+ def constants
40
+ # Global constants minus a few deprecated constants (to prevent warnings)
41
+ @constants = (Object.constants - %i[Bignum Fixnum NIL TRUE FALSE TimeoutError Data]).
42
+ sort.
43
+ map { |sym| [sym, Object.const_get(sym).class, Object.const_get(sym)] }.
44
+ reject { |_sym, klass, _val| klass == Class || klass == Module }
45
+ end
46
+
47
+ def extensions
48
+ @obj_extensions = Object.methods.select { |meth| Object.method(meth).source_location }.
49
+ sort.
50
+ map { |meth| [meth, *Object.method(meth).source_location] }
51
+ end
52
+
40
53
  end
41
54
  end
@@ -1,12 +1,19 @@
1
- # frozen-string-literal: true
2
-
1
+ # frozen_string_literal: true
3
2
  module Tuttle
4
3
  module ApplicationHelper
4
+ BUNDLER_GEM_PATHS_REGEX = %r{(#{Bundler.rubygems.gem_dir}|#{File.realpath(Bundler.rubygems.gem_dir)})+(/bundler)*/gems}
5
+
6
+ # Display true/false label with text overrides
5
7
  def truth_label(is_true, true_label = 'true', false_label = 'false')
6
8
  content_tag(:span, is_true ? true_label : false_label,
7
9
  class: ['label', is_true ? 'label-success' : 'label-danger'])
8
10
  end
9
11
 
12
+ # Display label if condition is true
13
+ def true_label(is_true, true_label = 'true')
14
+ content_tag(:span, true_label, class: %w[label label-success]) if is_true
15
+ end
16
+
10
17
  def tuttle_redacted(enumarator)
11
18
  enumarator.collect do |key, value|
12
19
  yield key, redact_by_key(key, value)
@@ -21,10 +28,65 @@ module Tuttle
21
28
  main_app.respond_to?(:root_url) ? main_app.root_url : '/'
22
29
  end
23
30
 
31
+ def link_to_rails_guide(file, title)
32
+ content_tag(:a, title, :href => rails_guides_versioned_url(file + '.html'))
33
+ end
34
+
24
35
  def rails_guides_versioned_url(path)
25
36
  "http://guides.rubyonrails.org/v#{Tuttle::VersionDetector.rails_major_minor}/#{path}"
26
37
  end
27
38
 
39
+ def display_path(path)
40
+ return if path.blank?
41
+ display_location =
42
+ if path.start_with?(Rails.root.to_s)
43
+ path.sub(Rails.root.to_s, "$RAILS_ROOT")
44
+ elsif File.realpath(path).start_with?(File.realpath(Bundler.rubygems.gem_dir))
45
+ File.realpath(path).sub(BUNDLER_GEM_PATHS_REGEX, "$GEMS")
46
+ else
47
+ path
48
+ end
49
+ expanded_path = File.expand_path(path)
50
+ content_tag(:span, display_location, :class => 'tuttle-path', :data => { :initial => path, :expanded => expanded_path })
51
+ end
52
+
53
+ def display_source_locaction(path, line)
54
+ return content_tag(:span, "Unknown", :class => 'tuttle-path') if path.nil?
55
+
56
+ display_location = file_location(path)
57
+ expanded_path = File.expand_path(path)
58
+ content_tag(:span, :class => 'tuttle-path', :data => { :initial => path, :expanded => expanded_path }) do
59
+ "#{display_location}##{line}"
60
+ end
61
+ end
62
+
63
+ def file_location(path)
64
+ if path.start_with?(Rails.root.to_s)
65
+ path.gsub(Rails.root.to_s, "$RAILS_ROOT")
66
+ elsif path.start_with?(RbConfig::CONFIG['rubylibdir'])
67
+ path.gsub(RbConfig::CONFIG['rubylibdir'], "$RUBY_LIB_DIR")
68
+ elsif path == "<internal:prelude>"
69
+ path
70
+ elsif File.realpath(path).start_with?(File.realpath(Bundler.rubygems.gem_dir))
71
+ File.realpath(path).gsub(BUNDLER_GEM_PATHS_REGEX, "$GEMS")
72
+ else
73
+ path
74
+ end
75
+ end
76
+
77
+ def value_inspect(val, hide_nil: false)
78
+ case val
79
+ when NilClass
80
+ content_tag(:code, val.inspect) unless hide_nil
81
+ when String
82
+ content_tag(:code, val.inspect)
83
+ when Symbol
84
+ content_tag(:code, val.inspect)
85
+ else
86
+ val.inspect
87
+ end
88
+ end
89
+
28
90
  private
29
91
 
30
92
  def redact_by_key(key, value)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Tuttle
2
3
  class ConfigurationRegistry
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Tuttle
2
3
  class VersionDetector
3
4
 
@@ -2,28 +2,30 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
6
  <title>Tuttle</title>
8
7
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
9
8
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
10
- <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1" crossorigin="anonymous">
11
- <%= stylesheet_link_tag "//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.6.0/styles/default.min.css" %>
9
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
10
+ <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" integrity="sha256-3YM6A3pH4QFCl9WbSU8oXF5N6W/2ylvW0o2g+Z6TmLQ=" crossorigin="anonymous" />
12
11
  <%= content_for(:stylesheets) -%>
13
12
  <link rel="icon" href="//s3.amazonaws.com/tuttle-assets/images/favicon.ico">
14
13
  <style>
15
14
  html { overflow: -moz-scrollbars-vertical; overflow-y: scroll; }
16
15
  body { padding-top: 50px; }
17
16
  table.not-wide { width: auto; }
18
- pre code.hljs { background-color: #f5f5f5; }
17
+ table code { color: black; background-color: inherit; padding: 0; }
18
+ table.table-condensed tbody tr td:first-child { padding-left: 0; }
19
+ table .nowrap { white-space: nowrap; }
19
20
  a[href*="github.com"] { white-space: nowrap; }
20
21
  a[href*="github.com"]:after { font-family: FontAwesome; content: "\f09b"; display: inline-block; color: initial; padding-left: 3px; }
22
+ details :focus { outline: none; }
21
23
  </style>
22
24
  <%= csrf_meta_tags %>
23
25
  </head>
24
26
  <body>
25
27
 
26
- <nav class="navbar-wrapper navbar-inverse navbar-fixed-top" role="navigation">
28
+ <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
27
29
  <div class="container">
28
30
  <div class="navbar-header">
29
31
  <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
@@ -50,6 +52,12 @@
50
52
  <li><%= link_to 'Asset Pipeline', rails_assets_path %></li>
51
53
  <li><%= link_to 'Caching', rails_cache_path %></li>
52
54
  <li role="separator" class="divider"></li>
55
+ <%- if defined?(::I18n) %>
56
+ <li><%= link_to 'Internationalization', i18n_path %></li>
57
+ <li><%= link_to 'Localization', i18n_localize_path %></li>
58
+ <li><%= link_to 'Translations', i18n_translations_path %></li>
59
+ <li role="separator" class="divider"></li>
60
+ <% end %>
53
61
  <li><%= link_to 'Database', rails_database_path %></li>
54
62
  <li><%= link_to 'Schema Cache', rails_schema_cache_path %></li>
55
63
  <li role="separator" class="divider"></li>
@@ -88,6 +96,12 @@
88
96
  <%- if defined?(::GetProcessMem) %>
89
97
  <li><%= link_to 'GetProcessMem', gems_get_process_mem_path %></li>
90
98
  <%- end %>
99
+ <%- if defined?(::ExecJS) %>
100
+ <li><%= link_to 'ExecJS', execjs_path %></li>
101
+ <%- end %>
102
+ <%- if defined?(::Rack::Attack) %>
103
+ <li><%= link_to 'Rack::Attack', rack_attack_path %></li>
104
+ <%- end %>
91
105
  <li><%= link_to 'HTTP Clients', gems_http_clients_path %></li>
92
106
  <li><%= link_to 'JSON', gems_json_path %></li>
93
107
  <li><%= link_to 'Other', gems_other_path %></li>
@@ -99,6 +113,8 @@
99
113
  <li><%= link_to 'Overview', ruby_path %></li>
100
114
  <li class="divider"></li>
101
115
  <li><%= link_to 'Tuning', ruby_tuning_path %></li>
116
+ <li><%= link_to 'Extensions', ruby_extensions_path %></li>
117
+ <li><%= link_to 'Constants', ruby_constants_path %></li>
102
118
  <li><%= link_to 'Miscellaneous', ruby_miscellaneous_path %></li>
103
119
  </ul>
104
120
  </li>
@@ -115,7 +131,7 @@
115
131
 
116
132
  <script src="//code.jquery.com/jquery-2.2.4.min.js" integrity="sha384-rY/jv8mMhqDabXSo+UCggqKtdmBfd3qC2/KvyTDNQ6PcUJXaxK1tMepoQda4g5vB" crossorigin="anonymous"></script>
117
133
  <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
118
- <%= javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.7.0/highlight.min.js" %>
134
+ <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js" integrity="sha256-/BfiIkHlHoVihZdc6TFuj7MmJ0TWcWsMXkeDFwhi0zw=" crossorigin="anonymous"></script>
119
135
  <%= content_for(:javascripts) -%>
120
136
  <script>hljs.initHighlightingOnLoad();</script>
121
137
  </body>