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
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Delfos
|
3
|
+
module Patching
|
4
|
+
# containers for the individual modules created to log each method call
|
5
|
+
module ClassMethodLogging
|
6
|
+
end
|
7
|
+
|
8
|
+
module InstanceMethodLogging
|
9
|
+
end
|
10
|
+
|
11
|
+
module ModuleDefiningMethods
|
12
|
+
def module_definition(klass, method_name, class_method, &block)
|
13
|
+
definer = ModuleDefiner.new(klass, method_name, class_method)
|
14
|
+
|
15
|
+
if block_given?
|
16
|
+
definer.perform(&block)
|
17
|
+
else
|
18
|
+
definer.perform
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ModuleDefiner
|
24
|
+
attr_reader :klass, :method_name, :class_method
|
25
|
+
|
26
|
+
def initialize(klass, method_name, class_method)
|
27
|
+
@klass, @method_name, @class_method = klass, method_name, class_method
|
28
|
+
end
|
29
|
+
|
30
|
+
def perform(&block)
|
31
|
+
safe_method_name = safe_method_name()
|
32
|
+
safe_class_name = safe_class_name()
|
33
|
+
module_type = class_method ? "ClassMethodLogging" : "InstanceMethodLogging"
|
34
|
+
find_or_create = method(:find_or_create)
|
35
|
+
|
36
|
+
m = nil
|
37
|
+
Patching.const_get(module_type).instance_eval do
|
38
|
+
namespace = find_or_create.call(self, safe_class_name)
|
39
|
+
|
40
|
+
m = find_or_create.call(namespace, safe_method_name)
|
41
|
+
|
42
|
+
m.class_eval(&block) if block_given?
|
43
|
+
|
44
|
+
m
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def safe_class_name
|
51
|
+
module_safe_name(klass.name || klass.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def safe_method_name
|
55
|
+
module_safe_name(method_name.to_s)
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_or_create(container, module_name)
|
59
|
+
module_name = module_name.tr(":", "_")
|
60
|
+
|
61
|
+
result = container.const_get(module_name)
|
62
|
+
|
63
|
+
# E.g. finding `::A' instead of Delfos::Patching::InstanceMethodLogging::A
|
64
|
+
if result == klass || result.name[module_name] == result.name
|
65
|
+
create(container, module_name)
|
66
|
+
else
|
67
|
+
result
|
68
|
+
end
|
69
|
+
rescue NameError => e
|
70
|
+
raise unless e.message[module_name]
|
71
|
+
create(container, module_name)
|
72
|
+
end
|
73
|
+
|
74
|
+
def create(container, module_name)
|
75
|
+
m = Module.new
|
76
|
+
|
77
|
+
container.const_set(module_name, m)
|
78
|
+
return m
|
79
|
+
rescue Exception => e
|
80
|
+
m
|
81
|
+
end
|
82
|
+
|
83
|
+
def module_safe_name(string, _uppercase_first_letter = true)
|
84
|
+
string = string.sub(/^[a-z\d]*/) { $&.capitalize }
|
85
|
+
|
86
|
+
string.
|
87
|
+
gsub(/(?:_|(\/))([a-z\d]*)/) { "#{Regexp.last_match(1)}#{Regexp.last_match(2).capitalize}" }.
|
88
|
+
gsub("/", "::").
|
89
|
+
gsub(/\=/, "Equals").
|
90
|
+
gsub(/\<\=\>/, "Spaceship").
|
91
|
+
gsub(/\<\=/, "LessThanOrEqualTo").
|
92
|
+
gsub(/\>\=/, "GreaterThanOrEqualTo").
|
93
|
+
gsub(/\#\<Class\:0x(.*)\>/) { "AnonymousClass_#{Regexp.last_match(1)}" }.
|
94
|
+
gsub(/\>/, "GreaterThan").
|
95
|
+
gsub(/\</, "LessThan").
|
96
|
+
gsub(/!\~/, "NotMatchOperator").
|
97
|
+
gsub(/\~/, "MatchOperator").
|
98
|
+
gsub(/\?/, "QuestionMark").
|
99
|
+
gsub(/\!$/, "Bang").
|
100
|
+
gsub(/\+/, "Plus").
|
101
|
+
gsub(/\[\]/, "SquareBrackets")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Delfos
|
3
|
+
module Patching
|
4
|
+
class Unstubber
|
5
|
+
extend ModuleDefiningMethods
|
6
|
+
|
7
|
+
def self.unstub_all!
|
8
|
+
MUTEX.synchronize do
|
9
|
+
Thread.current[:__delfos_disable_patching] = true
|
10
|
+
end
|
11
|
+
|
12
|
+
MethodCache.each_method do |klass_name, method, class_method|
|
13
|
+
klass = eval(klass_name)
|
14
|
+
|
15
|
+
unstub!(klass, method.name, class_method)
|
16
|
+
end
|
17
|
+
|
18
|
+
MUTEX.synchronize do
|
19
|
+
Thread.current[:__delfos_disable_patching] = false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.unstub!(klass, method_name, class_method)
|
24
|
+
module_definition(klass, method_name, class_method) do |m|
|
25
|
+
begin
|
26
|
+
remove_method :"#{method_name}"
|
27
|
+
rescue NameError => e
|
28
|
+
raise unless e.message["method `#{method_name}' not defined in"]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/delfos/setup.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Delfos
|
3
|
+
module Setup
|
4
|
+
extend self
|
5
|
+
attr_accessor :neo4j
|
6
|
+
|
7
|
+
def perform!(call_site_logger: nil, application_directories: nil)
|
8
|
+
self.application_directories = application_directories
|
9
|
+
self.call_site_logger = call_site_logger
|
10
|
+
|
11
|
+
perform_patching!
|
12
|
+
end
|
13
|
+
|
14
|
+
def application_directories=(dirs)
|
15
|
+
dirs ||= %w(app lib)
|
16
|
+
require "pathname"
|
17
|
+
Delfos.application_directories = Array(dirs).map { |f| Pathname.new(File.expand_path(f.to_s)) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def call_site_logger
|
21
|
+
@call_site_logger ||= default_call_site_logger
|
22
|
+
end
|
23
|
+
|
24
|
+
def call_site_logger=(call_site_logger)
|
25
|
+
@call_site_logger = call_site_logger || default_call_site_logger
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_call_site_logger
|
29
|
+
Delfos.setup_neo4j!
|
30
|
+
|
31
|
+
require "delfos/neo4j/informer"
|
32
|
+
Delfos:: Neo4j::Informer.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def reset!
|
36
|
+
if defined? Delfos::CallStack
|
37
|
+
Delfos::CallStack.pop_until_top!
|
38
|
+
Delfos::CallStack.reset!
|
39
|
+
end
|
40
|
+
|
41
|
+
if defined? Delfos::Neo4j::Batch::Execution
|
42
|
+
begin
|
43
|
+
Delfos::Neo4j::Batch::Execution.flush!
|
44
|
+
rescue
|
45
|
+
Delfos::Neo4j::QueryExecution::ExpiredTransaction
|
46
|
+
end
|
47
|
+
|
48
|
+
Delfos::Neo4j::Batch::Execution.reset!
|
49
|
+
end
|
50
|
+
|
51
|
+
# unstubbing depends upon MethodCache being still defined
|
52
|
+
# so this order is important
|
53
|
+
unstub_all!
|
54
|
+
remove_cached_methods!
|
55
|
+
|
56
|
+
remove_patching!
|
57
|
+
|
58
|
+
Delfos::MethodLogging.reset! if defined?(Delfos::MethodLogging) && Delfos::MethodLogging.respond_to?(:reset!)
|
59
|
+
|
60
|
+
Delfos.neo4j = nil
|
61
|
+
Delfos.logger = nil
|
62
|
+
Delfos.application_directories = nil
|
63
|
+
Delfos.call_site_logger = nil
|
64
|
+
@call_site_logger = nil
|
65
|
+
Delfos.neo4j = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def unstub_all!
|
69
|
+
return unless defined? Delfos::Patching::Unstubber
|
70
|
+
|
71
|
+
Delfos::Patching::Unstubber.unstub_all!
|
72
|
+
end
|
73
|
+
|
74
|
+
def remove_cached_methods!
|
75
|
+
return unless defined? Delfos::Patching::MethodCache
|
76
|
+
|
77
|
+
Delfos::Patching::MethodCache.reset!
|
78
|
+
end
|
79
|
+
|
80
|
+
def remove_patching!
|
81
|
+
load "delfos/patching/basic_object_remove.rb"
|
82
|
+
end
|
83
|
+
|
84
|
+
def perform_patching!
|
85
|
+
load "delfos/patching/basic_object.rb"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delfos
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Burns
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: binding_of_caller
|
@@ -30,6 +30,20 @@ dependencies:
|
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 0.7.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: webmock
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
33
47
|
- !ruby/object:Gem::Dependency
|
34
48
|
name: pry-byebug
|
35
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -99,22 +113,35 @@ extensions: []
|
|
99
113
|
extra_rdoc_files: []
|
100
114
|
files:
|
101
115
|
- lib/delfos.rb
|
102
|
-
- lib/delfos/
|
103
|
-
- lib/delfos/
|
104
|
-
- lib/delfos/
|
105
|
-
- lib/delfos/
|
116
|
+
- lib/delfos/call_stack.rb
|
117
|
+
- lib/delfos/call_stack/stack.rb
|
118
|
+
- lib/delfos/file_system/common_path.rb
|
119
|
+
- lib/delfos/file_system/distance_calculation.rb
|
120
|
+
- lib/delfos/file_system/path_determination.rb
|
121
|
+
- lib/delfos/file_system/relation.rb
|
106
122
|
- lib/delfos/method_logging.rb
|
107
|
-
- lib/delfos/method_logging/
|
108
|
-
- lib/delfos/method_logging/args.rb
|
123
|
+
- lib/delfos/method_logging/call_site_parsing.rb
|
109
124
|
- lib/delfos/method_logging/code_location.rb
|
110
|
-
- lib/delfos/
|
111
|
-
- lib/delfos/neo4j
|
125
|
+
- lib/delfos/method_logging/method_parameters.rb
|
126
|
+
- lib/delfos/neo4j.rb
|
127
|
+
- lib/delfos/neo4j/batch/execution.rb
|
128
|
+
- lib/delfos/neo4j/call_stack_query.rb
|
129
|
+
- lib/delfos/neo4j/distance/call_site_fetcher.rb
|
130
|
+
- lib/delfos/neo4j/distance/update.rb
|
112
131
|
- lib/delfos/neo4j/informer.rb
|
113
|
-
- lib/delfos/neo4j/query_execution.rb
|
132
|
+
- lib/delfos/neo4j/query_execution/errors.rb
|
133
|
+
- lib/delfos/neo4j/query_execution/http.rb
|
134
|
+
- lib/delfos/neo4j/query_execution/http_query.rb
|
135
|
+
- lib/delfos/neo4j/query_execution/sync.rb
|
136
|
+
- lib/delfos/neo4j/query_execution/transactional.rb
|
137
|
+
- lib/delfos/neo4j/schema.rb
|
114
138
|
- lib/delfos/patching/basic_object.rb
|
115
139
|
- lib/delfos/patching/basic_object_remove.rb
|
140
|
+
- lib/delfos/patching/method_cache.rb
|
116
141
|
- lib/delfos/patching/method_override.rb
|
117
|
-
- lib/delfos/patching/
|
142
|
+
- lib/delfos/patching/module_defining_methods.rb
|
143
|
+
- lib/delfos/patching/unstubber.rb
|
144
|
+
- lib/delfos/setup.rb
|
118
145
|
homepage: https://github.com/markburns/delfos
|
119
146
|
licenses:
|
120
147
|
- MIT
|
@@ -131,12 +158,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
131
158
|
version: '0'
|
132
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
160
|
requirements:
|
134
|
-
- - "
|
161
|
+
- - ">="
|
135
162
|
- !ruby/object:Gem::Version
|
136
|
-
version:
|
163
|
+
version: '0'
|
137
164
|
requirements: []
|
138
165
|
rubyforge_project:
|
139
|
-
rubygems_version: 2.5.
|
166
|
+
rubygems_version: 2.5.2
|
140
167
|
signing_key:
|
141
168
|
specification_version: 4
|
142
169
|
summary: Runtime type analysis
|
data/lib/delfos/common_path.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require "pathname"
|
3
|
-
|
4
|
-
module Delfos
|
5
|
-
module CommonPath
|
6
|
-
class << self
|
7
|
-
SEPARATOR = "/"
|
8
|
-
|
9
|
-
def included_in?(p1, paths)
|
10
|
-
paths = paths.map do |p2|
|
11
|
-
common = common_parent_directory_path(p1, p2)
|
12
|
-
common.to_s.length >= p2.to_s.length
|
13
|
-
end
|
14
|
-
|
15
|
-
paths.compact.detect { |v| v }
|
16
|
-
end
|
17
|
-
|
18
|
-
def common_parent_directory_path(path_a, path_b)
|
19
|
-
dirs = [File.expand_path(path_a.to_s), File.expand_path(path_b.to_s)]
|
20
|
-
|
21
|
-
dir1, dir2 = dirs.minmax.map { |dir| dir.split(SEPARATOR) }
|
22
|
-
|
23
|
-
path_from(dir1, dir2, path_a, path_b)
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def path_from(dir1, dir2, path_a, path_b)
|
29
|
-
common_path = common_path(dir1, dir2)
|
30
|
-
common_path, path_a, path_b = append_trailing_slashes!(common_path, path_a, path_b)
|
31
|
-
|
32
|
-
Pathname.new(common_path) if valid_length?(common_path, path_a, path_b)
|
33
|
-
end
|
34
|
-
|
35
|
-
def valid_length?(common_path, path_a, path_b)
|
36
|
-
(common_path.to_s.length <= path_a.to_s.length) || (common_path.to_s.length <= path_b.to_s.length)
|
37
|
-
end
|
38
|
-
|
39
|
-
def common_path(dir1, dir2)
|
40
|
-
dir1.
|
41
|
-
zip(dir2).
|
42
|
-
take_while { |dn1, dn2| dn1 == dn2 }.
|
43
|
-
map(&:first).
|
44
|
-
join(SEPARATOR)
|
45
|
-
end
|
46
|
-
|
47
|
-
def append_trailing_slashes!(*paths)
|
48
|
-
paths.map do |path|
|
49
|
-
if Pathname.new(path).directory?
|
50
|
-
path += SEPARATOR if path && path.to_s[-1] != SEPARATOR
|
51
|
-
end
|
52
|
-
|
53
|
-
path
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require_relative "neo4j/execution_persistence"
|
3
|
-
|
4
|
-
module Delfos
|
5
|
-
class ExecutionChain
|
6
|
-
EXECUTION_CHAIN_MUTEX = Mutex.new
|
7
|
-
|
8
|
-
def self.reset!
|
9
|
-
EXECUTION_CHAIN_MUTEX.synchronize do
|
10
|
-
Thread.current[:_delfos__execution_chain] = nil
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.execution_chain
|
15
|
-
EXECUTION_CHAIN_MUTEX.synchronize do
|
16
|
-
Thread.current[:_delfos__execution_chain] ||= new
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.push(method_object)
|
21
|
-
execution_chain.push(method_object)
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.pop
|
25
|
-
execution_chain.pop
|
26
|
-
end
|
27
|
-
|
28
|
-
def push(method_object)
|
29
|
-
call_sites.push(method_object)
|
30
|
-
self.stack_depth += 1
|
31
|
-
|
32
|
-
self.execution_count += self.stack_depth == 1 ? 1 : 0
|
33
|
-
end
|
34
|
-
|
35
|
-
def pop
|
36
|
-
popping_empty_stack! if self.stack_depth.zero?
|
37
|
-
|
38
|
-
self.stack_depth -= 1
|
39
|
-
|
40
|
-
save_and_reset! if self.stack_depth.zero?
|
41
|
-
end
|
42
|
-
|
43
|
-
def stack_depth
|
44
|
-
@stack_depth ||= 0
|
45
|
-
end
|
46
|
-
|
47
|
-
def execution_count
|
48
|
-
@execution_count ||= 0
|
49
|
-
end
|
50
|
-
|
51
|
-
def call_sites
|
52
|
-
@call_sites ||= []
|
53
|
-
end
|
54
|
-
|
55
|
-
def step_count
|
56
|
-
call_sites.length
|
57
|
-
end
|
58
|
-
|
59
|
-
attr_writer :stack_depth, :step_count, :execution_count, :call_sites
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
class PoppingEmptyStackError < StandardError
|
64
|
-
end
|
65
|
-
|
66
|
-
def popping_empty_stack!
|
67
|
-
raise PoppingEmptyStackError
|
68
|
-
end
|
69
|
-
|
70
|
-
def save_and_reset!
|
71
|
-
Neo4j::ExecutionPersistence.save!(self) if call_sites.length.positive?
|
72
|
-
self.call_sites = []
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|