robe-server 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ ## Robe server
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/robe-server.svg)](https://badge.fury.io/rb/robe-server)
4
+ [![Build Status](https://travis-ci.org/AfsmNGhr/robe-server.svg?branch=master)](https://travis-ci.org/AfsmNGhr/robe-server "Build status from Travis CI")
5
+ [![Coverage Status](https://coveralls.io/repos/github/AfsmNGhr/robe-server/badge.svg?branch=master)](https://coveralls.io/github/AfsmNGhr/robe-server?branch=master)
6
+
7
+ Server for [robe](https://github.com/dgutov/robe)
8
+
9
+ ## Install
10
+
11
+ ```.ruby
12
+ # Gemfile
13
+
14
+ gem 'robe-server'
15
+ ```
16
+
17
+ or
18
+
19
+ ```.bash
20
+ $ gem install robe-server
21
+ ```
@@ -0,0 +1,10 @@
1
+ require 'rake'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new do |t|
5
+ t.verbose = false
6
+ t.fail_on_error = false
7
+ end
8
+
9
+ RSpec::Core::RakeTask.new(:spec)
10
+ task default: :spec
@@ -0,0 +1,39 @@
1
+ require 'robe/sash'
2
+ require 'robe/server'
3
+
4
+ module Robe
5
+ class << self
6
+ attr_accessor :server
7
+
8
+ def start(port = 0)
9
+ return running_string if @server
10
+
11
+ @server = Server.new(Sash.new, port)
12
+
13
+ ['INT', 'TERM'].each do |signal|
14
+ trap(signal) { stop }
15
+ end
16
+ Thread.new do
17
+ unless Thread.current[:__yard_registry__]
18
+ Thread.current[:__yard_registry__] = Thread.main[:__yard_registry__]
19
+ end
20
+ @server.start
21
+ end
22
+
23
+ @server.wait_for_it
24
+
25
+ running_string
26
+ end
27
+
28
+ def stop
29
+ @server.shutdown
30
+ @server = nil
31
+ end
32
+
33
+ private
34
+
35
+ def running_string
36
+ "robe on #{@server.port}"
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,37 @@
1
+ class Module
2
+ unless method_defined?(:__name__)
3
+ alias_method :__name__, :name
4
+ end
5
+
6
+ if method_defined?(:singleton_class?)
7
+ alias_method :__singleton_class__?, :singleton_class?
8
+ else
9
+ def __singleton_class__?
10
+ self != Class && ancestors.first != self
11
+ end
12
+ end
13
+
14
+ unless method_defined?(:__singleton_class__)
15
+ alias_method :__singleton_class__, :singleton_class
16
+ end
17
+
18
+ unless method_defined?(:__include__?)
19
+ alias_method :__include__?, :include?
20
+ end
21
+
22
+ unless method_defined?(:__instance_methods__)
23
+ alias_method :__instance_methods__, :instance_methods
24
+ end
25
+
26
+ unless method_defined?(:__public_instance_methods__)
27
+ alias_method :__public_instance_methods__, :public_instance_methods
28
+ end
29
+
30
+ unless method_defined?(:__protected_instance_methods__)
31
+ alias_method :__protected_instance_methods__, :protected_instance_methods
32
+ end
33
+
34
+ unless method_defined?(:__private_instance_methods__)
35
+ alias_method :__private_instance_methods__, :private_instance_methods
36
+ end
37
+ end
@@ -0,0 +1,14 @@
1
+ require 'robe/visor'
2
+
3
+ module Robe
4
+ class JVisor < Visor
5
+ def each_object(mod)
6
+ # http://jira.codehaus.org/browse/JRUBY-7027
7
+ ObjectSpace.each_object(mod).select { |m| m.respond_to? :name }
8
+ end
9
+
10
+ def descendants(cls)
11
+ ObjectSpace.each_object(Class).select { |c| c < cls }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,215 @@
1
+ require 'robe/sash/doc_for'
2
+ require 'robe/type_space'
3
+ require 'robe/scanners'
4
+ require 'robe/visor'
5
+ require 'robe/jvisor'
6
+ require 'robe/core_ext'
7
+ require 'robe/sash/includes_tracker'
8
+
9
+ module Robe
10
+ class Sash
11
+ attr_accessor :visor, :name_cache
12
+
13
+ def initialize(visor = pick_visor)
14
+ @visor = visor
15
+ init_name_cache
16
+ end
17
+
18
+ def class_locations(name, mod)
19
+ locations = {}
20
+ if (obj = visor.resolve_context(name, mod)) and obj.is_a? Module
21
+ methods = obj.methods(false).map { |m| obj.method(m) } +
22
+ obj.__instance_methods__(false).map { |m| obj.instance_method(m) }
23
+ methods.each do |m|
24
+ if loc = m.source_location
25
+ path = loc[0]
26
+ locations[path] ||= 0
27
+ locations[path] += 1
28
+ end
29
+ end
30
+ end
31
+ if defined? Class.class_attribute and Class != obj
32
+ locations.delete Class.method(:class_attribute).source_location[0]
33
+ end
34
+ locations.keys.sort { |k1, k2| -(locations[k1] <=> locations[k2]) }
35
+ end
36
+
37
+ def modules
38
+ visor.each_object(Module).map { |mod| name_cache[mod] }.compact
39
+ end
40
+
41
+ def targets(obj)
42
+ obj = visor.resolve_const(obj)
43
+ if obj.is_a? Module
44
+ module_methods = obj.methods.map { |m| method_spec(obj.method(m)) }
45
+ instance_methods = (obj.__instance_methods__ +
46
+ obj.__private_instance_methods__(false))
47
+ .map { |m| method_spec(obj.instance_method(m)) }
48
+ [name_cache[obj]] + module_methods + instance_methods
49
+ else
50
+ self.targets(obj.class.to_s)
51
+ end
52
+ end
53
+
54
+ def find_method(mod, inst, sym)
55
+ mod.__send__(inst ? :instance_method : :method, sym)
56
+ end
57
+
58
+ def find_method_owner(mod, inst, sym)
59
+ begin
60
+ find_method(mod, inst, sym).owner
61
+ rescue NameError
62
+ end
63
+ end
64
+
65
+ def method_spec(method)
66
+ owner, inst = method.owner, nil
67
+ if owner.__singleton_class__?
68
+ name = owner.to_s[/Class:([A-Z][^\(> ]*)/, 1] # defined in an eigenclass
69
+ elsif name = name_cache[owner]
70
+ inst = true
71
+ elsif !owner.is_a?(Class)
72
+ name, inst = IncludesTracker.method_owner_and_inst(owner, name_cache)
73
+ end
74
+ # XXX: We can speed this up further by only returning the
75
+ # method's (or owner's) object_id here, and resolve the "real"
76
+ # host's name only when it's really needed. But that would break
77
+ # the current 'meta' impl in company-robe, for one thing.
78
+ [name, inst, method.name, method.parameters] + method.source_location.to_a
79
+ end
80
+
81
+ def doc_for(mod, inst, sym)
82
+ resolved = visor.resolve_const(mod)
83
+ DocFor.new(find_method(resolved, inst, sym.to_sym)).format
84
+ end
85
+
86
+ def method_targets(name, target, mod, instance, superc, conservative)
87
+ sym = name.to_sym
88
+ space = TypeSpace.new(visor, target, mod, instance, superc)
89
+ special_method = superc
90
+
91
+ scanner = ModuleScanner.new(sym, special_method || !target)
92
+
93
+ space.scan_with(scanner)
94
+ targets = scanner.candidates
95
+
96
+ if targets
97
+ targets.delete(Class.instance_method(:new))
98
+ filter_targets!(space, targets, instance, sym)
99
+ end
100
+
101
+ sc = space.target_type.singleton_class
102
+
103
+ if !instance && (sym == :new) && targets.all? { |t| t.owner < sc }
104
+ ctor_space = TypeSpace.new(visor, target, mod, true, superc)
105
+ ctor_scanner = ModuleScanner.new(:initialize, true)
106
+ ctor_space.scan_with(ctor_scanner)
107
+ ctor_targets = ctor_scanner.candidates
108
+ filter_targets!(ctor_space, ctor_targets, true, :initialize)
109
+ targets += ctor_targets
110
+ end
111
+
112
+ if targets.empty? && (target || !conservative) && !special_method
113
+ unless target
114
+ scanner.scan_methods(Kernel, :__private_instance_methods__)
115
+ end
116
+ scanner.check_private = false
117
+ scanner.scan(visor.each_object(Module), true, true)
118
+ targets = scanner.candidates
119
+ end
120
+
121
+ targets.map { |method| method_spec(method) }
122
+ .sort_by { |(mname)| mname ? mname.scan(/::/).length : 99 }
123
+ end
124
+
125
+ def filter_targets!(space, targets, instance, sym)
126
+ owner = find_method_owner(space.target_type, instance, sym)
127
+ if owner
128
+ targets.reject! do |method|
129
+ !(method.owner <= owner) &&
130
+ targets.find { |other| other.owner < method.owner }
131
+ end
132
+ end
133
+ end
134
+
135
+ def complete_method(prefix, target, mod, instance)
136
+ space = TypeSpace.new(visor, target, mod, instance, nil)
137
+ scanner = MethodScanner.new(prefix, !target)
138
+
139
+ space.scan_with(scanner)
140
+
141
+ if scanner.candidates.empty?
142
+ scanner.check_private = false
143
+ scanner.scan(visor.each_object(Module), true, true)
144
+ end
145
+
146
+ scanner.candidates.map { |m| method_spec(m) }
147
+ end
148
+
149
+ def complete_const(prefix, mod)
150
+ colons = prefix.rindex("::")
151
+ tail = colons ? prefix[colons + 2..-1] : prefix
152
+ if !colons
153
+ path = [Object]
154
+ path += visor.resolve_path(mod) if mod
155
+ path.flat_map do |m|
156
+ complete_const_in_module(tail, m)
157
+ end
158
+ else
159
+ base_name = prefix[0..colons + 1]
160
+ base = unless colons == 0
161
+ if mod
162
+ visor.resolve_context(base_name[0..-3], mod)
163
+ else
164
+ visor.resolve_const(base_name)
165
+ end
166
+ end
167
+ complete_const_in_module(tail, base || Object)
168
+ end.map { |c| "#{base_name}#{c}" }
169
+ end
170
+
171
+ def complete_const_in_module(tail, base)
172
+ base.constants.grep(/^#{Regexp.escape(tail)}/)
173
+ end
174
+
175
+ def rails_refresh
176
+ if defined?(Rails.application.reloader)
177
+ Rails.application.reloader.reload!
178
+ else
179
+ ActionDispatch::Reloader.cleanup!
180
+ ActionDispatch::Reloader.prepare!
181
+ end
182
+ Rails.application.eager_load!
183
+ init_name_cache
184
+ end
185
+
186
+ def load_path
187
+ $LOAD_PATH
188
+ end
189
+
190
+ def ping
191
+ "pong"
192
+ end
193
+
194
+ def call(path, body)
195
+ _, endpoint, *args = path.split("/").map { |s| s == "-" ? nil : s }
196
+ value = public_send(endpoint.to_sym, *args)
197
+ value.to_json
198
+ end
199
+
200
+ private
201
+
202
+ def pick_visor
203
+ if RUBY_ENGINE == "jruby"
204
+ JVisor.new
205
+ else
206
+ Visor.new
207
+ end
208
+ end
209
+
210
+ def init_name_cache
211
+ # https://www.ruby-forum.com/topic/167055
212
+ @name_cache = Hash.new { |h, mod| h[mod] = mod.__name__ }
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,57 @@
1
+ require 'pry'
2
+ require 'ostruct'
3
+
4
+ begin
5
+ require 'pry-doc' if RUBY_ENGINE == "ruby"
6
+ rescue LoadError
7
+ # Whatever, it's optional.
8
+ end
9
+
10
+ module Robe
11
+ class Sash
12
+ class DocFor
13
+ def initialize(method)
14
+ @method = method
15
+ end
16
+
17
+ def format
18
+ info = self.class.method_struct(@method)
19
+ {docstring: info.docstring,
20
+ source: info.source,
21
+ aliases: info.aliases,
22
+ visibility: visibility}
23
+ end
24
+
25
+ def visibility
26
+ owner, name = @method.owner, @method.name
27
+ if owner.__public_instance_methods__(false).include?(name)
28
+ :public
29
+ elsif owner.__protected_instance_methods__(false).include?(name)
30
+ :protected
31
+ elsif owner.__private_instance_methods__(false).include?(name)
32
+ :private
33
+ end
34
+ end
35
+
36
+ def self.method_struct(method)
37
+ begin
38
+ info = Pry::Method.new(method)
39
+
40
+ if info.dynamically_defined?
41
+ doc = ""
42
+ source = "# This method was defined outside of a source file."
43
+ else
44
+ doc = info.doc
45
+ source = (info.source? ? info.source : "# Not available.")
46
+ end
47
+
48
+ OpenStruct.new(docstring: doc, source: source,
49
+ aliases: info.aliases.map(&:to_sym))
50
+ rescue Pry::CommandError
51
+ message = $!.message =~ /pry-doc/ ? $!.message : ""
52
+ return OpenStruct.new(docstring: message)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,75 @@
1
+ require 'robe/core_ext'
2
+
3
+ module Robe
4
+ class Sash
5
+ class IncludesTracker
6
+ def self.method_owner_and_inst(owner, name_cache)
7
+ includers = maybe_scan
8
+
9
+ mod, inst = includers[owner].first
10
+
11
+ if mod
12
+ [name_cache[mod], inst]
13
+ else
14
+ [nil, true]
15
+ end
16
+ end
17
+
18
+ def self.reset!
19
+ @@hosts = nil
20
+ end
21
+
22
+ private
23
+
24
+ def self.maybe_scan
25
+ includers = @@hosts
26
+
27
+ unless includers
28
+ @@hosts = includers = Hash.new { |h, k| h[k] = [] }
29
+
30
+ ObjectSpace.each_object(Module) do |cl|
31
+ next unless cl.respond_to?(:included_modules)
32
+ next if cl.__singleton_class__?
33
+ cl.included_modules.each { |mod| includers[mod] << [cl, true] }
34
+ sc = cl.__singleton_class__
35
+ sc.included_modules.each { |mod| includers[mod] << [cl, nil] }
36
+ end
37
+ end
38
+
39
+ includers
40
+ end
41
+
42
+ if Module.respond_to?(:prepend)
43
+ module Invalidator
44
+ def included(other)
45
+ IncludesTracker.reset!
46
+ super(other)
47
+ end
48
+
49
+ def extended(other)
50
+ IncludesTracker.reset!
51
+ super(other)
52
+ end
53
+ end
54
+
55
+ Module.send(:prepend, Invalidator)
56
+ else
57
+ Module.class_eval do
58
+ alias_method :__orig_included, :included
59
+ alias_method :__orig_extended, :extended
60
+
61
+ # Cannot hook into this method without :prepend.
62
+ def included(other)
63
+ IncludesTracker.reset!
64
+ __orig_included(other)
65
+ end
66
+
67
+ def extended(other)
68
+ IncludesTracker.reset!
69
+ __orig_extended(other)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end