robe-server 1.0.2

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.
@@ -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