summaryrefslogtreecommitdiff
path: root/lib/irb/completion.rb
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-03-13 01:28:27 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-03-13 01:28:27 +0000
commit583d903c2ba5de82bd3eb2eb687b1c107938f9e2 (patch)
treefdcf85a724adbf449a0bfed09dcdfb2b5a131731 /lib/irb/completion.rb
parent0faf01862435676ba15552b99f282ba49dba620a (diff)
Speed up func1.func2 completion by using Set for ignored modules
And thus avoiding Module#name calls. Those are slow, especially in larger projects, with lots of anonymous modules. [Fix GH-1798] From: Dmitry Gutov <dgutov@yandex.ru> git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62732 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/irb/completion.rb')
-rw-r--r--lib/irb/completion.rb39
1 files changed, 28 insertions, 11 deletions
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index e7499a8e2b..1b9d96b8f9 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -169,18 +169,9 @@ module IRB
else
# func1.func2
candidates = []
+ to_ignore = ignored_modules
ObjectSpace.each_object(Module){|m|
- begin
- name = m.name
- rescue Exception
- name = ""
- end
- begin
- next if name != "IRB::Context" and
- /^(IRB|SLex|RubyLex|RubyToken)/ =~ name
- rescue Exception
- next
- end
+ next if (to_ignore.include?(m) rescue true)
candidates.concat m.instance_methods(false).collect{|x| x.to_s}
}
candidates.sort!
@@ -218,6 +209,32 @@ module IRB
end
end
end
+
+ def self.ignored_modules
+ # We could cache the result, but this is very fast already.
+ # By using this approach, we avoid Module#name calls, which are
+ # relatively slow when there are a lot of anonymous modules defined.
+ require 'set'
+ s = Set.new
+
+ scanner = lambda do |m|
+ next if s.include?(m) # IRB::ExtendCommandBundle::EXCB recurses.
+ s << m
+ m.constants(false).each do |c|
+ value = m.const_get(c)
+ scanner.call(value) if value.is_a?(Module)
+ end
+ end
+
+ %i(IRB SLex RubyLex RubyToken).each do |sym|
+ next unless Object.const_defined?(sym)
+ scanner.call(Object.const_get(sym))
+ end
+
+ s.delete(IRB::Context) if defined?(IRB::Context)
+
+ s
+ end
end
end