arca 2.2.0 → 2.3.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 +5 -5
- data/README.md +12 -2
- data/arca.gemspec +1 -1
- data/examples/active_record_lint_test.rb +42 -0
- data/examples/audit-callbacks.rb +75 -0
- data/lib/arca/collector.rb +2 -2
- data/lib/arca/model.rb +5 -3
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 326dbd7961f9ccfe0b39d77572d3fcc6599179feaf88a81f3fdfdc64ce0bb8e2
|
4
|
+
data.tar.gz: e0298827379b3759f81eaac23fb9d626b8ce20ae4150a4c44b01379157c6263a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 421d318fdbabf614179e883b5b009d3f7f8a560dbaed1c885ddcc09d14f656f774b162f3d111c576cf0b2fc5f63bfe913e7be09cb043c1c84a8fc18961a9a1c4
|
7
|
+
data.tar.gz: 6d9f740fb81d86ef2b2ede9b803ac04e77a3327b2053f48e4cbcbf551217293939cacba68b0c5ef87e47e8c90972eb7afe96ead015364011b7d34a21c0f6dae1
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# ActiveRecord Callback Analyzer
|
2
2
|
|
3
|
-
Arca is a callback analyzer for ActiveRecord models ideally suited for digging yourself out of callback hell. At best it will help you move towards a [more maintainable design](http://adequate.io/culling-the-activerecord-lifecycle) and at worst it can be used in your test suite to give you feedback when callbacks change.
|
3
|
+
Arca is a callback analyzer for ActiveRecord models ideally suited for digging yourself out of callback hell. At best it will help you move towards a [more maintainable design](https://web.archive.org/web/20161016162603/http://adequate.io/culling-the-activerecord-lifecycle) and at worst it can be used in your test suite to give you feedback when callbacks change.
|
4
4
|
|
5
5
|
Arca helps you answer questions like:
|
6
6
|
|
@@ -10,6 +10,8 @@ Arca helps you answer questions like:
|
|
10
10
|
|
11
11
|
The Arca library has two main components, the collector and the reporter. Include the collector module in ActiveRecord::Base before your models are loaded.
|
12
12
|
|
13
|
+
At GitHub, we test callbacks by whitelisting existing callbacks, and adding a lint test to ensure new callbacks are not added without review. The [examples](examples) folder is a good starting point.
|
14
|
+
|
13
15
|
## Requirements
|
14
16
|
|
15
17
|

|
@@ -34,7 +36,9 @@ class ActiveRecord::Base
|
|
34
36
|
include Arca::Collector
|
35
37
|
end
|
36
38
|
|
37
|
-
# load your app
|
39
|
+
# load your app. It's important to setup before loading your models because Arca
|
40
|
+
# works by wrapping itself around the callback method definitions (before_save,
|
41
|
+
# after_save, etc) and then records how and where those methods are used.
|
38
42
|
```
|
39
43
|
|
40
44
|
In this example the `Annoucements` module is included in `Ticket` and defines it's own callback.
|
@@ -212,6 +216,12 @@ have to update this test to make it pass.
|
|
212
216
|
---------------------------------------------
|
213
217
|
```
|
214
218
|
|
219
|
+
## Contributors
|
220
|
+
|
221
|
+
- [@jonmagic](https://github.com/jonmagic)
|
222
|
+
- [@jch](https://github.com/jch)
|
223
|
+
- [@bensheldon](https://github.com/bensheldon)
|
224
|
+
|
215
225
|
## License
|
216
226
|
|
217
227
|
The MIT License (MIT)
|
data/arca.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "arca"
|
3
|
-
spec.version = "2.
|
3
|
+
spec.version = "2.3.0"
|
4
4
|
spec.date = "2015-08-07"
|
5
5
|
spec.summary = "ActiveRecord callback analyzer"
|
6
6
|
spec.description = "Arca is a callback analyzer for ActiveRecord ideally suited for digging yourself out of callback hell"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "minitest"
|
2
|
+
|
3
|
+
class ActiveRecordLintTest < Minitest::Test
|
4
|
+
def test_callbacks_must_be_defined_in_the_base_model_file
|
5
|
+
whitelist_path = File.expand_path("../active_record_callback_whitelist.txt", __FILE__)
|
6
|
+
whitelisted_callbacks = if File.exists?(whitelist_path)
|
7
|
+
File.read(whitelist_path).split("\n")
|
8
|
+
else
|
9
|
+
""
|
10
|
+
end
|
11
|
+
|
12
|
+
# git grep... list classes with a parent. Does not handle classes nested within a module
|
13
|
+
# xargs... arca analyze. We skip line numbers so we can diff the results
|
14
|
+
# grep... filter for callbacks defined in external files or callbacks without names
|
15
|
+
#
|
16
|
+
# To update the whitelist, save the output up to script/audit-callbacks.
|
17
|
+
callback_output = IO.popen(<<-CMD).read
|
18
|
+
git grep -h '^class.*< ' -- '*.rb' | cut -d' ' -f 2 | sort -u | \
|
19
|
+
xargs bundle exec audit-callbaks.rb --skip-line-num | \
|
20
|
+
grep -E 'external:true|block$'
|
21
|
+
CMD
|
22
|
+
|
23
|
+
actual_callbacks = callback_output.split("\n")
|
24
|
+
|
25
|
+
new_bad_callbacks = actual_callbacks - whitelisted_callbacks
|
26
|
+
unnecessary_whitelist_entries = whitelisted_callbacks - actual_callbacks
|
27
|
+
|
28
|
+
message = ""
|
29
|
+
if new_bad_callbacks.any?
|
30
|
+
message << "The following ActiveRecord callbacks must be defined in the base model file with a named method:\n\n"
|
31
|
+
message << new_bad_callbacks.join("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
if unnecessary_whitelist_entries.any?
|
35
|
+
message << "\n\n" unless message.empty?
|
36
|
+
message << "Hooray! You removed a bad ActiveRecord callback. Please update #{whitelist_path} and remove the following\n\n"
|
37
|
+
message << unnecessary_whitelist_entries.join("\n")
|
38
|
+
end
|
39
|
+
|
40
|
+
assert message.empty?, message
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Prints a list of Active Record callbacks for the given models
|
2
|
+
#
|
3
|
+
# Usage:
|
4
|
+
# bundle exec audit-callbacks.rb [--skip-line-num] [Model1 Model2...]
|
5
|
+
#
|
6
|
+
skip_line_num = false
|
7
|
+
if ARGV.first == "--skip-line-num"
|
8
|
+
ARGV.shift
|
9
|
+
skip_line_num = true
|
10
|
+
end
|
11
|
+
|
12
|
+
unless ARGV.size > 0
|
13
|
+
$stderr.puts "No models specified. Try script/audit-callbacks User Issue."
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
|
17
|
+
# Arca must be required after ActiveRecord, but before the environment loads so
|
18
|
+
# we can install Arca::Collector.
|
19
|
+
require "active_record"
|
20
|
+
require "arca"
|
21
|
+
class ActiveRecord::Base
|
22
|
+
include Arca::Collector
|
23
|
+
end
|
24
|
+
|
25
|
+
require "config/environment"
|
26
|
+
|
27
|
+
# Returns a formatted string of a callback analysis.
|
28
|
+
#
|
29
|
+
# Examples:
|
30
|
+
#
|
31
|
+
# An unnamed (block) before_destroy callback defined in the same file as the model
|
32
|
+
# Ability before_destroy app/models/ability.rb external:false block
|
33
|
+
#
|
34
|
+
# A after_destroy callback named `dereference_asset` defined in a file outside of the model (external:true)
|
35
|
+
# Avatar after_destroy app/models/asset_uploadable.rb external:true dereference_asset
|
36
|
+
#
|
37
|
+
# A before_save callback defined by a callback class
|
38
|
+
# IssueComment before_save app/models/referrer.rb external:true Referrer::ReferenceMentionsCallback
|
39
|
+
#
|
40
|
+
def format_callback(callback, skip_line_num:)
|
41
|
+
path = Arca.relative_path(callback.callback_file_path)
|
42
|
+
path << ":#{callback.callback_line_number}" unless skip_line_num
|
43
|
+
|
44
|
+
# Arca outputs object ids which triggers a diff
|
45
|
+
# e.g. #<Referrer::ReferenceMentionsCallback:0x007f8bca3a1b48>
|
46
|
+
target = if match = /#<(.+):.+>/.match(callback.target_symbol.to_s)
|
47
|
+
match[1]
|
48
|
+
else
|
49
|
+
callback.target_symbol
|
50
|
+
end
|
51
|
+
|
52
|
+
[
|
53
|
+
callback.model.name,
|
54
|
+
callback.callback_symbol,
|
55
|
+
path,
|
56
|
+
"external:#{callback.external_callback?}",
|
57
|
+
target
|
58
|
+
].map(&:to_s).join(" ")
|
59
|
+
end
|
60
|
+
|
61
|
+
ARGV.each do |model_name|
|
62
|
+
begin
|
63
|
+
model_class = model_name.constantize
|
64
|
+
rescue NameError # test classes
|
65
|
+
next
|
66
|
+
end
|
67
|
+
|
68
|
+
next unless model_class.ancestors.include?(ActiveRecord::Base)
|
69
|
+
|
70
|
+
Arca[model_class].analyzed_callbacks.each do |callback_symbol, callbacks|
|
71
|
+
callbacks.each do |callback|
|
72
|
+
puts format_callback(callback, skip_line_num: skip_line_num)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/arca/collector.rb
CHANGED
@@ -33,8 +33,8 @@ module Arca
|
|
33
33
|
# Duplicate args before modifying.
|
34
34
|
args_copy = args.dup
|
35
35
|
|
36
|
-
# Add target_symbol :inline to args_copy if a block
|
37
|
-
# was given.
|
36
|
+
# Add target_symbol :inline to args_copy if given a block or Proc and
|
37
|
+
# class name if a class or instance was given.
|
38
38
|
if block
|
39
39
|
args_copy.unshift(:inline)
|
40
40
|
elsif args_copy.first.kind_of?(Proc)
|
data/lib/arca/model.rb
CHANGED
@@ -15,9 +15,11 @@ module Arca
|
|
15
15
|
# they are used in the life cycle of an ActiveRecord model.
|
16
16
|
CALLBACKS = [
|
17
17
|
:after_initialize, :after_find, :after_touch, :before_validation, :after_validation,
|
18
|
-
:before_save, :around_save, :after_save, :
|
19
|
-
:
|
20
|
-
:
|
18
|
+
:before_save, :around_save, :after_save, :after_save_commit,
|
19
|
+
:before_create, :around_create, :after_create, :after_create_commit,
|
20
|
+
:before_update, :around_update, :after_update, :after_update_commit,
|
21
|
+
:before_destroy, :around_destroy, :after_destroy, :after_destroy_commit,
|
22
|
+
:after_commit, :after_rollback
|
21
23
|
]
|
22
24
|
|
23
25
|
# Public: ActiveRecord model class.
|
metadata
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Hoyt
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
date: 2015-08-07 00:00:00.000000000 Z
|
@@ -79,6 +79,8 @@ files:
|
|
79
79
|
- README.md
|
80
80
|
- Rakefile
|
81
81
|
- arca.gemspec
|
82
|
+
- examples/active_record_lint_test.rb
|
83
|
+
- examples/audit-callbacks.rb
|
82
84
|
- gemfiles/Gemfile_activerecord-3.2
|
83
85
|
- gemfiles/Gemfile_activerecord-4.2
|
84
86
|
- lib/arca.rb
|
@@ -99,7 +101,7 @@ homepage: https://github.com/jonmagic/arca
|
|
99
101
|
licenses:
|
100
102
|
- MIT
|
101
103
|
metadata: {}
|
102
|
-
post_install_message:
|
104
|
+
post_install_message:
|
103
105
|
rdoc_options: []
|
104
106
|
require_paths:
|
105
107
|
- lib
|
@@ -114,9 +116,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
116
|
- !ruby/object:Gem::Version
|
115
117
|
version: '0'
|
116
118
|
requirements: []
|
117
|
-
|
118
|
-
|
119
|
-
signing_key:
|
119
|
+
rubygems_version: 3.5.5
|
120
|
+
signing_key:
|
120
121
|
specification_version: 4
|
121
122
|
summary: ActiveRecord callback analyzer
|
122
123
|
test_files:
|