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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/delfos.rb +22 -78
  3. data/lib/delfos/call_stack.rb +39 -0
  4. data/lib/delfos/call_stack/stack.rb +59 -0
  5. data/lib/delfos/file_system/common_path.rb +62 -0
  6. data/lib/delfos/{distance/calculation.rb → file_system/distance_calculation.rb} +4 -15
  7. data/lib/delfos/file_system/path_determination.rb +37 -0
  8. data/lib/delfos/{distance → file_system}/relation.rb +1 -1
  9. data/lib/delfos/method_logging.rb +32 -49
  10. data/lib/delfos/method_logging/call_site_parsing.rb +74 -0
  11. data/lib/delfos/method_logging/code_location.rb +34 -98
  12. data/lib/delfos/method_logging/{args.rb → method_parameters.rb} +17 -18
  13. data/lib/delfos/neo4j.rb +58 -0
  14. data/lib/delfos/neo4j/batch/execution.rb +149 -0
  15. data/lib/delfos/neo4j/{execution_persistence.rb → call_stack_query.rb} +12 -22
  16. data/lib/delfos/neo4j/distance/call_site_fetcher.rb +19 -0
  17. data/lib/delfos/neo4j/distance/update.rb +50 -0
  18. data/lib/delfos/neo4j/informer.rb +62 -34
  19. data/lib/delfos/neo4j/query_execution/errors.rb +30 -0
  20. data/lib/delfos/neo4j/query_execution/http.rb +61 -0
  21. data/lib/delfos/neo4j/query_execution/http_query.rb +67 -0
  22. data/lib/delfos/neo4j/query_execution/sync.rb +35 -0
  23. data/lib/delfos/neo4j/query_execution/transactional.rb +68 -0
  24. data/lib/delfos/neo4j/schema.rb +73 -0
  25. data/lib/delfos/patching/basic_object.rb +1 -5
  26. data/lib/delfos/patching/method_cache.rb +83 -0
  27. data/lib/delfos/patching/method_override.rb +76 -66
  28. data/lib/delfos/patching/module_defining_methods.rb +105 -0
  29. data/lib/delfos/patching/unstubber.rb +34 -0
  30. data/lib/delfos/setup.rb +88 -0
  31. metadata +42 -15
  32. data/lib/delfos/common_path.rb +0 -58
  33. data/lib/delfos/execution_chain.rb +0 -75
  34. data/lib/delfos/method_logging/added_methods.rb +0 -67
  35. data/lib/delfos/neo4j/distance_update.rb +0 -73
  36. data/lib/delfos/neo4j/query_execution.rb +0 -79
  37. 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: 942050257d2df0f604039c76a5503f892118ba8c
4
- data.tar.gz: bbafde8bed085d9c67c75d6ff9d065f578b8d8b1
3
+ metadata.gz: 87475ed3a25d014e199e651988f4d3183561816a
4
+ data.tar.gz: 0c2441e45f0dfbe6b272e0904654907fba9f53d2
5
5
  SHA512:
6
- metadata.gz: 26f22aa726e32d4aaaffc19aebcfad37d0a19150bb85cd4aa709d358d9733258954168837adcc31af470440cbd69d7ae8106ff6616f20277507c0d58ed3db6cf
7
- data.tar.gz: 9aa2570f3afda8ec7aa4e9abd998385adc0d3dedd0acc32344b2758815d38ed2b2f326a880490310b0264c20caf00642679a665c45d7694a45ac092a195ab44f
6
+ metadata.gz: 84f4de34ff44908ce8794643553ece54cd9914cc519502d3bfb3adfc3caa0e97effbefa65aba573f1ade386839798c496bd7adf10822ff9ff3c9734459ec1bcc
7
+ data.tar.gz: 9fd34ca930e93e73a5e16294a6fc4a94464accd3f8b91353a9a8c94d99a418ef7494855b79f064334ed102a70107a9049f3e1e554f37e4c88e5681392cd7d85d
@@ -1,100 +1,44 @@
1
1
  # frozen_string_literal: true
2
- require "delfos/neo4j/informer"
2
+ require "delfos/setup"
3
3
 
4
4
  module Delfos
5
5
  class << self
6
- attr_writer :application_directories
6
+ attr_accessor :application_directories
7
+ attr_writer :logger, :neo4j
7
8
 
8
- def check_setup!
9
- raise "Delfos.setup! has not been called" unless neo4j_config && logger
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 wipe_db!
13
- Delfos.setup_neo4j!
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 reset!
23
- @application_directories = []
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 unstub_all!
41
- if defined? Delfos::Patching::MethodOverride
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 remove_added_methods!
50
- if defined? Delfos::MethodLogging::AddedMethods
51
- Delfos::MethodLogging::AddedMethods.instance_eval { @instance = nil }
52
- end
26
+ def neo4j
27
+ setup_neo4j!
53
28
  end
54
29
 
55
- def remove_patching!
56
- load "delfos/patching/basic_object_remove.rb"
30
+ def setup_neo4j!
31
+ require "delfos/neo4j"
32
+ @neo4j ||= Delfos::Neo4j.config
57
33
  end
58
34
 
59
- def setup!(logger: Delfos::Neo4j::Informer.new,
60
- neo4j_url: nil,
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
- attr_reader :neo4j
91
-
92
- Neo4jOptions = Struct.new(:url, :username, :password) do
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 Distance
6
- class Calculation
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,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Delfos
3
- module Distance
3
+ module FileSystem
4
4
  class Relation
5
5
  attr_reader :start_path, :finish_path
6
6
 
@@ -1,69 +1,52 @@
1
1
  # frozen_string_literal: true
2
- require "pathname"
3
- require "forwardable" unless defined? Forwardable
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/args"
8
- require_relative "execution_chain"
5
+ require_relative "method_logging/method_parameters"
9
6
 
10
7
  module Delfos
11
- class << self
12
- attr_accessor :logger, :application_directories
13
- attr_writer :method_logging
8
+ module MethodLogging
9
+ extend self
14
10
 
15
- def method_logging
16
- @method_logging ||= ::Delfos::MethodLogging
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
- class ApplicationDirectoriesNotDefined < StandardError
21
- def initialize(*_args)
22
- super "Please set Delfos.application_directories"
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
- module MethodLogging
27
- class << self
28
- def check_setup!
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
- def log(call_site, called_object, called_method, class_method, arguments)
33
- check_setup!
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
- Delfos.logger.debug(arguments, call_site, called_code)
38
- end
28
+ def include_file?(file)
29
+ !exclude_file?(file)
30
+ end
39
31
 
40
- def include_any_path_in_logging?(paths)
41
- Array(paths).inject(false) do |result, path|
42
- result || include_file_in_logging?(path)
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
- def exclude?(method)
47
- file, _line_number = method.source_location
48
- return true unless file
49
-
50
- exclude_file_from_logging?(File.expand_path(file))
51
- end
38
+ def reset!
39
+ @cache = nil
40
+ end
52
41
 
53
- def include_file_in_logging?(file)
54
- !exclude_file_from_logging?(file)
55
- end
42
+ private
56
43
 
57
- def exclude_file_from_logging?(file)
58
- check_setup!
59
- path = Pathname.new(File.expand_path(file))
44
+ def with_cache(key)
45
+ cache.include?(key) ? cache[key] : cache[key] = yield
46
+ end
60
47
 
61
- if Delfos.application_directories.is_a? Proc
62
- Delfos.application_directories.call(path)
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