yoda-language-server 0.7.0 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c06ab67892292a50ff422a252b794cf49f38dad60a8b32e7faf14936a2b648e
4
- data.tar.gz: 20546678432670fae9b613a6d55e23f6ee3b2c544d6a6b62ff3ff80d6bd3e376
3
+ metadata.gz: a1135858460f719a79d288fd6210011d1380f39ecedf817b06277aa400277e79
4
+ data.tar.gz: 5fa3c98c453be13419c9e3225d5cbeea81ee1103e77812a1097f251f29c4a39d
5
5
  SHA512:
6
- metadata.gz: 0eac21b1b1b73f3d3864c2cdb37c2f8df39c9be6841518b59282d5b89c8b64d54972c9c8b9318d35273250c9c740465d7c2156098e0629ee0df831a05ad41e2a
7
- data.tar.gz: 9b9991e147783643687d6c259c45c9ab45cfa009df5a60a23f1dce36571c5dc9a61d8a12bb70d57a79f30bf2288ed24933ea84e4a54c0df583b820ed54357cc6
6
+ metadata.gz: 6dffa44d4bb6dbe751fdb34c0f47ea2b371deae46e22b85da27dc0c2c57938d8203f593b0990cea379dc708d34c060173dff6c512e2603edc98808d9131b9026
7
+ data.tar.gz: 2df74769182891b2ef9926a89abf8e8487e4a734a87719ead05374c3bc6b52db53ec4b3f01186de03af60bbf5f54bb1a323a3803a908d78f106fbd3a3d874b90
data/lib/yoda/store.rb CHANGED
@@ -5,6 +5,7 @@ module Yoda
5
5
  require 'yoda/store/actions'
6
6
  require 'yoda/store/adapters'
7
7
  require 'yoda/store/project'
8
+ require 'yoda/store/registry_cache'
8
9
  require 'yoda/store/registry'
9
10
  require 'yoda/store/objects'
10
11
  require 'yoda/store/query'
@@ -1,3 +1,6 @@
1
+ require 'set'
2
+ require 'forwardable'
3
+
1
4
  module Yoda
2
5
  module Store
3
6
  module Objects
@@ -36,7 +39,7 @@ module Yoda
36
39
 
37
40
  # @return [Hash{ Symbol => Object }]
38
41
  def attributes
39
- @attributes ||= instances.map { |i| default_attributes.merge(i.to_h) }.reduce { |a, b| merge_attributes(a, b) }
42
+ @attributes ||= normalize_attributes(instances.map { |i| default_attributes.merge(i.to_h) }.reduce { |a, b| merge_attributes(a, b) })
40
43
  end
41
44
 
42
45
  # @param one [Hash{ Symbol => Object }]
@@ -45,15 +48,15 @@ module Yoda
45
48
  {
46
49
  path: one[:path] || another[:path],
47
50
  document: one[:document] + (one[:document].empty? || another[:document].empty? ? '' : "\n") + another[:document],
48
- tag_list: one[:tag_list] + another[:tag_list],
49
- sources: one[:sources] + another[:sources],
51
+ tag_list: PendingArray.append(one[:tag_list], another[:tag_list]),
52
+ sources: PendingSet.merge(one[:sources], another[:sources]),
50
53
  primary_source: one[:primary_source] || another[:primary_source],
51
- instance_method_addresses: (one[:instance_method_addresses] + another[:instance_method_addresses]).uniq,
52
- mixin_addresses: (one[:mixin_addresses] + another[:mixin_addresses]).uniq,
53
- constant_addresses: (one[:constant_addresses] + another[:constant_addresses]).uniq,
54
+ instance_method_addresses: PendingSet.merge(one[:instance_method_addresses], another[:instance_method_addresses]),
55
+ mixin_addresses: PendingSet.merge(one[:mixin_addresses], another[:mixin_addresses]),
56
+ constant_addresses: PendingSet.merge(one[:constant_addresses], another[:constant_addresses]),
54
57
  visibility: one[:visibility] || another[:visibility],
55
58
  parameters: one[:parameters].empty? ? another[:parameters] : one[:parameters],
56
- overloads: one[:overloads] + another[:overloads],
59
+ overloads: PendingArray.append(one[:overloads], another[:overloads]),
57
60
  superclass_path: select_superclass(one, another),
58
61
  value: one[:value] || another[:value],
59
62
  }
@@ -78,6 +81,26 @@ module Yoda
78
81
  }
79
82
  end
80
83
 
84
+ # @param attrs [Hash{ Symbol => Object }]
85
+ # @return [Hash{ Symbol => Object }]
86
+ def normalize_attributes(attrs)
87
+ {
88
+ path: attrs[:path],
89
+ document: attrs[:document],
90
+ tag_list: attrs[:tag_list].to_a,
91
+ sources: attrs[:sources].to_a,
92
+ primary_source: attrs[:primary_source],
93
+ instance_method_addresses: attrs[:instance_method_addresses].to_a,
94
+ mixin_addresses: attrs[:mixin_addresses].to_a,
95
+ constant_addresses: attrs[:constant_addresses].to_a,
96
+ visibility: attrs[:visibility],
97
+ parameters: attrs[:parameters].to_a,
98
+ overloads: attrs[:overloads].to_a,
99
+ superclass_path: attrs[:superclass_path],
100
+ value: attrs[:value],
101
+ }
102
+ end
103
+
81
104
  # @param one [Hash{ Symbol => Object }]
82
105
  # @param another [Hash{ Symbol => Object }]
83
106
  # @return [ScopedPath]
@@ -88,6 +111,66 @@ module Yoda
88
111
  another[:superclass_path] || one[:superclass_path]
89
112
  end
90
113
  end
114
+
115
+ class PendingArray
116
+ extend Forwardable
117
+
118
+ # @param els1 [Array<Object>, PendingArray]
119
+ # @param others [Array<Array<Object>, PendingArray>]
120
+ def self.append(els, *others)
121
+ if els.is_a?(PendingArray)
122
+ others.reduce(els) { |array, item| array.append(item) }
123
+ else
124
+ append(PendingArray.new(els), *others)
125
+ end
126
+ end
127
+
128
+ # @return [Array<Object>]
129
+ attr_reader :array
130
+
131
+ delegate %i(to_a each) => :array
132
+
133
+ # @param els [Array<Object>]
134
+ def initialize(els)
135
+ @array = els.dup
136
+ end
137
+
138
+ # @param els [Array<Object>]
139
+ def append(els)
140
+ array.push(*els)
141
+ self
142
+ end
143
+ end
144
+
145
+ class PendingSet
146
+ extend Forwardable
147
+
148
+ # @param els1 [Array<Object>, PendingSet]
149
+ # @param els2 [Array<Object>, PendingSet]
150
+ def self.merge(els1, els2)
151
+ if els1.is_a?(PendingSet)
152
+ els1.merge(els2)
153
+ else
154
+ PendingSet.new(els1).merge(els2)
155
+ end
156
+ end
157
+
158
+ # @return [Set<Object>]
159
+ attr_reader :set
160
+
161
+ delegate %i(to_a each) => :set
162
+
163
+ # @param els [Array<Object>]
164
+ def initialize(els)
165
+ @set = Set.new(els)
166
+ end
167
+
168
+ # @param els [Array<Object>]
169
+ def merge(els)
170
+ set.merge(els)
171
+ self
172
+ end
173
+ end
91
174
  end
92
175
  end
93
176
  end
@@ -9,9 +9,10 @@ module Yoda
9
9
  attr_reader :registry
10
10
 
11
11
  # @param id [String]
12
- def initialize(id)
12
+ # @param [Array[Addressable], nil]
13
+ def initialize(id, contents = nil)
13
14
  @id = id
14
- @registry = Hash.new
15
+ @registry = (contents || []).map { |content| [content.address.to_sym, content] }.to_h
15
16
  end
16
17
 
17
18
  # @param addressable [Addressable]
@@ -1,78 +1,110 @@
1
+ require 'set'
2
+
1
3
  module Yoda
2
4
  module Store
3
5
  module Objects
4
6
  # PatchSet manages patch updates and patch outdates.
5
7
  # Besides, this class provides api to modify objects by using owning patches.
6
8
  class PatchSet
7
- # @return [{ Symbol => Array<Symbol> }]
8
- attr_reader :address_index
9
+ class AddressIndex
10
+ def initialize
11
+ @index = Hash.new
12
+ end
9
13
 
10
- # @return [{ Symbol => Patch }]
11
- attr_reader :patches
14
+ # @param address [Symbol]
15
+ # @return [Set<Symbol>]
16
+ def get(address)
17
+ index[address] ||= Set.new
18
+ end
19
+
20
+ # @return [Set<Symbol>]
21
+ def keys
22
+ index.keys
23
+ end
24
+
25
+ # @param patch [Patch]
26
+ # @return [void]
27
+ def register(patch)
28
+ patch.keys.each do |key|
29
+ index[key.to_sym] ||= Set.new
30
+ index[key.to_sym].add(patch.id.to_sym)
31
+ end
32
+ end
33
+
34
+ # @param patch [Patch]
35
+ # @return [void]
36
+ def delete(patch)
37
+ patch.keys.each do |key|
38
+ (index[key.to_sym] || []).delete(patch.id.to_sym)
39
+ end
40
+ end
41
+
42
+ private
43
+ # @return [{ Symbol => Array<Symbol> }]
44
+ attr_reader :index
45
+ end
12
46
 
13
47
  def initialize
14
48
  @patches = Hash.new
15
- @address_index = Hash.new
49
+ @address_index = AddressIndex.new
16
50
  end
17
51
 
18
52
  # @param patch [Patch]
19
53
  # @return [void]
20
54
  def register(patch)
21
- register_to_index(patch)
55
+ address_index.register(patch)
22
56
  patches[patch.id.to_sym] = patch
23
57
  end
24
58
 
25
59
  # @param id [String, Symbol]
26
60
  def delete(id)
61
+ if patch = patches[id.to_sym]
62
+ address_index.delete(patch)
63
+ end
27
64
  patches.delete(id.to_sym)
28
65
  end
29
66
 
30
67
  # @param object [Addressable]
31
68
  # @return [Addressable]
32
69
  def patch(object)
33
- check_outdated_index(object.address.to_sym)
34
- objects_in_patch = (address_index[object.address.to_sym] || []).map { |patch_id| patches[patch_id].find(object.address.to_sym) }
70
+ objects_in_patch = get_patches(object.address)
35
71
  Merger.new([object, *objects_in_patch]).merged_instance
36
72
  end
37
73
 
38
74
  # @param address [String, Symbol]
39
75
  # @return [Addressable, nil]
40
76
  def find(address)
41
- check_outdated_index(address.to_sym)
42
- if (patch_ids = address_index[address.to_sym] || []).empty?
77
+ if (patches = get_patches(address)).empty?
43
78
  nil
44
79
  else
45
- objects = patch_ids.map { |id| patches[id].find(address.to_sym) }
46
- Merger.new(objects).merged_instance
80
+ Merger.new(patches).merged_instance
47
81
  end
48
82
  end
49
83
 
50
84
  # @return [Array<Symbol>]
51
85
  def keys
52
- address_index.keys
86
+ address_index.keys.to_a
53
87
  end
54
88
 
55
89
  # @param address [String, Symbol]
56
90
  # @return [true, false]
57
91
  def has_key?(address)
58
- check_outdated_index(address.to_sym)
59
- address_index[address.to_sym] && !address_index[address.to_sym].empty?
92
+ !address_index.get(address.to_sym).empty?
60
93
  end
61
94
 
62
95
  private
63
96
 
64
- # @param patch [Patch]
65
- # @return [void]
66
- def register_to_index(patch)
67
- patch.keys.each do |key|
68
- address_index[key.to_sym] ||= []
69
- address_index[key.to_sym].push(patch.id.to_sym)
70
- end
71
- end
97
+ # @return [AddressIndex]
98
+ attr_reader :address_index
99
+
100
+ # @return [{ Symbol => Patch }]
101
+ attr_reader :patches
72
102
 
73
- # @param address [Symbol]
74
- def check_outdated_index(address)
75
- (address_index[address] || []).select! { |patch_id| patches[patch_id].has_key?(address) }
103
+ # @param address [String, Symbol]
104
+ # @return [Array<Patch>]
105
+ def get_patches(address)
106
+ patch_ids = address_index.get(address.to_sym)
107
+ patch_ids.map { |id| patches[id].find(address.to_sym) }
76
108
  end
77
109
  end
78
110
  end
@@ -12,6 +12,8 @@ module Yoda
12
12
  def initialize(adapter = nil)
13
13
  @patch_set = Objects::PatchSet.new
14
14
  @adapter = adapter
15
+ @registry_cache = RegistryCache.new
16
+ @lock = Concurrent::ReentrantReadWriteLock.new
15
17
  end
16
18
 
17
19
  # @return [Objects::ProjectStatus, nil]
@@ -32,10 +34,12 @@ module Yoda
32
34
  # @return [Objects::Base, nil]
33
35
  def find(path)
34
36
  lock.with_read_lock do
35
- if adapter&.exist?(path)
36
- patch_set.patch(adapter.get(path))
37
- else
38
- patch_set.find(path)
37
+ registry_cache.fetch_or_calc(path) do
38
+ if adapter&.exist?(path)
39
+ patch_set.patch(adapter.get(path))
40
+ else
41
+ patch_set.find(path)
42
+ end
39
43
  end
40
44
  end
41
45
  end
@@ -43,6 +47,7 @@ module Yoda
43
47
  # @param patch [Patch]
44
48
  def add_patch(patch)
45
49
  lock.with_write_lock do
50
+ registry_cache.clear_from_patch(patch)
46
51
  patch_set.register(patch)
47
52
  end
48
53
  end
@@ -57,6 +62,7 @@ module Yoda
57
62
 
58
63
  def clear
59
64
  lock.with_write_lock do
65
+ registry_cache.delete_all
60
66
  adapter.clear
61
67
  end
62
68
  end
@@ -77,6 +83,7 @@ module Yoda
77
83
  adapter.sync
78
84
  Logger.info "saved #{el_keys.length} keys."
79
85
  @patch_set = Objects::PatchSet.new
86
+ registry_cache.delete_all
80
87
  end
81
88
  end
82
89
 
@@ -88,10 +95,11 @@ module Yoda
88
95
  # @return [Objects::PatchSet]
89
96
  attr_reader :patch_set
90
97
 
98
+ # @return [RegistryCache]
99
+ attr_reader :registry_cache
100
+
91
101
  # @return [Concurrent::ReentrantReadWriteLock]
92
- def lock
93
- @lock ||= Concurrent::ReentrantReadWriteLock.new
94
- end
102
+ attr_reader :lock
95
103
 
96
104
  def keys
97
105
  Set.new(adapter&.keys.map(&:to_s) || []).union(patch_set.keys)
@@ -0,0 +1,40 @@
1
+ require 'concurrent'
2
+
3
+ module Yoda
4
+ module Store
5
+ # Registry Cache is a cache layer for {Registry}.
6
+ # This class intended to reduce patch calculations of {PatchSet#patch}.
7
+ class RegistryCache
8
+ def initialize
9
+ @data = Concurrent::Map.new
10
+ end
11
+
12
+ # @param key [String, Symbol]
13
+ def fetch_or_calc(key)
14
+ if cache = data.get(key.to_sym)
15
+ return cache
16
+ end
17
+ yield.tap { |value| data.put_if_absent(key.to_sym, value) }
18
+ end
19
+
20
+ # @param key [String, Symbol]
21
+ def delete(key)
22
+ data.delete(key.to_sym)
23
+ end
24
+
25
+ def delete_all
26
+ data.clear
27
+ end
28
+
29
+ # @param patch [Objects::Patch]
30
+ def clear_from_patch(patch)
31
+ patch.keys.each { |key| delete(key) }
32
+ end
33
+
34
+ private
35
+
36
+ # @return [Concurrent::Map]
37
+ attr_reader :data
38
+ end
39
+ end
40
+ end
data/lib/yoda/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yoda
2
- VERSION = "0.7.0"
2
+ VERSION = "0.7.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yoda-language-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomoya Chiba
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-09-28 00:00:00.000000000 Z
11
+ date: 2018-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yard
@@ -446,6 +446,7 @@ files:
446
446
  - lib/yoda/store/query/find_method.rb
447
447
  - lib/yoda/store/query/find_signature.rb
448
448
  - lib/yoda/store/registry.rb
449
+ - lib/yoda/store/registry_cache.rb
449
450
  - lib/yoda/store/yard_importer.rb
450
451
  - lib/yoda/typing.rb
451
452
  - lib/yoda/typing/context.rb