yoda-language-server 0.7.0 → 0.7.1

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