is_this_used 0.1.11 → 0.1.14

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4abf2fd80c83d0bb580066755b650e74538f9f3b77494d400528b33efa03eedb
4
- data.tar.gz: 90185ef813d1d14182b20d1a4cbf4ea6d358867edd8e8b958c8f06ec82636ffe
3
+ metadata.gz: 9ee3077f21a391a8be63d34431215b2a230b03155cd50ae99466079f796ef7de
4
+ data.tar.gz: 8df3bc2329e894929843ecc61481cccd8b357ca09fa11cc63f917ade6af7dcb0
5
5
  SHA512:
6
- metadata.gz: 9f8139f3bdc1006462040512f875697043079c9acdf70738b8388afa1108bc7cb44b89e17f38b40b6d8dfac9138317cbaff645f42fa07b4c9782b1a821c32e3b
7
- data.tar.gz: 6d569fafa4e91e7d29727989e35386981a5f095b384cd4b38f230db22aead2d87dd125a6bbf364ae10a8b92fddf48f6cfbbd8be57087318ff62df24aaada795b
6
+ metadata.gz: 1417d2134db8d73a852036164e7b71cef3ac3cdb4888162abe111734bf28a5e20b1eb13d4206ac5ccd302fa1b680b25a09a15e201075147ceb5727320095e9d8
7
+ data.tar.gz: ca93f1e66d50095f4e21d7a968c6769a05122259259dcdcac4c8295093ac987e1f736698217f9cb032789b31a5000e620473a296d2773d8a439f92a011f0059b
data/README.md CHANGED
@@ -40,6 +40,8 @@ actually occur.
40
40
 
41
41
  ## Usage
42
42
 
43
+ ### `is_this_used?`
44
+
43
45
  is_this_used is pretty simple. Let's say you have a class (or module) like this...
44
46
 
45
47
  ```ruby
@@ -75,7 +77,7 @@ in the `potential_crufts` table that looks like this:
75
77
 
76
78
  | id | owner_name | method_name | method_type | invocations | deleted_at | created_at | updated_at |
77
79
  | --- | ------------ | --------------- | --------------- | ----------- | ---------- | ------------------- | ------------------- |
78
- | 1 | SomeOldClass | some_old_method | instance_method | 0 | null | 2022-01-21 14:07:48 | 2022-01-21 14:07:48 |
80
+ | 1 | SomeOldClass | some_old_method | instance_method | 0 | null | 2022-01-21 14:07:48 | 2022-01-21 14:07:48 |
79
81
 
80
82
  This is easily accessed using the `IsThisUsed::PotentialCruft` model class.
81
83
 
@@ -102,7 +104,7 @@ So, having annotated the method, you can check this table after a while. If you
102
104
  you have a reasonably good hint that the method may not actually be used. Of course, you should consider that there are
103
105
  some processes that are not run frequently at all, so this gem isn't a panacea. Think before you delete!
104
106
 
105
- ### Tracking Stacks
107
+ #### Tracking Stacks
106
108
 
107
109
  In the case that a method _is_ actually invoked, the `invocations` value is incremented and a record is created in
108
110
  the `potential_cruft_stacks` table for each unique invocation stacktrace. This can be used to determine which methods
@@ -148,7 +150,7 @@ The `label` and `base_label` fields come from Ruby's `Thread::Backtrace::Locatio
148
150
  difference is, as the docs simply say this about `base_label`: "Usually same as label, without decoration". 🤷 Anyhow,
149
151
  it's there if you need it.
150
152
 
151
- ### Tracking Arguments
153
+ #### Tracking Arguments
152
154
 
153
155
  In addition to tracking stacks, you can track details about arguments provided to tracked methods. For example, let's say you have the following method:
154
156
 
@@ -196,8 +198,11 @@ The above would result in the following records in `potential_cruft_arguments` (
196
198
  | 1619ec6af47253461e87ebf1923a8a83 | ["color", "locality"] | 1 |
197
199
  | 88c8205498de97d4ef06b249006bb68b | ["status"] | 1 |
198
200
 
201
+ ### `is_any_of_this_stuff_used?`
199
202
 
203
+ Let's say you have a class and you're wondering what, if anything, in that class is used. You probably don't want to tag every single method in that class with `is_this_used?`. Instead, you can add `is_any_of_this_stuff_used?` as the last line in that class. When the class is loaded, is_this_used will identify all of the instance and class methods defined directly on the object itself and track each one of those, just as if you'd tagged them individually with `is_this_used?`.
200
204
 
205
+ The `is_any_of_this_stuff_used?` method does not accept any arguments and cannot be used to track arguments. However, you can use both `is_this_used?` and `is_any_of_this_stuff_used?` at the same time. If you want to track everything in a class, but track arguments for a specific method, simply tag that method with `is_this_used?` and specify the `track_arguments` argument. Be sure to place `is_any_of_this_stuff_used?` as the last line within the class. Now that one method will have its arguments tracked while the others will simply be tracked normally.
201
206
 
202
207
  ## Models
203
208
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- is_this_used (0.1.11)
4
+ is_this_used (0.1.12)
5
5
  activerecord (>= 5.2)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- is_this_used (0.1.11)
4
+ is_this_used (0.1.12)
5
5
  activerecord (>= 5.2)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- is_this_used (0.1.11)
4
+ is_this_used (0.1.12)
5
5
  activerecord (>= 5.2)
6
6
 
7
7
  GEM
@@ -7,6 +7,10 @@ class CreatePotentialCruftArguments < ActiveRecord::Migration<%= migration_versi
7
7
  t.json :arguments, null: false
8
8
  t.integer :occurrences, null: false, index: true, default: 0
9
9
  t.timestamps
10
+
11
+ t.index %i[potential_cruft_id arguments_hash],
12
+ unique: true,
13
+ name: 'index_pca_on_potential_cruft_id_and_arguments_hash'
10
14
  end
11
15
  end
12
16
  end
@@ -7,6 +7,10 @@ class CreatePotentialCruftStacks < ActiveRecord::Migration<%= migration_version
7
7
  t.json :stack, null: false
8
8
  t.integer :occurrences, null: false, index: true, default: 0
9
9
  t.timestamps
10
+
11
+ t.index %i[potential_cruft_id stack_hash],
12
+ unique: true,
13
+ name: 'index_pcs_on_potential_cruft_id_and_stack_hash'
10
14
  end
11
15
  end
12
16
  end
@@ -11,7 +11,10 @@ class CreatePotentialCrufts < ActiveRecord::Migration<%= migration_version %>
11
11
 
12
12
  t.index :owner_name
13
13
  t.index :method_name
14
- t.index %i(owner_name method_name)
14
+ t.index %i[owner_name method_name]
15
+ t.index %i[owner_name method_name method_type],
16
+ unique: true,
17
+ name: 'index_pc_on_owner_name_and_method_name_and_method_type'
15
18
  end
16
19
  end
17
20
  end
@@ -21,18 +21,26 @@ module IsThisUsed
21
21
 
22
22
  potential_cruft_stack =
23
23
  PotentialCruftStack.find_by(
24
- potential_cruft: potential_cruft, stack_hash: stack_hash
24
+ stack_hash: stack_hash
25
25
  )
26
- potential_cruft_stack ||=
27
- PotentialCruftStack.new(
28
- potential_cruft: potential_cruft,
29
- stack_hash: stack_hash,
30
- stack: stack
31
- )
32
-
33
- potential_cruft_stack.occurrences += 1
34
26
 
35
- potential_cruft_stack.save
27
+ potential_cruft_stack ||= begin
28
+ PotentialCruftStack.create(
29
+ potential_cruft: potential_cruft,
30
+ stack_hash: stack_hash,
31
+ stack: stack
32
+ )
33
+ rescue ActiveRecord::RecordNotUnique
34
+ PotentialCruftStack.find_by(
35
+ stack_hash: stack_hash
36
+ )
37
+ end
38
+
39
+ potential_cruft_stack.with_lock do
40
+ potential_cruft_stack.reload
41
+ potential_cruft_stack.occurrences += 1
42
+ potential_cruft_stack.save!
43
+ end
36
44
  end
37
45
 
38
46
  def self.filtered_stack
@@ -55,18 +63,24 @@ module IsThisUsed
55
63
 
56
64
  potential_cruft_argument =
57
65
  PotentialCruftArgument.find_by(
58
- potential_cruft: potential_cruft, arguments_hash: arguments_hash
66
+ arguments_hash: arguments_hash
59
67
  )
60
- potential_cruft_argument ||=
61
- PotentialCruftArgument.new(
62
- potential_cruft: potential_cruft,
63
- arguments_hash: arguments_hash,
64
- arguments: arguments
65
- )
66
-
67
- potential_cruft_argument.occurrences += 1
68
-
69
- potential_cruft_argument.save
68
+ potential_cruft_argument ||= begin
69
+ PotentialCruftArgument.create(
70
+ potential_cruft: potential_cruft,
71
+ arguments_hash: arguments_hash,
72
+ arguments: arguments
73
+ )
74
+ rescue ActiveRecord::RecordNotUnique
75
+ PotentialCruftArgument.find_by(
76
+ arguments_hash: arguments_hash
77
+ )
78
+ end
79
+
80
+ potential_cruft_argument.with_lock do
81
+ potential_cruft_argument.occurrences += 1
82
+ potential_cruft_argument.save!
83
+ end
70
84
  end
71
85
  end
72
86
 
@@ -75,17 +89,23 @@ module IsThisUsed
75
89
  end
76
90
 
77
91
  module ClassMethods
92
+ def potentially_crufty_methods_being_tracked
93
+ @potentially_crufty_methods_being_tracked ||= []
94
+ end
95
+
78
96
  def is_this_used?(method_name, method_type: nil, track_arguments: false)
79
97
  IsThisUsed::Util::LogSuppressor.suppress_logging do
80
98
  method_type ||= determine_method_type(method_name)
99
+
100
+ tracked_method_identifier = "#{method_name}/#{method_type}"
101
+ return if potentially_crufty_methods_being_tracked.include?(tracked_method_identifier)
102
+
81
103
  target_method = target_method(method_name, method_type)
82
104
 
83
- potential_cruft =
84
- PotentialCruft.find_or_create_by(
85
- owner_name: self.name,
86
- method_name: method_name,
87
- method_type: method_type
88
- )
105
+ potential_cruft = create_or_find_potential_cruft(
106
+ method_name: method_name,
107
+ method_type: method_type
108
+ )
89
109
 
90
110
  potential_cruft.update(deleted_at: nil) if potential_cruft.deleted_at.present?
91
111
 
@@ -106,19 +126,34 @@ module IsThisUsed
106
126
  target_method.call(*args)
107
127
  end
108
128
  end
129
+
130
+ potentially_crufty_methods_being_tracked << tracked_method_identifier
109
131
  end
110
- rescue ActiveRecord::StatementInvalid, NoMethodError => e
132
+ rescue ActiveRecord::StatementInvalid => e
111
133
  raise unless e.cause.present? && e.cause.instance_of?(Mysql2::Error)
112
134
 
113
135
  Rails.logger.warn(
114
136
  'There was an error recording potential cruft. Does the potential_crufts table exist? Have migrations been run?'
115
137
  )
138
+ rescue NoMethodError
139
+ Rails.logger.warn(
140
+ 'There was an error recording potential cruft. Have migrations been run?'
141
+ )
116
142
  rescue Mysql2::Error::ConnectionError, ActiveRecord::ConnectionNotEstablished
117
143
  Rails.logger.warn(
118
144
  'There was an error recording potential cruft due to being unable to connect to the database. This may be a non-issue in cases where the database is intentionally not available.'
119
145
  )
120
146
  end
121
147
 
148
+ def is_any_of_this_stuff_used?
149
+ own_instance_methods.each do |instance_method|
150
+ is_this_used?(instance_method, method_type: INSTANCE_METHOD)
151
+ end
152
+ own_class_methods.each do |class_method|
153
+ is_this_used?(class_method, method_type: CLASS_METHOD)
154
+ end
155
+ end
156
+
122
157
  def target_method(method_name, method_type)
123
158
  case method_type
124
159
  when INSTANCE_METHOD
@@ -129,12 +164,8 @@ module IsThisUsed
129
164
  end
130
165
 
131
166
  def determine_method_type(method_name)
132
- is_instance_method =
133
- (self.instance_methods + self.private_instance_methods).include?(
134
- method_name
135
- )
136
- is_class_method =
137
- (self.methods + self.private_methods).include?(method_name)
167
+ is_instance_method = all_instance_methods(self).include?(method_name)
168
+ is_class_method = all_class_methods(self).include?(method_name)
138
169
 
139
170
  if is_instance_method && is_class_method
140
171
  raise AmbiguousMethodType.new(self.name, method_name)
@@ -146,6 +177,47 @@ module IsThisUsed
146
177
  raise NoSuchMethod.new(self.name, method_name)
147
178
  end
148
179
  end
180
+
181
+ def all_instance_methods(object)
182
+ object.instance_methods + object.private_instance_methods
183
+ end
184
+
185
+ def all_class_methods(object)
186
+ object.methods + object.private_methods
187
+ end
188
+
189
+ def own_instance_methods
190
+ ancestors_instance_methods =
191
+ (self.ancestors - [self])
192
+ .map {|ancestor| all_instance_methods(ancestor)}
193
+ .flatten
194
+ .uniq
195
+
196
+ all_instance_methods(self) - ancestors_instance_methods
197
+ end
198
+
199
+ def own_class_methods
200
+ ancestors_class_methods =
201
+ (self.ancestors - [self])
202
+ .map {|ancestor| all_class_methods(ancestor)}
203
+ .flatten
204
+ .uniq
205
+
206
+ all_class_methods(self) -
207
+ all_instance_methods(IsThisUsed::CruftTracker::ClassMethods) -
208
+ ancestors_class_methods
209
+ end
210
+
211
+ def create_or_find_potential_cruft(method_name:, method_type:)
212
+ PotentialCruft.find_or_create_by(owner_name: self.name,
213
+ method_name: method_name,
214
+ method_type: method_type)
215
+
216
+ rescue ActiveRecord::RecordNotUnique
217
+ PotentialCruft.find_by(owner_name: self.name,
218
+ method_name: method_name,
219
+ method_type: method_type)
220
+ end
149
221
  end
150
222
  end
151
223
 
@@ -7,6 +7,7 @@ module IsThisUsed
7
7
  initial_log_level = ActiveRecord::Base.logger.level
8
8
  ActiveRecord::Base.logger.level = :error
9
9
  yield
10
+ ensure
10
11
  ActiveRecord::Base.logger.level = initial_log_level
11
12
  end
12
13
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IsThisUsed
4
- VERSION = '0.1.11'
4
+ VERSION = '0.1.14'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: is_this_used
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Doug Hughes
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-10 00:00:00.000000000 Z
11
+ date: 2022-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -253,7 +253,7 @@ homepage: https://github.com/dhughes/is_this_used
253
253
  licenses:
254
254
  - MIT
255
255
  metadata: {}
256
- post_install_message:
256
+ post_install_message:
257
257
  rdoc_options: []
258
258
  require_paths:
259
259
  - lib
@@ -269,7 +269,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
269
269
  version: '0'
270
270
  requirements: []
271
271
  rubygems_version: 3.0.3.1
272
- signing_key:
272
+ signing_key:
273
273
  specification_version: 4
274
274
  summary: Provides a system to track method usage somewhat unobtrusively.
275
275
  test_files: []