arca 2.2.0 → 2.3.1

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
- 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: