[前][次][番号順一覧][スレッド一覧]

ruby-changes:50585

From: nobu <ko1@a...>
Date: Tue, 13 Mar 2018 10:28:33 +0900 (JST)
Subject: [ruby-changes:50585] nobu:r62732 (trunk): Speed up func1.func2 completion by using Set for ignored modules

nobu	2018-03-13 10:28:27 +0900 (Tue, 13 Mar 2018)

  New Revision: 62732

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=62732

  Log:
    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@y...>

  Modified files:
    trunk/lib/irb/completion.rb
Index: lib/irb/completion.rb
===================================================================
--- lib/irb/completion.rb	(revision 62731)
+++ lib/irb/completion.rb	(revision 62732)
@@ -169,18 +169,9 @@ module IRB https://github.com/ruby/ruby/blob/trunk/lib/irb/completion.rb#L169
         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 https://github.com/ruby/ruby/blob/trunk/lib/irb/completion.rb#L209
         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
 

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]