advisor 0.1.0 → 0.2.0.pre
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/.travis.yml +7 -0
- data/Gemfile.lock +10 -1
- data/Readme.org +2 -0
- data/advisor.gemspec +2 -0
- data/lib/advisor/advices/metriks.rb +97 -0
- data/lib/advisor/advices.rb +1 -0
- data/lib/advisor/builtin_advisors.rb +1 -0
- data/lib/advisor/factory.rb +4 -0
- data/lib/advisor/version.rb +1 -1
- data/spec/advisor/advices/call_logger_spec.rb +1 -1
- data/spec/advisor/advices/metriks_spec.rb +178 -0
- metadata +21 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc4b02e3e1fcc423abfbce5f70d121ac973ec5f4
|
4
|
+
data.tar.gz: b9f60ba8b0437012e6334eef615fa158a457f293
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cf7cf08b21ec53349f10453f3be8653a8ec2c2e0cd2f03f7d014fa487410a52d882688e1a91eec2399be061baad8df5083e6fba3600371c44a209d9c35b8f11
|
7
|
+
data.tar.gz: a3fa5127caf63ac8259a74c45b6b3757e07a9998690e0ebb0688c0d47a6b0857405d0fade6e9f841f8a9c24e0f5f57c3264097d0a97501a8a490d8f50ab85c5d
|
data/.travis.yml
ADDED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
advisor (0.
|
4
|
+
advisor (0.2.0)
|
5
|
+
metriks
|
5
6
|
|
6
7
|
GEM
|
7
8
|
remote: https://rubygems.org/
|
@@ -9,9 +10,17 @@ GEM
|
|
9
10
|
ast (2.0.0)
|
10
11
|
astrolabe (1.3.0)
|
11
12
|
parser (>= 2.2.0.pre.3, < 3.0)
|
13
|
+
atomic (1.1.99)
|
14
|
+
avl_tree (1.2.1)
|
15
|
+
atomic (~> 1.1)
|
12
16
|
coderay (1.1.0)
|
13
17
|
diff-lcs (1.2.5)
|
18
|
+
hitimes (1.2.2)
|
14
19
|
method_source (0.8.2)
|
20
|
+
metriks (0.9.9.7)
|
21
|
+
atomic (~> 1.0)
|
22
|
+
avl_tree (~> 1.2.0)
|
23
|
+
hitimes (~> 1.1)
|
15
24
|
parser (2.2.0.3)
|
16
25
|
ast (>= 1.1, < 3.0)
|
17
26
|
powerpack (0.1.0)
|
data/Readme.org
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
* Advisor: Solve your cross-cutting concerns without mumbo-jumbo.
|
2
2
|
|
3
|
+
[[https://travis-ci.org/rranelli/advisor.svg?branch=master][https://travis-ci.org/rranelli/advisor.svg]]
|
4
|
+
|
3
5
|
=Advisor= is Ruby gem that enables you to solve cross-cutting concerns without
|
4
6
|
the usual =method-renaming= present in most alternatives.
|
5
7
|
|
data/advisor.gemspec
CHANGED
@@ -18,6 +18,8 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^bin\/}) { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
+
spec.add_dependency 'metriks'
|
22
|
+
|
21
23
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
22
24
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
23
25
|
spec.add_development_dependency 'rake', '~> 10.0'
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'metriks'
|
3
|
+
|
4
|
+
module Advisor
|
5
|
+
module Advices
|
6
|
+
class Metriks
|
7
|
+
class << self
|
8
|
+
attr_accessor :default_logger
|
9
|
+
end
|
10
|
+
self.default_logger = Logger.new(STDOUT)
|
11
|
+
|
12
|
+
def initialize(object, method, _call_args, **opts)
|
13
|
+
@object = object
|
14
|
+
@method = method
|
15
|
+
|
16
|
+
@instruments = Array(opts.fetch(:with)).uniq
|
17
|
+
@logger = opts[:logger] || Metriks.default_logger
|
18
|
+
|
19
|
+
fail 'No instruments defined' if instruments.empty?
|
20
|
+
fail 'Unknown Instrument' unless instruments.all?(&known_instrument?)
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :object, :method, :logger, :instruments
|
24
|
+
|
25
|
+
INSTRUMENTS = [
|
26
|
+
:counter, :timer, :gauge, :call_meter, :result_meter
|
27
|
+
]
|
28
|
+
|
29
|
+
def self.applier_method
|
30
|
+
:measure
|
31
|
+
end
|
32
|
+
|
33
|
+
def call
|
34
|
+
(timed? ? timed_call { yield } : yield)
|
35
|
+
.tap { |result| instruments.each(&measure(result)) }
|
36
|
+
rescue => e
|
37
|
+
logger.warn(e)
|
38
|
+
raise
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def timed_call
|
44
|
+
timer.time
|
45
|
+
yield.tap do
|
46
|
+
timer.stop
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def measure(result)
|
51
|
+
# How I wish I had currying...
|
52
|
+
lambda do |instrument|
|
53
|
+
is_numeric = result.is_a?(Fixnum)
|
54
|
+
|
55
|
+
case instrument
|
56
|
+
when :counter then counter.increment
|
57
|
+
when :call_meter then call_meter.mark
|
58
|
+
when :result_meter then is_numeric && result_meter.mark(result)
|
59
|
+
when :gauge then is_numeric && gauge.set(result)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def timed?
|
65
|
+
instruments.include?(:timer)
|
66
|
+
end
|
67
|
+
|
68
|
+
def metric_prefix
|
69
|
+
"#{object.class}##{method}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def timer
|
73
|
+
::Metriks.timer("#{metric_prefix}_#{__callee__}")
|
74
|
+
end
|
75
|
+
|
76
|
+
def counter
|
77
|
+
::Metriks.counter("#{metric_prefix}_#{__callee__}")
|
78
|
+
end
|
79
|
+
|
80
|
+
def gauge
|
81
|
+
::Metriks.gauge("#{metric_prefix}_#{__callee__}")
|
82
|
+
end
|
83
|
+
|
84
|
+
def call_meter
|
85
|
+
::Metriks.meter("#{metric_prefix}_#{__callee__}")
|
86
|
+
end
|
87
|
+
|
88
|
+
def result_meter
|
89
|
+
::Metriks.meter("#{metric_prefix}_#{__callee__}")
|
90
|
+
end
|
91
|
+
|
92
|
+
def known_instrument?
|
93
|
+
-> (instrument) { INSTRUMENTS.include?(instrument) }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/advisor/advices.rb
CHANGED
data/lib/advisor/factory.rb
CHANGED
data/lib/advisor/version.rb
CHANGED
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Advisor
|
4
|
+
module Advices
|
5
|
+
describe Metriks do
|
6
|
+
subject(:advice) do
|
7
|
+
described_class.new(
|
8
|
+
object,
|
9
|
+
method,
|
10
|
+
args,
|
11
|
+
logger: logger,
|
12
|
+
with: instruments
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:object) { OpenStruct.new(when: '2015-12-18') }
|
17
|
+
let(:method) { 'the_force_awakens' }
|
18
|
+
let(:args) { ['vai ser zika', 'demais'] }
|
19
|
+
let(:logger) { instance_double(Logger, warn: nil) }
|
20
|
+
|
21
|
+
let(:block) { -> { 42 } }
|
22
|
+
|
23
|
+
context 'when no instruments are specified' do
|
24
|
+
let(:instruments) { [] }
|
25
|
+
|
26
|
+
it { expect { call }.to raise_error }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '.applier_method' do
|
30
|
+
subject { Metriks.applier_method }
|
31
|
+
it { is_expected.to eq(:measure) }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#call' do
|
35
|
+
subject(:call) { advice.call(&block) }
|
36
|
+
|
37
|
+
let(:instruments) { %i(counter result_meter call_meter gauge) }
|
38
|
+
|
39
|
+
shared_examples_for 'instruments && measuring' do
|
40
|
+
it('returns the block call value') { is_expected.to eq(42) }
|
41
|
+
|
42
|
+
it 'instantiates a counter with the right metric name' do
|
43
|
+
expect(::Metriks).to receive(:counter)
|
44
|
+
.with('OpenStruct#the_force_awakens_counter')
|
45
|
+
.and_call_original
|
46
|
+
|
47
|
+
subject
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'instantiates gauge with the right metric name' do
|
51
|
+
expect(::Metriks).to receive(:gauge)
|
52
|
+
.with('OpenStruct#the_force_awakens_gauge')
|
53
|
+
.and_call_original
|
54
|
+
|
55
|
+
subject
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'instantiates a method call and a meter with the right metric names' do
|
59
|
+
expect(::Metriks).to receive(:meter)
|
60
|
+
.with('OpenStruct#the_force_awakens_call_meter')
|
61
|
+
.and_call_original
|
62
|
+
|
63
|
+
expect(::Metriks).to receive(:meter)
|
64
|
+
.with('OpenStruct#the_force_awakens_result_meter')
|
65
|
+
.and_call_original
|
66
|
+
|
67
|
+
subject
|
68
|
+
end
|
69
|
+
|
70
|
+
let(:result_meter) { instance_double(::Metriks::Meter) }
|
71
|
+
let(:call_meter) { instance_double(::Metriks::Meter) }
|
72
|
+
|
73
|
+
it 'increments a method call counter' do
|
74
|
+
expect(::Metriks).to receive_message_chain(
|
75
|
+
:counter, :increment
|
76
|
+
)
|
77
|
+
|
78
|
+
subject
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'marks a method call and a block result value meter' do
|
82
|
+
expect(::Metriks).to receive(:meter)
|
83
|
+
.with('OpenStruct#the_force_awakens_result_meter')
|
84
|
+
.and_return(result_meter)
|
85
|
+
|
86
|
+
expect(result_meter).to receive(:mark)
|
87
|
+
.with(42)
|
88
|
+
|
89
|
+
expect(::Metriks).to receive(:meter)
|
90
|
+
.with('OpenStruct#the_force_awakens_call_meter')
|
91
|
+
.and_return(call_meter)
|
92
|
+
|
93
|
+
expect(call_meter).to receive(:mark)
|
94
|
+
|
95
|
+
subject
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'sets the block result value gauge' do
|
99
|
+
expect(::Metriks).to receive_message_chain(
|
100
|
+
:gauge, :set
|
101
|
+
).with(42)
|
102
|
+
|
103
|
+
subject
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'when the block return value is not numeric' do
|
107
|
+
let(:block) { -> { :war_in_the_stars } }
|
108
|
+
|
109
|
+
it 'does not instantiate a block return value meter' do
|
110
|
+
expect(::Metriks).to receive(:meter)
|
111
|
+
.with('OpenStruct#the_force_awakens_call_meter')
|
112
|
+
.and_return(call_meter)
|
113
|
+
expect(call_meter).to receive(:mark)
|
114
|
+
|
115
|
+
expect(::Metriks).not_to receive(:meter)
|
116
|
+
.with('OpenStruct#the_force_awakens_result_meter')
|
117
|
+
|
118
|
+
subject
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'does not instantiate a block return value gauge' do
|
122
|
+
expect(::Metriks).not_to receive(:gauge)
|
123
|
+
|
124
|
+
subject
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'instantiates a method call meter and marks it' do
|
128
|
+
expect(::Metriks).to receive(:counter)
|
129
|
+
.and_call_original
|
130
|
+
|
131
|
+
subject
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
it_behaves_like 'instruments && measuring'
|
137
|
+
|
138
|
+
context 'when using a timer' do
|
139
|
+
let(:instruments) { %i(counter result_meter call_meter gauge timer) }
|
140
|
+
|
141
|
+
let(:timer) { instance_double(::Metriks::Timer) }
|
142
|
+
|
143
|
+
before do
|
144
|
+
allow(::Metriks).to receive(:timer)
|
145
|
+
.and_return(timer)
|
146
|
+
|
147
|
+
allow(timer).to receive(:time)
|
148
|
+
allow(timer).to receive(:stop)
|
149
|
+
end
|
150
|
+
|
151
|
+
it_behaves_like 'instruments && measuring'
|
152
|
+
|
153
|
+
it 'finds the right timer metric' do
|
154
|
+
expect(::Metriks).to receive(:timer)
|
155
|
+
.with('OpenStruct#the_force_awakens_timer')
|
156
|
+
|
157
|
+
call
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'times the method call' do
|
161
|
+
expect(timer).to receive(:time)
|
162
|
+
expect(timer).to receive(:stop)
|
163
|
+
|
164
|
+
call
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'when there are duplicate instruments' do
|
169
|
+
let(:instruments) do
|
170
|
+
%i(counter result_meter call_meter counter gauge gauge)
|
171
|
+
end
|
172
|
+
|
173
|
+
it_behaves_like 'instruments && measuring'
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: advisor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renan Ranelli
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: metriks
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,6 +105,7 @@ files:
|
|
91
105
|
- ".rspec"
|
92
106
|
- ".rubocop.yml"
|
93
107
|
- ".ruby-version"
|
108
|
+
- ".travis.yml"
|
94
109
|
- Gemfile
|
95
110
|
- Gemfile.lock
|
96
111
|
- Rakefile
|
@@ -99,10 +114,12 @@ files:
|
|
99
114
|
- lib/advisor.rb
|
100
115
|
- lib/advisor/advices.rb
|
101
116
|
- lib/advisor/advices/call_logger.rb
|
117
|
+
- lib/advisor/advices/metriks.rb
|
102
118
|
- lib/advisor/builtin_advisors.rb
|
103
119
|
- lib/advisor/factory.rb
|
104
120
|
- lib/advisor/version.rb
|
105
121
|
- spec/advisor/advices/call_logger_spec.rb
|
122
|
+
- spec/advisor/advices/metriks_spec.rb
|
106
123
|
- spec/advisor/builtin_advisors_spec.rb
|
107
124
|
- spec/advisor/factory_spec.rb
|
108
125
|
- spec/spec_helper.rb
|
@@ -121,9 +138,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
121
138
|
version: '2.0'
|
122
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
140
|
requirements:
|
124
|
-
- - "
|
141
|
+
- - ">"
|
125
142
|
- !ruby/object:Gem::Version
|
126
|
-
version:
|
143
|
+
version: 1.3.1
|
127
144
|
requirements: []
|
128
145
|
rubyforge_project:
|
129
146
|
rubygems_version: 2.2.2
|