arca 2.2.0 → 2.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b0591095b4b348fcbd76cf72ef3cea8aeecb8016
4
- data.tar.gz: bd32d70f3788e5238761d3368b6944b923860c54
2
+ SHA256:
3
+ metadata.gz: 9653b1c97af42cfa6437b583a2b7a24f99397ad8f6b8f9dc6b6ff39897187187
4
+ data.tar.gz: 46afe8ebabfbd4cad7d08c78f0303226409984adce61f0b12240bcd8b318ca1a
5
5
  SHA512:
6
- metadata.gz: 9ea28b0b452751d96980314871b79df23b5ea261e9defbc9e3f331690d1c5ca4f4fee7b8c6c65461298faab770034c1c58e752b89cd9f5aa833b032b784a5c5b
7
- data.tar.gz: 5477fd14ed651d2681b8167db4ef3ee5ea60ae7246f73cb9e9e36c025df1f2747678d1db410b47113d8f78985bde696cf25b2cfee7e4b69bd90e92f35f001250
6
+ metadata.gz: dd5e0a8bab34fbcd7c6f8b5ca4156f64adbbfa0d9a94d33d791b91f90b0962cb94c8649ec94a861993f4170b88c0ce63239ea1de6f78ccca15f4e39bd7d7a7ed
7
+ data.tar.gz: 7abcf185d338042bfabe79d3f6875e943b373af87a24d2b56859e4202b7eb7021e5b552fc6b9da5ef68ff60aae0a6806dce5e3045b669eacc13a11f60e44877e
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
  ![travis-ci build status](https://travis-ci.org/jonmagic/arca.svg)
@@ -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,13 @@ 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
+ - [@jasonkim](https://github.com/jasonkim)
225
+
215
226
  ## License
216
227
 
217
228
  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.2.0"
3
+ spec.version = "2.3.1"
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"
@@ -13,8 +13,8 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = "https://github.com/jonmagic/arca"
14
14
  spec.license = "MIT"
15
15
 
16
- spec.add_development_dependency "activerecord", "~> 4.2"
17
- spec.add_development_dependency "minitest", "~> 5.7"
18
- spec.add_development_dependency "pry", "~> 0.10"
19
- spec.add_development_dependency "rake", "~> 10.4"
16
+ spec.add_development_dependency "activerecord", "~> 7.1"
17
+ spec.add_development_dependency "minitest", "~> 5.22"
18
+ spec.add_development_dependency "pry", "~> 0.14"
19
+ spec.add_development_dependency "rake", "~> 13.2"
20
20
  end
@@ -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
@@ -6,7 +6,7 @@ module Arca
6
6
 
7
7
  # Internal: Regular expression used for extracting the file path and line
8
8
  # number from a caller line.
9
- ARCA_CALLBACK_FINDER_REGEXP = /\A(.+)\:(\d+)\:in\s`.+'\z/
9
+ ARCA_CALLBACK_FINDER_REGEXP = /\A(.+)\:(\d+)\:in\s[`'].+'\z/
10
10
  private_constant :ARCA_CALLBACK_FINDER_REGEXP
11
11
 
12
12
  # Internal: Array of conditional symbols.
@@ -21,7 +21,7 @@ module Arca
21
21
  end
22
22
 
23
23
  # Find the callback methods defined on this class.
24
- callback_method_symbols = singleton_methods.grep /^(after|around|before)\_/
24
+ callback_method_symbols = singleton_methods.grep(/^(after|around|before)\_/)
25
25
 
26
26
  callback_method_symbols.each do |callback_symbol|
27
27
  # Find the UnboundMethod for the callback.
@@ -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, Proc, or Class
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)
@@ -58,7 +58,7 @@ module Arca
58
58
 
59
59
  # Extract the model file path from the caller stack.
60
60
  caller.each do |line|
61
- if match = /\A(.+):\d+:in\s`<class:#{name.split("::").last}>'/.match(line)
61
+ if match = /\A(.+):\d+:in\s[`']<class:#{name.split("::").last}>'/.match(line)
62
62
  self.arca_callback_data[:model_file_path] = match[1]
63
63
  break
64
64
  end
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, :before_create, :around_create,
19
- :after_create, :before_update, :around_update, :after_update,
20
- :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
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.
data/lib/arca/report.rb CHANGED
@@ -61,7 +61,7 @@ module Arca
61
61
  # from conditionals for an instance of the model being reported during the
62
62
  # lifecycle of the object.
63
63
  def calculated_permutations
64
- permutations = model.analyzed_callbacks.inject([]) do |results, (key, analyzed_callbacks)|
64
+ model.analyzed_callbacks.inject([]) do |results, (key, analyzed_callbacks)|
65
65
  results << 2 ** number_of_unique_conditionals(analyzed_callbacks)
66
66
  end.sum - number_of_unique_conditionals(model.analyzed_callbacks_array)
67
67
  end
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.2.0
4
+ version: 2.3.1
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
@@ -16,56 +16,56 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.2'
19
+ version: '7.1'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.2'
26
+ version: '7.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '5.7'
33
+ version: '5.22'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '5.7'
40
+ version: '5.22'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0.10'
47
+ version: '0.14'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0.10'
54
+ version: '0.14'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '10.4'
61
+ version: '13.2'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '10.4'
68
+ version: '13.2'
69
69
  description: Arca is a callback analyzer for ActiveRecord ideally suited for digging
70
70
  yourself out of callback hell
71
71
  email: jonmagic@gmail.com
@@ -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
- rubyforge_project:
118
- rubygems_version: 2.2.2
119
- signing_key:
119
+ rubygems_version: 3.5.3
120
+ signing_key:
120
121
  specification_version: 4
121
122
  summary: ActiveRecord callback analyzer
122
123
  test_files: