delfos 0.0.1.pre.rc1 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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