Class: IRB::Completion
- Inherits:
-
Object
- Object
- IRB::Completion
- Defined in:
- lib/irb/ext/completion.rb
Constant Summary collapse
- TYPE =
Convenience constants for sexp access of Ripper::SexpBuilder.
0
- VALUE =
1
- CALLEE =
3
- RESERVED_UPCASE_WORDS =
%w{ BEGIN END }
- RESERVED_DOWNCASE_WORDS =
%w{ alias and begin break case class def defined do else elsif end ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield }
Instance Attribute Summary collapse
-
#source ⇒ Object
readonly
Returns the value of attribute source.
Instance Method Summary collapse
-
#call(source) ⇒ Object
Returns an array of possible completion results, with the current IRB::Context.
-
#constants ⇒ Object
TODO: test and or fix the fact that we need to get constants from the singleton class.
- #context ⇒ Object
- #evaluate(s) ⇒ Object
- #format_methods(receiver, methods, filter) ⇒ Object
- #instance_methods ⇒ Object
- #instance_methods_of(klass) ⇒ Object
- #local_variables ⇒ Object
- #match_methods_vars_or_consts_in_scope(symbol) ⇒ Object
- #methods_of_object(root) ⇒ Object
- #methods_of_object_in_variable(path) ⇒ Object
- #results ⇒ Object
- #unwind_callstack(root, stack = []) ⇒ Object
Instance Attribute Details
#source ⇒ Object (readonly)
Returns the value of attribute source.
39 40 41 |
# File 'lib/irb/ext/completion.rb', line 39 def source @source end |
Instance Method Details
#call(source) ⇒ Object
Returns an array of possible completion results, with the current IRB::Context.
This is meant to be used with Readline which takes a completion proc.
49 50 51 52 |
# File 'lib/irb/ext/completion.rb', line 49 def call(source) @source = source results end |
#constants ⇒ Object
TODO: test and or fix the fact that we need to get constants from the singleton class.
72 73 74 |
# File 'lib/irb/ext/completion.rb', line 72 def constants evaluate('Object.constants + self.class.constants + (class << self; constants; end)').map(&:to_s) end |
#context ⇒ Object
41 42 43 |
# File 'lib/irb/ext/completion.rb', line 41 def context IRB::Driver.current.context end |
#evaluate(s) ⇒ Object
54 55 56 |
# File 'lib/irb/ext/completion.rb', line 54 def evaluate(s) context.__evaluate__(s) end |
#format_methods(receiver, methods, filter) ⇒ Object
144 145 146 |
# File 'lib/irb/ext/completion.rb', line 144 def format_methods(receiver, methods, filter) (filter ? methods.grep(/^#{filter}/) : methods).map { |m| "#{receiver}.#{m}" } end |
#instance_methods ⇒ Object
62 63 64 |
# File 'lib/irb/ext/completion.rb', line 62 def instance_methods context.object.methods.map(&:to_s) end |
#instance_methods_of(klass) ⇒ Object
66 67 68 |
# File 'lib/irb/ext/completion.rb', line 66 def instance_methods_of(klass) evaluate(klass).instance_methods end |
#local_variables ⇒ Object
58 59 60 |
# File 'lib/irb/ext/completion.rb', line 58 def local_variables evaluate('local_variables').map(&:to_s) end |
#match_methods_vars_or_consts_in_scope(symbol) ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/irb/ext/completion.rb', line 126 def match_methods_vars_or_consts_in_scope(symbol) var = symbol[VALUE] filter = var[VALUE] case var[TYPE] when :@ident local_variables + instance_methods + RESERVED_DOWNCASE_WORDS when :@gvar global_variables.map(&:to_s) when :@const if symbol[TYPE] == :top_const_ref filter = "::#{filter}" Object.constants.map { |c| "::#{c}" } else constants + RESERVED_UPCASE_WORDS end end.grep(/^#{Regexp.quote(filter)}/) end |
#methods_of_object(root) ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/irb/ext/completion.rb', line 148 def methods_of_object(root) result = case root[TYPE] # [:unary, :-@, [x, …]] # ^ when :unary then return methods_of_object(root[2]) # TODO: do we really need this? when :var_ref, :top_const_ref then return methods_of_object_in_variable(root) when :array, :words_add, :qwords_add then Array when :@int then Fixnum when :@float then Float when :hash then Hash when :lambda then Proc when :dot2, :dot3 then Range when :regexp_literal then Regexp when :string_literal then String when :symbol_literal, :dyna_symbol then Symbol end.instance_methods end |
#methods_of_object_in_variable(path) ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/irb/ext/completion.rb', line 166 def methods_of_object_in_variable(path) type, name = path[VALUE][0..1] if path[TYPE] == :top_const_ref if type == :@const && Object.constants.include?(name.to_sym) evaluate("::#{name}").methods end else case type when :@ident evaluate(name).methods if local_variables.include?(name) when :@gvar eval(name).methods if global_variables.include?(name.to_sym) when :@const evaluate(name).methods if constants.include?(name) end end end |
#results ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/irb/ext/completion.rb', line 76 def results source = @source filter = nil # if ends with period, remove it to remove the syntax error it causes call = (source[-1,1] == '.') receiver = source = source[0..-2] if call if sexp = Ripper::SexpBuilder.new(source).parse # [:program, [:stmts_add, [:stmts_new], [x, …]]] # ^ root = sexp[1][2] # [:call, [:hash, nil], :".", [:@ident, x, …]] if root[TYPE] == :call call = true stack = unwind_callstack(root) # [[:var_ref, [:@const, "Klass", [1, 0]]], [:call, "new"]] # [[:var_ref, [:@ident, "klass", [1, 0]]], [:call, "new"], [:call, "filter"]] if stack[1][VALUE] == 'new' klass = stack[0][VALUE][VALUE] filter = stack[2][VALUE] if stack[2] receiver = "#{klass}.new" methods = instance_methods_of(klass) else filter = root[CALLEE][VALUE] filter = stack[1][VALUE] receiver = source[0..-(filter.length + 2)] root = root[VALUE] end end if call format_methods(receiver, methods || methods_of_object(root), filter) else match_methods_vars_or_consts_in_scope(root) end.sort.uniq end end |
#unwind_callstack(root, stack = []) ⇒ Object
116 117 118 119 120 121 122 123 124 |
# File 'lib/irb/ext/completion.rb', line 116 def unwind_callstack(root, stack = []) if root[TYPE] == :call stack.unshift [:call, root[CALLEE][VALUE]] unwind_callstack(root[VALUE], stack) else stack.unshift root end stack end |