delfos 0.0.1 → 0.0.2.pre.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/lib/delfos.rb +72 -13
  3. data/lib/delfos/call_stack.rb +9 -9
  4. data/lib/delfos/call_stack/stack.rb +18 -18
  5. data/lib/delfos/file_system.rb +16 -0
  6. data/lib/delfos/file_system/app_directories.rb +42 -0
  7. data/lib/delfos/file_system/common_path.rb +17 -11
  8. data/lib/delfos/file_system/distance_calculation.rb +12 -3
  9. data/lib/delfos/file_system/path_determination.rb +4 -1
  10. data/lib/delfos/file_system/relation.rb +1 -0
  11. data/lib/delfos/method_trace.rb +59 -0
  12. data/lib/delfos/method_trace/call_handler.rb +48 -0
  13. data/lib/delfos/method_trace/code_location.rb +35 -0
  14. data/lib/delfos/method_trace/code_location/call_site.rb +38 -0
  15. data/lib/delfos/method_trace/code_location/container_method_factory.rb +71 -0
  16. data/lib/delfos/method_trace/code_location/eval_in_caller.rb +17 -0
  17. data/lib/delfos/method_trace/code_location/filename_helpers.rb +46 -0
  18. data/lib/delfos/method_trace/code_location/method.rb +58 -0
  19. data/lib/delfos/neo4j.rb +4 -4
  20. data/lib/delfos/neo4j/batch/execution.rb +30 -88
  21. data/lib/delfos/neo4j/batch/retryable.rb +101 -0
  22. data/lib/delfos/neo4j/call_site_query.rb +89 -0
  23. data/lib/delfos/neo4j/distance/call_site_fetcher.rb +1 -0
  24. data/lib/delfos/neo4j/distance/update.rb +22 -5
  25. data/lib/delfos/neo4j/live/call_site_logger.rb +17 -0
  26. data/lib/delfos/neo4j/offline/call_site_logger.rb +39 -0
  27. data/lib/delfos/neo4j/offline/importer.rb +68 -0
  28. data/lib/delfos/neo4j/query_execution/errors.rb +13 -3
  29. data/lib/delfos/neo4j/query_execution/http.rb +1 -0
  30. data/lib/delfos/neo4j/query_execution/http_query.rb +20 -15
  31. data/lib/delfos/neo4j/query_execution/sync.rb +1 -0
  32. data/lib/delfos/neo4j/query_execution/transactional.rb +24 -13
  33. data/lib/delfos/neo4j/schema.rb +5 -19
  34. data/lib/delfos/setup.rb +76 -44
  35. metadata +77 -18
  36. data/lib/delfos/method_logging.rb +0 -52
  37. data/lib/delfos/method_logging/call_site_parsing.rb +0 -74
  38. data/lib/delfos/method_logging/code_location.rb +0 -89
  39. data/lib/delfos/method_logging/method_parameters.rb +0 -53
  40. data/lib/delfos/neo4j/call_stack_query.rb +0 -88
  41. data/lib/delfos/neo4j/informer.rb +0 -128
  42. data/lib/delfos/patching/basic_object.rb +0 -14
  43. data/lib/delfos/patching/basic_object_remove.rb +0 -7
  44. data/lib/delfos/patching/method_cache.rb +0 -83
  45. data/lib/delfos/patching/method_override.rb +0 -148
  46. data/lib/delfos/patching/module_defining_methods.rb +0 -105
  47. data/lib/delfos/patching/unstubber.rb +0 -34
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class BasicObject
4
- def self.method_added(*_args); end
5
-
6
- def self.singleton_method_added(*_args); end
7
- end
@@ -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