module WebConsole
  # A context lets you get object names related to the current session binding.
  class Context
    def initialize(binding)
      @binding = binding
    end

    # Extracts entire objects which can be called by the current session unless the objpath is present.
    # Otherwise, it extracts methods and constants of the object specified by the objpath.
    def extract(objpath)
      if objpath.present?
        local(objpath)
      else
        global
      end
    end

    private

      GLOBAL_OBJECTS = [
        'global_variables',
        'local_variables',
        'instance_variables',
        'instance_methods',
        'class_variables',
        'methods',
        'Object.constants',
        'Kernel.methods',
      ]

      def global
        SortedSet.new GLOBAL_OBJECTS.map { |cmd| eval(cmd) }.flatten
      end

      def local(objpath)
        SortedSet.new [
          eval("#{objpath}.methods").map { |m| "#{objpath}.#{m}" },
          eval("#{objpath}.constants").map { |c| "#{objpath}::#{c}" },
        ].flatten
      end

      def eval(cmd)
        @binding.eval(cmd) rescue []
      end
  end
end

module WebConsole
  # A context lets you get object names related to the current session binding.
  class Context
    def initialize(binding)
      @binding = binding
    end

    # Extracts entire objects which can be called by the current session unless
    # the inputs is present.
    #
    # Otherwise, it extracts methods and constants of the object specified by
    # the input.
    def extract(input = nil)
      input.present? ? local(input) : global
    end

    private

      GLOBAL_OBJECTS = [
        'instance_variables',
        'local_variables',
        'methods',
        'class_variables',
        'Object.constants',
        'global_variables'
      ]

      def global
        GLOBAL_OBJECTS.map { |cmd| eval(cmd) }.flatten
      end

      def local(input)
        [
          eval("#{input}.methods").map { |m| "#{input}.#{m}" },
          eval("#{input}.constants").map { |c| "#{input}::#{c}" },
        ].flatten
      end

      def eval(cmd)
        @binding.eval(cmd) rescue []
      end
  end
end

Sort the input by scope groups
Sort the input by scope groups

This change makes sure that more local variables and methods come before
constants and global variables. It also eliminates naturally eliminates
duplicate results as we don't try to extract overlapping methods.
