chronicles 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +9 -0
- data/.metrics +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +9 -0
- data/.yardopts +3 -0
- data/Gemfile +5 -0
- data/Guardfile +15 -0
- data/LICENSE +21 -0
- data/README.md +198 -0
- data/Rakefile +22 -0
- data/chronicles.gemspec +22 -0
- data/config/metrics/STYLEGUIDE +230 -0
- data/config/metrics/cane.yml +5 -0
- data/config/metrics/churn.yml +6 -0
- data/config/metrics/flay.yml +2 -0
- data/config/metrics/metric_fu.yml +15 -0
- data/config/metrics/reek.yml +1 -0
- data/config/metrics/roodi.yml +24 -0
- data/config/metrics/rubocop.yml +77 -0
- data/config/metrics/saikuro.yml +3 -0
- data/config/metrics/simplecov.yml +8 -0
- data/config/metrics/yardstick.yml +37 -0
- data/lib/chronicles.rb +80 -0
- data/lib/chronicles/injector.rb +28 -0
- data/lib/chronicles/methods.rb +53 -0
- data/lib/chronicles/updater.rb +50 -0
- data/lib/chronicles/version.rb +9 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/tests/chronicles/injector_spec.rb +82 -0
- data/spec/tests/chronicles/methods_spec.rb +88 -0
- data/spec/tests/chronicles/updater_spec.rb +143 -0
- data/spec/tests/chronicles_spec.rb +197 -0
- metadata +99 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
folders: # The list of folders to be used by any metric.
|
3
|
+
- lib
|
4
|
+
- app
|
5
|
+
metrics: # The list of allowed metrics. The other metrics are disabled.
|
6
|
+
- cane
|
7
|
+
- churn
|
8
|
+
- flay
|
9
|
+
- flog
|
10
|
+
- reek
|
11
|
+
- roodi
|
12
|
+
- saikuro
|
13
|
+
format: html
|
14
|
+
output: tmp/metric_fu
|
15
|
+
verbose: false
|
@@ -0,0 +1 @@
|
|
1
|
+
---
|
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
AssignmentInConditionalCheck:
|
3
|
+
CaseMissingElseCheck:
|
4
|
+
ClassLineCountCheck:
|
5
|
+
line_count: 300
|
6
|
+
ClassNameCheck:
|
7
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
8
|
+
ClassVariableCheck:
|
9
|
+
CyclomaticComplexityBlockCheck:
|
10
|
+
complexity: 4
|
11
|
+
CyclomaticComplexityMethodCheck:
|
12
|
+
complexity: 8
|
13
|
+
EmptyRescueBodyCheck:
|
14
|
+
ForLoopCheck:
|
15
|
+
MethodLineCountCheck:
|
16
|
+
line_count: 20
|
17
|
+
MethodNameCheck:
|
18
|
+
pattern: !ruby/regexp /^[\||\^|\&|\!]$|^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
|
19
|
+
ModuleLineCountCheck:
|
20
|
+
line_count: 300
|
21
|
+
ModuleNameCheck:
|
22
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
23
|
+
ParameterNumberCheck:
|
24
|
+
parameter_count: 5
|
@@ -0,0 +1,77 @@
|
|
1
|
+
---
|
2
|
+
# settings added by the 'hexx-suit' module
|
3
|
+
# output: "tmp/rubocop"
|
4
|
+
# format: "html"
|
5
|
+
|
6
|
+
AllCops:
|
7
|
+
Exclude:
|
8
|
+
- '**/db/schema.rb'
|
9
|
+
|
10
|
+
Lint/HandleExceptions:
|
11
|
+
Exclude:
|
12
|
+
- '**/*_spec.rb'
|
13
|
+
|
14
|
+
Lint/RescueException:
|
15
|
+
Exclude:
|
16
|
+
- '**/*_spec.rb'
|
17
|
+
|
18
|
+
Style/AccessorMethodName:
|
19
|
+
Exclude:
|
20
|
+
- '**/*_spec.rb'
|
21
|
+
|
22
|
+
Style/AsciiComments:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/ClassAndModuleChildren:
|
26
|
+
Exclude:
|
27
|
+
- '**/*_spec.rb'
|
28
|
+
|
29
|
+
Style/Documentation:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Style/EmptyLinesAroundBlockBody:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Style/EmptyLinesAroundClassBody:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Style/EmptyLinesAroundMethodBody:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Style/EmptyLinesAroundModuleBody:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Style/EmptyLineBetweenDefs:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
Style/FileName:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
Style/MethodCallParentheses:
|
51
|
+
Exclude:
|
52
|
+
- '**/updater.rb'
|
53
|
+
|
54
|
+
Style/RaiseArgs:
|
55
|
+
EnforcedStyle: compact
|
56
|
+
|
57
|
+
Style/SingleLineMethods:
|
58
|
+
Exclude:
|
59
|
+
- '**/*_spec.rb'
|
60
|
+
|
61
|
+
Style/SingleSpaceBeforeFirstArg:
|
62
|
+
Enabled: false
|
63
|
+
|
64
|
+
Style/SpecialGlobalVars:
|
65
|
+
Exclude:
|
66
|
+
- '**/Gemfile'
|
67
|
+
- '**/*.gemspec'
|
68
|
+
|
69
|
+
Style/StringLiterals:
|
70
|
+
EnforcedStyle: double_quotes
|
71
|
+
|
72
|
+
Style/StringLiteralsInInterpolation:
|
73
|
+
EnforcedStyle: double_quotes
|
74
|
+
|
75
|
+
Style/TrivialAccessors:
|
76
|
+
Exclude:
|
77
|
+
- '**/*_spec.rb'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
---
|
2
|
+
# Settings added by the 'hexx-suit' gem
|
3
|
+
output: "tmp/yardstick/output.log"
|
4
|
+
path: "lib/**/*.rb"
|
5
|
+
rules:
|
6
|
+
ApiTag::Presence:
|
7
|
+
enabled: true
|
8
|
+
exclude: []
|
9
|
+
ApiTag::Inclusion:
|
10
|
+
enabled: true
|
11
|
+
exclude: []
|
12
|
+
ApiTag::ProtectedMethod:
|
13
|
+
enabled: true
|
14
|
+
exclude: []
|
15
|
+
ApiTag::PrivateMethod:
|
16
|
+
enabled: false
|
17
|
+
exclude: []
|
18
|
+
ExampleTag:
|
19
|
+
enabled: true
|
20
|
+
exclude: []
|
21
|
+
ReturnTag:
|
22
|
+
enabled: true
|
23
|
+
exclude: []
|
24
|
+
Summary::Presence:
|
25
|
+
enabled: true
|
26
|
+
exclude: []
|
27
|
+
Summary::Length:
|
28
|
+
enabled: true
|
29
|
+
exclude: []
|
30
|
+
Summary::Delimiter:
|
31
|
+
enabled: true
|
32
|
+
exclude: []
|
33
|
+
Summary::SingleLine:
|
34
|
+
enabled: true
|
35
|
+
exclude: []
|
36
|
+
threshold: 100
|
37
|
+
verbose: false
|
data/lib/chronicles.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative "chronicles/version"
|
4
|
+
require_relative "chronicles/methods"
|
5
|
+
require_relative "chronicles/updater"
|
6
|
+
require_relative "chronicles/injector"
|
7
|
+
|
8
|
+
# The module adds features to keep chronicles of object's methods calls
|
9
|
+
module Chronicles
|
10
|
+
|
11
|
+
# @!attribute [r] chronicles
|
12
|
+
# Returns the array of object methods having been called
|
13
|
+
#
|
14
|
+
# @return [Array<Symbol>]
|
15
|
+
def chronicles
|
16
|
+
@chronicles ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
# Starts registation of calls of the selected methods of the object
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# class Test
|
23
|
+
# include Chronicles
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# test = Test.new
|
27
|
+
# test.start_chronicles only: :foo
|
28
|
+
# test.foo
|
29
|
+
# test.bar
|
30
|
+
# test.baz
|
31
|
+
# test.foo
|
32
|
+
# test.chronicles # => [:foo, :foo]
|
33
|
+
#
|
34
|
+
# @param [Hash] options
|
35
|
+
# describes the selection of methods to include to chronicles
|
36
|
+
# @option options [Boolean] :public (true)
|
37
|
+
# whether public methods should be looked after
|
38
|
+
# @option options [Boolean] :protected (true)
|
39
|
+
# whether protected methods should be looked after
|
40
|
+
# @option options [Boolean] :private (true)
|
41
|
+
# whether private methods should be looked after
|
42
|
+
# @option options [Array<#to_sym>] :except ([])
|
43
|
+
# the whitelist of methods that shouldn't be looked after
|
44
|
+
# @option options [Array<#to_sym>] :only ([])
|
45
|
+
# the whitelist of methods that should be looked after
|
46
|
+
#
|
47
|
+
# @return [undefined]
|
48
|
+
def start_chronicles(**options)
|
49
|
+
Injector.new(self, "chronicles << __method__", options).run
|
50
|
+
end
|
51
|
+
|
52
|
+
# Stops registation of calls of the selected methods of the object
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# class Test
|
56
|
+
# include Chronicles
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# test = Test.new
|
60
|
+
# test.start_chronicles
|
61
|
+
# test.foo
|
62
|
+
# test.bar
|
63
|
+
# test.baz
|
64
|
+
# test.chronicles # => [:foo, :bar, :baz]
|
65
|
+
#
|
66
|
+
# test.stop_chronicles except: :foo
|
67
|
+
# test.foo
|
68
|
+
# test.bar
|
69
|
+
# test.baz
|
70
|
+
# test.chronicles # => [:foo, :bar, :baz, :foo]
|
71
|
+
#
|
72
|
+
# @param (see #start_chronicles)
|
73
|
+
# @option (see #start_chronicles)
|
74
|
+
#
|
75
|
+
# @return [undefined]
|
76
|
+
def stop_chronicles(**options)
|
77
|
+
Injector.new(self, options).run
|
78
|
+
end
|
79
|
+
|
80
|
+
end # module Chronicles
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Chronicles
|
4
|
+
|
5
|
+
# Injects the code to object methods selected by options
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class Injector
|
9
|
+
|
10
|
+
attr_reader :object, :code, :list
|
11
|
+
|
12
|
+
def initialize(object, code = nil, **options)
|
13
|
+
@object = object
|
14
|
+
@code = code
|
15
|
+
@list = Methods.new(object, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def updaters
|
19
|
+
list.map { |name| Updater.new(object, name, code) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
updaters.each(&:run)
|
24
|
+
end
|
25
|
+
|
26
|
+
end # class Injector
|
27
|
+
|
28
|
+
end # module Chronicles
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Chronicles
|
4
|
+
|
5
|
+
# Array of object methods selected by options
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class Methods < Array
|
9
|
+
|
10
|
+
def initialize(object, **options)
|
11
|
+
@object = object
|
12
|
+
@options = options
|
13
|
+
super(whitelist.empty? ? list : list & whitelist)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :object, :options
|
19
|
+
|
20
|
+
def list
|
21
|
+
[public_list, protected_list, private_list].flatten.compact - blacklist
|
22
|
+
end
|
23
|
+
|
24
|
+
def whitelist
|
25
|
+
Array(options[:only]).map(&:to_sym)
|
26
|
+
end
|
27
|
+
|
28
|
+
def blacklist
|
29
|
+
Array(options[:except]).map(&:to_sym)
|
30
|
+
end
|
31
|
+
|
32
|
+
def public_list
|
33
|
+
return if options[:public].equal?(false)
|
34
|
+
object.public_methods - Object.public_instance_methods - own_list
|
35
|
+
end
|
36
|
+
|
37
|
+
def own_list
|
38
|
+
%i(chronicles start_chronicles stop_chronicles)
|
39
|
+
end
|
40
|
+
|
41
|
+
def protected_list
|
42
|
+
return if options[:protected].equal?(false)
|
43
|
+
object.protected_methods
|
44
|
+
end
|
45
|
+
|
46
|
+
def private_list
|
47
|
+
return if options[:private].equal?(false)
|
48
|
+
object.private_methods - Object.private_instance_methods
|
49
|
+
end
|
50
|
+
|
51
|
+
end # class Methods
|
52
|
+
|
53
|
+
end # module Chronicles
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Chronicles
|
4
|
+
|
5
|
+
# Reloads object method
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class Updater
|
9
|
+
|
10
|
+
def initialize(object, name, code = nil)
|
11
|
+
@object = object
|
12
|
+
@name = name
|
13
|
+
@code = code
|
14
|
+
type
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :object, :name, :code
|
18
|
+
|
19
|
+
def type
|
20
|
+
@type ||= %w(public private protected).detect do |item|
|
21
|
+
object.public_send("#{ item }_methods").include? name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def klass
|
26
|
+
object.singleton_class
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
redefine_method
|
31
|
+
protect_method
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def redefine_method
|
37
|
+
code = code()
|
38
|
+
klass.__send__ :define_method, name do |*args|
|
39
|
+
instance_eval(code) if code
|
40
|
+
super(*args)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def protect_method
|
45
|
+
klass.instance_eval "#{ type } :#{ name }"
|
46
|
+
end
|
47
|
+
|
48
|
+
end # class Updater
|
49
|
+
|
50
|
+
end # module Chronicles
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Chronicles::Injector do
|
4
|
+
|
5
|
+
let(:object) { double foo: nil, bar: nil, baz: nil }
|
6
|
+
let(:options) { { only: %i(foo bar), private: false } }
|
7
|
+
let(:code) { "chronicles << __method__" }
|
8
|
+
subject { described_class.new object, code, options }
|
9
|
+
|
10
|
+
describe "#object" do
|
11
|
+
|
12
|
+
it "is initialized" do
|
13
|
+
expect(subject.object).to eq object
|
14
|
+
end
|
15
|
+
|
16
|
+
end # describe #object
|
17
|
+
|
18
|
+
describe "#list" do
|
19
|
+
|
20
|
+
let(:list) { Chronicles::Methods.new(object, options).to_a }
|
21
|
+
|
22
|
+
it "is initialized" do
|
23
|
+
expect(subject.list).to eq list
|
24
|
+
end
|
25
|
+
|
26
|
+
end # describe #list
|
27
|
+
|
28
|
+
describe "#code" do
|
29
|
+
|
30
|
+
it "is initialized" do
|
31
|
+
expect(subject.code).to eq code
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can be nil" do
|
35
|
+
subject = described_class.new object, options
|
36
|
+
expect(subject.code).to be_nil
|
37
|
+
end
|
38
|
+
|
39
|
+
end # describe #code
|
40
|
+
|
41
|
+
describe "#updaters" do
|
42
|
+
|
43
|
+
let(:list) { %i(foo bar baz) }
|
44
|
+
before { allow(subject).to receive(:list).and_return list }
|
45
|
+
|
46
|
+
it "returns updaters" do
|
47
|
+
subject.updaters.each do |updater|
|
48
|
+
expect(updater).to be_kind_of Chronicles::Updater
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "constructed for #object" do
|
53
|
+
subject.updaters.each do |updater|
|
54
|
+
expect(updater.object).to eq subject.object
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it "constructed for #list of methods" do
|
59
|
+
expect(subject.updaters.map(&:name)).to eq subject.list
|
60
|
+
end
|
61
|
+
|
62
|
+
it "constructed for #code" do
|
63
|
+
subject.updaters.each do |updater|
|
64
|
+
expect(updater.code).to eq subject.code
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end # describe #updaters
|
69
|
+
|
70
|
+
describe ".run" do
|
71
|
+
|
72
|
+
let(:updaters) { 2.times.map { double run: nil } }
|
73
|
+
before { allow(subject).to receive(:updaters).and_return updaters }
|
74
|
+
|
75
|
+
it "runs updaters" do
|
76
|
+
updaters.each { |updater| expect(updater).to receive(:run) }
|
77
|
+
subject.run
|
78
|
+
end
|
79
|
+
|
80
|
+
end # describe .run
|
81
|
+
|
82
|
+
end # describe Chronicles::Injector
|