deforest 0.0.1 → 1.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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/deforest/application.js +1 -1
- data/app/assets/javascripts/deforest/bootstrap.js +4356 -0
- data/app/assets/javascripts/deforest/bootstrap.js.map +1 -0
- data/app/assets/stylesheets/deforest/{application.css → application.scss} +0 -0
- data/app/assets/stylesheets/deforest/bootstrap-grid.css +3872 -0
- data/app/assets/stylesheets/deforest/bootstrap.css +10332 -0
- data/app/assets/stylesheets/deforest/bootstrap.css.map +1 -0
- data/app/controllers/deforest/files_controller.rb +27 -4
- data/app/models/deforest/log.rb +9 -6
- data/app/views/deforest/files/_percentile_table.html.erb +35 -0
- data/app/views/deforest/files/dashboard.html.erb +26 -25
- data/config/routes.rb +1 -0
- data/lib/deforest/version.rb +1 -1
- data/lib/deforest.rb +73 -54
- data/lib/tasks/deforest_initializer.rb +2 -0
- data/test/deforest_test.rb +11 -6
- data/test/dummy/app/models/comment.rb +12 -0
- data/test/dummy/app/models/post.rb +19 -0
- data/test/dummy/app/models/special/custom/post.rb +2 -0
- data/test/dummy/app/models/special/post.rb +2 -0
- data/test/dummy/app/models/user.rb +3 -0
- data/test/dummy/config/initializers/deforest.rb +7 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20230211204438_create_users.rb +1 -1
- data/test/dummy/db/migrate/20230216154544_create_posts.rb +11 -0
- data/test/dummy/db/migrate/20230218121433_create_special_posts.rb +10 -0
- data/test/dummy/db/migrate/20230218161957_create_special_custom_posts.rb +10 -0
- data/test/dummy/db/migrate/20230219174900_create_comments.rb +11 -0
- data/test/dummy/db/schema.rb +28 -4
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/deforest.log +0 -0
- data/test/dummy/log/development.log +188 -0
- data/test/dummy/log/test.log +12072 -0
- data/test/dummy/test/fixtures/comments.yml +11 -0
- data/test/dummy/test/fixtures/special/custom/posts.yml +9 -0
- data/test/dummy/test/fixtures/special/posts.yml +9 -0
- data/test/dummy/test/models/comment_test.rb +7 -0
- data/test/dummy/test/models/special/custom/post_test.rb +7 -0
- data/test/dummy/test/models/special/post_test.rb +7 -0
- data/test/dummy/test/test_helper.rb +20 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/-T/-T8OIATNI3evoKq5bZdOBNbU0tZeQYxDHGmMOQnF2MM.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/5L/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/5U/5U1ZhgjUSyIuw2yEYRCbe2n0xGeyHmYwnDlSdtQ2Dnw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/AX/AXrDvl0RN_5S8jW0MwnE13ukiiihtUTsaSvoKDVlam4.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Cz/Cz2gWla4RNTXNuZf93le7clQqax63V1EHdQWaHR0s-8.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/DS/DSvREN-eIb--STC5GdXcwmlJjFTw6ZmUVNmW_Sdh1-s.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/GH/GH5mD035fZ1hsoErrkyMEorz6bwqi30T9a8f3zBIqtE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/NL/NLspqKUPe4g6Q4WEvWHMjSTqkF8YS4m2vcBhHBuhVqc.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/OI/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/S3/S36SlXZyuQfqj2KG4e2Dpj_ZdUQbe2VflfsqjgLNSag.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Sh/ShNcRHXrLA44HDRhTj2J11rZhqAuc56Kdr5Ea6O31Mk.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/TL/TLNT1dXfMKTBmLi7RI_AoPSFmUtB9LfMeG6OuTkR1HQ.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/ba/ba0VOL0KrwkwcfcuKSnYe1tT0ccddXS8z2KVn_cjtnI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/eV/eVN4NMxJn9WpXFRvBaX65H7Ni3Ux4agZLg6r04-9Zf0.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/gK/gKO1oowLJsUvxaYbr5rucOzM9MDl7D4Ppj8l7q3AX0g.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/h-/h-Bt2tKoZ131FgeX_De5387nfrje85Zsquko2lu_uL4.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/hR/hRDjpdlCa6CLHs-KV6u1wHhQ842r9m1R5eEpivfiFBE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/hZ/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/jD/jDJ0_EfCHu9gwyqis3I2-EsrfB7dBs8YZzvyqaWoOjU.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/ly/ly49UX-4__EP86mWF_vobKTgvtAGLxUXqGOAPOzY53g.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/pE/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/qM/qMiFkN6R1w5uIr6HRgTrSHnbEVddbDAVdz0D1XF7T2I.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/th/thNa8SIbNZvQMtDF3-dUnEJNEFYxRsND8XYtqA2t328.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/ui/uiFXrn_ILoEjcXpHWygBCsbEcWFKSiMvofYK6-saGVY.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/xw/xwxSZPjNVcvVU7DwpeJBJ1ZX6yyIFiCvf0GKrN6bZgc.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/yp/ypFoyURV_Y0NHlBKznetHE6cVjR-mmRHcGSGQ_hERVg.cache +2 -0
- data/test/fixtures/posts.yml +11 -0
- data/test/models/deforest/log_test.rb +2 -1
- data/test/models/post_test.rb +35 -0
- metadata +119 -9
- data/test/dummy/deforest_db_sync.txt +0 -1
@@ -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[
|
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[
|
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[
|
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,6 +40,22 @@ 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
|
@@ -46,5 +63,11 @@ module Deforest
|
|
46
63
|
raise ActionController::RoutingError.new('Not Found')
|
47
64
|
end
|
48
65
|
end
|
66
|
+
|
67
|
+
def should_render_source
|
68
|
+
if !Deforest.render_source_on_browser
|
69
|
+
redirect_to files_dashboard_path and return
|
70
|
+
end
|
71
|
+
end
|
49
72
|
end
|
50
73
|
end
|
data/app/models/deforest/log.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
module Deforest
|
2
2
|
class Log < ActiveRecord::Base
|
3
3
|
def model_name
|
4
|
-
|
5
|
-
|
6
|
-
|
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 '
|
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
|
-
|
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
|
-
<
|
2
|
-
|
3
|
-
<
|
4
|
-
|
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
|
-
<
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
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
|
data/lib/deforest/version.rb
CHANGED
data/lib/deforest.rb
CHANGED
@@ -4,18 +4,14 @@ 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
|
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
|
8
8
|
@@last_saved_log_file_at = nil
|
9
9
|
@@saving_log_file = false
|
10
10
|
|
11
|
-
def self.
|
12
|
-
|
13
|
-
|
14
|
-
|
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/","")
|
11
|
+
def self.get_app_classes(dir)
|
12
|
+
Dir["#{Rails.root}#{dir}/**/*.rb"].each do |f|
|
13
|
+
idx = f.index(dir)
|
14
|
+
models_heirarchy = f[idx..-1].gsub(dir,"")
|
19
15
|
exec_str = ""
|
20
16
|
loop do
|
21
17
|
parent, *children = models_heirarchy.split("/")
|
@@ -29,59 +25,79 @@ module Deforest
|
|
29
25
|
end
|
30
26
|
begin
|
31
27
|
model = exec_str.constantize
|
28
|
+
yield model
|
32
29
|
rescue
|
33
30
|
puts "Deforest warning: could not track #{exec_str}"
|
34
31
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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) }
|
51
|
-
end
|
52
|
-
old_method.bind(self).call(*args, &block)
|
53
|
-
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.override_instance_methods_for(klass, dir)
|
36
|
+
klass.instance_methods(false).each do |mname|
|
37
|
+
klass.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?(dir)
|
43
|
+
Deforest.insert_into_logs(mname, file_name, line_no)
|
54
44
|
end
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
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) }
|
69
|
-
end
|
70
|
-
old_method.unbind.bind(self).call(*args, &block)
|
45
|
+
if @@last_saved_log_file_at < Deforest.write_logs_to_db_every.ago && !@@saving_log_file
|
46
|
+
Deforest.parse_and_save_log_file()
|
47
|
+
t = Time.zone.now
|
48
|
+
@@last_saved_log_file_at = t
|
49
|
+
File.open("deforest_db_sync.txt", "w") { |fl| fl.write(t.to_i) }
|
71
50
|
end
|
51
|
+
old_method.bind(self).call(*args, &block)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.override_class_methods_for(klass, dir)
|
58
|
+
klass.singleton_methods(false).each do |mname|
|
59
|
+
klass.singleton_class.send(:alias_method, "old_#{mname}", mname)
|
60
|
+
klass.define_singleton_method mname do |*args, &block|
|
61
|
+
old_method = self.singleton_method("old_#{mname}")
|
62
|
+
file_name, line_no = old_method.source_location
|
63
|
+
if file_name.include?(dir)
|
64
|
+
Deforest.insert_into_logs(mname, file_name, line_no)
|
65
|
+
end
|
66
|
+
if @@last_saved_log_file_at < Deforest.write_logs_to_db_every.ago && !@@saving_log_file
|
67
|
+
Deforest.parse_and_save_log_file()
|
68
|
+
t = Time.zone.now
|
69
|
+
@@last_saved_log_file_at = t
|
70
|
+
File.open("deforest_db_sync.txt", "w") { |fl| fl.write(t.to_i) }
|
71
|
+
end
|
72
|
+
old_method.unbind.bind(self).call(*args, &block)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.initialize!
|
78
|
+
if block_given?
|
79
|
+
yield self
|
80
|
+
end
|
81
|
+
self.initialize_db_sync_file()
|
82
|
+
Deforest.track_dirs.each do |dir|
|
83
|
+
self.get_app_classes(dir) do |model|
|
84
|
+
if model.present?
|
85
|
+
self.override_instance_methods_for(model, dir)
|
86
|
+
self.override_class_methods_for(model, dir) unless dir.include?("/app/controllers")
|
72
87
|
end
|
73
88
|
end
|
74
89
|
end
|
75
90
|
end
|
76
91
|
|
77
92
|
def self.initialize_db_sync_file
|
78
|
-
|
93
|
+
File.open("deforest.log", "w") unless File.exist?("deforest.log")
|
94
|
+
if File.exist?("deforest_db_sync.txt")
|
79
95
|
@@last_saved_log_file_at = Time.at(File.open("deforest_db_sync.txt").read.to_i)
|
80
96
|
else
|
81
97
|
File.open("deforest_db_sync.txt", "w") do |f|
|
82
|
-
current_time = Time.zone.now
|
98
|
+
current_time = Time.zone.now
|
83
99
|
@@last_saved_log_file_at = current_time
|
84
|
-
f.write(current_time)
|
100
|
+
f.write(current_time.to_i)
|
85
101
|
end
|
86
102
|
end
|
87
103
|
end
|
@@ -107,16 +123,19 @@ module Deforest
|
|
107
123
|
end
|
108
124
|
end
|
109
125
|
hash.each do |loc, count|
|
110
|
-
|
126
|
+
t = Time.zone.now
|
127
|
+
sql_stmt += "(#{loc.split("|").map { |s| "'#{s}'" }.join(",")}, #{count}, '#{t}', '#{t}'),"
|
111
128
|
end
|
112
129
|
sql_stmt.chomp!(",")
|
113
130
|
sql_stmt += ";"
|
114
|
-
|
115
|
-
|
116
|
-
File.
|
117
|
-
|
118
|
-
|
119
|
-
|
131
|
+
if hash.present?
|
132
|
+
ActiveRecord::Base.connection.execute(sql_stmt)
|
133
|
+
if File.exist?("deforest_tmp.log")
|
134
|
+
File.delete("deforest.log")
|
135
|
+
File.rename("deforest_tmp.log", "deforest.log")
|
136
|
+
else
|
137
|
+
File.delete("deforest.log")
|
138
|
+
end
|
120
139
|
end
|
121
140
|
@@saving_log_file = false
|
122
141
|
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
|
data/test/deforest_test.rb
CHANGED
@@ -2,15 +2,20 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class DeforestTest < ActiveSupport::TestCase
|
4
4
|
setup do
|
5
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
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
|
Binary file
|
data/test/dummy/db/schema.rb
CHANGED
@@ -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:
|
14
|
+
ActiveRecord::Schema.define(version: 20230219174900) do
|
15
15
|
|
16
|
-
create_table "
|
17
|
-
t.
|
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 "
|
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"
|
data/test/dummy/db/test.sqlite3
CHANGED
Binary file
|
File without changes
|