solargraph 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,25 +27,22 @@ module Solargraph
27
27
  Server.prepare_workspace params['workspace']
28
28
  { "status" => "ok"}.to_json
29
29
  rescue Exception => e
30
- STDERR.puts e
31
- STDERR.puts e.backtrace.join("\n")
32
- { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
30
+ send_exception e
33
31
  end
34
32
  end
35
33
 
36
34
  post '/update' do
37
35
  content_type :json
38
36
  begin
37
+ workspace = find_local_workspace(params['filename'], params['workspace'])
39
38
  # @type [Solargraph::ApiMap]
40
- api_map = get_api_map(params['workspace'])
39
+ api_map = get_api_map(workspace)
41
40
  unless api_map.nil?
42
41
  api_map.update params['filename']
43
42
  end
44
43
  { "status" => "ok"}.to_json
45
44
  rescue Exception => e
46
- STDERR.puts e
47
- STDERR.puts e.backtrace.join("\n")
48
- { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
45
+ send_exception e
49
46
  end
50
47
  end
51
48
 
@@ -53,17 +50,15 @@ module Solargraph
53
50
  content_type :json
54
51
  begin
55
52
  sugg = []
56
- workspace = params['workspace']
53
+ workspace = find_local_workspace(params['filename'], params['workspace'])
57
54
  api_map = get_api_map(workspace)
58
55
  with_all = params['all'] == '1' ? true : false
59
56
  code_map = CodeMap.new(code: params['text'], filename: params['filename'], api_map: api_map, cursor: [params['line'].to_i, params['column'].to_i])
60
57
  offset = code_map.get_offset(params['line'].to_i, params['column'].to_i)
61
- sugg = code_map.suggest_at(offset, with_snippets: params['with_snippets'] == '1' ? true : false, filtered: true)
58
+ sugg = code_map.suggest_at(offset, filtered: true)
62
59
  JSON.generate({ "status" => "ok", "suggestions" => sugg.map{|s| s.as_json(all: with_all)} })
63
60
  rescue Exception => e
64
- STDERR.puts e
65
- STDERR.puts e.backtrace.join("\n")
66
- { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
61
+ send_exception e
67
62
  end
68
63
  end
69
64
 
@@ -71,23 +66,21 @@ module Solargraph
71
66
  content_type :json
72
67
  begin
73
68
  sugg = []
74
- workspace = params['workspace'] || nil
69
+ workspace = find_local_workspace(params['filename'], params['workspace'])
75
70
  api_map = get_api_map(workspace)
76
71
  code_map = CodeMap.new(code: params['text'], filename: params['filename'], api_map: api_map, cursor: [params['line'].to_i, params['column'].to_i])
77
72
  offset = code_map.get_offset(params['line'].to_i, params['column'].to_i)
78
73
  sugg = code_map.signatures_at(offset)
79
74
  { "status" => "ok", "suggestions" => sugg.map{|s| s.as_json(all: true)} }.to_json
80
75
  rescue Exception => e
81
- STDERR.puts e
82
- STDERR.puts e.backtrace.join("\n")
83
- { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
76
+ send_exception e
84
77
  end
85
78
  end
86
79
 
87
80
  post '/resolve' do
88
81
  content_type :json
89
82
  begin
90
- workspace = params['workspace'] || nil
83
+ workspace = find_local_workspace(params['filename'], params['workspace'])
91
84
  result = []
92
85
  api_map = get_api_map(workspace)
93
86
  unless api_map.nil?
@@ -96,26 +89,38 @@ module Solargraph
96
89
  end
97
90
  { "status" => "ok", "suggestions" => result.map{|s| s.as_json(all: true)} }.to_json
98
91
  rescue Exception => e
99
- STDERR.puts e
100
- STDERR.puts e.backtrace.join("\n")
101
- { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
92
+ send_exception e
93
+ end
94
+ end
95
+
96
+ post '/define' do
97
+ content_type :json
98
+ begin
99
+ sugg = []
100
+ workspace = find_local_workspace(params['filename'], params['workspace'])
101
+ api_map = get_api_map(workspace)
102
+ code_map = CodeMap.new(code: params['text'], filename: params['filename'], api_map: @@api_hash[workspace], cursor: [params['line'].to_i, params['column'].to_i])
103
+ offset = code_map.get_offset(params['line'].to_i, params['column'].to_i)
104
+ sugg = code_map.define_symbol_at(offset)
105
+ { "status" => "ok", "suggestions" => sugg }.to_json
106
+ rescue Exception => e
107
+ send_exception e
102
108
  end
103
109
  end
104
110
 
111
+ # @deprecated Use /define instead.
105
112
  post '/hover' do
106
113
  content_type :json
107
114
  begin
108
115
  sugg = []
109
- workspace = params['workspace'] || nil
116
+ workspace = find_local_workspace(params['filename'], params['workspace'])
110
117
  api_map = get_api_map(workspace)
111
118
  code_map = CodeMap.new(code: params['text'], filename: params['filename'], api_map: @@api_hash[workspace], cursor: [params['line'].to_i, params['column'].to_i])
112
119
  offset = code_map.get_offset(params['line'].to_i, params['column'].to_i)
113
120
  sugg = code_map.resolve_object_at(offset)
114
121
  { "status" => "ok", "suggestions" => sugg }.to_json
115
122
  rescue Exception => e
116
- STDERR.puts e
117
- STDERR.puts e.backtrace.join("\n")
118
- { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
123
+ send_exception e
119
124
  end
120
125
  end
121
126
 
@@ -128,6 +133,7 @@ module Solargraph
128
133
 
129
134
  get '/document' do
130
135
  workspace = params['workspace']
136
+ workspace.gsub!(/\\/, '/') unless workspace.nil?
131
137
  api_map = get_api_map(workspace) || Solargraph::ApiMap.new
132
138
  @objects = api_map.document(params['query'])
133
139
  erb :document
@@ -161,28 +167,61 @@ module Solargraph
161
167
  h.html_markup_ruby(code)
162
168
  end
163
169
 
170
+ def send_exception e
171
+ STDERR.puts e
172
+ STDERR.puts e.backtrace.join("\n")
173
+ { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
174
+ end
175
+
176
+ def find_local_workspace file, workspace
177
+ workspace.gsub!(/\\/, '/') unless workspace.nil?
178
+ unless file.nil? or workspace.nil?
179
+ file.gsub!(/\\/, '/') unless file.nil?
180
+ return nil unless file.start_with?(workspace)
181
+ dir = File.dirname(file)
182
+ while dir.start_with?(workspace)
183
+ return dir if @@api_hash.has_key?(dir)
184
+ dir = File.dirname(dir)
185
+ end
186
+ end
187
+ workspace
188
+ end
189
+
164
190
  class << self
165
191
  def prepare_workspace directory
192
+ return if directory.nil?
166
193
  Thread.new do
167
- api_map = Solargraph::ApiMap.new(directory)
168
- api_map.yard_map
169
- @@semaphore.synchronize do
170
- @@api_hash[directory] = api_map
194
+ directory.gsub!(/\\/, '/') unless directory.nil?
195
+ configs = Dir[File.join(directory, '**', '.solargraph.yml')]
196
+ resolved = []
197
+ configs.each do |cf|
198
+ dir = File.dirname(cf)
199
+ generate_api_map dir
200
+ resolved.push dir
171
201
  end
202
+ generate_api_map directory unless resolved.include?(directory)
203
+ end
204
+ end
205
+
206
+ def generate_api_map(directory)
207
+ api_map = Solargraph::ApiMap.new(directory)
208
+ api_map.yard_map
209
+ @@semaphore.synchronize do
210
+ @@api_hash[directory] = api_map
172
211
  end
173
212
  end
174
213
 
175
214
  def run!
176
215
  Thread.new do
177
216
  while true
178
- watch_workspaces
217
+ check_workspaces
179
218
  sleep 1
180
219
  end
181
220
  end
182
221
  super
183
222
  end
184
223
 
185
- def watch_workspaces
224
+ def check_workspaces
186
225
  @@semaphore.synchronize do
187
226
  changed = {}
188
227
  @@api_hash.each_pair do |w, a|
@@ -56,7 +56,7 @@ module Solargraph
56
56
  begin
57
57
  code_map = CodeMap.new(code: text, filename: filename)
58
58
  offset = code_map.get_offset(options[:line], options[:column])
59
- sugg = code_map.suggest_at(offset, with_snippets: true, filtered: true)
59
+ sugg = code_map.suggest_at(offset, filtered: true)
60
60
  result = { "status" => "ok", "suggestions" => sugg }.to_json
61
61
  STDOUT.puts result
62
62
  rescue Exception => e
@@ -11,7 +11,6 @@ module Solargraph
11
11
  METHOD = 'Method'
12
12
  MODULE = 'Module'
13
13
  PROPERTY = 'Property'
14
- SNIPPET = 'Snippet'
15
14
  VARIABLE = 'Variable'
16
15
 
17
16
  # @return [String]
@@ -65,6 +64,10 @@ module Solargraph
65
64
  @path ||= (code_object.nil? ? label : code_object.path)
66
65
  end
67
66
 
67
+ def namespace
68
+ @namespace ||= path.split(/[#\.]/)[0]
69
+ end
70
+
68
71
  # @return [String]
69
72
  def to_s
70
73
  label
@@ -114,7 +117,8 @@ module Solargraph
114
117
  #
115
118
  # @return [Boolean]
116
119
  def has_doc?
117
- !documentation.empty?
120
+ #!documentation.empty?
121
+ !docstring.nil? and !docstring.all.empty?
118
122
  end
119
123
 
120
124
  def as_json args = {}
@@ -142,7 +146,7 @@ module Solargraph
142
146
  #
143
147
  # @param pin [Solargraph::Pin::Base]
144
148
  def self.pull pin, return_type = nil
145
- Suggestion.new(pin.name, insert: pin.name.gsub(/=/, ' = '), kind: pin.kind, docstring: pin.docstring, detail: pin.namespace, arguments: pin.parameters, path: pin.path, return_type: return_type || pin.return_type, location: pin.location)
149
+ Suggestion.new(pin.name, insert: pin.name.gsub(/=$/, ' = '), kind: pin.kind, docstring: pin.docstring, detail: pin.namespace, arguments: pin.parameters, path: pin.path, return_type: return_type || pin.return_type, location: pin.location)
146
150
  end
147
151
  end
148
152
  end
@@ -1,3 +1,3 @@
1
1
  module Solargraph
2
- VERSION = '0.16.0'
2
+ VERSION = '0.17.0'
3
3
  end
@@ -8,7 +8,7 @@ module Solargraph
8
8
  module CoreDocs
9
9
  class SourceNotAvailableError < StandardError;end
10
10
 
11
- SOURCE = 'http://solargraph.org/download'
11
+ SOURCE = 'https://solargraph.org/download'
12
12
 
13
13
  class << self
14
14
  def cache_dir
@@ -1,4 +1,5 @@
1
1
  require 'yard'
2
+ require 'bundler'
2
3
 
3
4
  module Solargraph
4
5
  class YardMap
@@ -18,24 +19,17 @@ module Solargraph
18
19
 
19
20
  def initialize required: [], workspace: nil
20
21
  @workspace = workspace
21
- used = []
22
22
  # HACK: YardMap needs its own copy of this array
23
23
  @required = required.clone
24
24
  @namespace_yardocs = {}
25
- @required.each do |r|
26
- if workspace.nil? or !File.exist?(File.join workspace, 'lib', "#{r}.rb")
27
- g = r.split('/').first
28
- unless used.include?(g)
29
- used.push g
30
- gy = YARD::Registry.yardoc_file_for_gem(g)
31
- if gy.nil?
32
- STDERR.puts "Required path not found: #{r}"
33
- else
34
- yardocs.unshift gy
35
- add_gem_dependencies g
36
- end
25
+ if !workspace.nil? and File.exist?(File.join workspace, 'Gemfile')
26
+ Bundler.with_clean_env do
27
+ Bundler.environment.chdir(workspace) do
28
+ process_requires
37
29
  end
38
30
  end
31
+ else
32
+ process_requires
39
33
  end
40
34
  yardocs.push CoreDocs.yardoc_file
41
35
  yardocs.uniq!
@@ -154,11 +148,11 @@ module Solargraph
154
148
  ns = find_first_resolved_namespace(yard, namespace, scope)
155
149
  unless ns.nil?
156
150
  ns.meths(scope: :class, visibility: visibility).each { |m|
157
- n = m.to_s.split(/[\.#]/).last.gsub(/=/, ' = ')
151
+ n = m.to_s.split(/[\.#]/).last.gsub(/=$/, ' = ')
158
152
  label = "#{n}"
159
153
  args = get_method_args(m)
160
154
  kind = (m.is_attribute? ? Suggestion::FIELD : Suggestion::METHOD)
161
- meths.push Suggestion.new(label, insert: "#{n.gsub(/=/, ' = ')}", kind: kind, docstring: m.docstring, code_object: m, detail: "#{ns}", location: "#{m.file}:#{m.line}", arguments: args)
155
+ meths.push Suggestion.new(label, insert: n, kind: kind, docstring: m.docstring, code_object: m, detail: "#{ns}", location: object_location(m), arguments: args)
162
156
  }
163
157
  # Collect superclass methods
164
158
  if ns.kind_of?(YARD::CodeObjects::ClassObject) and !ns.superclass.nil?
@@ -172,7 +166,7 @@ module Solargraph
172
166
  meths.delete_if{|m| m.label == 'new'}
173
167
  label = "#{i}"
174
168
  args = get_method_args(i)
175
- meths.push Suggestion.new('new', kind: Suggestion::METHOD, docstring: i.docstring, code_object: i, detail: "#{ns}", location: "#{i.file}:#{i.line}", arguments: args)
169
+ meths.push Suggestion.new('new', kind: Suggestion::METHOD, docstring: i.docstring, code_object: i, detail: "#{ns}", location: object_location(i), arguments: args)
176
170
  end
177
171
  end
178
172
  end
@@ -197,11 +191,13 @@ module Solargraph
197
191
  unless ns.nil?
198
192
  ns.meths(scope: :instance, visibility: visibility).each { |m|
199
193
  n = m.to_s.split(/[\.#]/).last
200
- if n.to_s.match(/^[a-z]/i) and (namespace == 'Kernel' or !m.to_s.start_with?('Kernel#')) and !m.docstring.to_s.include?(':nodoc:')
194
+ # @todo Return method names like []?
195
+ #if n.to_s.match(/^[a-z]/i) and (namespace == 'Kernel' or !m.to_s.start_with?('Kernel#')) and !m.docstring.to_s.include?(':nodoc:')
196
+ if (namespace == 'Kernel' or !m.to_s.start_with?('Kernel#')) and !m.docstring.to_s.include?(':nodoc:')
201
197
  label = "#{n}"
202
198
  args = get_method_args(m)
203
199
  kind = (m.is_attribute? ? Suggestion::FIELD : Suggestion::METHOD)
204
- meths.push Suggestion.new(label, insert: "#{n.gsub(/=/, ' = ')}", kind: kind, docstring: m.docstring, code_object: m, detail: m.namespace, location: "#{m.file}:#{m.line}", arguments: args)
200
+ meths.push Suggestion.new(label, insert: "#{n.gsub(/=$/, ' = ')}", kind: kind, docstring: m.docstring, code_object: m, detail: m.namespace, location: object_location(m), arguments: args)
205
201
  end
206
202
  }
207
203
  if ns.kind_of?(YARD::CodeObjects::ClassObject) and namespace != 'Object'
@@ -361,6 +357,53 @@ module Solargraph
361
357
  end
362
358
  end
363
359
 
360
+ def process_requires
361
+ used = []
362
+ @required.each do |r|
363
+ if workspace.nil? or !File.exist?(File.join workspace, 'lib', "#{r}.rb")
364
+ unless used.include?(r)
365
+ used.push r
366
+ result = find_yardoc(r)
367
+ if result.nil?
368
+ STDERR.puts "Required path not found: #{r}"
369
+ else
370
+ yardocs.unshift result unless yardocs.include?(result)
371
+ end
372
+ end
373
+ end
374
+ end
375
+ end
376
+
377
+ def find_yardoc path
378
+ result = nil
379
+ spec = Gem::Specification.find_by_path(path)
380
+ result = YARD::Registry.yardoc_file_for_gem(spec.name) unless spec.nil?
381
+ if result.nil?
382
+ $LOAD_PATH.each do |base|
383
+ source_file = File.join(base, "#{path}.rb")
384
+ if File.exist?(source_file)
385
+ if base.start_with?(Bundler.bundle_path.to_s)
386
+ match = File.dirname(base).split('/').last.match(/^([a-z0-9\-_]*?)-([0-9]+\.[0-9]+\.[0-9]+)/i)
387
+ unless match.nil? or match[1].nil?
388
+ result = YARD::Registry.yardoc_file_for_gem(match[1])
389
+ add_gem_dependencies match[1]
390
+ break
391
+ end
392
+ end
393
+ yp = File.join(File.dirname(base), '.yardoc')
394
+ if File.exist?(yp)
395
+ result = yp
396
+ break
397
+ else
398
+ # @todo Keep trying?
399
+ end
400
+ break
401
+ end
402
+ end
403
+ end
404
+ result
405
+ end
406
+
364
407
  def add_gem_dependencies gem_name
365
408
  spec = Gem::Specification.find_by_name(gem_name)
366
409
  (spec.dependencies - spec.development_dependencies).each do |dep|
@@ -368,8 +411,7 @@ module Solargraph
368
411
  if gy.nil?
369
412
  STDERR.puts "Required path not found: #{dep.name}"
370
413
  else
371
- #STDERR.puts "Adding #{gy}"
372
- yardocs.unshift gy
414
+ yardocs.unshift gy unless yardocs.include?(gy)
373
415
  end
374
416
  end
375
417
  end
@@ -396,5 +438,14 @@ module Solargraph
396
438
  result.push @@stdlib_yardoc if result.empty? and @@stdlib_namespaces.include?(namespace)
397
439
  result
398
440
  end
441
+
442
+ # @param obj [YARD::CodeObjects::Base]
443
+ def object_location obj
444
+ # @todo Locations from YardMaps are temporarily disabled pending a
445
+ # method for resolving the source file's absolute path.
446
+ return nil
447
+ return nil if obj.file.nil? or obj.line.nil?
448
+ "#{obj.file}:#{obj.line - 1}:0"
449
+ end
399
450
  end
400
451
  end
data/lib/solargraph.rb CHANGED
@@ -8,13 +8,13 @@ module Solargraph
8
8
  autoload :CodeMap, 'solargraph/code_map'
9
9
  autoload :NodeMethods, 'solargraph/node_methods'
10
10
  autoload :Suggestion, 'solargraph/suggestion'
11
- autoload :Snippets, 'solargraph/snippets'
12
11
  autoload :Server, 'solargraph/server'
13
12
  autoload :YardMap, 'solargraph/yard_map'
14
13
  autoload :Pin, 'solargraph/pin'
15
14
  autoload :LiveMap, 'solargraph/live_map'
16
15
  autoload :ServerMethods, 'solargraph/server_methods'
17
16
  autoload :Plugin, 'solargraph/plugin'
17
+ autoload :CoreFills, 'solargraph/core_fills'
18
18
 
19
19
  YARDOC_PATH = File.join(File.realpath(File.dirname(__FILE__)), '..', 'yardoc')
20
20
  YARD_EXTENSION_FILE = File.join(File.realpath(File.dirname(__FILE__)), 'yard-solargraph.rb')
@@ -1,4 +1,6 @@
1
1
  require 'yard'
2
2
 
3
- # Define a @type tag to be used for documenting variables
3
+ # Define a @type tag for documenting variables
4
4
  YARD::Tags::Library.define_tag("Type", :type, :with_types_and_name)
5
+ # Define a @yieldself tag for documenting block contexts
6
+ YARD::Tags::Library.define_tag("Yieldself", :yieldself, :with_types)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solargraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-17 00:00:00.000000000 Z
11
+ date: 2018-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -170,6 +170,7 @@ executables:
170
170
  extensions: []
171
171
  extra_rdoc_files: []
172
172
  files:
173
+ - ".yardopts"
173
174
  - bin/solargraph
174
175
  - bin/solargraph-runtime
175
176
  - lib/solargraph.rb
@@ -179,6 +180,7 @@ files:
179
180
  - lib/solargraph/api_map/source.rb
180
181
  - lib/solargraph/api_map/source_to_yard.rb
181
182
  - lib/solargraph/code_map.rb
183
+ - lib/solargraph/core_fills.rb
182
184
  - lib/solargraph/live_map.rb
183
185
  - lib/solargraph/live_map/cache.rb
184
186
  - lib/solargraph/node_methods.rb
@@ -206,7 +208,6 @@ files:
206
208
  - lib/solargraph/server.rb
207
209
  - lib/solargraph/server_methods.rb
208
210
  - lib/solargraph/shell.rb
209
- - lib/solargraph/snippets.rb
210
211
  - lib/solargraph/suggestion.rb
211
212
  - lib/solargraph/version.rb
212
213
  - lib/solargraph/views/_method.erb
@@ -1,186 +0,0 @@
1
- require 'json'
2
-
3
- module Solargraph
4
- module Snippets
5
- def self.definitions
6
- @definitions ||= JSON.parse('{
7
- "Exception block": {
8
- "prefix": "begin",
9
- "body": [
10
- "begin",
11
- "\t$1",
12
- "rescue => exception",
13
- "\t",
14
- "end"
15
- ]
16
- },
17
- "Exception block with ensure": {
18
- "prefix": "begin ensure",
19
- "body": [
20
- "begin",
21
- "\t$1",
22
- "rescue => exception",
23
- "\t",
24
- "ensure",
25
- "\t",
26
- "end"
27
- ]
28
- },
29
- "Exception block with else": {
30
- "prefix": "begin else",
31
- "body": [
32
- "begin",
33
- "\t$1",
34
- "rescue => exception",
35
- "\t",
36
- "else",
37
- "\t",
38
- "end"
39
- ]
40
- },
41
- "Exception block with else and ensure": {
42
- "prefix": "begin else ensure",
43
- "body": [
44
- "begin",
45
- "\t$1",
46
- "rescue => exception",
47
- "\t",
48
- "else",
49
- "\t",
50
- "ensure",
51
- "\t",
52
- "end"
53
- ]
54
- },
55
- "Class definition with initialize": {
56
- "prefix": "class init",
57
- "body": [
58
- "class ${ClassName}",
59
- "\tdef initialize",
60
- "\t\t$0",
61
- "\tend",
62
- "end"
63
- ]
64
- },
65
- "Class definition": {
66
- "prefix": "class",
67
- "body": [
68
- "class ${ClassName}",
69
- "\t$0",
70
- "end"
71
- ]
72
- },
73
- "for loop": {
74
- "prefix": "for",
75
- "body": [
76
- "for ${value} in ${enumerable} do",
77
- "\t$0",
78
- "end"
79
- ]
80
- },
81
- "if": {
82
- "prefix": "if",
83
- "body": [
84
- "if ${test}",
85
- "\t$0",
86
- "end"
87
- ]
88
- },
89
- "if else": {
90
- "prefix": "if else",
91
- "body": [
92
- "if ${test}",
93
- "\t$0",
94
- "else",
95
- "\t",
96
- "end"
97
- ]
98
- },
99
- "if elsif": {
100
- "prefix": "if elsif",
101
- "body": [
102
- "if ${test}",
103
- "\t$0",
104
- "elsif ",
105
- "\t",
106
- "end"
107
- ]
108
- },
109
- "if elsif else": {
110
- "prefix": "if elsif else",
111
- "body": [
112
- "if ${test}",
113
- "\t$0",
114
- "elsif ",
115
- "\t",
116
- "else",
117
- "\t",
118
- "end"
119
- ]
120
- },
121
- "forever loop": {
122
- "prefix": "loop",
123
- "body": [
124
- "loop do",
125
- "\t$0",
126
- "end"
127
- ]
128
- },
129
- "Module definition": {
130
- "prefix": "module",
131
- "body": [
132
- "module ${ModuleName}",
133
- "\t$0",
134
- "end"
135
- ]
136
- },
137
- "unless": {
138
- "prefix": "unless",
139
- "body": [
140
- "unless ${test}",
141
- "\t$0",
142
- "end"
143
- ]
144
- },
145
- "until loop": {
146
- "prefix": "until",
147
- "body": [
148
- "until ${test}",
149
- "\t$0",
150
- "end"
151
- ]
152
- },
153
- "while loop": {
154
- "prefix": "while",
155
- "body": [
156
- "while ${test}",
157
- "\t$0",
158
- "end"
159
- ]
160
- },
161
- "method definition": {
162
- "prefix": "def",
163
- "body": [
164
- "def ${method_name}",
165
- "\t$0",
166
- "end"
167
- ],
168
- "description": "Snippet for method definitions"
169
- },
170
- "defined?": {
171
- "prefix": "defined?",
172
- "body": [
173
- "defined?"
174
- ],
175
- "description": "Something silly"
176
- }
177
- }')
178
- end
179
-
180
- def self.keywords
181
- @keywords ||= [
182
- 'begin', 'class', 'for', 'if', 'module', 'unless', 'until', 'while', 'def', 'defined?'
183
- ]
184
- end
185
- end
186
- end