delfos 0.0.1 → 0.0.2.pre.rc2
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 +72 -13
- data/lib/delfos/call_stack.rb +9 -9
- data/lib/delfos/call_stack/stack.rb +18 -18
- data/lib/delfos/file_system.rb +16 -0
- data/lib/delfos/file_system/app_directories.rb +42 -0
- data/lib/delfos/file_system/common_path.rb +17 -11
- data/lib/delfos/file_system/distance_calculation.rb +12 -3
- data/lib/delfos/file_system/path_determination.rb +4 -1
- data/lib/delfos/file_system/relation.rb +1 -0
- data/lib/delfos/method_trace.rb +59 -0
- data/lib/delfos/method_trace/call_handler.rb +48 -0
- data/lib/delfos/method_trace/code_location.rb +35 -0
- data/lib/delfos/method_trace/code_location/call_site.rb +38 -0
- data/lib/delfos/method_trace/code_location/container_method_factory.rb +71 -0
- data/lib/delfos/method_trace/code_location/eval_in_caller.rb +17 -0
- data/lib/delfos/method_trace/code_location/filename_helpers.rb +46 -0
- data/lib/delfos/method_trace/code_location/method.rb +58 -0
- data/lib/delfos/neo4j.rb +4 -4
- data/lib/delfos/neo4j/batch/execution.rb +30 -88
- data/lib/delfos/neo4j/batch/retryable.rb +101 -0
- data/lib/delfos/neo4j/call_site_query.rb +89 -0
- data/lib/delfos/neo4j/distance/call_site_fetcher.rb +1 -0
- data/lib/delfos/neo4j/distance/update.rb +22 -5
- data/lib/delfos/neo4j/live/call_site_logger.rb +17 -0
- data/lib/delfos/neo4j/offline/call_site_logger.rb +39 -0
- data/lib/delfos/neo4j/offline/importer.rb +68 -0
- data/lib/delfos/neo4j/query_execution/errors.rb +13 -3
- data/lib/delfos/neo4j/query_execution/http.rb +1 -0
- data/lib/delfos/neo4j/query_execution/http_query.rb +20 -15
- data/lib/delfos/neo4j/query_execution/sync.rb +1 -0
- data/lib/delfos/neo4j/query_execution/transactional.rb +24 -13
- data/lib/delfos/neo4j/schema.rb +5 -19
- data/lib/delfos/setup.rb +76 -44
- metadata +77 -18
- data/lib/delfos/method_logging.rb +0 -52
- data/lib/delfos/method_logging/call_site_parsing.rb +0 -74
- data/lib/delfos/method_logging/code_location.rb +0 -89
- data/lib/delfos/method_logging/method_parameters.rb +0 -53
- data/lib/delfos/neo4j/call_stack_query.rb +0 -88
- data/lib/delfos/neo4j/informer.rb +0 -128
- data/lib/delfos/patching/basic_object.rb +0 -14
- data/lib/delfos/patching/basic_object_remove.rb +0 -7
- data/lib/delfos/patching/method_cache.rb +0 -83
- data/lib/delfos/patching/method_override.rb +0 -148
- data/lib/delfos/patching/module_defining_methods.rb +0 -105
- data/lib/delfos/patching/unstubber.rb +0 -34
@@ -1,83 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require "Forwardable" unless defined? Forwardable
|
3
|
-
|
4
|
-
module Delfos
|
5
|
-
module Patching
|
6
|
-
class MethodCache
|
7
|
-
class << self
|
8
|
-
extend Forwardable
|
9
|
-
|
10
|
-
def_delegators :instance,
|
11
|
-
:files_for,
|
12
|
-
:append,
|
13
|
-
:find
|
14
|
-
|
15
|
-
def reset!
|
16
|
-
@instance = nil
|
17
|
-
end
|
18
|
-
|
19
|
-
def instance
|
20
|
-
@instance ||= new
|
21
|
-
end
|
22
|
-
|
23
|
-
def each_method
|
24
|
-
instance.send(:added_methods).each do |klass, methods|
|
25
|
-
methods.each do |k, m|
|
26
|
-
class_method = !!(k[/^ClassMethod_/])
|
27
|
-
yield klass, m, class_method
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def initialize
|
34
|
-
@added_methods = {}
|
35
|
-
end
|
36
|
-
|
37
|
-
def files_for(klass)
|
38
|
-
fetch(klass).
|
39
|
-
values.
|
40
|
-
map(&:source_location).
|
41
|
-
compact.
|
42
|
-
map(&:first).
|
43
|
-
compact.
|
44
|
-
uniq
|
45
|
-
end
|
46
|
-
|
47
|
-
def append(klass:, method:)
|
48
|
-
class_method = method.respond_to?(:receiver) && method.receiver.is_a?(Class)
|
49
|
-
key = key_for(class_method, method.name)
|
50
|
-
m = fetch(klass)[key]
|
51
|
-
|
52
|
-
fetch(klass)[key] = method if m.nil?
|
53
|
-
end
|
54
|
-
|
55
|
-
def find(klass:, method_name:, class_method:)
|
56
|
-
key = key_for(class_method, method_name)
|
57
|
-
|
58
|
-
fetch(klass)[key]
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
attr_reader :added_methods
|
64
|
-
|
65
|
-
def key_for(class_method, method_name)
|
66
|
-
class_method ? "ClassMethod_#{method_name}" : "InstanceMethod_#{method_name}"
|
67
|
-
end
|
68
|
-
|
69
|
-
def fetch(klass)
|
70
|
-
# Find method definitions defined in klass or its ancestors
|
71
|
-
super_klass = klass.ancestors.detect do |k|
|
72
|
-
(fetch_without_default(k) || {}).values.length.positive?
|
73
|
-
end
|
74
|
-
|
75
|
-
added_methods[(super_klass || klass).to_s] ||= {}
|
76
|
-
end
|
77
|
-
|
78
|
-
def fetch_without_default(klass)
|
79
|
-
added_methods[klass.to_s]
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,148 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "delfos/method_logging"
|
4
|
-
require "delfos/call_stack"
|
5
|
-
|
6
|
-
require_relative "module_defining_methods"
|
7
|
-
require_relative "unstubber"
|
8
|
-
|
9
|
-
module Delfos
|
10
|
-
module Patching
|
11
|
-
MUTEX = Mutex.new
|
12
|
-
|
13
|
-
class MethodOverride
|
14
|
-
include ModuleDefiningMethods
|
15
|
-
|
16
|
-
class << self
|
17
|
-
def setup(klass, name, private_methods, class_method:)
|
18
|
-
return if skip_meta_programming_defined_method?
|
19
|
-
|
20
|
-
MUTEX.synchronize do
|
21
|
-
return if Thread.current[:__delfos_disable_patching]
|
22
|
-
end
|
23
|
-
|
24
|
-
instance = new(klass, name, private_methods, class_method)
|
25
|
-
|
26
|
-
instance.ensure_method_recorded_once!
|
27
|
-
end
|
28
|
-
|
29
|
-
META_PROGRAMMING_REGEX = /`define_method'\z|`attr_accessor'\z|`attr_reader'\z|`attr_writer'\z/
|
30
|
-
|
31
|
-
def skip_meta_programming_defined_method?
|
32
|
-
stack = caller.dup
|
33
|
-
|
34
|
-
i = stack.index do |l|
|
35
|
-
l["delfos/patching/basic_object.rb"]
|
36
|
-
end
|
37
|
-
|
38
|
-
return unless i
|
39
|
-
|
40
|
-
result = stack[i + 1][META_PROGRAMMING_REGEX]
|
41
|
-
|
42
|
-
return unless result
|
43
|
-
|
44
|
-
Delfos.logger.debug "Skipping setting up delfos logging of method defined by #{result} #{stack[i+1]}"
|
45
|
-
true
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
attr_reader :klass, :name, :private_methods, :class_method
|
52
|
-
|
53
|
-
def initialize(klass, name, private_methods, class_method)
|
54
|
-
@klass = klass
|
55
|
-
@name = name
|
56
|
-
@private_methods = private_methods
|
57
|
-
@class_method = class_method
|
58
|
-
original_method # ensure memoized method is the original not the overridden one
|
59
|
-
end
|
60
|
-
|
61
|
-
def ensure_method_recorded_once!
|
62
|
-
record_method! { setup }
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
# Redefine the method at runtime to enabling logging to Neo4j
|
67
|
-
def setup
|
68
|
-
cm = class_method
|
69
|
-
with_stack = method(:with_stack)
|
70
|
-
method_name = name
|
71
|
-
om = original_method
|
72
|
-
|
73
|
-
mod = module_definition(klass, name, class_method) do
|
74
|
-
define_method(method_name) do |*args, **kw_args, &block|
|
75
|
-
stack = caller.dup
|
76
|
-
caller_binding = binding.dup
|
77
|
-
parameters = Delfos::MethodLogging::MethodParameters.new(args, kw_args, block)
|
78
|
-
|
79
|
-
call_site = Delfos::MethodLogging::CodeLocation.from_call_site(stack, caller_binding)
|
80
|
-
|
81
|
-
if call_site
|
82
|
-
Delfos::MethodLogging.log(call_site, self, om, cm, parameters)
|
83
|
-
end
|
84
|
-
|
85
|
-
with_stack.call(call_site) do
|
86
|
-
if !kw_args.empty?
|
87
|
-
super(*args, **kw_args, &block)
|
88
|
-
else
|
89
|
-
super(*args, &block)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
return unless mod
|
95
|
-
|
96
|
-
if class_method
|
97
|
-
klass.prepend mod
|
98
|
-
else
|
99
|
-
klass.instance_eval { prepend mod }
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def with_stack(call_site)
|
104
|
-
return yield unless call_site
|
105
|
-
|
106
|
-
begin
|
107
|
-
CallStack.push(call_site)
|
108
|
-
yield
|
109
|
-
ensure
|
110
|
-
CallStack.pop
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def original_method
|
115
|
-
@original_method ||= if class_method
|
116
|
-
klass.method(name)
|
117
|
-
else
|
118
|
-
klass.instance_method(name)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
private
|
123
|
-
|
124
|
-
def record_method!
|
125
|
-
return true if bail?
|
126
|
-
MethodCache.append(klass: klass, method: original_method)
|
127
|
-
|
128
|
-
yield
|
129
|
-
end
|
130
|
-
|
131
|
-
def bail?
|
132
|
-
method_has_been_added? || private_method? || exclude?
|
133
|
-
end
|
134
|
-
|
135
|
-
def method_has_been_added?
|
136
|
-
MethodCache.find(klass: klass, class_method: class_method, method_name: name)
|
137
|
-
end
|
138
|
-
|
139
|
-
def private_method?
|
140
|
-
private_methods.include?(name.to_sym)
|
141
|
-
end
|
142
|
-
|
143
|
-
def exclude?
|
144
|
-
::Delfos::MethodLogging.exclude?(original_method)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
@@ -1,105 +0,0 @@
|
|
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
|
@@ -1,34 +0,0 @@
|
|
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
|