delfos 0.0.1.pre.rc1 → 0.0.1
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/lib/delfos.rb +22 -78
- data/lib/delfos/call_stack.rb +39 -0
- data/lib/delfos/call_stack/stack.rb +59 -0
- data/lib/delfos/file_system/common_path.rb +62 -0
- data/lib/delfos/{distance/calculation.rb → file_system/distance_calculation.rb} +4 -15
- data/lib/delfos/file_system/path_determination.rb +37 -0
- data/lib/delfos/{distance → file_system}/relation.rb +1 -1
- data/lib/delfos/method_logging.rb +32 -49
- data/lib/delfos/method_logging/call_site_parsing.rb +74 -0
- data/lib/delfos/method_logging/code_location.rb +34 -98
- data/lib/delfos/method_logging/{args.rb → method_parameters.rb} +17 -18
- data/lib/delfos/neo4j.rb +58 -0
- data/lib/delfos/neo4j/batch/execution.rb +149 -0
- data/lib/delfos/neo4j/{execution_persistence.rb → call_stack_query.rb} +12 -22
- data/lib/delfos/neo4j/distance/call_site_fetcher.rb +19 -0
- data/lib/delfos/neo4j/distance/update.rb +50 -0
- data/lib/delfos/neo4j/informer.rb +62 -34
- data/lib/delfos/neo4j/query_execution/errors.rb +30 -0
- data/lib/delfos/neo4j/query_execution/http.rb +61 -0
- data/lib/delfos/neo4j/query_execution/http_query.rb +67 -0
- data/lib/delfos/neo4j/query_execution/sync.rb +35 -0
- data/lib/delfos/neo4j/query_execution/transactional.rb +68 -0
- data/lib/delfos/neo4j/schema.rb +73 -0
- data/lib/delfos/patching/basic_object.rb +1 -5
- data/lib/delfos/patching/method_cache.rb +83 -0
- data/lib/delfos/patching/method_override.rb +76 -66
- data/lib/delfos/patching/module_defining_methods.rb +105 -0
- data/lib/delfos/patching/unstubber.rb +34 -0
- data/lib/delfos/setup.rb +88 -0
- metadata +42 -15
- data/lib/delfos/common_path.rb +0 -58
- data/lib/delfos/execution_chain.rb +0 -75
- data/lib/delfos/method_logging/added_methods.rb +0 -67
- data/lib/delfos/neo4j/distance_update.rb +0 -73
- data/lib/delfos/neo4j/query_execution.rb +0 -79
- data/lib/delfos/patching/unstubbing_spec_helper.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87475ed3a25d014e199e651988f4d3183561816a
|
4
|
+
data.tar.gz: 0c2441e45f0dfbe6b272e0904654907fba9f53d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84f4de34ff44908ce8794643553ece54cd9914cc519502d3bfb3adfc3caa0e97effbefa65aba573f1ade386839798c496bd7adf10822ff9ff3c9734459ec1bcc
|
7
|
+
data.tar.gz: 9fd34ca930e93e73a5e16294a6fc4a94464accd3f8b91353a9a8c94d99a418ef7494855b79f064334ed102a70107a9049f3e1e554f37e4c88e5681392cd7d85d
|
data/lib/delfos.rb
CHANGED
@@ -1,100 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "delfos/
|
2
|
+
require "delfos/setup"
|
3
3
|
|
4
4
|
module Delfos
|
5
5
|
class << self
|
6
|
-
|
6
|
+
attr_accessor :application_directories
|
7
|
+
attr_writer :logger, :neo4j
|
7
8
|
|
8
|
-
def
|
9
|
-
|
9
|
+
def setup!(logger: nil, call_site_logger: nil, application_directories: nil)
|
10
|
+
self.logger = logger if logger
|
11
|
+
Delfos::Setup.perform!(call_site_logger: call_site_logger, application_directories: application_directories)
|
10
12
|
end
|
11
13
|
|
12
|
-
def
|
13
|
-
Delfos.
|
14
|
-
|
15
|
-
require "delfos/neo4j/query_execution"
|
16
|
-
Delfos::Neo4j::QueryExecution.execute <<-QUERY
|
17
|
-
MATCH (m)-[rel]->(n)
|
18
|
-
DELETE m,rel,n
|
19
|
-
QUERY
|
14
|
+
def call_site_logger
|
15
|
+
Delfos::Setup.call_site_logger
|
20
16
|
end
|
21
17
|
|
22
|
-
def
|
23
|
-
|
24
|
-
@method_logging = nil
|
25
|
-
@neo4j = nil
|
26
|
-
@logger = nil
|
27
|
-
|
28
|
-
if defined? Delfos::ExecutionChain
|
29
|
-
Delfos::ExecutionChain.reset!
|
30
|
-
end
|
31
|
-
|
32
|
-
# unstubbing depends upon AddedMethods being still defined
|
33
|
-
# so this order is important
|
34
|
-
unstub_all!
|
35
|
-
remove_added_methods!
|
36
|
-
|
37
|
-
remove_patching!
|
18
|
+
def call_site_logger=(call_site_logger)
|
19
|
+
Delfos::Setup.call_site_logger = call_site_logger
|
38
20
|
end
|
39
21
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
if Delfos::Patching::MethodOverride.respond_to?(:unstub_all!)
|
44
|
-
Delfos::Patching::MethodOverride.unstub_all!
|
45
|
-
end
|
46
|
-
end
|
22
|
+
def logger
|
23
|
+
@logger ||= default_logger
|
47
24
|
end
|
48
25
|
|
49
|
-
def
|
50
|
-
|
51
|
-
Delfos::MethodLogging::AddedMethods.instance_eval { @instance = nil }
|
52
|
-
end
|
26
|
+
def neo4j
|
27
|
+
setup_neo4j!
|
53
28
|
end
|
54
29
|
|
55
|
-
def
|
56
|
-
|
30
|
+
def setup_neo4j!
|
31
|
+
require "delfos/neo4j"
|
32
|
+
@neo4j ||= Delfos::Neo4j.config
|
57
33
|
end
|
58
34
|
|
59
|
-
def
|
60
|
-
|
61
|
-
neo4j_username: nil,
|
62
|
-
neo4j_password: nil,
|
63
|
-
application_directories: nil)
|
64
|
-
application_directories ||= %w(app lib)
|
65
|
-
|
66
|
-
@application_directories = if application_directories.is_a?(Proc)
|
67
|
-
application_directories
|
68
|
-
else
|
69
|
-
Array(application_directories).map { |f| Pathname.new(File.expand_path(f.to_s)) }
|
70
|
-
end
|
71
|
-
|
72
|
-
@logger = logger
|
73
|
-
|
74
|
-
setup_neo4j!(neo4j_url, neo4j_username, neo4j_password)
|
75
|
-
|
76
|
-
perform_patching!
|
77
|
-
end
|
78
|
-
|
79
|
-
def setup_neo4j!(url = nil, username = nil, password = nil)
|
80
|
-
url ||= ENV["NEO4J_URL"] || "http://localhost:7474"
|
81
|
-
username ||= ENV["NEO4J_USERNAME"] || "neo4j"
|
82
|
-
password ||= ENV["NEO4J_PASSWORD"] || "password"
|
83
|
-
@neo4j = Neo4jOptions.new(url, username, password)
|
84
|
-
end
|
85
|
-
|
86
|
-
def perform_patching!
|
87
|
-
load "delfos/patching/basic_object.rb"
|
35
|
+
def reset!
|
36
|
+
Delfos::Setup.reset!
|
88
37
|
end
|
89
38
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
def to_s
|
94
|
-
" url: #{url}\n username: #{username}\n password: #{password}"
|
95
|
-
end
|
39
|
+
def default_logger
|
40
|
+
require "logger"
|
41
|
+
Logger.new(STDOUT)
|
96
42
|
end
|
97
|
-
|
98
|
-
attr_reader :application_directories, :neo4j_host, :neo4j_username, :neo4j_password
|
99
43
|
end
|
100
44
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "neo4j"
|
3
|
+
require_relative "neo4j/call_stack_query"
|
4
|
+
require_relative "call_stack/stack"
|
5
|
+
|
6
|
+
module Delfos
|
7
|
+
module CallStack
|
8
|
+
CALL_STACK_MUTEX = Mutex.new
|
9
|
+
extend self
|
10
|
+
|
11
|
+
def reset!
|
12
|
+
CALL_STACK_MUTEX.synchronize do
|
13
|
+
Thread.current[:_delfos__call_stack] = nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def stack
|
18
|
+
CALL_STACK_MUTEX.synchronize do
|
19
|
+
Thread.current[:_delfos__call_stack] ||= Stack.new(on_empty: method(:save!))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def push(method_object)
|
24
|
+
stack.push(method_object)
|
25
|
+
end
|
26
|
+
|
27
|
+
def pop
|
28
|
+
stack.pop
|
29
|
+
end
|
30
|
+
|
31
|
+
def pop_until_top!
|
32
|
+
stack.pop_until_top!
|
33
|
+
end
|
34
|
+
|
35
|
+
def save!(call_sites, execution_number)
|
36
|
+
Delfos::MethodLogging.save_call_stack(call_sites, execution_number)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Delfos
|
3
|
+
module CallStack
|
4
|
+
class Stack
|
5
|
+
def initialize(on_empty: nil)
|
6
|
+
@on_empty = on_empty
|
7
|
+
end
|
8
|
+
|
9
|
+
def push(method_object)
|
10
|
+
call_sites.push(method_object)
|
11
|
+
self.stack_depth += 1
|
12
|
+
|
13
|
+
self.execution_count += self.stack_depth == 1 ? 1 : 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def pop
|
17
|
+
popping_empty_stack! if self.stack_depth.zero?
|
18
|
+
|
19
|
+
self.stack_depth -= 1
|
20
|
+
|
21
|
+
if stack_depth.zero? && call_sites.length.positive?
|
22
|
+
@on_empty&.call(call_sites, execution_count)
|
23
|
+
self.call_sites = []
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def pop_until_top!
|
28
|
+
pop while self.stack_depth.positive?
|
29
|
+
end
|
30
|
+
|
31
|
+
def stack_depth
|
32
|
+
@stack_depth ||= 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def execution_count
|
36
|
+
@execution_count ||= 0
|
37
|
+
end
|
38
|
+
|
39
|
+
def call_sites
|
40
|
+
@call_sites ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
def step_count
|
44
|
+
call_sites.length
|
45
|
+
end
|
46
|
+
|
47
|
+
attr_writer :stack_depth, :step_count, :execution_count, :call_sites
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def popping_empty_stack!
|
52
|
+
raise PoppingEmptyStackError
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class PoppingEmptyStackError < StandardError
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
module Delfos
|
5
|
+
module FileSystem
|
6
|
+
module CommonPath
|
7
|
+
class << self
|
8
|
+
SEPARATOR = "/"
|
9
|
+
|
10
|
+
def included_in?(p1, paths)
|
11
|
+
paths.any? do |p2|
|
12
|
+
common = common_parent(p1, p2)
|
13
|
+
common.to_s.length >= p2.to_s.length
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def common_parent(path_a, path_b)
|
18
|
+
dirs = [
|
19
|
+
File.expand_path(path_a.to_s),
|
20
|
+
File.expand_path(path_b.to_s),
|
21
|
+
]
|
22
|
+
|
23
|
+
dir1, dir2 = dirs.minmax.map { |dir| dir.split(SEPARATOR) }
|
24
|
+
|
25
|
+
path_from(dir1, dir2, path_a, path_b)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def path_from(dir1, dir2, path_a, path_b)
|
31
|
+
common_path = common_path(dir1, dir2)
|
32
|
+
common_path, path_a, path_b = append_trailing_slashes!(common_path, path_a, path_b)
|
33
|
+
|
34
|
+
Pathname.new(common_path) if valid_length?(common_path, path_a, path_b)
|
35
|
+
end
|
36
|
+
|
37
|
+
def valid_length?(common_path, path_a, path_b)
|
38
|
+
l = common_path.to_s.length
|
39
|
+
(l <= path_a.to_s.length) || (l <= path_b.to_s.length)
|
40
|
+
end
|
41
|
+
|
42
|
+
def common_path(dir1, dir2)
|
43
|
+
dir1.
|
44
|
+
zip(dir2).
|
45
|
+
take_while { |dn1, dn2| dn1 == dn2 }.
|
46
|
+
map(&:first).
|
47
|
+
join(SEPARATOR)
|
48
|
+
end
|
49
|
+
|
50
|
+
def append_trailing_slashes!(*paths)
|
51
|
+
paths.map do |path|
|
52
|
+
if Pathname.new(path).directory?
|
53
|
+
path += SEPARATOR if path && path.to_s[-1] != SEPARATOR
|
54
|
+
end
|
55
|
+
|
56
|
+
path
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require_relative "relation"
|
3
|
+
require_relative "path_determination"
|
3
4
|
|
4
5
|
module Delfos
|
5
|
-
module
|
6
|
-
class
|
6
|
+
module FileSystem
|
7
|
+
class DistanceCalculation
|
7
8
|
attr_reader :path_a, :path_b
|
8
9
|
|
9
10
|
def initialize(path_a, path_b)
|
10
|
-
@path_a = path_a
|
11
|
-
@path_b = path_b
|
11
|
+
@path_a, @path_b = PathDetermination.for(path_a, path_b)
|
12
12
|
end
|
13
13
|
|
14
14
|
attr_reader :traversal_a, :traversal_b
|
@@ -42,17 +42,6 @@ module Delfos
|
|
42
42
|
siblings(path).select { |f| File.directory?(f) }
|
43
43
|
end
|
44
44
|
|
45
|
-
def in_start_directory?(path)
|
46
|
-
return false if path.directory?
|
47
|
-
path_a.dirname == path
|
48
|
-
end
|
49
|
-
|
50
|
-
def in_finish_directory?(path)
|
51
|
-
return false if path.directory?
|
52
|
-
|
53
|
-
path_b.dirname == path
|
54
|
-
end
|
55
|
-
|
56
45
|
def traversal_path
|
57
46
|
TraversalPathCalculator.new(path_a, path_b).path
|
58
47
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Delfos
|
3
|
+
module FileSystem
|
4
|
+
class PathDetermination
|
5
|
+
def self.for(*files)
|
6
|
+
files.map { |f| new(f).full_path }
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(file)
|
10
|
+
@file = Pathname.new(strip_block_message(file))
|
11
|
+
end
|
12
|
+
|
13
|
+
def full_path
|
14
|
+
return @file.realpath if File.exist?(@file)
|
15
|
+
|
16
|
+
Delfos.application_directories.map do |d|
|
17
|
+
path = try_path { d + @file }
|
18
|
+
|
19
|
+
path || try_path do
|
20
|
+
Pathname.new(d + @file.to_s.gsub(%r{[^/]*/}, ""))
|
21
|
+
end
|
22
|
+
end.compact.first
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def strip_block_message(f)
|
28
|
+
f.to_s.split(" in block").first
|
29
|
+
end
|
30
|
+
|
31
|
+
def try_path
|
32
|
+
path = yield
|
33
|
+
path if path.exist?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,69 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "
|
3
|
-
|
4
|
-
require "binding_of_caller"
|
5
|
-
require_relative "common_path"
|
2
|
+
require "delfos/file_system/common_path"
|
3
|
+
|
6
4
|
require_relative "method_logging/code_location"
|
7
|
-
require_relative "method_logging/
|
8
|
-
require_relative "execution_chain"
|
5
|
+
require_relative "method_logging/method_parameters"
|
9
6
|
|
10
7
|
module Delfos
|
11
|
-
|
12
|
-
|
13
|
-
attr_writer :method_logging
|
8
|
+
module MethodLogging
|
9
|
+
extend self
|
14
10
|
|
15
|
-
def
|
16
|
-
|
11
|
+
def save_call_stack(call_sites, execution_number)
|
12
|
+
Delfos.call_site_logger.save_call_stack(call_sites, execution_number)
|
17
13
|
end
|
18
|
-
end
|
19
14
|
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
def log(call_site, called_object, called_method, class_method, parameters)
|
16
|
+
called_code = CodeLocation.from_called(called_object, called_method, class_method)
|
17
|
+
|
18
|
+
Delfos.call_site_logger.log(parameters, call_site, called_code)
|
23
19
|
end
|
24
|
-
end
|
25
20
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
raise Delfos::ApplicationDirectoriesNotDefined unless Delfos.application_directories
|
30
|
-
end
|
21
|
+
def exclude?(method)
|
22
|
+
file, = method.source_location
|
23
|
+
return true unless file
|
31
24
|
|
32
|
-
|
33
|
-
|
34
|
-
arguments = Args.new(arguments)
|
35
|
-
called_code = CodeLocation.from_called(called_object, called_method, class_method)
|
25
|
+
exclude_file?(File.expand_path(file))
|
26
|
+
end
|
36
27
|
|
37
|
-
|
38
|
-
|
28
|
+
def include_file?(file)
|
29
|
+
!exclude_file?(file)
|
30
|
+
end
|
39
31
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
32
|
+
def exclude_file?(file)
|
33
|
+
with_cache(file) do
|
34
|
+
!FileSystem::CommonPath.included_in?(File.expand_path(file), Delfos.application_directories)
|
44
35
|
end
|
36
|
+
end
|
45
37
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
exclude_file_from_logging?(File.expand_path(file))
|
51
|
-
end
|
38
|
+
def reset!
|
39
|
+
@cache = nil
|
40
|
+
end
|
52
41
|
|
53
|
-
|
54
|
-
!exclude_file_from_logging?(file)
|
55
|
-
end
|
42
|
+
private
|
56
43
|
|
57
|
-
|
58
|
-
|
59
|
-
|
44
|
+
def with_cache(key)
|
45
|
+
cache.include?(key) ? cache[key] : cache[key] = yield
|
46
|
+
end
|
60
47
|
|
61
|
-
|
62
|
-
|
63
|
-
else
|
64
|
-
!CommonPath.included_in?(path, Delfos.application_directories)
|
65
|
-
end
|
66
|
-
end
|
48
|
+
def cache
|
49
|
+
@cache ||= {}
|
67
50
|
end
|
68
51
|
end
|
69
52
|
end
|