arca 1.0.0 → 2.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/README.md +7 -8
- data/arca.gemspec +1 -1
- data/lib/arca/callback_analysis.rb +1 -0
- data/lib/arca/collector.rb +27 -31
- data/lib/arca/report.rb +5 -2
- data/lib/arca.rb +4 -16
- data/test/fixtures/announcements.rb +1 -0
- data/test/fixtures/ticket.rb +0 -1
- data/test/lib/arca/callback_analysis_test.rb +8 -8
- data/test/lib/arca/collector_test.rb +16 -17
- data/test/lib/arca/model_test.rb +6 -6
- data/test/test_helper.rb +4 -3
- metadata +1 -3
- data/test/fixtures/bar.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca8734a74ea5a5b2ab9c36ec62439ecb515a9669
|
4
|
+
data.tar.gz: 2638b950202f3f0c760bebeb7bf4f39ebc75adcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4dfcbd12c0f48b3c33db3de0be2855edc7bb829b8fc7712f7a9666c27c8480cf7d6e8730a8a64859a1cc8ab27ff110d0d5b01da799e49ed2ecbf036a9463f5d
|
7
|
+
data.tar.gz: edc74a7ad1d0e13e57802db09dcacb9c0c9b45f4c8e3c366d7727870a721b5b137259ea8c5e3bed544cee82a85df663d64fe03dca9f89dcea466e2f5154512a4
|
data/README.md
CHANGED
@@ -16,20 +16,21 @@ Add the gem to your Gemfile and run `bundle`.
|
|
16
16
|
gem 'arca'
|
17
17
|
```
|
18
18
|
|
19
|
-
|
19
|
+
In your test helper (`test/test_helper.rb` for example) require the Arca library and include the `Arca::Collector` in `ActiveRecord::Base`.
|
20
20
|
|
21
21
|
```
|
22
22
|
require "arca"
|
23
23
|
|
24
|
-
|
25
|
-
Arca
|
24
|
+
class ActiveRecord::Base
|
25
|
+
include Arca::Collector
|
26
|
+
end
|
26
27
|
```
|
27
28
|
|
28
|
-
|
29
|
+
In this example the `Annoucements` module is included in `Ticket` and defines it's own callback.
|
30
|
+
|
29
31
|
|
30
32
|
```ruby
|
31
33
|
class Ticket < ActiveRecord::Base
|
32
|
-
include Arca::Collector
|
33
34
|
include Announcements
|
34
35
|
|
35
36
|
before_save :set_title, :set_body
|
@@ -53,8 +54,6 @@ class Ticket < ActiveRecord::Base
|
|
53
54
|
end
|
54
55
|
```
|
55
56
|
|
56
|
-
In this example the `Annoucements` module is included in `Ticket` and defines it's own callback.
|
57
|
-
|
58
57
|
```ruby
|
59
58
|
module Announcements
|
60
59
|
def self.included(base)
|
@@ -69,7 +68,7 @@ module Announcements
|
|
69
68
|
end
|
70
69
|
```
|
71
70
|
|
72
|
-
|
71
|
+
Use `Arca[Ticket].report` to analyze the callbacks for the `Ticket` class.
|
73
72
|
|
74
73
|
```ruby
|
75
74
|
> Arca.root_path = `pwd`.chomp
|
data/arca.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "arca"
|
3
|
-
spec.version = "
|
3
|
+
spec.version = "2.0.0"
|
4
4
|
spec.date = "2015-07-11"
|
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"
|
data/lib/arca/collector.rb
CHANGED
@@ -4,35 +4,22 @@ module Arca
|
|
4
4
|
# about how callbacks are being used.
|
5
5
|
module Collector
|
6
6
|
|
7
|
-
# Error raised if Arca.model_root_path is nil.
|
8
|
-
class ModelRootPathRequired < StandardError; end
|
9
|
-
|
10
7
|
# Internal: Regular expression used for extracting the file path and line
|
11
8
|
# number from a caller line.
|
12
|
-
|
13
|
-
private_constant :
|
9
|
+
ARCA_CALLBACK_FINDER_REGEXP = /\A(.+)\:(\d+)\:in\s`.+'\z/
|
10
|
+
private_constant :ARCA_CALLBACK_FINDER_REGEXP
|
14
11
|
|
15
12
|
# Internal: Array of conditional symbols.
|
16
|
-
ARCA_CONDITIONALS = [:if, :unless]
|
13
|
+
ARCA_CONDITIONALS = [:if, :unless, :on]
|
17
14
|
private_constant :ARCA_CONDITIONALS
|
18
15
|
|
19
16
|
# http://ruby-doc.org/core-2.2.1/Module.html#method-i-included
|
20
17
|
def self.included(base)
|
21
|
-
# Raise error if Arca.model_root_path is nil.
|
22
|
-
raise ModelRootPathRequired if Arca.model_root_path.nil?
|
23
|
-
|
24
|
-
# Get the file path to the model class that included the collector.
|
25
|
-
model_file_path, = caller[0].partition(":")
|
26
|
-
|
27
18
|
base.class_eval do
|
28
|
-
|
29
|
-
|
30
|
-
@callbacks ||= {}
|
19
|
+
define_singleton_method(:arca_callback_data) do
|
20
|
+
@arca_callback_data ||= Hash.new {|k,v| k[v] = [] }
|
31
21
|
end
|
32
22
|
|
33
|
-
# Collect the model_file_path.
|
34
|
-
arca_callback_data[:model_file_path] = model_file_path
|
35
|
-
|
36
23
|
# Find the callback methods defined on this class.
|
37
24
|
callback_method_symbols = singleton_methods.grep /^(after|around|before)\_/
|
38
25
|
|
@@ -42,23 +29,32 @@ module Arca
|
|
42
29
|
|
43
30
|
# Redefine the callback method so that data can be collected each time
|
44
31
|
# the callback is used for this class.
|
45
|
-
define_singleton_method(callback_method.name) do |*args|
|
32
|
+
define_singleton_method(callback_method.name) do |*args, &block|
|
46
33
|
# Duplicate args before modifying.
|
47
34
|
args_copy = args.dup
|
48
35
|
|
49
|
-
#
|
50
|
-
|
36
|
+
# Add target_symbol :block to args_copy if a block was given.
|
37
|
+
if block
|
38
|
+
args_copy << :block
|
39
|
+
else
|
40
|
+
# Get the options hash from the end of the args Array if it exists.
|
41
|
+
options = args_copy.pop if args[-1].is_a?(Hash)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get the callback file path and line number from the caller stack.
|
45
|
+
callback_file_path, callback_line_number = ARCA_CALLBACK_FINDER_REGEXP.match(caller.first)[1..2]
|
46
|
+
|
47
|
+
# Extract the model file path from the caller stack.
|
48
|
+
caller.each do |line|
|
49
|
+
if match = /\A(.+):\d+:in\s`<class:#{name.split("::").last}>'/.match(line)
|
50
|
+
self.arca_callback_data[:model_file_path] = match[1]
|
51
|
+
break
|
52
|
+
end
|
53
|
+
end
|
51
54
|
|
52
55
|
# Iterate through the rest of the args. Each remaining arguement is
|
53
56
|
# a Symbol representing the callback target method.
|
54
57
|
args_copy.each do |target_symbol|
|
55
|
-
|
56
|
-
# Find the caller line where the callback is used.
|
57
|
-
line = caller.find {|line| line =~ /#{Regexp.escape(Arca.model_root_path)}/ }
|
58
|
-
|
59
|
-
# Parse the line in order to extract the file path and line number.
|
60
|
-
callback_line_matches = line.match(ARCA_LINE_PARSER_REGEXP)
|
61
|
-
|
62
58
|
# Find the conditional symbol if it exists in the options hash.
|
63
59
|
conditional_symbol = ARCA_CONDITIONALS.
|
64
60
|
find {|conditional| options && options.has_key?(conditional) }
|
@@ -76,8 +72,8 @@ module Arca
|
|
76
72
|
# this callback_symbol.
|
77
73
|
arca_callback_data[callback_symbol] << {
|
78
74
|
:callback_symbol => callback_symbol,
|
79
|
-
:callback_file_path =>
|
80
|
-
:callback_line_number =>
|
75
|
+
:callback_file_path => callback_file_path,
|
76
|
+
:callback_line_number => callback_line_number.to_i,
|
81
77
|
:target_symbol => target_symbol,
|
82
78
|
:conditional_symbol => conditional_symbol,
|
83
79
|
:conditional_target_symbol => conditional_target_symbol
|
@@ -86,7 +82,7 @@ module Arca
|
|
86
82
|
end
|
87
83
|
|
88
84
|
# Bind the callback method to self and call it with args.
|
89
|
-
callback_method.bind(self).call(*args)
|
85
|
+
callback_method.bind(self).call(*args, &block)
|
90
86
|
end
|
91
87
|
end
|
92
88
|
end
|
data/lib/arca/report.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
1
3
|
module Arca
|
2
4
|
class Report
|
5
|
+
extend Forwardable
|
3
6
|
|
4
7
|
# Arca::Report takes an Arca::Model and compiles the analyzed callback data
|
5
8
|
# into a short overview report for the model.
|
@@ -51,8 +54,8 @@ module Arca
|
|
51
54
|
number_of_unique_conditionals(model.analyzed_callbacks_array)
|
52
55
|
end
|
53
56
|
|
54
|
-
|
55
|
-
:external_targets_count, :external_conditionals_count
|
57
|
+
def_delegators :model, :lines_between_count, :external_callbacks_count,
|
58
|
+
:external_targets_count, :external_conditionals_count
|
56
59
|
|
57
60
|
# Public: Integer representing the possible number of permutations stemming
|
58
61
|
# from conditionals for an instance of the model being reported during the
|
data/lib/arca.rb
CHANGED
@@ -20,7 +20,7 @@ module Arca
|
|
20
20
|
Arca::Model.new(klass)
|
21
21
|
end
|
22
22
|
|
23
|
-
# Public:
|
23
|
+
# Public: Writer method for configuring the root path of the
|
24
24
|
# project where Arca is being used. Setting Arca.root_path will makes
|
25
25
|
# inspecting analyzed callbacks easier by shortening absolute paths to
|
26
26
|
# relative paths.
|
@@ -32,19 +32,7 @@ module Arca
|
|
32
32
|
|
33
33
|
# Public: String representing the root path for the project.
|
34
34
|
def self.root_path
|
35
|
-
@root_path
|
36
|
-
end
|
37
|
-
|
38
|
-
# Public: (required) Writer method for configuring the root path to the models
|
39
|
-
# for the project where Arca is being used. This path is required by the
|
40
|
-
# Arca::Collector for finding the correct line in the caller Array.
|
41
|
-
def self.model_root_path=(path)
|
42
|
-
@model_root_path = path.to_s
|
43
|
-
end
|
44
|
-
|
45
|
-
# Public: String representing the path to the models for the project.
|
46
|
-
def self.model_root_path
|
47
|
-
@model_root_path
|
35
|
+
@root_path ||= Dir.pwd
|
48
36
|
end
|
49
37
|
|
50
38
|
# Public: Helper method for turning absolute paths into relative paths.
|
@@ -55,8 +43,8 @@ module Arca
|
|
55
43
|
def self.relative_path(path)
|
56
44
|
return if path.nil?
|
57
45
|
|
58
|
-
if
|
59
|
-
path.sub(/^#{Regexp.escape(
|
46
|
+
if root_path
|
47
|
+
path.sub(/^#{Regexp.escape(root_path) || ""}\//, "")
|
60
48
|
else
|
61
49
|
path
|
62
50
|
end
|
data/test/fixtures/ticket.rb
CHANGED
@@ -84,9 +84,9 @@ class Arca::CallbackAnalysisTest < Minitest::Test
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def test_target_line_number
|
87
|
-
assert_equal
|
88
|
-
assert_equal
|
89
|
-
assert_equal
|
87
|
+
assert_equal 9, announce_save.target_line_number
|
88
|
+
assert_equal 7, set_title.target_line_number
|
89
|
+
assert_equal 15, upcase_title.target_line_number
|
90
90
|
end
|
91
91
|
|
92
92
|
def test_external_target?
|
@@ -96,9 +96,9 @@ class Arca::CallbackAnalysisTest < Minitest::Test
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def test_lines_to_target
|
99
|
-
assert_equal
|
100
|
-
assert_equal
|
101
|
-
assert_equal
|
99
|
+
assert_equal 5, announce_save.lines_to_target
|
100
|
+
assert_equal 2, set_title.lines_to_target
|
101
|
+
assert_equal 9, upcase_title.lines_to_target
|
102
102
|
end
|
103
103
|
|
104
104
|
def test_conditional_symbol
|
@@ -122,12 +122,12 @@ class Arca::CallbackAnalysisTest < Minitest::Test
|
|
122
122
|
def test_conditional_target_line_number
|
123
123
|
assert_nil announce_save.conditional_target_line_number
|
124
124
|
assert_nil set_title.conditional_target_line_number
|
125
|
-
assert_equal
|
125
|
+
assert_equal 19, upcase_title.conditional_target_line_number
|
126
126
|
end
|
127
127
|
|
128
128
|
def test_lines_to_conditional_target
|
129
129
|
assert_nil announce_save.lines_to_conditional_target
|
130
130
|
assert_nil set_title.lines_to_conditional_target
|
131
|
-
assert_equal
|
131
|
+
assert_equal 13, upcase_title.lines_to_conditional_target
|
132
132
|
end
|
133
133
|
end
|
@@ -3,51 +3,50 @@ require_relative "../../test_helper"
|
|
3
3
|
class Arca::CollectorTest < Minitest::Test
|
4
4
|
def test_collects_callback_data
|
5
5
|
callbacks = Ticket.arca_callback_data
|
6
|
+
assert_equal 1, callbacks[:after_save].size
|
7
|
+
assert_equal 4, callbacks[:before_save].size
|
6
8
|
|
7
9
|
callback = callbacks[:after_save][0]
|
8
10
|
assert_equal :after_save, callback[:callback_symbol]
|
9
11
|
assert_match "test/fixtures/announcements.rb", callback[:callback_file_path]
|
10
|
-
assert_equal
|
12
|
+
assert_equal 5, callback[:callback_line_number]
|
11
13
|
assert_equal :announce_save, callback[:target_symbol]
|
12
14
|
assert_nil callback[:conditional_symbol]
|
13
15
|
assert_nil callback[:conditional_target_symbol]
|
14
16
|
|
15
17
|
callback = callbacks[:before_save][0]
|
16
18
|
assert_equal :before_save, callback[:callback_symbol]
|
19
|
+
assert_match "test/fixtures/announcements.rb", callback[:callback_file_path]
|
20
|
+
assert_equal 4, callback[:callback_line_number]
|
21
|
+
assert_equal :block, callback[:target_symbol]
|
22
|
+
assert_nil callback[:conditional_symbol]
|
23
|
+
assert_nil callback[:conditional_target_symbol]
|
24
|
+
|
25
|
+
callback = callbacks[:before_save][1]
|
26
|
+
assert_equal :before_save, callback[:callback_symbol]
|
17
27
|
assert_match "test/fixtures/ticket.rb", callback[:callback_file_path]
|
18
|
-
assert_equal
|
28
|
+
assert_equal 4, callback[:callback_line_number]
|
19
29
|
assert_equal :set_title, callback[:target_symbol]
|
20
30
|
assert_nil callback[:conditional_symbol]
|
21
31
|
assert_nil callback[:conditional_target_symbol]
|
22
32
|
|
23
|
-
callback = callbacks[:before_save][
|
33
|
+
callback = callbacks[:before_save][2]
|
24
34
|
assert_equal :before_save, callback[:callback_symbol]
|
25
35
|
assert_match "test/fixtures/ticket.rb", callback[:callback_file_path]
|
26
|
-
assert_equal
|
36
|
+
assert_equal 4, callback[:callback_line_number]
|
27
37
|
assert_equal :set_body, callback[:target_symbol]
|
28
38
|
assert_nil callback[:conditional_symbol]
|
29
39
|
assert_nil callback[:conditional_target_symbol]
|
30
40
|
|
31
|
-
callback = callbacks[:before_save][
|
41
|
+
callback = callbacks[:before_save][3]
|
32
42
|
assert_equal :before_save, callback[:callback_symbol]
|
33
43
|
assert_match "test/fixtures/ticket.rb", callback[:callback_file_path]
|
34
|
-
assert_equal
|
44
|
+
assert_equal 5, callback[:callback_line_number]
|
35
45
|
assert_equal :upcase_title, callback[:target_symbol]
|
36
46
|
assert_equal :if, callback[:conditional_symbol]
|
37
47
|
assert_equal :title_is_a_shout?, callback[:conditional_target_symbol]
|
38
48
|
end
|
39
49
|
|
40
|
-
def test_arca_model_root_path_is_required
|
41
|
-
model_root_path = Arca.model_root_path
|
42
|
-
Arca.instance_variable_set(:@model_root_path, nil)
|
43
|
-
|
44
|
-
assert_raises(Arca::Collector::ModelRootPathRequired) do
|
45
|
-
require_relative "../../fixtures/bar"
|
46
|
-
end
|
47
|
-
|
48
|
-
Arca.model_root_path = model_root_path
|
49
|
-
end
|
50
|
-
|
51
50
|
def test_callback_is_reapplied_with_original_args
|
52
51
|
foo = Foo.new
|
53
52
|
refute foo.boop?
|
data/test/lib/arca/model_test.rb
CHANGED
@@ -12,7 +12,7 @@ class Arca::ModelTest < Minitest::Test
|
|
12
12
|
def test_source_location
|
13
13
|
source_location = model.source_location(:set_title)
|
14
14
|
assert_match "test/fixtures/ticket.rb", source_location[:file_path]
|
15
|
-
assert_equal
|
15
|
+
assert_equal 7, source_location[:line_number]
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_source_location_with_method_symbol_with_no_associated_method
|
@@ -28,25 +28,25 @@ class Arca::ModelTest < Minitest::Test
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def test_analyzed_callbacks
|
31
|
-
assert_equal
|
31
|
+
assert_equal 4, model.analyzed_callbacks[:before_save].size
|
32
32
|
assert_equal 1, model.analyzed_callbacks[:after_save].size
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_analyzed_callbacks_array
|
36
|
-
assert_equal
|
36
|
+
assert_equal 5, model.analyzed_callbacks_array.size
|
37
37
|
assert model.analyzed_callbacks_array[0].is_a?(Arca::CallbackAnalysis)
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_analyzed_callbacks_count
|
41
|
-
assert_equal
|
41
|
+
assert_equal 5, model.analyzed_callbacks_count
|
42
42
|
end
|
43
43
|
|
44
44
|
def test_lines_between_count
|
45
|
-
assert_equal
|
45
|
+
assert_equal 5, model.lines_between_count
|
46
46
|
end
|
47
47
|
|
48
48
|
def test_external_callbacks_count
|
49
|
-
assert_equal
|
49
|
+
assert_equal 2, model.external_callbacks_count
|
50
50
|
end
|
51
51
|
|
52
52
|
def test_external_targets_count
|
data/test/test_helper.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
2
2
|
require "active_record"
|
3
3
|
require "minitest/autorun"
|
4
|
-
|
5
4
|
require "arca"
|
6
|
-
|
7
|
-
|
5
|
+
|
6
|
+
class ActiveRecord::Base
|
7
|
+
include Arca::Collector
|
8
|
+
end
|
8
9
|
|
9
10
|
require_relative "fixtures/announcements"
|
10
11
|
require_relative "fixtures/ticket"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Hoyt
|
@@ -70,7 +70,6 @@ files:
|
|
70
70
|
- lib/arca/model.rb
|
71
71
|
- lib/arca/report.rb
|
72
72
|
- test/fixtures/announcements.rb
|
73
|
-
- test/fixtures/bar.rb
|
74
73
|
- test/fixtures/foo.rb
|
75
74
|
- test/fixtures/ticket.rb
|
76
75
|
- test/lib/arca/callback_analysis_test.rb
|
@@ -105,7 +104,6 @@ specification_version: 4
|
|
105
104
|
summary: ActiveRecord callback analyzer
|
106
105
|
test_files:
|
107
106
|
- test/fixtures/announcements.rb
|
108
|
-
- test/fixtures/bar.rb
|
109
107
|
- test/fixtures/foo.rb
|
110
108
|
- test/fixtures/ticket.rb
|
111
109
|
- test/lib/arca/callback_analysis_test.rb
|
data/test/fixtures/bar.rb
DELETED