tuttle 0.0.6 → 0.0.8

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 (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
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  Tuttle::Engine.routes.draw do
2
3
 
3
4
  root :to => 'home#index'
@@ -10,7 +11,7 @@ Tuttle::Engine.routes.draw do
10
11
 
11
12
  namespace :ruby do
12
13
  get '', :action => :index
13
- get :miscellaneous, :tuning
14
+ get :miscellaneous, :tuning, :extensions, :constants
14
15
  end
15
16
 
16
17
  namespace :gems do
@@ -18,6 +19,11 @@ Tuttle::Engine.routes.draw do
18
19
  get :get_process_mem, :http_clients, :json, :other
19
20
  end
20
21
 
22
+ namespace :i18n do
23
+ get '', :action => :index
24
+ get :localize, :translations
25
+ end
26
+
21
27
  namespace :active_support do
22
28
  get '', :action => :index
23
29
  get :dependencies, :inflectors, :time_zones
@@ -52,4 +58,12 @@ Tuttle::Engine.routes.draw do
52
58
  get '/cancancan/rule_tester' => 'cancancan#rule_tester'
53
59
  end
54
60
 
61
+ if defined?(::ExecJS)
62
+ get '/execjs' => 'execjs#index'
63
+ end
64
+
65
+ if defined?(::Rack::Attack)
66
+ get '/rack-attack' => 'rack_attack#index'
67
+ end
68
+
55
69
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'tuttle/version'
2
3
 
3
4
  # TODO: clean this up so that mattr_accessor is not needed
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'tuttle'
2
3
  require 'rails/engine'
3
4
 
@@ -26,7 +27,7 @@ module Tuttle
26
27
 
27
28
  next unless Tuttle.enabled
28
29
 
29
- @logger = ::Logger.new("#{Rails.root}/log/tuttle.log")
30
+ @logger = ::Logger.new(Rails.root.join('log', 'tuttle.log'))
30
31
  Tuttle::Engine.logger.info('Tuttle engine started')
31
32
 
32
33
  Tuttle.automount_engine = true if Tuttle.automount_engine.nil?
@@ -34,9 +35,7 @@ module Tuttle
34
35
  mount_engine! if Tuttle.automount_engine
35
36
  use_profiling_middleware! if Tuttle.enable_profiling
36
37
 
37
- if Tuttle.track_notifications
38
- Tuttle::Instrumenter.initialize_tuttle_instrumenter
39
- end
38
+ Tuttle::Instrumenter.initialize_tuttle_instrumenter if Tuttle.track_notifications
40
39
  end
41
40
 
42
41
  config.to_prepare do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Tuttle
2
3
  class Instrumenter
3
4
 
@@ -20,7 +21,8 @@ module Tuttle
20
21
  # Hitting the cache inspector page will enable it for that session.
21
22
  Tuttle::Engine.logger.info('Initializing cache_read subscriber')
22
23
  ActiveSupport::Notifications.subscribe('cache_read.active_support') do |*args|
23
- cache_call_location = caller_locations.detect { |cl| cl.path.start_with?("#{Rails.root}/app".freeze) }
24
+ app_path = Rails.root.join('app').to_s
25
+ cache_call_location = caller_locations.detect { |cl| cl.path.start_with?(app_path) }
24
26
  event = ActiveSupport::Notifications::Event.new(*args)
25
27
 
26
28
  Tuttle::Engine.logger.info("Cache Read called: #{cache_call_location.path} on line #{cache_call_location.lineno} :: #{event.payload.inspect}")
@@ -11,7 +11,7 @@ module Tuttle
11
11
  def call(env)
12
12
  query_string = env['QUERY_STRING']
13
13
 
14
- tuttle_profiler_action = /(^|[&?])tuttle\-profiler=([\w\-]*)/.match(query_string) { |m| m[2] }
14
+ tuttle_profiler_action = /(^|[&?])tuttle-profiler=([\w\-]*)/.match(query_string) { |m| m[2] }
15
15
 
16
16
  case tuttle_profiler_action
17
17
  when 'memory_profiler', 'memory'
@@ -67,7 +67,7 @@ module Tuttle
67
67
  query_params = Rack::Utils.parse_nested_query(query_string)
68
68
  options = {}
69
69
  options[:threshold] = Float(query_params['ruby-prof_threshold']) if query_params.key?('ruby-prof_threshold')
70
- rubyprof_printer = /ruby\-prof_printer=([\w]*)/.match(query_string) { |m| m[1] }
70
+ rubyprof_printer = /ruby-prof_printer=([\w]*)/.match(query_string) { |m| m[1] }
71
71
 
72
72
  data = ::RubyProf::Profile.profile do
73
73
  _, _, body = @app.call(env)
@@ -96,10 +96,10 @@ module Tuttle
96
96
  end
97
97
 
98
98
  # These methods *may* cause the method cache to be invalidated
99
- TRACE_METHODS = Set.new([:extend, :include, :const_set, :remove_const, :alias_method, :remove_method,
100
- :prepend, :append_features, :prepend_features,
101
- :public_constant, :private_constant, :autoload,
102
- :define_method, :define_singleton_method])
99
+ TRACE_METHODS = Set.new(%i[extend include const_set remove_const alias_method remove_method
100
+ prepend append_features prepend_features
101
+ public_constant private_constant autoload
102
+ define_method define_singleton_method])
103
103
 
104
104
  def profile_busted(env, _query_string)
105
105
  # Note: Requires Busted (of course) and DTrace so will need much better error handling and information
@@ -166,7 +166,7 @@ module Tuttle
166
166
 
167
167
  # Prepare the output
168
168
  output = "\nRubyVM.stat: Before After Change\n".dup
169
- [:global_method_state, :global_constant_state, :class_serial].each do |stat|
169
+ %i[global_method_state global_constant_state class_serial].each do |stat|
170
170
  output << format("%-22s %-10d %-10d %+d\n",
171
171
  stat,
172
172
  vmstat_before[stat],
@@ -195,18 +195,18 @@ module Tuttle
195
195
 
196
196
  output << "\nTraces (method cache clearing calls): (#{cache_busters.size} times)\n"
197
197
  cache_busters.each do |trace_info|
198
- if trace_info[:event] == :c_call
199
- output << format("%s\#%s: %s %s\n",
198
+ output << if trace_info[:event] == :c_call
199
+ format("%s\#%s: %s %s\n",
200
200
  trace_info[:defined_class],
201
201
  trace_info[:method_id],
202
202
  trace_info[:target_class],
203
203
  trace_info[:location])
204
204
  else
205
- output << format("Class Definition: %s %s %s\n",
205
+ format("Class Definition: %s %s %s\n",
206
206
  trace_info[:target_class],
207
207
  trace_info[:defined_class],
208
208
  trace_info[:location])
209
- end
209
+ end
210
210
  end
211
211
 
212
212
  [200,
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Tuttle
2
3
  module Presenters
3
4
  module ActionDispatch
@@ -24,8 +25,39 @@ module Tuttle
24
25
  rack_app.respond_to?(:dispatcher?)
25
26
  end
26
27
 
27
- def internal_to_rails?
28
- true == internal?
28
+ def route_problem
29
+ # TODO: this does not handle ImplicitRender actions where the method does not exist but the template does
30
+ return @route_problem if defined?(@route_problem)
31
+ @route_problem =
32
+ if controller_klass
33
+ if requirements[:action] && controller_klass.action_methods.exclude?(action)
34
+ 'Action does not exist'
35
+ end
36
+ elsif requirements[:controller]
37
+ 'Controller does not exist'
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def controller_klass
44
+ return @controller_klass if defined?(@controller_klass)
45
+ @controller_klass =
46
+ if requirements[:controller].present?
47
+ begin
48
+ controller_reference(controller)
49
+ rescue NameError
50
+ # No class is defined for the give route
51
+ # puts "NameError for #{requirements[:controller]}"
52
+ nil
53
+ end
54
+ end
55
+ end
56
+
57
+ # Copied from <actionpack>/lib/action_dispatch/routing/route_set.rb
58
+ def controller_reference(controller_param)
59
+ const_name = "#{controller_param.camelize}Controller"
60
+ ::ActiveSupport::Dependencies.constantize(const_name)
29
61
  end
30
62
 
31
63
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ require_dependency 'tuttle/presenters/base_presenter'
3
+
4
+ module Tuttle
5
+ module Presenters
6
+ module ActiveRecord
7
+ class ReflectionPresenter < ::Tuttle::Presenters::BasePresenter
8
+
9
+ def name; super.inspect end
10
+ def macro; super.inspect end
11
+ def type; super rescue 'Unknown' end
12
+
13
+ def inverse_of
14
+ if has_inverse?
15
+ h.content_tag(:span, has_inverse?.inspect, class: options[:inverse_of].present? ? 'specified' : 'autodetected')
16
+ end
17
+ end
18
+
19
+ def scoped?
20
+ # TODO: potentially show the scope
21
+ h.true_label(scope.present?, 'scoped')
22
+ end
23
+
24
+ def polymorphic?
25
+ h.true_label(super, 'polymorphic')
26
+ end
27
+
28
+ def validate?
29
+ h.true_label(super, 'validate')
30
+ end
31
+
32
+ def options_dependent; options[:dependent] rescue 'Unknown' end
33
+ def options_class_name; options[:class_name] rescue 'Unknown' end
34
+
35
+ def options_autosave
36
+ h.true_label(options[:autosave].present?, 'autosave')
37
+ end
38
+
39
+ def options_required
40
+ ## Todo handle auto-required?
41
+ h.true_label(options[:required].present?, 'required')
42
+ end
43
+
44
+ def foreign_key; super rescue 'Unknown' end
45
+
46
+ def options_other
47
+ other_options = options.except(:polymorphic, :dependent, :class_name, :autosave, :before_add, :before_remove)
48
+ other_options.inspect unless other_options.empty?
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ require 'delegate'
3
+
4
+ module Tuttle
5
+ module Presenters
6
+ module ActiveSupport
7
+ module Callbacks
8
+ class CallbackWrapper < DelegateClass(::ActiveSupport::Callbacks::Callback)
9
+ def safe_source_location(controller_instance)
10
+ controller_instance.method(filter).try(:source_location)
11
+ rescue StandardError
12
+ [nil, nil]
13
+ end
14
+ end
15
+
16
+ class CallbackChainWrapper < DelegateClass(::ActiveSupport::Callbacks::CallbackChain)
17
+ delegate :size, to: :chain
18
+
19
+ def each(&block)
20
+ chain.map { |cb| CallbackWrapper.new(::Tuttle::Presenters::ActiveSupport::Callbacks::CallbackWrapper.new(cb)) } .each(&block)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ require 'tuttle'
3
+ require 'delegate'
4
+
5
+ module Tuttle
6
+ module Presenters
7
+ class BasePresenter < SimpleDelegator
8
+ def initialize(delegate, view)
9
+ @view = view
10
+ super(delegate)
11
+ end
12
+
13
+ # noinspection RubyInstanceMethodNamingConvention
14
+ def h
15
+ @view
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Tuttle
2
3
  module Presenters
3
4
  module RackMiniProfiler
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'ruby-prof/printers/call_stack_printer'
2
3
 
3
4
  # This is a modified version of the RubyProf::CallStackPrinter
@@ -27,7 +28,7 @@ module Tuttle
27
28
 
28
29
  @result.threads.each do |thread|
29
30
  @overall_time = thread.total_time
30
- thread_info = "Thread: #{thread.id}"
31
+ thread_info = "Thread: #{thread.id}".dup
31
32
  thread_info << ", Fiber: #{thread.fiber_id}" unless thread.id == thread.fiber_id
32
33
  thread_info << format(' (%4.2f%% ~ %f)', (@overall_time / @overall_threads_time) * 100, @overall_time)
33
34
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Tuttle
2
- VERSION = '0.0.6'.freeze
3
+ VERSION = '0.0.8'.freeze
3
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tuttle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Gynn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-09 00:00:00.000000000 Z
11
+ date: 2018-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,35 +16,30 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.0.0
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '5.1'
19
+ version: 4.1.0
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - ">="
28
25
  - !ruby/object:Gem::Version
29
- version: 4.0.0
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '5.1'
26
+ version: 4.1.0
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: appraisal
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
- - - "~>"
31
+ - - ">="
38
32
  - !ruby/object:Gem::Version
39
- version: '0'
33
+ version: 2.2.0
40
34
  type: :development
41
35
  prerelease: false
42
36
  version_requirements: !ruby/object:Gem::Requirement
43
37
  requirements:
44
- - - "~>"
38
+ - - ">="
45
39
  - !ruby/object:Gem::Version
46
- version: '0'
47
- description: Rails server inspector
40
+ version: 2.2.0
41
+ description: Tuttle is a tool for Rails developers to inspect the runtime configuration
42
+ information of their applications, libraries, and frameworks.
48
43
  email:
49
44
  - davegynn@gmail.com
50
45
  executables: []
@@ -61,9 +56,12 @@ files:
61
56
  - app/controllers/tuttle/application_controller.rb
62
57
  - app/controllers/tuttle/cancancan_controller.rb
63
58
  - app/controllers/tuttle/devise_controller.rb
59
+ - app/controllers/tuttle/execjs_controller.rb
64
60
  - app/controllers/tuttle/gems_controller.rb
65
61
  - app/controllers/tuttle/home_controller.rb
62
+ - app/controllers/tuttle/i18n_controller.rb
66
63
  - app/controllers/tuttle/paperclip_controller.rb
64
+ - app/controllers/tuttle/rack_attack_controller.rb
67
65
  - app/controllers/tuttle/rack_mini_profiler_controller.rb
68
66
  - app/controllers/tuttle/rails_controller.rb
69
67
  - app/controllers/tuttle/request_controller.rb
@@ -83,13 +81,19 @@ files:
83
81
  - app/views/tuttle/cancancan/index.html.erb
84
82
  - app/views/tuttle/cancancan/rule_tester.html.erb
85
83
  - app/views/tuttle/devise/index.html.erb
84
+ - app/views/tuttle/execjs/index.html.erb
86
85
  - app/views/tuttle/gems/get_process_mem.html.erb
87
86
  - app/views/tuttle/gems/http_clients.html.erb
88
87
  - app/views/tuttle/gems/index.html.erb
89
88
  - app/views/tuttle/gems/json.html.erb
90
89
  - app/views/tuttle/gems/other.html.erb
91
90
  - app/views/tuttle/home/index.html.erb
91
+ - app/views/tuttle/i18n/_translation_entry.html.erb
92
+ - app/views/tuttle/i18n/index.html.erb
93
+ - app/views/tuttle/i18n/localize.html.erb
94
+ - app/views/tuttle/i18n/translations.html.erb
92
95
  - app/views/tuttle/paperclip/index.html.erb
96
+ - app/views/tuttle/rack_attack/index.html.erb
93
97
  - app/views/tuttle/rack_mini_profiler/index.html.erb
94
98
  - app/views/tuttle/rails/_cache_dalli_store.html.erb
95
99
  - app/views/tuttle/rails/_cache_memory_store.html.erb
@@ -107,6 +111,8 @@ files:
107
111
  - app/views/tuttle/rails/routes.html.erb
108
112
  - app/views/tuttle/rails/schema_cache.html.erb
109
113
  - app/views/tuttle/request/index.html.erb
114
+ - app/views/tuttle/ruby/constants.html.erb
115
+ - app/views/tuttle/ruby/extensions.html.erb
110
116
  - app/views/tuttle/ruby/index.html.erb
111
117
  - app/views/tuttle/ruby/miscellaneous.html.erb
112
118
  - app/views/tuttle/ruby/tuning.html.erb
@@ -120,6 +126,9 @@ files:
120
126
  - lib/tuttle/instrumenter.rb
121
127
  - lib/tuttle/middleware/request_profiler.rb
122
128
  - lib/tuttle/presenters/action_dispatch/routing/route_wrapper.rb
129
+ - lib/tuttle/presenters/active_record/reflection_presenter.rb
130
+ - lib/tuttle/presenters/active_support/callbacks.rb
131
+ - lib/tuttle/presenters/base_presenter.rb
123
132
  - lib/tuttle/presenters/rack_mini_profiler/client_settings.rb
124
133
  - lib/tuttle/ruby_prof/fast_call_stack_printer.rb
125
134
  - lib/tuttle/version.rb
@@ -135,7 +144,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
135
144
  requirements:
136
145
  - - ">="
137
146
  - !ruby/object:Gem::Version
138
- version: 2.0.0
147
+ version: 2.1.0
139
148
  required_rubygems_version: !ruby/object:Gem::Requirement
140
149
  requirements:
141
150
  - - ">="
@@ -143,8 +152,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
152
  version: '0'
144
153
  requirements: []
145
154
  rubyforge_project:
146
- rubygems_version: 2.5.2
155
+ rubygems_version: 2.7.5
147
156
  signing_key:
148
157
  specification_version: 4
149
- summary: Tuttle for Rails
158
+ summary: Rails runtime configuration inspector
150
159
  test_files: []