delfos 0.0.1.pre.beta

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 504300a4ec558fbb0620996b4f1452dfd7f7424c
4
+ data.tar.gz: cf3adbd6030184d208a52d7586a816cc1d365668
5
+ SHA512:
6
+ metadata.gz: be9e77733e7d6af4ac90e62a5bbfac8ae056dbd2b6839e4a16e0c82960e64dd83d93ef8b72787b1b411f992687a67327790a3e9a9367c0dfeabe503c66d931a4
7
+ data.tar.gz: 6358c9cf62d2a2db3cf12b1fd025edc65e71c3982ad3d1d56a1d8adfb871777111da61f1dcb62ad17a213069666ce59594c24a4a75fc951991610998bf2d8b9b
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+ require "delfos/version"
3
+ require "delfos/method_logging"
4
+ require "delfos/neo4j/query_execution"
5
+ require "delfos/neo4j/informer"
6
+
7
+ module Delfos
8
+ class << self
9
+ def check_setup!
10
+ raise "Delfos.setup! has not been called" unless neo4j_config && logger
11
+ end
12
+
13
+ def wipe_db!
14
+ Delfos.setup!(application_directories: [])
15
+ Delfos::Neo4j::QueryExecution.execute <<-QUERY
16
+ MATCH (m)-[rel]->(n)
17
+ DELETE m,rel,n
18
+ QUERY
19
+ end
20
+
21
+ def reset!
22
+ @application_directories = []
23
+ @neo4j_config = nil
24
+ @logger = nil
25
+ remove_patching!
26
+ end
27
+
28
+ def remove_patching!
29
+ load "delfos/remove_patching.rb"
30
+ begin
31
+ Delfos::Patching.instance_eval { @added_methods = nil }
32
+ rescue
33
+ nil
34
+ end
35
+ end
36
+
37
+ def setup!(
38
+ connection_type: :server_db,
39
+ logger: Delfos::Neo4j::Informer.new,
40
+ host:"http://localhost:7474",
41
+ auth: { basic_auth: { username: "neo4j", password: "password" } },
42
+ application_directories: nil)
43
+
44
+ @application_directories = application_directories.map{|f| Pathname.new(File.expand_path(f.to_s))}
45
+ @logger = logger
46
+
47
+ @neo4j_config = [connection_type, host, auth]
48
+
49
+ perform_patching!
50
+ end
51
+
52
+ def perform_patching!
53
+ load "delfos/perform_patching.rb"
54
+ end
55
+
56
+ attr_reader :application_directories, :neo4j_config
57
+ end
58
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ require "pathname"
3
+
4
+ module Delfos
5
+ module CommonPath
6
+ class << self
7
+ SEPARATOR = "/"
8
+
9
+ def included_in?(p1, paths)
10
+ paths = paths.map do |p2|
11
+ common = common_parent_directory_path(p1, p2)
12
+ common.to_s.length >= p2.to_s.length
13
+ end
14
+
15
+ paths.compact.detect { |v| v }
16
+ end
17
+
18
+ def common_parent_directory_path(path_a, path_b)
19
+ dirs = [File.expand_path(path_a.to_s), File.expand_path(path_b.to_s)]
20
+
21
+ dir1, dir2 = dirs.minmax.map { |dir| dir.split(SEPARATOR) }
22
+
23
+ path_from(dir1, dir2, path_a, path_b)
24
+ end
25
+
26
+ private
27
+
28
+ def path_from(dir1, dir2, path_a, path_b)
29
+ common_path = common_path(dir1, dir2)
30
+ common_path, path_a, path_b = append_trailing_slashes!(common_path, path_a, path_b)
31
+
32
+ if valid_length?(common_path, path_a, path_b)
33
+ Pathname.new(common_path)
34
+ end
35
+ end
36
+
37
+ def valid_length?(common_path, path_a, path_b)
38
+ (common_path.to_s.length <= path_a.to_s.length) || (common_path.to_s.length <= path_b.to_s.length)
39
+ end
40
+
41
+ def common_path(dir1, dir2)
42
+ dir1.
43
+ zip(dir2).
44
+ take_while { |dn1, dn2| dn1 == dn2 }.
45
+ map(&:first).
46
+ join(SEPARATOR)
47
+ end
48
+
49
+ def append_trailing_slashes!(*paths)
50
+ paths.map do |path|
51
+ if Pathname.new(path).directory?
52
+ path += SEPARATOR if path && path.to_s[-1] != SEPARATOR
53
+ end
54
+
55
+ path
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+ require_relative "relation"
3
+
4
+ module Delfos
5
+ module Distance
6
+ class Calculation
7
+ attr_reader :path_a, :path_b
8
+
9
+ def initialize(path_a, path_b)
10
+ @path_a = path_a
11
+ @path_b = path_b
12
+ end
13
+
14
+ attr_reader :traversal_a, :traversal_b
15
+
16
+ def traversals
17
+ result = []
18
+ path = traversal_path
19
+
20
+ path.each_cons(2) do |start, finish|
21
+ klass = klass_for(start, finish)
22
+ result.push(klass.new(start, finish))
23
+ end
24
+
25
+ result
26
+ end
27
+
28
+ def klass_for(a, b)
29
+ return ChildFile if b + ".." == a
30
+ Relation
31
+ end
32
+
33
+ def sum_traversals
34
+ traversals.inject(0) { |a, e| a + e.distance }
35
+ end
36
+
37
+ def sum_possible_traversals
38
+ traversals.inject(0) { |a, e| a + e.possible_length }
39
+ end
40
+
41
+ def sibling_directories(path)
42
+ siblings(path).select { |f| File.directory?(f) }
43
+ end
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
+ def traversal_path
57
+ TraversalPathCalculator.new(path_a, path_b).path
58
+ end
59
+
60
+ class TraversalPathCalculator
61
+ attr_reader :path_a, :path_b
62
+
63
+ def initialize(path_a, path_b)
64
+ @path_a = path_a
65
+ @path_b = path_b
66
+ end
67
+
68
+ def path
69
+ return [path_a, path_b] if same_directory?
70
+
71
+ current_path = path_a
72
+
73
+ traversal.descend do |p|
74
+ current_path = full(path_a, p)
75
+ result.process(current_path)
76
+ end
77
+
78
+ result
79
+ end
80
+
81
+ def same_directory?
82
+ path_a.dirname == path_b.dirname
83
+ end
84
+
85
+ def result
86
+ @result ||= Result.new([path_a])
87
+ end
88
+
89
+ def traversal
90
+ path_b.relative_path_from(path_a)
91
+ end
92
+
93
+ def full(start, traversal)
94
+ start.realpath + Pathname.new(traversal)
95
+ end
96
+
97
+ class Result < Array
98
+ def initialize(*args)
99
+ super
100
+ @in_parent = false
101
+ end
102
+
103
+ def process(i)
104
+ if @in_parent
105
+ @in_parent = false
106
+ remove_parent(i)
107
+ else
108
+ add_item(i)
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ def add_item(i)
115
+ @in_parent = ((last && last + "..") == i)
116
+ push i
117
+ end
118
+
119
+ def remove_parent(i)
120
+ return unless same_dir?(i)
121
+
122
+ pop
123
+ push(i)
124
+ end
125
+
126
+ def same_dir?(i)
127
+ self[-2] && self[-2].dirname == i.dirname
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+ module Delfos
3
+ module Distance
4
+ class Relation
5
+ attr_reader :start_path, :finish_path
6
+
7
+ def initialize(start_path, finish_path)
8
+ @start_path = start_path
9
+ @finish_path = finish_path
10
+ end
11
+
12
+ def other_files
13
+ RelatedPaths.new(start_path).files
14
+ end
15
+
16
+ def other_directories
17
+ RelatedPaths.new(start_path).directories
18
+ end
19
+
20
+ def distance
21
+ return traversed_files.length if both_files?
22
+ return traversed_directories.length if both_directories?
23
+
24
+ traversed_files.length + traversed_directories.length
25
+ end
26
+
27
+ def possible_length
28
+ other_files.length + other_directories.length
29
+ end
30
+
31
+ def traversed_files
32
+ start_at_end = (start_path.file? && finish_path.directory?)
33
+
34
+ subset_to_traverse(collection: other_files,
35
+ start: start_path,
36
+ finish: finish_path,
37
+ start_at_end: start_at_end)
38
+ end
39
+
40
+ def traversed_directories
41
+ start_at_end = (start_path.file? && finish_path.directory?) || (start_path.directory? && finish_path.file?)
42
+
43
+ subset_to_traverse(collection: other_directories,
44
+ start: start_path,
45
+ finish: finish_path,
46
+ start_at_end: start_at_end)
47
+ end
48
+
49
+ def subset_to_traverse(collection:, start:, finish:, start_at_end: true)
50
+ start_index, finish_index = indexes_from(collection, start, finish, start_at_end)
51
+
52
+ Array collection[start_index..finish_index]
53
+ end
54
+
55
+ private
56
+
57
+ def both_files?
58
+ start_path.file? && finish_path.file?
59
+ end
60
+
61
+ def both_directories?
62
+ start_path.directory? && finish_path.directory?
63
+ end
64
+
65
+ def indexes_from(collection, start, finish, start_at_end)
66
+ start_index = index_from(collection, start, start_at_end: start_at_end)
67
+ finish_index = index_from(collection, finish, start_at_end: start_at_end, reverse: true)
68
+
69
+ if start_index.zero? && finish_index.zero?
70
+ finish_index = collection.length - 1
71
+ end
72
+
73
+ [start_index, finish_index].sort
74
+ end
75
+
76
+ def index_from(collection, value, reverse: false, start_at_end: false)
77
+ index = collection.index value
78
+
79
+ if index.nil?
80
+ index = start_at_end && !reverse ? collection.length - 1 : 0
81
+ end
82
+
83
+ index
84
+ end
85
+
86
+ class RelatedPaths
87
+ attr_reader :path
88
+
89
+ def initialize(path)
90
+ @path = path
91
+ end
92
+
93
+ def files
94
+ all.select(&:file?)
95
+ end
96
+
97
+ def directories
98
+ all.select(&:directory?)
99
+ end
100
+
101
+ private
102
+
103
+ def all
104
+ Dir.glob(path.dirname + "*").map { |f| Pathname.new(f) }
105
+ end
106
+ end
107
+ end
108
+
109
+ class ChildFile < Relation
110
+ def other_files
111
+ RelatedPaths.new(start_path + "*").files
112
+ end
113
+
114
+ def other_directories
115
+ RelatedPaths.new(start_path + "*").directories
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,74 @@
1
+ require_relative "neo4j/execution_persistence"
2
+
3
+ module Delfos
4
+ class ExecutionChain
5
+ METHOD_CHAIN_MUTEX = Mutex.new
6
+
7
+ def self.reset!
8
+ METHOD_CHAIN_MUTEX.synchronize do
9
+ Thread.current[:_delfos__execution_chain__method_chain] = nil
10
+ end
11
+ end
12
+
13
+ def self.method_chain
14
+ METHOD_CHAIN_MUTEX.synchronize do
15
+ Thread.current[:_delfos__execution_chain__method_chain] ||= new
16
+ end
17
+ end
18
+
19
+ def self.push(method_object)
20
+ method_chain.push(method_object)
21
+ end
22
+
23
+ def self.pop
24
+ method_chain.pop
25
+ end
26
+
27
+ def push(method_object)
28
+ self.call_sites.push(method_object)
29
+ self.stack_depth += 1
30
+
31
+ self.execution_count += self.stack_depth == 1 ? 1 : 0
32
+ end
33
+
34
+ def pop
35
+ popping_empty_stack! if self.stack_depth == 0
36
+
37
+ self.stack_depth -= 1
38
+
39
+ save_and_reset! if self.stack_depth == 0
40
+ end
41
+
42
+ def stack_depth
43
+ @stack_depth ||= 0
44
+ end
45
+
46
+ def execution_count
47
+ @execution_count ||= 0
48
+ end
49
+
50
+ def call_sites
51
+ @call_sites ||= []
52
+ end
53
+
54
+ def step_count
55
+ call_sites.length
56
+ end
57
+
58
+ private
59
+
60
+ class PoppingEmptyStackError < StandardError
61
+ end
62
+
63
+ def popping_empty_stack!
64
+ raise PoppingEmptyStackError
65
+ end
66
+
67
+ def save_and_reset!
68
+ Neo4j::ExecutionPersistence.save!(self) if call_sites.length > 0
69
+ self.call_sites = []
70
+ end
71
+
72
+ attr_writer :stack_depth, :step_count, :execution_count, :call_sites
73
+ end
74
+ end