Permalink
Browse files

0.0.3 - Add tests and with_tracing for boxed tracing

  • Loading branch information...
baweaver committed Jan 27, 2019
1 parent 1033efc commit 34036b7f2d169c72ae33981fa6548eb281836da6
Showing with 314 additions and 25 deletions.
  1. +38 −1 Gemfile.lock
  2. +15 −0 Guardfile
  3. +29 −18 README.md
  4. +31 −0 lib/trace_spy/method.rb
  5. +1 −1 lib/trace_spy/version.rb
  6. +199 −0 spec/trace_spy/method_spec.rb
  7. +0 −5 spec/trace_spy_spec.rb
  8. +1 −0 trace_spy.gemspec
@@ -1,17 +1,50 @@
PATH
remote: .
specs:
trace_spy (0.0.2)
trace_spy (0.0.3)
qo (~> 0.5)

GEM
remote: https://rubygems.org/
specs:
any (0.1.0)
coderay (1.1.2)
diff-lcs (1.3)
ffi (1.10.0)
formatador (0.2.5)
guard (2.15.0)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
lumberjack (>= 1.0.12, < 2.0)
nenv (~> 0.1)
notiffany (~> 0.0)
pry (>= 0.9.12)
shellany (~> 0.0)
thor (>= 0.18.1)
guard-compat (1.2.1)
guard-rspec (4.7.3)
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
lumberjack (1.0.13)
method_source (0.9.2)
nenv (0.3.0)
notiffany (0.1.1)
nenv (~> 0.1)
shellany (~> 0.0)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
qo (0.5.0)
any (= 0.1.0)
rake (10.5.0)
rb-fsevent (0.10.3)
rb-inotify (0.10.0)
ffi (~> 1.0)
rspec (3.8.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
@@ -25,12 +58,16 @@ GEM
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.0)
ruby_dep (1.5.0)
shellany (0.0.1)
thor (0.20.3)

PLATFORMS
ruby

DEPENDENCIES
bundler (~> 1.17)
guard-rspec (~> 4.0)
rake (~> 10.0)
rspec (~> 3.0)
trace_spy!
@@ -0,0 +1,15 @@
guard :rspec, cmd: "bundle exec rspec" do
require "guard/rspec/dsl"

dsl = Guard::RSpec::Dsl.new(self)

# RSpec files
rspec = dsl.rspec
watch(rspec.spec_helper) { rspec.spec_dir }
watch(rspec.spec_support) { rspec.spec_dir }
watch(rspec.spec_files)

# Ruby files
ruby = dsl.ruby
dsl.watch_spec_files_for(ruby.lib_files)
end
@@ -63,26 +63,37 @@ testing_spy = TraceSpy::Method.new(:testing) do |spy|
end
end
testing_spy.enable
# => false
# If you want to manually enable/disable the trace, use:
#
# testing_spy.enable
# testing_spy.disable
#
# Otherwise, use:
# Outside of this block, the trace is inactive:
testing_spy.with_tracing do
p testing(1, 2, 3)
# My args were 1, 2, 3: {:a=>1, :b=>2, :c=>3}
# I got an even return: 6
# => 6
p testing(21, 2, 3) rescue 'nope'
# I encountered an error: heck
# => 'nope'
p testing(*%w(foo bar baz))
# Oh hey! You called me with strings: {:a=>"foo", :b=>"bar", :c=>"baz"}
# Strings in, Strings out no?: foobarbaz
# => 'foobarbaz'
p testing(1, 2, 4)
# I saw d was a local in here!: {:a=>1, :b=>2, :c=>4, :d=>5}
# => 7
end
p testing(1, 2, 3)
# My args were 1, 2, 3: {:a=>1, :b=>2, :c=>3}
# I got an even return: 6
# Back to normal
testing(1, 2, 3)
# => 6
p testing(21, 2, 3) rescue 'nope'
# I encountered an error: heck
# => 'nope'
p testing(*%w(foo bar baz))
# Oh hey! You called me with strings: {:a=>"foo", :b=>"bar", :c=>"baz"}
# Strings in, Strings out no?: foobarbaz
# => 'foobarbaz'
p testing(1, 2, 4)
# I saw d was a local in here!: {:a=>1, :b=>2, :c=>4, :d=>5}
# => 7
```

## Installation
@@ -65,6 +65,37 @@ def initialize(method_name, from_class: Any, &fn)
yield(self) if block_given?
end

# Allows to run a block of code in the context of a tracer with the
# convenient side-effect of not having to remember to turn it off
# afterwards.
#
# Tracer will only be active within the block, and will be disabled
# afterwards
#
# @since 0.0.3
#
# @example
# The tracer will only be active within the block:
#
# ```ruby
# tracer.with_tracing do
# # tasks
# end
# ```
#
# @param &traced_function [Proc]
# Function to execute with tracing enabled
#
# @return [TrueClass]
# Result of disabling the tracer
def with_tracing(&traced_function)
self.enable

yield

self.disable
end

# Creates a Spy on function arguments
#
# @since 0.0.1
@@ -1,3 +1,3 @@
module TraceSpy
VERSION = "0.0.2"
VERSION = "0.0.3"
end
@@ -0,0 +1,199 @@
RSpec.describe TraceSpy::Method do
def standard_method(a, b, c)
a + b + c
end

def local_method(a, b, c)
d = 10

a + b + c + d
end

def exception_method(a)
raise 'heck' unless a > 5

a + 5
end

let(:method_name) { :standard_method }
let(:klass) { Any }
let(:spy_function) { proc {} }

let(:target) { double('target') }

let(:subject) {
TraceSpy::Method.new(method_name, from_class: klass, &spy_function)
}

describe '.initialize' do
it 'creates a new Method spy' do
expect(subject).to be_a(TraceSpy::Method)
end
end

describe 'Argument Spies' do
let(:spy_function) {
-> spy {
spy.on_arguments do |m|
m.when(a: 5) { |args| target.call(args) }
end
}
}

it 'can spy on an arguments value' do
subject.with_tracing do
expect(target).to receive(:call).with(
a: 5,
b: 2,
c: 3
)

expect(standard_method(5, 2, 3)).to eq(10)
end
end

it 'will not be called if the argument predicate is not matched' do
subject.with_tracing do
expect(target).not_to receive(:call)

expect(standard_method(1, 2, 3)).to eq(6)
end
end
end

describe 'Local Spies' do
let(:method_name) { :local_method }

let(:spy_function) {
-> spy {
spy.on_locals do |m|
m.when(d: 10) { |locals| target.call(locals) }
end
}
}

it 'can spy on an arguments value' do
subject.with_tracing do
expect(target).to receive(:call).with(
a: 5,
b: 2,
c: 3,
d: 10
)

local_method(5, 2, 3)
end
end

context 'When the local variable is not defined' do
let(:method_name) { :standard_method }

it 'will not be called if the argument predicate is not matched' do
subject.with_tracing do
expect(target).not_to receive(:call)

standard_method(1, 2, 3)
end
end
end
end

describe 'Return Spies' do
let(:spy_function) {
-> spy {
spy.on_return do |m|
m.when(:even?) { |return_value| target.call(return_value) }
end
}
}

it 'can spy on an arguments value' do
subject.with_tracing do
expect(target).to receive(:call).with(6)
expect(standard_method(1, 2, 3)).to eq(6)
end
end

it 'will not be called if the return predicate is not matched' do
subject.with_tracing do
expect(target).not_to receive(:call)
expect(standard_method(2, 2, 3)).to eq(7)
end
end
end

describe 'Exception Spies' do
let(:method_name) { :exception_method }

let(:spy_function) {
-> spy {
spy.on_exception do |m|
m.when(RuntimeError) { |e| target.call(e) }
end
}
}

it 'can spy on an arguments value' do
subject.with_tracing do
expect(target).to receive(:call).with(instance_of(RuntimeError))
expect { exception_method(1) }.to raise_error(RuntimeError, 'heck')
end
end

it 'will not be called if the return predicate is not matched' do
subject.with_tracing do
expect(target).not_to receive(:call)
expect(exception_method(6)).to eq(11)
end
end
end

describe '#current_local_variables' do
let(:method_name) { :local_method }

let(:spy_function) {
-> spy {
spy.on_return do |m|
m.when(:even?) { |_| target.call(spy.current_local_variables) }
end
}
}

it 'can reference the current local variables without needing on_locals' do
subject.with_tracing do
expect(target).to receive(:call).with(
a: 2,
b: 2,
c: 2,
d: 10
)

local_method(2, 2, 2)
end
end
end

describe '#current_arguments' do
let(:method_name) { :local_method }

let(:spy_function) {
-> spy {
spy.on_return do |m|
m.when(:even?) { |_| target.call(spy.current_arguments) }
end
}
}

it 'can reference the current arguments without needing on_arguments' do
subject.with_tracing do
expect(target).to receive(:call).with(
a: 2,
b: 2,
c: 2
)

local_method(2, 2, 2)
end
end
end
end
@@ -1,10 +1,5 @@
# TODO: Fix up specs, docs are about ready to go.
RSpec.describe TraceSpy do
it "has a version number" do
expect(TraceSpy::VERSION).not_to be nil
end

it "does something useful" do
expect(true).to eq(true)
end
end
Oops, something went wrong.

0 comments on commit 34036b7

Please sign in to comment.