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,74 +0,0 @@
1
- # frozen_string_literal: true
2
- require "binding_of_caller"
3
-
4
- module Delfos
5
- module MethodLogging
6
- class CallSiteParsing
7
- # This magic number is based on the implementation within this file.
8
- # If the line with `call_site_binding.of_caller(stack_index + STACK_OFFSET).receiver`
9
- # is moved up or down the call stack a test fails and we have to change `STACK_OFFSET`
10
- STACK_OFFSET = 5
11
-
12
- attr_reader :stack, :call_site_binding
13
-
14
- def initialize(stack, call_site_binding, stack_offset: nil)
15
- @stack = stack
16
- @call_site_binding = call_site_binding
17
- @stack_offset = stack_offset
18
- end
19
-
20
- def perform
21
- file, line_number, method_name = method_details
22
- return unless current && file && line_number && method_name
23
-
24
- CodeLocation.new(object: object,
25
- method_name: method_name.to_s,
26
- class_method: class_method,
27
- file: file,
28
- line_number: line_number)
29
- end
30
-
31
- private
32
-
33
- def class_method
34
- object.is_a? Module
35
- end
36
-
37
- def current
38
- stack.detect do |s|
39
- file = s.split(":")[0]
40
- Delfos::MethodLogging.include_file?(file)
41
- end
42
- end
43
-
44
- def object
45
- @object ||= call_site_binding.of_caller(stack_index + stack_offset).receiver
46
- end
47
-
48
- def stack_offset
49
- @stack_offset ||= STACK_OFFSET
50
- end
51
-
52
- def stack_index
53
- stack.index { |c| c == current }
54
- end
55
-
56
- METHOD_NAME_REGEX = /`(.*)'$/
57
-
58
- def method_details
59
- return unless current
60
- file, line_number, rest, more = current.split(":")
61
-
62
- rest = more.nil? ? rest : "#{rest}:#{more}"
63
- method_name = rest.match(METHOD_NAME_REGEX)&.[](1)
64
-
65
- return unless method_name && file && line_number
66
-
67
- method_name = method_name.delete("`")
68
- method_name = method_name.delete("'")
69
-
70
- [file, line_number.to_i, method_name]
71
- end
72
- end
73
- end
74
- end
@@ -1,89 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative "call_site_parsing"
3
-
4
- module Delfos
5
- module MethodLogging
6
- class CodeLocation
7
- class << self
8
- def from_call_site(stack, call_site_binding)
9
- CallSiteParsing.new(stack, call_site_binding).perform
10
- end
11
-
12
- def from_called(object, called_method, class_method)
13
- file, line_number = called_method.source_location
14
- return unless file && line_number
15
-
16
- new(object: object, method_name: called_method.name.to_s,
17
- class_method: class_method, file: file, line_number: line_number)
18
- end
19
-
20
- end
21
-
22
- attr_reader :object, :method_name, :class_method, :line_number
23
-
24
- def initialize(object:, method_name:, class_method:, file:, line_number:)
25
- @object = object
26
- @method_name = method_name
27
- @class_method = class_method
28
- @line_number = line_number.to_i
29
- @file = file
30
- end
31
-
32
- def file
33
- relative_filename @file
34
- end
35
-
36
- def klass
37
- object.is_a?(Class) ? object : object.class
38
- end
39
-
40
- def method_definition_file
41
- relative_filename(method_definition&.first || fallback_method_definition_file)
42
- end
43
-
44
- def method_definition_line
45
- method_definition&.last&.to_i || fallback_method_definition_line_number
46
- end
47
-
48
- def method_type
49
- class_method ? "ClassMethod" : "InstanceMethod"
50
- end
51
-
52
- private
53
-
54
- def relative_filename(f)
55
- return unless f
56
- file = f.to_s
57
-
58
- Delfos.application_directories.map do |d|
59
- file = relative_path(file, d)
60
- end
61
-
62
- file
63
- end
64
-
65
- def relative_path(file, dir)
66
- match = dir.to_s.split("/")[0..-2].join("/")
67
-
68
- if file[match]
69
- file = file.gsub(match, "").
70
- gsub(%r{^/}, "")
71
- end
72
-
73
- file
74
- end
75
-
76
- def fallback_method_definition_file
77
- @file
78
- end
79
-
80
- def fallback_method_definition_line_number
81
- 0
82
- end
83
-
84
- def method_definition
85
- @method_definition ||= Patching::MethodCache.find(klass: klass, method_name: method_name, class_method: class_method)&.source_location
86
- end
87
- end
88
- end
89
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
- require "delfos/patching/method_cache"
3
-
4
- module Delfos
5
- module MethodLogging
6
- class MethodParameters
7
- attr_reader :block
8
-
9
- def initialize(args=[], keyword_args=nil, block=nil)
10
- @raw_args = args
11
- @raw_keyword_args = keyword_args
12
- @block = block
13
- end
14
-
15
- def args
16
- @args ||= calculate_args(@raw_args)
17
- end
18
-
19
- def argument_classes
20
- (args + keyword_args).uniq
21
- end
22
-
23
- def keyword_args
24
- @keyword_args ||= calculate_args(@raw_keyword_args.values)
25
- end
26
-
27
- def as_json(*params)
28
- {arguments: args, keyword_arguments: keyword_args}
29
- end
30
-
31
- private
32
-
33
- def calculate_args(arguments)
34
- arguments.
35
- map { |o| o.is_a?(Class) ? o : o.class }.
36
- select { |k| keep?(k) }
37
- end
38
-
39
- def keep?(klass)
40
- files_for(klass).
41
- any? { |f| record?(f) }
42
- end
43
-
44
- def files_for(klass)
45
- Patching::MethodCache.files_for(klass)
46
- end
47
-
48
- def record?(f)
49
- Delfos::MethodLogging.include_file?(f)
50
- end
51
- end
52
- end
53
- end
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
- module Delfos
3
- module Neo4j
4
- class CallStackQuery
5
- def initialize(call_sites, execution_count)
6
- @call_sites = call_sites
7
-
8
- @execution_count = execution_count
9
- end
10
-
11
- def query
12
- map_call_sites do |c, i|
13
- call_site_query(c, i)
14
- end.join("\n")
15
- end
16
-
17
- def params
18
- params = {}
19
-
20
- map_call_sites do |c, i|
21
- params.merge!(call_site_params(c, i))
22
- end
23
-
24
- params
25
- end
26
-
27
- private
28
-
29
- attr_reader :call_sites, :execution_count
30
-
31
- def map_call_sites
32
- call_sites.compact.map.with_index do |c, i|
33
- yield c, i
34
- end
35
- end
36
-
37
- def call_site_query(_cs, i)
38
- <<-QUERY
39
- MERGE
40
-
41
- (
42
- k#{i}:Class { name: {klass#{i}} }
43
- )
44
-
45
- - [:OWNS] ->
46
-
47
- (
48
- m#{i} :Method {
49
- type: {method_type#{i}},
50
- name: {method_name#{i}},
51
- file: {method_definition_file#{i}},
52
- line_number: {method_definition_line#{i}}}
53
- )
54
-
55
- MERGE
56
-
57
- (m#{i})
58
-
59
- -[:CONTAINS]->
60
-
61
- (cs#{i}:CallSite {file: {file#{i}}, line_number: {line_number#{i}}})
62
-
63
- MERGE (e#{i}:CallStack{number: {execution_count#{i}}})
64
-
65
- MERGE (e#{i})
66
- -
67
- [:STEP {number: {step_number#{i}}}]
68
- ->
69
- (cs#{i})
70
- QUERY
71
- end
72
-
73
- def call_site_params(cs, i)
74
- {
75
- "klass#{i}" => cs.klass.to_s,
76
- "method_name#{i}" => cs.method_name,
77
- "method_type#{i}" => cs.method_type,
78
- "method_definition_file#{i}" => cs.method_definition_file,
79
- "execution_count#{i}" => execution_count,
80
- "method_definition_line#{i}" => cs.method_definition_line,
81
- "file#{i}" => cs.file,
82
- "line_number#{i}" => cs.line_number,
83
- "step_number#{i}" => i + 1,
84
- }
85
- end
86
- end
87
- end
88
- end
@@ -1,128 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Delfos
4
- module Neo4j
5
- class Informer
6
- def save_call_stack(call_sites, execution_number)
7
- q = Neo4j::CallStackQuery.new(call_sites, execution_number)
8
- Neo4j.execute(q.query, q.params)
9
- end
10
-
11
- def log(args, call_site, called_code)
12
- query = query_for(args, call_site, called_code)
13
- params = params_for(args, call_site, called_code)
14
-
15
- Neo4j.execute(query, params)
16
- end
17
-
18
- def params_for(args, call_site, called_code)
19
- assign_query_variables(args, call_site, called_code)
20
-
21
- params = query_variables.each_with_object({}) do |(klass, name), object|
22
- object[name] = klass.to_s
23
- end
24
-
25
- params["m1_type"] = call_site.method_type
26
- params["m1_name"] = call_site.method_name
27
- params["m1_file"] = call_site.method_definition_file
28
- params["m1_line_number"] = call_site.method_definition_line
29
-
30
- params["cs_file"] = call_site.file
31
- params["cs_line_number"] = call_site.line_number
32
-
33
- params["m2_type"] = called_code.method_type
34
- params["m2_name"] = called_code.method_name
35
- params["m2_file"] = called_code.method_definition_file
36
- params["m2_line_number"] = called_code.method_definition_line
37
-
38
- params
39
- end
40
-
41
- def query_for(args, call_site, called_code)
42
- assign_query_variables(args, call_site, called_code)
43
-
44
- klasses_query = query_variables.map do |_klass, name|
45
- "MERGE (#{name}:Class {name: {#{name}}})"
46
- end.join("\n")
47
-
48
- <<-QUERY
49
- #{klasses_query}
50
-
51
- MERGE (#{query_variable(call_site.klass)}) - [:OWNS] ->
52
- #{method_node("m1")}
53
-
54
- MERGE (m1) - [:CONTAINS] ->
55
- (cs:CallSite
56
- {
57
- file: {cs_file},
58
- line_number: {cs_line_number}
59
- }
60
- )
61
-
62
- MERGE (#{query_variable(called_code.klass)}) - [:OWNS] ->
63
- #{method_node("m2")}
64
-
65
- MERGE (cs) - [:CALLS] -> (m2)
66
-
67
- #{args_query args}
68
- QUERY
69
- end
70
-
71
- def assign_query_variables(args, call_site, called_code)
72
- klasses = [call_site.klass, called_code.klass] + args.argument_classes
73
-
74
- klasses.uniq.each do |k|
75
- query_variables.assign(k, "k")
76
- end
77
- end
78
-
79
- def method_node(id)
80
- <<-NODE
81
- (#{id}:Method
82
- {
83
- type: {#{id}_type},
84
- name: {#{id}_name},
85
- file: {#{id}_file},
86
- line_number: {#{id}_line_number}
87
- }
88
- )
89
- NODE
90
- end
91
-
92
- def args_query(args)
93
- query_text = args.argument_classes.map do |k|
94
- name = query_variable(k)
95
- "MERGE (cs) - [:ARG] -> (#{name})"
96
- end
97
-
98
- query_text.join("\n")
99
- end
100
-
101
- def query_variable(k)
102
- query_variables[k.to_s]
103
- end
104
-
105
- def query_variables
106
- @query_variables ||= QueryVariables.new
107
- end
108
-
109
- class QueryVariables < Hash
110
- def initialize(*args)
111
- super(*args)
112
- @counters = Hash.new(1)
113
- end
114
-
115
- def assign(klass, prefix)
116
- klass = klass.to_s
117
- val = self[klass]
118
- return val if val
119
-
120
- "#{prefix}#{@counters[prefix]}".tap do |v|
121
- self[klass] = v
122
- @counters[prefix] += 1
123
- end
124
- end
125
- end
126
- end
127
- end
128
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative "method_override"
3
-
4
- class BasicObject
5
- def self.method_added(name)
6
- ::Delfos::Patching::MethodOverride.setup(self, name, private_instance_methods, class_method: false)
7
- end
8
-
9
- def self.singleton_method_added(name)
10
- return if %i(define_method extended included inherited method_added singleton_method_added).include?(name)
11
-
12
- ::Delfos::Patching::MethodOverride.setup(self, name, private_methods, class_method: true)
13
- end
14
- end