holistic-ruby 0.1.0

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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.standard.yml +3 -0
  4. data/Gemfile +10 -0
  5. data/Gemfile.lock +52 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +35 -0
  8. data/Rakefile +8 -0
  9. data/config/logging.rb +6 -0
  10. data/exe/holistic-ruby +6 -0
  11. data/holistic-ruby.gemspec +34 -0
  12. data/lib/holistic/application.rb +29 -0
  13. data/lib/holistic/background_process.rb +11 -0
  14. data/lib/holistic/database/table.rb +78 -0
  15. data/lib/holistic/document/cursor.rb +9 -0
  16. data/lib/holistic/document/file.rb +36 -0
  17. data/lib/holistic/document/location.rb +35 -0
  18. data/lib/holistic/document/unsaved/change.rb +24 -0
  19. data/lib/holistic/document/unsaved/collection.rb +21 -0
  20. data/lib/holistic/document/unsaved/record.rb +83 -0
  21. data/lib/holistic/extensions/events.rb +37 -0
  22. data/lib/holistic/extensions/ruby/stdlib.rb +43 -0
  23. data/lib/holistic/language_server/current.rb +11 -0
  24. data/lib/holistic/language_server/format/file_uri.rb +19 -0
  25. data/lib/holistic/language_server/lifecycle.rb +59 -0
  26. data/lib/holistic/language_server/message.rb +21 -0
  27. data/lib/holistic/language_server/protocol.rb +45 -0
  28. data/lib/holistic/language_server/request.rb +21 -0
  29. data/lib/holistic/language_server/requests/lifecycle/exit.rb +10 -0
  30. data/lib/holistic/language_server/requests/lifecycle/initialize.rb +75 -0
  31. data/lib/holistic/language_server/requests/lifecycle/initialized.rb +13 -0
  32. data/lib/holistic/language_server/requests/lifecycle/shutdown.rb +14 -0
  33. data/lib/holistic/language_server/requests/text_document/completion.rb +68 -0
  34. data/lib/holistic/language_server/requests/text_document/did_change.rb +30 -0
  35. data/lib/holistic/language_server/requests/text_document/did_close.rb +33 -0
  36. data/lib/holistic/language_server/requests/text_document/did_open.rb +16 -0
  37. data/lib/holistic/language_server/requests/text_document/did_save.rb +33 -0
  38. data/lib/holistic/language_server/requests/text_document/find_references.rb +52 -0
  39. data/lib/holistic/language_server/requests/text_document/go_to_definition.rb +64 -0
  40. data/lib/holistic/language_server/response.rb +39 -0
  41. data/lib/holistic/language_server/router.rb +48 -0
  42. data/lib/holistic/language_server/stdio/parser.rb +65 -0
  43. data/lib/holistic/language_server/stdio/server.rb +46 -0
  44. data/lib/holistic/language_server/stdio/start.rb +48 -0
  45. data/lib/holistic/ruby/autocompletion/suggest.rb +75 -0
  46. data/lib/holistic/ruby/parser/constant_resolution.rb +61 -0
  47. data/lib/holistic/ruby/parser/live_editing/process_file_changed.rb +62 -0
  48. data/lib/holistic/ruby/parser/nesting_syntax.rb +76 -0
  49. data/lib/holistic/ruby/parser/program_visitor.rb +205 -0
  50. data/lib/holistic/ruby/parser/table_of_contents.rb +17 -0
  51. data/lib/holistic/ruby/parser.rb +26 -0
  52. data/lib/holistic/ruby/reference/find_referenced_scope.rb +18 -0
  53. data/lib/holistic/ruby/reference/record.rb +13 -0
  54. data/lib/holistic/ruby/reference/register.rb +15 -0
  55. data/lib/holistic/ruby/reference/repository.rb +71 -0
  56. data/lib/holistic/ruby/reference/unregister.rb +11 -0
  57. data/lib/holistic/ruby/scope/kind.rb +11 -0
  58. data/lib/holistic/ruby/scope/list_references.rb +32 -0
  59. data/lib/holistic/ruby/scope/location.rb +43 -0
  60. data/lib/holistic/ruby/scope/outline.rb +52 -0
  61. data/lib/holistic/ruby/scope/record.rb +52 -0
  62. data/lib/holistic/ruby/scope/register.rb +31 -0
  63. data/lib/holistic/ruby/scope/repository.rb +49 -0
  64. data/lib/holistic/ruby/scope/unregister.rb +27 -0
  65. data/lib/holistic/ruby/type_inference/clue/method_call.rb +15 -0
  66. data/lib/holistic/ruby/type_inference/clue/scope_reference.rb +13 -0
  67. data/lib/holistic/ruby/type_inference/conclusion.rb +20 -0
  68. data/lib/holistic/ruby/type_inference/solve.rb +110 -0
  69. data/lib/holistic/ruby/type_inference/solve_pending_references.rb +13 -0
  70. data/lib/holistic/version.rb +5 -0
  71. data/lib/holistic.rb +27 -0
  72. metadata +158 -0
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Reference
4
+ module FindReferencedScope
5
+ extend self
6
+
7
+ def call(application:, cursor:)
8
+ reference = application.references.find_by_cursor(cursor)
9
+
10
+ return :not_found if reference.nil?
11
+ return :could_not_find_referenced_scope if reference.conclusion.dependency_identifier.nil?
12
+
13
+ referenced_scope = application.scopes.find_by_fully_qualified_name(reference.conclusion.dependency_identifier)
14
+
15
+ [:referenced_scope_found, {reference:, referenced_scope:}]
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Reference
4
+ Record = ::Struct.new(
5
+ :scope,
6
+ :clues,
7
+ :conclusion,
8
+ :location,
9
+ keyword_init: true
10
+ ) do
11
+ def identifier = location.identifier
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Reference
4
+ module Register
5
+ extend self
6
+
7
+ def call(repository:, scope:, clues:, location:)
8
+ conclusion = ::Holistic::Ruby::TypeInference::Conclusion.pending
9
+
10
+ reference = ::Holistic::Ruby::Reference::Record.new(scope:, clues:, location:, conclusion:)
11
+
12
+ repository.register_reference(reference)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Reference
4
+ class Repository
5
+ attr_reader :table
6
+
7
+ INDICES = [
8
+ :file_path,
9
+ :type_inference_status,
10
+ :referenced_scope_fully_qualified_name
11
+ ].freeze
12
+
13
+ def initialize
14
+ @table = ::Holistic::Database::Table.new(primary_attribute: :identifier, indices: INDICES)
15
+ end
16
+
17
+ def register_reference(reference)
18
+ table.update({
19
+ reference:,
20
+ identifier: reference.identifier,
21
+ file_path: reference.location.file_path,
22
+ type_inference_status: reference.conclusion.status,
23
+ referenced_scope_fully_qualified_name: reference.conclusion.dependency_identifier
24
+ })
25
+ end
26
+
27
+ def find_by_cursor(cursor)
28
+ table.filter(:file_path, cursor.file_path).map { _1[:reference] }.each do |reference|
29
+ return reference if reference.location.contains?(cursor)
30
+ end
31
+
32
+ nil
33
+ end
34
+
35
+ def list_references_to(fully_qualified_scope_name)
36
+ table.filter(:referenced_scope_fully_qualified_name, fully_qualified_scope_name).map { _1[:reference] }
37
+ end
38
+
39
+ def list_references_in_file(file_path)
40
+ table.filter(:file_path, file_path).map { _1[:reference] }
41
+ end
42
+
43
+ def list_references_to_scopes_in_file(scopes:, file_path:)
44
+ scopes.list_scopes_in_file(file_path).flat_map do |scope|
45
+ table.filter(:referenced_scope_fully_qualified_name, scope.fully_qualified_name).map { _1[:reference] }
46
+ end
47
+ end
48
+
49
+ def list_references_pending_type_inference_conclusion
50
+ table.filter(:type_inference_status, ::Holistic::Ruby::TypeInference::STATUS_PENDING).map { _1[:reference] }
51
+ end
52
+
53
+ def delete(identifier)
54
+ table.delete(identifier)
55
+ end
56
+
57
+ concerning :TestHelpers do
58
+ def find_reference_to(scope_name)
59
+ table.all.map { _1[:reference] }.find do |reference|
60
+ reference.conclusion.dependency_identifier == scope_name || reference.clues.find { _1.to_s == scope_name }
61
+ end
62
+ end
63
+
64
+ def find_by_code_content(code_content)
65
+ table.all.map { _1[:reference] }.find do |reference|
66
+ reference.clues.find { _1.to_s == code_content }
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Reference
4
+ module Unregister
5
+ extend self
6
+
7
+ def call(repository:, reference:)
8
+ repository.delete(reference.identifier)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Scope
4
+ module Kind
5
+ ROOT = :root
6
+ MODULE = :module
7
+ CLASS = :class
8
+ METHOD = :method
9
+ LAMBDA = :lambda
10
+ end
11
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Scope
4
+ module ListReferences
5
+ extend self
6
+
7
+ QueryReferencesRecursively = ->(application, scope) do
8
+ references_to_scope = application.references.list_references_to(scope.fully_qualified_name)
9
+
10
+ references_to_child_scopes = scope.children.flat_map { QueryReferencesRecursively.call(application, _1) }
11
+
12
+ references_to_scope + references_to_child_scopes
13
+ end
14
+
15
+ Relevance = ->(reference) do
16
+ # TODO: should the location answer the kind of file it is? application code, config, spec, etc. Not sure.
17
+ looks_like_a_spec = reference.location.file_path.include?("_spec.rb") || reference.location.file_path.include?("_test.rb")
18
+
19
+ looks_like_a_spec ? 1 : 0
20
+ end
21
+
22
+ def call(application:, cursor:)
23
+ scope = application.scopes.find_by_cursor(cursor)
24
+
25
+ return :not_found if scope.nil?
26
+
27
+ references = QueryReferencesRecursively.call(application, scope).sort_by(&Relevance)
28
+
29
+ [:references_listed, {references:}]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Scope
4
+ class Location
5
+ class Collection
6
+ attr_reader :scope, :items
7
+
8
+ def initialize(scope, location)
9
+ raise ::ArgumentError if location.present? && !location.is_a?(Location)
10
+
11
+ @scope = scope
12
+ @items = location.nil? ? [] : [location]
13
+ end
14
+
15
+ def main
16
+ location_matching_scope_name || items.first
17
+ end
18
+
19
+ delegate :<<, to: :items
20
+ delegate :each, to: :items
21
+ delegate :map, to: :items
22
+ delegate :reject!, to: :items
23
+ delegate :any?, to: :items
24
+
25
+ private
26
+
27
+ def location_matching_scope_name
28
+ scope_name_in_snake_case = scope.name.underscore
29
+
30
+ items.find do |location|
31
+ ::File.basename(location.declaration.file_path) == "#{scope_name_in_snake_case}.rb"
32
+ end
33
+ end
34
+ end
35
+
36
+ attr_reader :declaration, :body
37
+
38
+ def initialize(declaration:, body:)
39
+ @declaration = declaration
40
+ @body = body
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Scope
4
+ module Outline
5
+ extend self
6
+
7
+ Result = ::Struct.new(
8
+ :declarations,
9
+ :dependencies,
10
+ :references,
11
+ :dependants,
12
+ keyword_init: true
13
+ )
14
+
15
+ QueryChildScopesRecursively = ->(application, scope) do
16
+ scope.children + scope.children.flat_map { QueryChildScopesRecursively[application, _1] }
17
+ end
18
+
19
+ QueryDependenciesRecursively = ->(application, outlined_scope, scope) do
20
+ is_local_dependency = ->(reference) do
21
+ scope = application.scopes.find_by_fully_qualified_name(reference.conclusion.dependency_identifier)
22
+
23
+ scope.eql?(outlined_scope) || scope.descendant?(outlined_scope)
24
+ end
25
+
26
+ dependencies = []
27
+
28
+ scope.locations.each do |scope_location|
29
+ application.references
30
+ .list_references_in_file(scope_location.declaration.file_path)
31
+ .filter { |reference| reference.scope == scope }
32
+ .filter { |reference| reference.conclusion.dependency_identifier.present? }
33
+ .reject(&is_local_dependency)
34
+ .tap { dependencies.concat(_1) }
35
+ end
36
+
37
+ scope.children.map(&QueryDependenciesRecursively.curry[application, outlined_scope]).flatten.concat(dependencies)
38
+ end
39
+
40
+ def call(application:, scope:)
41
+ declarations = QueryChildScopesRecursively.call(application, scope).sort_by { _1.fully_qualified_name }
42
+
43
+ dependencies = QueryDependenciesRecursively.call(application, scope, scope).uniq { _1.conclusion.dependency_identifier }
44
+
45
+ references = application.references.list_references_to(scope.fully_qualified_name)
46
+
47
+ dependants = references.map { |reference| reference.scope }.uniq
48
+
49
+ Result.new(declarations:, dependencies:, references:, dependants:)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Scope
4
+ class Record
5
+ attr_reader :kind, :name, :parent, :children, :locations
6
+
7
+ def initialize(kind:, name:, parent:, location: nil)
8
+ @kind = kind
9
+ @name = name
10
+ @parent = parent
11
+ @locations = Location::Collection.new(self, location)
12
+ @children = []
13
+ end
14
+
15
+ def fully_qualified_name
16
+ return "" if root?
17
+
18
+ separator =
19
+ if kind == Kind::METHOD
20
+ "#"
21
+ else
22
+ "::"
23
+ end
24
+
25
+ "#{parent.fully_qualified_name}#{separator}#{name}"
26
+ end
27
+
28
+ def root?
29
+ parent.nil?
30
+ end
31
+
32
+ def lambda?
33
+ kind == Kind::LAMBDA
34
+ end
35
+
36
+ def class?
37
+ kind == Kind::CLASS
38
+ end
39
+
40
+ def module?
41
+ kind == Kind::MODULE
42
+ end
43
+
44
+ def method?
45
+ kind == Kind::METHOD
46
+ end
47
+
48
+ def descendant?(other)
49
+ parent.present? && (parent == other || parent.descendant?(other))
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Scope
4
+ module Register
5
+ extend self
6
+
7
+ def call(repository:, parent:, kind:, name:, location:)
8
+ child_scope = append_location_to_existing_scope(scope: parent, name:, location:) || add_new_scope(parent:, kind:, name:, location:)
9
+
10
+ repository.register_scope(child_scope)
11
+
12
+ child_scope
13
+ end
14
+
15
+ private
16
+
17
+ def append_location_to_existing_scope(scope:, name:, location:)
18
+ child_scope = scope.children.find { _1.name == name }
19
+
20
+ return if child_scope.nil?
21
+
22
+ child_scope.tap { _1.locations << location }
23
+ end
24
+
25
+ def add_new_scope(parent:, kind:, name:, location:)
26
+ child_scope = Record.new(kind:, name:, parent:, location:)
27
+
28
+ child_scope.tap { parent.children << _1 }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Scope
4
+ class Repository
5
+ attr_reader :table
6
+
7
+ def initialize
8
+ @table = ::Holistic::Database::Table.new(primary_attribute: :fully_qualified_name, indices: [:file_paths])
9
+ end
10
+
11
+ def register_scope(scope)
12
+ table.update({
13
+ fully_qualified_name: scope.fully_qualified_name,
14
+ file_paths: scope.locations.map { |scope_location| scope_location.declaration.file_path },
15
+ scope:
16
+ })
17
+ end
18
+
19
+ def find_by_fully_qualified_name(fully_qualified_name)
20
+ table.find(fully_qualified_name).try(:dig, :scope)
21
+ end
22
+
23
+ def find_by_cursor(cursor)
24
+ table.filter(:file_paths, cursor.file_path).map { _1[:scope] }.each do |scope|
25
+ return scope if scope.locations.any? { _1.declaration.contains?(cursor) }
26
+ end
27
+
28
+ nil
29
+ end
30
+
31
+ def find_inner_most_scope_by_cursor(cursor)
32
+ scopes = table.filter(:file_paths, cursor.file_path).map { _1[:scope] }
33
+
34
+ matching_scopes = scopes.filter do |scope|
35
+ scope.locations.any? { _1.body.contains?(cursor) }
36
+ end
37
+
38
+ matching_scopes.last
39
+ end
40
+
41
+ def delete_by_fully_qualified_name(fully_qualified_name)
42
+ table.delete(fully_qualified_name)
43
+ end
44
+
45
+ def list_scopes_in_file(file_path)
46
+ table.filter(:file_paths, file_path).map { _1[:scope] }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::Scope
4
+ module Unregister
5
+ extend self
6
+
7
+ def call(repository:, fully_qualified_name:, file_path:)
8
+ scope = repository.find_by_fully_qualified_name(fully_qualified_name)
9
+
10
+ return :scope_not_found if scope.nil?
11
+
12
+ updated_locations = scope.locations.reject! { |scope_location| scope_location.declaration.file_path == file_path }
13
+
14
+ return :scope_not_defined_in_speciefied_file if updated_locations.nil?
15
+
16
+ if updated_locations.empty?
17
+ scope.parent.children.delete(scope)
18
+
19
+ repository.delete_by_fully_qualified_name(fully_qualified_name)
20
+ else
21
+ repository.register_scope(scope)
22
+ end
23
+
24
+ :definition_unregistered
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::TypeInference::Clue
4
+ MethodCall = ::Data.define(
5
+ :nesting,
6
+ :method_name,
7
+ :resolution_possibilities
8
+ ) do
9
+ def to_s
10
+ return method_name if nesting.nil?
11
+
12
+ "#{nesting}.#{method_name}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::TypeInference::Clue
4
+ ScopeReference = ::Struct.new(
5
+ :nesting,
6
+ :resolution_possibilities,
7
+ keyword_init: true
8
+ ) do
9
+ def to_s
10
+ nesting.to_s
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::TypeInference
4
+ STATUS_PENDING = :pending
5
+ STATUS_DONE = :done
6
+
7
+ Conclusion = ::Data.define(:status, :dependency_identifier) do
8
+ def self.pending
9
+ new(status: STATUS_PENDING, dependency_identifier: nil)
10
+ end
11
+
12
+ def self.unresolved
13
+ new(status: STATUS_DONE, dependency_identifier: nil)
14
+ end
15
+
16
+ def self.done(dependency_identifier)
17
+ new(status: STATUS_DONE, dependency_identifier:)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::TypeInference
4
+ module Solve
5
+ extend self
6
+
7
+ def call(application:, reference:)
8
+ reference.conclusion =
9
+ solve_scope_reference(application:, reference:) ||
10
+ solve_method_call(application:, reference:) ||
11
+ Conclusion.unresolved
12
+
13
+ application.references.register_reference(reference)
14
+ end
15
+
16
+ private
17
+
18
+ def solve_scope_reference(application:, reference:)
19
+ has_scope_reference_clue =
20
+ reference.clues.one? && reference.clues.first.is_a?(Clue::ScopeReference)
21
+
22
+ return unless has_scope_reference_clue
23
+
24
+ scope_reference_clue = reference.clues.first
25
+
26
+ referenced_scope = resolve_scope(
27
+ application:,
28
+ nesting: scope_reference_clue.nesting,
29
+ resolution_possibilities: scope_reference_clue.resolution_possibilities
30
+ )
31
+
32
+ if referenced_scope.present?
33
+ return Conclusion.done(referenced_scope.fully_qualified_name)
34
+ end
35
+
36
+ nil
37
+ end
38
+
39
+ SolveMethodCallInCurrentScope = ->(application:, reference:, method_call_clue:) do
40
+ referenced_method = resolve_method(application:, scope: reference.scope, method_name: method_call_clue.method_name)
41
+
42
+ return if referenced_method.nil?
43
+
44
+ Conclusion.done(referenced_method.fully_qualified_name)
45
+ end
46
+
47
+ SolveMethodCallInSpecifiedScope = ->(application:, reference:, method_call_clue:) do
48
+ referenced_scope = resolve_scope(
49
+ application:,
50
+ nesting: method_call_clue.nesting,
51
+ resolution_possibilities: method_call_clue.resolution_possibilities
52
+ )
53
+
54
+ return if referenced_scope.nil?
55
+
56
+ referenced_method = resolve_method(application:, scope: referenced_scope, method_name: method_call_clue.method_name)
57
+ referenced_method ||= application.extensions.dispatch(:resolve_method_call_known_scope, { reference:, referenced_scope:, method_call_clue: })
58
+
59
+ Conclusion.done(referenced_method.fully_qualified_name) if referenced_method.present?
60
+ end
61
+
62
+ SolveMethodCallInLocalVariable = ->(application:, reference:, method_call_clue:) do
63
+ # local_variable_name = method_call_clue.nesting.to_s
64
+ # referenced_scope = guess_scope_for_local_variable(scope: reference.scope, name: local_variable_name)
65
+
66
+ nil
67
+ end
68
+
69
+ def solve_method_call(application:, reference:)
70
+ has_method_call_clue = reference.clues.one? && reference.clues.first.is_a?(Clue::MethodCall)
71
+
72
+ return unless has_method_call_clue
73
+
74
+ method_call_clue = reference.clues.first
75
+
76
+ if method_call_clue.nesting.nil?
77
+ SolveMethodCallInCurrentScope.call(application:, reference:, method_call_clue:)
78
+ elsif method_call_clue.nesting.constant?
79
+ SolveMethodCallInSpecifiedScope.call(application:, reference:, method_call_clue:)
80
+ else
81
+ SolveMethodCallInLocalVariable.call(application:, reference:, method_call_clue:)
82
+ end
83
+ end
84
+
85
+ def resolve_scope(application:, nesting:, resolution_possibilities:)
86
+ resolution_possibilities = ["::"] if nesting.root_scope_resolution?
87
+
88
+ resolution_possibilities.each do |resolution_candidate|
89
+ fully_qualified_scope_name =
90
+ if resolution_candidate == "::"
91
+ "::#{nesting.to_s}"
92
+ else
93
+ "#{resolution_candidate}::#{nesting.to_s}"
94
+ end
95
+
96
+ scope = application.scopes.find_by_fully_qualified_name(fully_qualified_scope_name)
97
+
98
+ return scope if scope.present?
99
+ end
100
+
101
+ nil
102
+ end
103
+
104
+ def resolve_method(application:, scope:, method_name:)
105
+ method_fully_qualified_name = "#{scope.fully_qualified_name}##{method_name}"
106
+
107
+ application.scopes.find_by_fully_qualified_name(method_fully_qualified_name)
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic::Ruby::TypeInference
4
+ module SolvePendingReferences
5
+ extend self
6
+
7
+ def call(application:)
8
+ application.references.list_references_pending_type_inference_conclusion.each do |reference|
9
+ Solve.call(application:, reference:)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Holistic
4
+ VERSION = "0.1.0"
5
+ end
data/lib/holistic.rb ADDED
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "uri"
5
+ require "logger"
6
+
7
+ require "zeitwerk"
8
+ require "syntax_tree"
9
+
10
+ require "active_support/concern"
11
+ require "active_support/core_ext/module/concerning"
12
+ require "active_support/notifications"
13
+ require "active_support/inflector"
14
+
15
+ require_relative "../config/logging"
16
+
17
+ loader = ::Zeitwerk::Loader.for_gem
18
+ loader.setup
19
+
20
+ module Holistic
21
+ extend self
22
+
23
+ @logger = ::Logger.new(ENV["HOLISTIC_LOG_OUTPUT"])
24
+ attr_reader :logger
25
+ end
26
+
27
+ loader.eager_load