arca 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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