deforest 0.0.1 → 1.0.1

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/deforest/application.js +1 -1
  3. data/app/assets/javascripts/deforest/bootstrap.js +4356 -0
  4. data/app/assets/javascripts/deforest/bootstrap.js.map +1 -0
  5. data/app/assets/stylesheets/deforest/bootstrap-grid.css +3872 -0
  6. data/app/assets/stylesheets/deforest/bootstrap.css +10332 -0
  7. data/app/assets/stylesheets/deforest/bootstrap.css.map +1 -0
  8. data/app/controllers/deforest/application_controller.rb +1 -1
  9. data/app/controllers/deforest/files_controller.rb +28 -4
  10. data/app/models/deforest/log.rb +9 -6
  11. data/app/views/deforest/files/_percentile_table.html.erb +35 -0
  12. data/app/views/deforest/files/dashboard.html.erb +26 -25
  13. data/config/routes.rb +1 -0
  14. data/lib/deforest/version.rb +1 -1
  15. data/lib/deforest.rb +75 -61
  16. data/lib/tasks/deforest_initializer.rb +2 -0
  17. data/test/deforest_test.rb +11 -6
  18. data/test/dummy/app/models/comment.rb +12 -0
  19. data/test/dummy/app/models/post.rb +19 -0
  20. data/test/dummy/app/models/special/custom/post.rb +2 -0
  21. data/test/dummy/app/models/special/post.rb +2 -0
  22. data/test/dummy/app/models/user.rb +3 -0
  23. data/test/dummy/config/initializers/deforest.rb +7 -0
  24. data/test/dummy/db/development.sqlite3 +0 -0
  25. data/test/dummy/db/migrate/20230211204438_create_users.rb +1 -1
  26. data/test/dummy/db/migrate/20230216154544_create_posts.rb +11 -0
  27. data/test/dummy/db/migrate/20230218121433_create_special_posts.rb +10 -0
  28. data/test/dummy/db/migrate/20230218161957_create_special_custom_posts.rb +10 -0
  29. data/test/dummy/db/migrate/20230219174900_create_comments.rb +11 -0
  30. data/test/dummy/db/schema.rb +28 -4
  31. data/test/dummy/db/test.sqlite3 +0 -0
  32. data/test/dummy/deforest.log +0 -0
  33. data/test/dummy/log/development.log +188 -0
  34. data/test/dummy/log/test.log +15199 -0
  35. data/test/dummy/test/fixtures/comments.yml +11 -0
  36. data/test/dummy/test/fixtures/special/custom/posts.yml +9 -0
  37. data/test/dummy/test/fixtures/special/posts.yml +9 -0
  38. data/test/dummy/test/models/comment_test.rb +7 -0
  39. data/test/dummy/test/models/special/custom/post_test.rb +7 -0
  40. data/test/dummy/test/models/special/post_test.rb +7 -0
  41. data/test/dummy/test/test_helper.rb +20 -0
  42. data/test/dummy/tmp/cache/assets/sprockets/v3.0/-T/-T8OIATNI3evoKq5bZdOBNbU0tZeQYxDHGmMOQnF2MM.cache +1 -0
  43. data/test/dummy/tmp/cache/assets/sprockets/v3.0/5L/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +2 -0
  44. data/test/dummy/tmp/cache/assets/sprockets/v3.0/5U/5U1ZhgjUSyIuw2yEYRCbe2n0xGeyHmYwnDlSdtQ2Dnw.cache +1 -0
  45. data/test/dummy/tmp/cache/assets/sprockets/v3.0/AX/AXrDvl0RN_5S8jW0MwnE13ukiiihtUTsaSvoKDVlam4.cache +0 -0
  46. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Cz/Cz2gWla4RNTXNuZf93le7clQqax63V1EHdQWaHR0s-8.cache +1 -0
  47. data/test/dummy/tmp/cache/assets/sprockets/v3.0/DS/DSvREN-eIb--STC5GdXcwmlJjFTw6ZmUVNmW_Sdh1-s.cache +0 -0
  48. data/test/dummy/tmp/cache/assets/sprockets/v3.0/GH/GH5mD035fZ1hsoErrkyMEorz6bwqi30T9a8f3zBIqtE.cache +1 -0
  49. data/test/dummy/tmp/cache/assets/sprockets/v3.0/NL/NLspqKUPe4g6Q4WEvWHMjSTqkF8YS4m2vcBhHBuhVqc.cache +2 -0
  50. data/test/dummy/tmp/cache/assets/sprockets/v3.0/OI/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +2 -0
  51. data/test/dummy/tmp/cache/assets/sprockets/v3.0/S3/S36SlXZyuQfqj2KG4e2Dpj_ZdUQbe2VflfsqjgLNSag.cache +1 -0
  52. data/test/dummy/tmp/cache/assets/sprockets/v3.0/Sh/ShNcRHXrLA44HDRhTj2J11rZhqAuc56Kdr5Ea6O31Mk.cache +0 -0
  53. data/test/dummy/tmp/cache/assets/sprockets/v3.0/TL/TLNT1dXfMKTBmLi7RI_AoPSFmUtB9LfMeG6OuTkR1HQ.cache +1 -0
  54. data/test/dummy/tmp/cache/assets/sprockets/v3.0/ba/ba0VOL0KrwkwcfcuKSnYe1tT0ccddXS8z2KVn_cjtnI.cache +1 -0
  55. data/test/dummy/tmp/cache/assets/sprockets/v3.0/eV/eVN4NMxJn9WpXFRvBaX65H7Ni3Ux4agZLg6r04-9Zf0.cache +0 -0
  56. data/test/dummy/tmp/cache/assets/sprockets/v3.0/gK/gKO1oowLJsUvxaYbr5rucOzM9MDl7D4Ppj8l7q3AX0g.cache +1 -0
  57. data/test/dummy/tmp/cache/assets/sprockets/v3.0/h-/h-Bt2tKoZ131FgeX_De5387nfrje85Zsquko2lu_uL4.cache +0 -0
  58. data/test/dummy/tmp/cache/assets/sprockets/v3.0/hR/hRDjpdlCa6CLHs-KV6u1wHhQ842r9m1R5eEpivfiFBE.cache +1 -0
  59. data/test/dummy/tmp/cache/assets/sprockets/v3.0/hZ/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +2 -0
  60. data/test/dummy/tmp/cache/assets/sprockets/v3.0/jD/jDJ0_EfCHu9gwyqis3I2-EsrfB7dBs8YZzvyqaWoOjU.cache +1 -0
  61. data/test/dummy/tmp/cache/assets/sprockets/v3.0/ly/ly49UX-4__EP86mWF_vobKTgvtAGLxUXqGOAPOzY53g.cache +1 -0
  62. data/test/dummy/tmp/cache/assets/sprockets/v3.0/pE/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +2 -0
  63. data/test/dummy/tmp/cache/assets/sprockets/v3.0/qM/qMiFkN6R1w5uIr6HRgTrSHnbEVddbDAVdz0D1XF7T2I.cache +0 -0
  64. data/test/dummy/tmp/cache/assets/sprockets/v3.0/th/thNa8SIbNZvQMtDF3-dUnEJNEFYxRsND8XYtqA2t328.cache +0 -0
  65. data/test/dummy/tmp/cache/assets/sprockets/v3.0/ui/uiFXrn_ILoEjcXpHWygBCsbEcWFKSiMvofYK6-saGVY.cache +1 -0
  66. data/test/dummy/tmp/cache/assets/sprockets/v3.0/xw/xwxSZPjNVcvVU7DwpeJBJ1ZX6yyIFiCvf0GKrN6bZgc.cache +0 -0
  67. data/test/dummy/tmp/cache/assets/sprockets/v3.0/yp/ypFoyURV_Y0NHlBKznetHE6cVjR-mmRHcGSGQ_hERVg.cache +2 -0
  68. data/test/fixtures/posts.yml +11 -0
  69. data/test/models/deforest/log_test.rb +2 -1
  70. data/test/models/post_test.rb +35 -0
  71. metadata +125 -15
  72. data/test/dummy/deforest_db_sync.txt +0 -1
  73. /data/app/assets/stylesheets/deforest/{application.css → application.scss} +0 -0
@@ -1,5 +1,5 @@
1
1
  module Deforest
2
- class ApplicationController < ActionController::Base
2
+ class ApplicationController < ::ApplicationController
3
3
  protect_from_forgery with: :exception
4
4
  end
5
5
  end
@@ -3,19 +3,20 @@ require_dependency "deforest/application_controller"
3
3
  module Deforest
4
4
  class FilesController < ApplicationController
5
5
  before_action :check_if_admin_logged_in
6
+ before_action :should_render_source, only: [:index, :show]
6
7
 
7
8
  def dashboard
8
9
  @top_percentile_methods = {}
9
10
  @medium_percentile_methods = {}
10
11
  @low_percentile_methods = {}
11
12
 
12
- Deforest::Log.percentile().each do |log, pcnt|
13
+ Deforest::Log.percentile(params[:dir] || "/app/models").each do |log, pcnt|
13
14
  if pcnt >= Deforest.most_used_percentile_threshold
14
- @top_percentile_methods["#{log.model_name}##{log.method_name}"] = { color: "highlight-red", total_call_count: log.count_sum, file_name: log.file_name, line_no: log.line_no }
15
+ @top_percentile_methods[log.method_name] = { color: "highlight-red", total_call_count: log.count_sum, file_name: log.file_name, line_no: log.line_no }
15
16
  elsif pcnt <= Deforest.least_used_percentile_threshold
16
- @low_percentile_methods["#{log.model_name}##{log.method_name}"] = { color: "highlight-green", total_call_count: log.count_sum, file_name: log.file_name, line_no: log.line_no }
17
+ @low_percentile_methods[log.method_name] = { color: "highlight-green", total_call_count: log.count_sum, file_name: log.file_name, line_no: log.line_no }
17
18
  else
18
- @medium_percentile_methods["#{log.model_name}##{log.method_name}"] = { color: "highlight-yellow", total_call_count: log.count_sum, file_name: log.file_name, line_no: log.line_no }
19
+ @medium_percentile_methods[log.method_name] = { color: "highlight-yellow", total_call_count: log.count_sum, file_name: log.file_name, line_no: log.line_no }
19
20
  end
20
21
  end
21
22
  end
@@ -39,12 +40,35 @@ module Deforest
39
40
  # @full_path = "#{params[:path]}/#{params[:file_name]}.rb"
40
41
  end
41
42
 
43
+ def extension_data
44
+ result = Hash.new { |h,k| h[k] = [] }
45
+ Deforest.track_dirs.each do |dir|
46
+ Log.percentile(dir).each do |log, pcnt|
47
+ if pcnt >= Deforest.most_used_percentile_threshold
48
+ result[log.file_name] << { line_no: log.line_no, use_type: "most_used", call_count: log.count_sum }
49
+ elsif pcnt <= Deforest.least_used_percentile_threshold
50
+ result[log.file_name] << { line_no: log.line_no, use_type: "least_used", call_count: log.count_sum }
51
+ else
52
+ result[log.file_name] << { line_no: log.line_no, use_type: "medium_used", call_count: log.count_sum }
53
+ end
54
+ end
55
+ end
56
+ send_data result.to_json, filename: "deforest.json", type: "application/json", disposition: "attachment"
57
+ end
58
+
42
59
  private
43
60
 
44
61
  def check_if_admin_logged_in
45
62
  if send(Deforest.current_admin_method_name).blank?
63
+ puts "Make sure to set config.current_admin_method_name to the correct method in config/initializers/deforest.rb"
46
64
  raise ActionController::RoutingError.new('Not Found')
47
65
  end
48
66
  end
67
+
68
+ def should_render_source
69
+ if !Deforest.render_source_on_browser
70
+ redirect_to files_dashboard_path and return
71
+ end
72
+ end
49
73
  end
50
74
  end
@@ -1,14 +1,16 @@
1
1
  module Deforest
2
2
  class Log < ActiveRecord::Base
3
3
  def model_name
4
- idx = self.file_name.index(/\/app\/models\/(\w)*.rb/)
5
- if idx.present?
6
- self.file_name[idx, file_name.size].gsub("/app/models/", "").chomp(".rb").camelize
4
+ Deforest.track_dirs.map { |d| Regexp.escape(d) }.each do |d|
5
+ idx = self.file_name.index(/\#{d}\/(\w)*.rb/)
6
+ if idx.present?
7
+ return self.file_name[idx, file_name.size].gsub("#{d}/", "").chomp(".rb").camelize
8
+ end
7
9
  end
8
10
  end
9
11
 
10
- def self.percentile()
11
- grouped_logs = Deforest::Log.where("file_name like '%/app/models/%'").group(:file_name, :line_no, :method_name).select("file_name, line_no, method_name, SUM(count) AS count_sum")
12
+ def self.percentile(dir)
13
+ grouped_logs = Deforest::Log.where("file_name like '%#{dir}/%'").group(:file_name, :line_no, :method_name).select("file_name, line_no, method_name, SUM(count) AS count_sum")
12
14
  groups_of_count_sum = grouped_logs.group_by { |r| r.count_sum }
13
15
  n = groups_of_count_sum.size
14
16
  result = Hash.new { |h,k| h[k] = nil }
@@ -22,7 +24,8 @@ module Deforest
22
24
 
23
25
  def self.get_highlight_colors_for_file(file_name)
24
26
  result = {}
25
- self.percentile.select { |log, _| log.file_name == file_name }.each do |log, pcnt|
27
+ dir = Deforest.track_dirs.find { |d| file_name.include?(d) }
28
+ self.percentile(dir).select { |log, _| log.file_name == file_name }.each do |log, pcnt|
26
29
  result[log.line_no] = if pcnt <= Deforest.least_used_percentile_threshold
27
30
  "highlight-green"
28
31
  elsif pcnt >= Deforest.most_used_percentile_threshold
@@ -0,0 +1,35 @@
1
+ <h4><%= heading %></h4>
2
+ <table class="table table-striped">
3
+ <thead>
4
+ <tr>
5
+ <th>File Name</th>
6
+ <th>Method Name</th>
7
+ <th>Line Number</th>
8
+ <th>Count</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% method_stats.each do |method_name, color_and_count| %>
13
+ <tr>
14
+ <td>
15
+ <%= color_and_count[:file_name] %>
16
+ </td>
17
+ <td>
18
+ <% if Deforest.render_source_on_browser %>
19
+ <a href=<%= file_path(path: color_and_count[:file_name], line_no: color_and_count[:line_no]) %>>
20
+ <%= method_name %>
21
+ </a>
22
+ <% else %>
23
+ <%= method_name %>
24
+ <% end %>
25
+ </td>
26
+ <td>
27
+ <%= color_and_count[:line_no] %>
28
+ </td>
29
+ <td>
30
+ <%= color_and_count[:total_call_count] %>
31
+ </td>
32
+ </tr>
33
+ <% end %>
34
+ </tbody>
35
+ </table>
@@ -1,28 +1,29 @@
1
- <h2>Top <%= 100 - Deforest.most_used_percentile_threshold %> percentile</h2>
2
- <% @top_percentile_methods.each do |method_name, color_and_count| %>
3
- <a href=<%= file_path(path: "#{color_and_count[:file_name]}", line_no: color_and_count[:line_no]) %> class="<%= color_and_count[:color] %>"><%= method_name %> = <%= color_and_count[:total_call_count] %></a><br/><br/>
4
- <% end %>
1
+ <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
2
+ <a class="navbar-brand" href="#">Deforest</a>
3
+ <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
4
+ <span class="navbar-toggler-icon"></span>
5
+ </button>
5
6
 
6
- <h2>Bottom <%= Deforest.least_used_percentile_threshold %> percentile</h2>
7
- <% @low_percentile_methods.each do |method_name, color_and_count| %>
8
- <a href=<%= file_path(path: "#{color_and_count[:file_name]}", line_no: color_and_count[:line_no]) %> class="<%= color_and_count[:color] %>"><%= method_name %> = <%= color_and_count[:total_call_count] %></a><br/><br/>
9
- <% end %>
7
+ <div class="collapse navbar-collapse" id="navbarSupportedContent">
8
+ <ul class="navbar-nav mr-auto">
9
+ <li class="nav-item active">
10
+ <%= link_to "Extension Data", files_extension_data_path, class: "nav-link active", aria: { current: "page" } %>
11
+ </li>
12
+ <li class="nav-item dropdown">
13
+ <a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-expanded="false">
14
+ Directory
15
+ </a>
16
+ <div class="dropdown-menu">
17
+ <% Deforest.track_dirs.each do |dir| %>
18
+ <a class="dropdown-item" href="<%= files_dashboard_path(dir: dir) %>"><%= dir %></a>
19
+ <% end %>
20
+ </div>
21
+ </li>
22
+ </ul>
23
+ </div>
24
+ </nav>
10
25
 
11
- <h2>Between <%= Deforest.least_used_percentile_threshold %> and <%= Deforest.most_used_percentile_threshold %> percentile</h2>
12
- <% @medium_percentile_methods.each do |method_name, color_and_count| %>
13
- <a href=<%= file_path(path: "#{color_and_count[:file_name]}", line_no: color_and_count[:line_no]) %> class="<%= color_and_count[:color] %>"><%= method_name %> = <%= color_and_count[:total_call_count] %></a><br/><br/>
14
- <% end %>
15
26
 
16
- <style>
17
- .highlight-red {
18
- background: rgba(245, 66, 72, 0.8);
19
- }
20
- .highlight-yellow {
21
- background: rgba(240, 240, 5, 0.8);
22
- color: #000;
23
- }
24
- .highlight-green {
25
- background: rgba(0, 227, 38, 0.8);
26
- color: #000;
27
- }
28
- </style>
27
+ <%= render partial: "percentile_table", locals: { heading: "Top #{100 - Deforest.most_used_percentile_threshold} percentile", method_stats: @top_percentile_methods } %>
28
+ <%= render partial: "percentile_table", locals: { heading: "Bottom #{100 - Deforest.most_used_percentile_threshold} percentile", method_stats: @low_percentile_methods } %>
29
+ <%= render partial: "percentile_table", locals: { heading: "Between #{Deforest.least_used_percentile_threshold} and #{Deforest.most_used_percentile_threshold} percentile", method_stats: @medium_percentile_methods } %>
data/config/routes.rb CHANGED
@@ -2,4 +2,5 @@ Deforest::Engine.routes.draw do
2
2
  get "/files", controller: "files", action: "index"
3
3
  get "/file", controller: "files", action: "show"
4
4
  get "/files/dashboard", controller: "files", action: "dashboard"
5
+ get "/files/extension_data", controller: "files", action: "extension_data"
5
6
  end
@@ -1,3 +1,3 @@
1
1
  module Deforest
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.1"
3
3
  end
data/lib/deforest.rb CHANGED
@@ -4,18 +4,12 @@ require "active_support"
4
4
  require "active_record"
5
5
 
6
6
  module Deforest
7
- mattr_accessor :write_logs_to_db_every, :current_admin_method_name, :most_used_percentile_threshold, :least_used_percentile_threshold
8
- @@last_saved_log_file_at = nil
9
- @@saving_log_file = false
7
+ mattr_accessor :write_logs_to_db_every, :current_admin_method_name, :most_used_percentile_threshold, :least_used_percentile_threshold, :track_dirs, :render_source_on_browser, :last_saved_log_file_at, :saving_log_file
10
8
 
11
- def self.initialize!
12
- if block_given?
13
- yield self
14
- end
15
- self.initialize_db_sync_file()
16
- Dir["#{Rails.root}/app/models/**/*.rb"].map do |f|
17
- idx = f.index("app/models")
18
- models_heirarchy = f[idx..-1].gsub("app/models/","")
9
+ def self.get_app_classes(dir)
10
+ Dir["#{Rails.root}#{dir}/**/*.rb"].each do |f|
11
+ idx = f.index(dir)
12
+ models_heirarchy = f[idx..-1].gsub(dir,"")
19
13
  exec_str = ""
20
14
  loop do
21
15
  parent, *children = models_heirarchy.split("/")
@@ -29,73 +23,90 @@ module Deforest
29
23
  end
30
24
  begin
31
25
  model = exec_str.constantize
26
+ yield model
32
27
  rescue
33
28
  puts "Deforest warning: could not track #{exec_str}"
34
29
  end
35
- if model.present?
36
- model.instance_methods(false).each do |mname|
37
- model.instance_eval do
38
- alias_method "old_#{mname}", mname
39
- define_method mname do |*args, &block|
40
- old_method = self.class.instance_method("old_#{mname}")
41
- file_name, line_no = old_method.source_location
42
- if file_name.include?("/app/models")
43
- Deforest.insert_into_logs(mname, file_name, line_no)
44
- end
45
- Deforest.insert_into_logs(mname, file_name, line_no)
46
- if @@last_saved_log_file_at < Deforest.write_logs_to_db_every.ago && !@@saving_log_file
47
- Deforest.parse_and_save_log_file()
48
- t = Time.zone.now
49
- @@last_saved_log_file_at = t
50
- File.open("deforest_db_sync.txt", "w") { |fl| fl.write(t.to_i) }
30
+ end
31
+ end
32
+
33
+ def self.initialize!
34
+ if block_given?
35
+ yield self
36
+ end
37
+ self.initialize_db_sync_file()
38
+ Deforest.track_dirs.each do |dir|
39
+ self.get_app_classes(dir) do |klass|
40
+ if klass.present?
41
+ klass.prepend(Module.new do
42
+ klass.instance_methods(false).each do |mname|
43
+ method_location = klass.instance_method(mname).source_location
44
+ if method_location.first.ends_with?("#{klass.to_s.underscore}.rb")
45
+ define_method mname do |*args, &block|
46
+ file_name, line_no = method_location
47
+ if file_name.include?(dir)
48
+ Deforest.insert_into_logs(mname, file_name, line_no)
49
+ end
50
+ if Deforest.last_saved_log_file_at < Deforest.write_logs_to_db_every.ago && !Deforest.saving_log_file
51
+ Deforest.parse_and_save_log_file()
52
+ t = Time.zone.now
53
+ Deforest.last_saved_log_file_at = t
54
+ File.open("deforest_db_sync.txt", "w") { |fl| fl.write(t.to_i) }
55
+ end
56
+ super(*args, &block)
57
+ end
51
58
  end
52
- old_method.bind(self).call(*args, &block)
53
- end
54
- end
55
- end
56
- model.singleton_methods(false).each do |mname|
57
- model.singleton_class.send(:alias_method, "old_#{mname}", mname)
58
- model.define_singleton_method mname do |*args, &block|
59
- old_method = self.singleton_method("old_#{mname}")
60
- file_name, line_no = old_method.source_location
61
- if file_name.include?("/app/models")
62
- Deforest.insert_into_logs(mname, file_name, line_no)
63
59
  end
64
- if @@last_saved_log_file_at < Deforest.write_logs_to_db_every.ago && !@@saving_log_file
65
- Deforest.parse_and_save_log_file()
66
- t = Time.zone.now
67
- @@last_saved_log_file_at = t
68
- File.open("deforest_db_sync.txt", "w") { |fl| fl.write(t.to_i) }
60
+ end)
61
+
62
+ klass.singleton_class.prepend(Module.new do
63
+ klass.singleton_methods(false).each do |mname|
64
+ method_location = klass.singleton_method(mname).source_location
65
+ if method_location.first.ends_with?("#{klass.to_s.underscore}.rb")
66
+ define_method mname do |*args, &block|
67
+ file_name, line_no = method_location
68
+ if file_name.include?(dir)
69
+ Deforest.insert_into_logs(mname, file_name, line_no)
70
+ end
71
+ if Deforest.last_saved_log_file_at < Deforest.write_logs_to_db_every.ago && !Deforest.saving_log_file
72
+ Deforest.parse_and_save_log_file()
73
+ t = Time.zone.now
74
+ Deforest.last_saved_log_file_at = t
75
+ File.open("deforest_db_sync.txt", "w") { |fl| fl.write(t.to_i) }
76
+ end
77
+ super(*args, &block)
78
+ end
79
+ end
69
80
  end
70
- old_method.unbind.bind(self).call(*args, &block)
71
- end
81
+ end)
72
82
  end
73
83
  end
74
84
  end
75
85
  end
76
86
 
77
87
  def self.initialize_db_sync_file
78
- if File.exists?("deforest_db_sync.txt")
79
- @@last_saved_log_file_at = Time.at(File.open("deforest_db_sync.txt").read.to_i)
88
+ File.open("deforest.log", "w") unless File.exist?("deforest.log")
89
+ if File.exist?("deforest_db_sync.txt")
90
+ Deforest.last_saved_log_file_at = Time.at(File.open("deforest_db_sync.txt").read.to_i)
80
91
  else
81
92
  File.open("deforest_db_sync.txt", "w") do |f|
82
- current_time = Time.zone.now.to_i
83
- @@last_saved_log_file_at = current_time
84
- f.write(current_time)
93
+ current_time = Time.zone.now
94
+ Deforest.last_saved_log_file_at = current_time
95
+ f.write(current_time.to_i)
85
96
  end
86
97
  end
87
98
  end
88
99
 
89
100
  def self.insert_into_logs(method_name, file_name, line_no)
90
101
  key = "#{file_name}|#{line_no}|#{method_name}\n"
91
- log_file_name = @@saving_log_file ? "deforest_tmp.log" : "deforest.log"
102
+ log_file_name = Deforest.saving_log_file ? "deforest_tmp.log" : "deforest.log"
92
103
  File.open(log_file_name, "a") do |f|
93
104
  f.write(key)
94
105
  end
95
106
  end
96
107
 
97
108
  def self.parse_and_save_log_file
98
- @@saving_log_file = true
109
+ Deforest.saving_log_file = true
99
110
  sql_stmt = "INSERT INTO deforest_logs (file_name, line_no, method_name, count, created_at, updated_at) VALUES "
100
111
  hash = {}
101
112
  File.foreach("deforest.log") do |line|
@@ -107,18 +118,21 @@ module Deforest
107
118
  end
108
119
  end
109
120
  hash.each do |loc, count|
110
- sql_stmt += "(#{loc.split("|").map { |s| "'#{s}'" }.join(",")}, #{count}, current_timestamp, current_timestamp),"
121
+ t = Time.zone.now
122
+ sql_stmt += "(#{loc.split("|").map { |s| "'#{s}'" }.join(",")}, #{count}, '#{t}', '#{t}'),"
111
123
  end
112
124
  sql_stmt.chomp!(",")
113
125
  sql_stmt += ";"
114
- ActiveRecord::Base.connection.execute(sql_stmt)
115
- if File.exists?("deforest_tmp.log")
116
- File.delete("deforest.log")
117
- File.rename("deforest_tmp.log", "deforest.log")
118
- else
119
- File.delete("deforest.log")
126
+ if hash.present?
127
+ ActiveRecord::Base.connection.execute(sql_stmt)
128
+ if File.exist?("deforest_tmp.log")
129
+ File.delete("deforest.log")
130
+ File.rename("deforest_tmp.log", "deforest.log")
131
+ else
132
+ File.delete("deforest.log")
133
+ end
120
134
  end
121
- @@saving_log_file = false
135
+ Deforest.saving_log_file = false
122
136
  end
123
137
 
124
138
  def self.prepare_file_for_render(file)
@@ -136,7 +150,7 @@ module Deforest
136
150
  line +
137
151
  "</span>&nbsp;&nbsp;" +
138
152
  "<span class='method_call_count'>#{line_no_count[idx]}</span>" +
139
- "<span class='last_accessed'>last called at: #{last_log_for_current_line.created_at.strftime('%m/%d/%Y')}</span>"
153
+ "<span class='last_accessed'>last called at: #{last_log_for_current_line.created_at.localtime.strftime('%m/%d/%Y')}</span>"
140
154
  else
141
155
  "<span>#{line}</span>"
142
156
  end
@@ -3,4 +3,6 @@ Deforest.initialize! do |config|
3
3
  config.current_admin_method_name = :current_admin
4
4
  config.most_used_percentile_threshold = 80
5
5
  config.least_used_percentile_threshold = 20
6
+ config.track_dirs = ["/app/models", "/app/controllers", "/app/helpers"]
7
+ config.render_source_on_browser = true
6
8
  end
@@ -2,15 +2,20 @@ require 'test_helper'
2
2
 
3
3
  class DeforestTest < ActiveSupport::TestCase
4
4
  setup do
5
- Deforest.class_variable_set("@@last_saved_log_file_at", nil)
5
+ File.open("deforest_db_sync.txt", "w") { |f| f.write(1.hour.ago.to_i.to_s) }
6
+ Deforest.initialize_db_sync_file
7
+ Deforest.class_variable_set('@@write_logs_to_db_every', 1.minute)
8
+ end
9
+
10
+ teardown do
11
+ File.delete("deforest_db_sync.txt") if File.exist?("deforest_db_sync.txt")
12
+ File.delete("deforest.log") if File.exist?("deforest.log")
6
13
  end
7
14
 
8
15
  test "initialize db_sync_file when db_sync_file does not exist" do
9
- if File.exist?("deforest_db_sync.txt")
10
- File.delete("deforest_db_sync.txt")
11
- Deforest.initialize_db_sync_file
12
- assert Deforest.class_variable_get("@@last_saved_log_file_at") > 1.minute.ago.to_i
13
- end
16
+ File.delete("deforest_db_sync.txt")
17
+ Deforest.initialize_db_sync_file
18
+ assert Deforest.class_variable_get("@@last_saved_log_file_at") > 1.minute.ago
14
19
  end
15
20
 
16
21
  test "initialize db_sync_file when db_sync_file does exist" do
@@ -0,0 +1,12 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :post
3
+
4
+ def stupid_comment?
5
+ stupid_words = ["very good", "nice"]
6
+ self.body.length < 20 && stupid_words.find { |w| self.body.include?(w) }
7
+ end
8
+
9
+ def contains_embedded_links?
10
+ (self.body =~ /<a.*>.+<\/a>/i) != nil
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ class Post < ActiveRecord::Base
2
+ has_many :comments
3
+
4
+ def self.get_titles
5
+ Post.all.map(&:title)
6
+ end
7
+
8
+ def get_title_with_italics
9
+ "<i>#{self.title}</i>"
10
+ end
11
+
12
+ def self.get_posts_created_after(date)
13
+ self.where("DATE(created_at) > DATE(?)", date)
14
+ end
15
+
16
+ def self.posts_created_yesterday
17
+ self.where("DATE(created_at) = DATE(?)", Date.yesterday)
18
+ end
19
+ end
@@ -0,0 +1,2 @@
1
+ class Special::Custom::Post < ActiveRecord::Base
2
+ end
@@ -0,0 +1,2 @@
1
+ class Special::Post < ActiveRecord::Base
2
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+
3
+ end
@@ -0,0 +1,7 @@
1
+ Deforest.initialize! do |config|
2
+ config.write_logs_to_db_every = 1.minute
3
+ config.current_admin_method_name = :current_admin
4
+ config.most_used_percentile_threshold = 80
5
+ config.least_used_percentile_threshold = 20
6
+ config.track_dirs = ["/app/models"]
7
+ end
Binary file
@@ -1,6 +1,6 @@
1
1
  class CreateUsers < ActiveRecord::Migration
2
2
  def change
3
- create_table :deforest_users do |t|
3
+ create_table :users do |t|
4
4
  t.string :first_name
5
5
  t.string :last_name
6
6
  t.string :email
@@ -0,0 +1,11 @@
1
+ class CreatePosts < ActiveRecord::Migration
2
+ def change
3
+ create_table :posts do |t|
4
+ t.string :title
5
+ t.text :body
6
+ t.integer :author_id
7
+
8
+ t.timestamps null: false
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ class CreateSpecialPosts < ActiveRecord::Migration
2
+ def change
3
+ create_table :special_posts do |t|
4
+ t.string :title
5
+ t.text :body
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ class CreateSpecialCustomPosts < ActiveRecord::Migration
2
+ def change
3
+ create_table :special_custom_posts do |t|
4
+ t.string :title
5
+ t.text :body
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ class CreateComments < ActiveRecord::Migration
2
+ def change
3
+ create_table :comments do |t|
4
+ t.text :body
5
+ t.integer :author_id
6
+ t.integer :post_id
7
+
8
+ t.timestamps null: false
9
+ end
10
+ end
11
+ end
@@ -11,10 +11,12 @@
11
11
  #
12
12
  # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(version: 20230211204438) do
14
+ ActiveRecord::Schema.define(version: 20230219174900) do
15
15
 
16
- create_table "ar_internal_metadata", primary_key: "key", force: :cascade do |t|
17
- t.string "value"
16
+ create_table "comments", force: :cascade do |t|
17
+ t.text "body"
18
+ t.integer "author_id"
19
+ t.integer "post_id"
18
20
  t.datetime "created_at", null: false
19
21
  t.datetime "updated_at", null: false
20
22
  end
@@ -28,7 +30,29 @@ ActiveRecord::Schema.define(version: 20230211204438) do
28
30
  t.datetime "updated_at", null: false
29
31
  end
30
32
 
31
- create_table "deforest_users", force: :cascade do |t|
33
+ create_table "posts", force: :cascade do |t|
34
+ t.string "title"
35
+ t.text "body"
36
+ t.integer "author_id"
37
+ t.datetime "created_at", null: false
38
+ t.datetime "updated_at", null: false
39
+ end
40
+
41
+ create_table "special_custom_posts", force: :cascade do |t|
42
+ t.string "title"
43
+ t.text "body"
44
+ t.datetime "created_at", null: false
45
+ t.datetime "updated_at", null: false
46
+ end
47
+
48
+ create_table "special_posts", force: :cascade do |t|
49
+ t.string "title"
50
+ t.text "body"
51
+ t.datetime "created_at", null: false
52
+ t.datetime "updated_at", null: false
53
+ end
54
+
55
+ create_table "users", force: :cascade do |t|
32
56
  t.string "first_name"
33
57
  t.string "last_name"
34
58
  t.string "email"
Binary file
File without changes