rink 1.0.0
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.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/LICENSE +20 -0
- data/README.rdoc +135 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/bin/rink +66 -0
- data/lib/core_ext/object.rb +15 -0
- data/lib/rink/console.rb +335 -0
- data/lib/rink/delegation.rb +139 -0
- data/lib/rink/input_method/base.rb +41 -0
- data/lib/rink/input_method/file.rb +24 -0
- data/lib/rink/input_method/io.rb +34 -0
- data/lib/rink/input_method/readline.rb +49 -0
- data/lib/rink/io_methods.rb +44 -0
- data/lib/rink/lexer.rb +58 -0
- data/lib/rink/line_processor/base.rb +23 -0
- data/lib/rink/line_processor/pure_ruby.rb +180 -0
- data/lib/rink/output_method/base.rb +31 -0
- data/lib/rink/output_method/io.rb +22 -0
- data/lib/rink.rb +12 -0
- data/rink.gemspec +83 -0
- data/spec/lib/core_ext/object_spec.rb +19 -0
- data/spec/lib/rink/console_spec.rb +129 -0
- data/spec/lib/rink/io_methods_spec.rb +39 -0
- data/spec/lib/rink/pure_ruby_line_processor_spec.rb +33 -0
- data/spec/lib/rink_spec.rb +5 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +12 -0
- metadata +110 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
module Rink
|
2
|
+
# Blatantly ripped from ActiveSupport and pasted here to avoid the extra dependency.
|
3
|
+
# Only applied to objects internal to Rink.
|
4
|
+
module Delegation
|
5
|
+
# Provides a delegate class method to easily expose contained objects' methods
|
6
|
+
# as your own. Pass one or more methods (specified as symbols or strings)
|
7
|
+
# and the name of the target object as the final <tt>:to</tt> option (also a symbol
|
8
|
+
# or string). At least one method and the <tt>:to</tt> option are required.
|
9
|
+
#
|
10
|
+
# Delegation is particularly useful with Active Record associations:
|
11
|
+
#
|
12
|
+
# class Greeter < ActiveRecord::Base
|
13
|
+
# def hello() "hello" end
|
14
|
+
# def goodbye() "goodbye" end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# class Foo < ActiveRecord::Base
|
18
|
+
# belongs_to :greeter
|
19
|
+
# delegate :hello, :to => :greeter
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Foo.new.hello # => "hello"
|
23
|
+
# Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
|
24
|
+
#
|
25
|
+
# Multiple delegates to the same target are allowed:
|
26
|
+
#
|
27
|
+
# class Foo < ActiveRecord::Base
|
28
|
+
# belongs_to :greeter
|
29
|
+
# delegate :hello, :goodbye, :to => :greeter
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# Foo.new.goodbye # => "goodbye"
|
33
|
+
#
|
34
|
+
# Methods can be delegated to instance variables, class variables, or constants
|
35
|
+
# by providing them as a symbols:
|
36
|
+
#
|
37
|
+
# class Foo
|
38
|
+
# CONSTANT_ARRAY = [0,1,2,3]
|
39
|
+
# @@class_array = [4,5,6,7]
|
40
|
+
#
|
41
|
+
# def initialize
|
42
|
+
# @instance_array = [8,9,10,11]
|
43
|
+
# end
|
44
|
+
# delegate :sum, :to => :CONSTANT_ARRAY
|
45
|
+
# delegate :min, :to => :@@class_array
|
46
|
+
# delegate :max, :to => :@instance_array
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# Foo.new.sum # => 6
|
50
|
+
# Foo.new.min # => 4
|
51
|
+
# Foo.new.max # => 11
|
52
|
+
#
|
53
|
+
# Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
|
54
|
+
# is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
|
55
|
+
# delegated to.
|
56
|
+
#
|
57
|
+
# Person = Struct.new(:name, :address)
|
58
|
+
#
|
59
|
+
# class Invoice < Struct.new(:client)
|
60
|
+
# delegate :name, :address, :to => :client, :prefix => true
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# john_doe = Person.new("John Doe", "Vimmersvej 13")
|
64
|
+
# invoice = Invoice.new(john_doe)
|
65
|
+
# invoice.client_name # => "John Doe"
|
66
|
+
# invoice.client_address # => "Vimmersvej 13"
|
67
|
+
#
|
68
|
+
# It is also possible to supply a custom prefix.
|
69
|
+
#
|
70
|
+
# class Invoice < Struct.new(:client)
|
71
|
+
# delegate :name, :address, :to => :client, :prefix => :customer
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# invoice = Invoice.new(john_doe)
|
75
|
+
# invoice.customer_name # => "John Doe"
|
76
|
+
# invoice.customer_address # => "Vimmersvej 13"
|
77
|
+
#
|
78
|
+
# If the object to which you delegate can be nil, you may want to use the
|
79
|
+
# :allow_nil option. In that case, it returns nil instead of raising a
|
80
|
+
# NoMethodError exception:
|
81
|
+
#
|
82
|
+
# class Foo
|
83
|
+
# attr_accessor :bar
|
84
|
+
# def initialize(bar = nil)
|
85
|
+
# @bar = bar
|
86
|
+
# end
|
87
|
+
# delegate :zoo, :to => :bar
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# Foo.new.zoo # raises NoMethodError exception (you called nil.zoo)
|
91
|
+
#
|
92
|
+
# class Foo
|
93
|
+
# attr_accessor :bar
|
94
|
+
# def initialize(bar = nil)
|
95
|
+
# @bar = bar
|
96
|
+
# end
|
97
|
+
# delegate :zoo, :to => :bar, :allow_nil => true
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# Foo.new.zoo # returns nil
|
101
|
+
#
|
102
|
+
def delegate(*methods)
|
103
|
+
options = methods.pop
|
104
|
+
unless options.is_a?(Hash) && to = options[:to]
|
105
|
+
raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
|
106
|
+
end
|
107
|
+
|
108
|
+
if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/
|
109
|
+
raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
|
110
|
+
end
|
111
|
+
|
112
|
+
prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_"
|
113
|
+
|
114
|
+
file, line = caller.first.split(':', 2)
|
115
|
+
line = line.to_i
|
116
|
+
|
117
|
+
methods.each do |method|
|
118
|
+
on_nil =
|
119
|
+
if options[:allow_nil]
|
120
|
+
'return'
|
121
|
+
else
|
122
|
+
%(raise "#{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
|
123
|
+
end
|
124
|
+
|
125
|
+
module_eval(<<-EOS, file, line)
|
126
|
+
def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block)
|
127
|
+
#{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block)
|
128
|
+
rescue NoMethodError # rescue NoMethodError
|
129
|
+
if #{to}.nil? # if client.nil?
|
130
|
+
#{on_nil}
|
131
|
+
else # else
|
132
|
+
raise # raise
|
133
|
+
end # end
|
134
|
+
end # end
|
135
|
+
EOS
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Rink
|
2
|
+
module InputMethod
|
3
|
+
class Base
|
4
|
+
STDIN_FILE_NAME = "(line)"
|
5
|
+
|
6
|
+
def initialize(prompt = " > ", file = STDIN_FILE_NAME)
|
7
|
+
@prompt = prompt
|
8
|
+
@output = nil
|
9
|
+
@filename = file
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :filename
|
13
|
+
attr_accessor :prompt
|
14
|
+
attr_accessor :output
|
15
|
+
|
16
|
+
def input
|
17
|
+
raise NotImplementedError, "input"
|
18
|
+
end
|
19
|
+
|
20
|
+
def print(*args)
|
21
|
+
@output.print(*args) if @output
|
22
|
+
end
|
23
|
+
|
24
|
+
def puts(*args)
|
25
|
+
@output.puts(*args) if @output
|
26
|
+
end
|
27
|
+
|
28
|
+
def write(*args)
|
29
|
+
@output.write(*args) if @output
|
30
|
+
end
|
31
|
+
|
32
|
+
def gets
|
33
|
+
raise NotImplementedError, "gets"
|
34
|
+
end
|
35
|
+
|
36
|
+
def readable_after_eof?
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rink
|
2
|
+
module InputMethod
|
3
|
+
class File < Rink::InputMethod::Base
|
4
|
+
def initialize(file)
|
5
|
+
super
|
6
|
+
@io = file
|
7
|
+
@line_num = 0
|
8
|
+
@lines = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def eof?
|
12
|
+
@io.eof?
|
13
|
+
end
|
14
|
+
|
15
|
+
def gets
|
16
|
+
print @prompt
|
17
|
+
line = @lines[@line_num += 1] = @io.gets
|
18
|
+
line += "\n" unless !line || line =~ /\n/
|
19
|
+
print(line)
|
20
|
+
line
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rink
|
2
|
+
module InputMethod
|
3
|
+
class IO < Rink::InputMethod::Base
|
4
|
+
attr_accessor :input
|
5
|
+
|
6
|
+
def initialize(input = $stdin)
|
7
|
+
super()
|
8
|
+
@input = input
|
9
|
+
@line_num = 0
|
10
|
+
@lines = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def gets
|
14
|
+
print @prompt
|
15
|
+
line = @lines[@line_num += 1] = input.gets
|
16
|
+
line += "\n" unless !line || line =~ /\n/
|
17
|
+
print line if line
|
18
|
+
line
|
19
|
+
end
|
20
|
+
|
21
|
+
def eof?
|
22
|
+
input.eof?
|
23
|
+
end
|
24
|
+
|
25
|
+
def readable_after_eof?
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def [](line_number)
|
30
|
+
@lines[line_number]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
begin
|
2
|
+
require 'readline'
|
3
|
+
|
4
|
+
module Rink
|
5
|
+
module InputMethod
|
6
|
+
class Readline < Rink::InputMethod::Base
|
7
|
+
attr_accessor :completion_append_character, :completion_proc, :prompt
|
8
|
+
|
9
|
+
def initialize(completion_proc = proc { |line| [] })
|
10
|
+
super()
|
11
|
+
|
12
|
+
@completion_append_character = nil
|
13
|
+
@completion_proc = completion_proc
|
14
|
+
@line_num = 0
|
15
|
+
@lines = []
|
16
|
+
@eof = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def gets
|
20
|
+
# in case they were changed. Do we need this here?
|
21
|
+
::Readline.completion_append_character = completion_append_character
|
22
|
+
::Readline.completion_proc = completion_proc
|
23
|
+
|
24
|
+
if line = ::Readline.readline(@prompt, false)
|
25
|
+
::Readline::HISTORY.push(line) if !line.empty?
|
26
|
+
@lines[@line_num += 1] = line + "\n"
|
27
|
+
else
|
28
|
+
@eof = true
|
29
|
+
line
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def eof?
|
34
|
+
@eof
|
35
|
+
end
|
36
|
+
|
37
|
+
def readable_after_eof?
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
def [](line_num)
|
42
|
+
@line[num]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
rescue LoadError
|
48
|
+
# Fail silently. Rink will fall back to an IO input type with STDIN.
|
49
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "input_method/base"))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "input_method/readline"))
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "input_method/io"))
|
4
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "input_method/file"))
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "output_method/base"))
|
6
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "output_method/io"))
|
7
|
+
require 'stringio'
|
8
|
+
|
9
|
+
module Rink
|
10
|
+
module IOMethods
|
11
|
+
def setup_input_method(input)
|
12
|
+
@input = case input
|
13
|
+
when Rink::InputMethod::Base
|
14
|
+
input
|
15
|
+
when STDIN
|
16
|
+
defined?(Rink::InputMethod::Readline) ? Rink::InputMethod::Readline.new : Rink::InputMethod::IO.new
|
17
|
+
when File
|
18
|
+
Rink::InputMethod::File.new(input)
|
19
|
+
when String
|
20
|
+
Rink::InputMethod::IO.new(StringIO.new(input))
|
21
|
+
when ::IO, StringIO
|
22
|
+
Rink::InputMethod::IO.new(input)
|
23
|
+
#when nil
|
24
|
+
# nil
|
25
|
+
else raise ArgumentError, "Unexpected input type: #{input.class}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def setup_output_method(output)
|
30
|
+
@output = case output
|
31
|
+
when Rink::OutputMethod::Base
|
32
|
+
output
|
33
|
+
when STDOUT, STDERR, ::IO, StringIO then
|
34
|
+
Rink::OutputMethod::IO.new(output)
|
35
|
+
when String
|
36
|
+
Rink::OutputMethod::IO.new(StringIO.new(output))
|
37
|
+
when nil then
|
38
|
+
nil
|
39
|
+
else
|
40
|
+
raise ArgumentError, "Unexpected ouptut type: #{output.class}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/rink/lexer.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'irb/ruby-lex'
|
2
|
+
|
3
|
+
module Rink
|
4
|
+
class Lexer < ::RubyLex
|
5
|
+
extend Rink::Delegation
|
6
|
+
attr_accessor :output
|
7
|
+
delegate :print, :puts, :write, :p, :to => :output
|
8
|
+
|
9
|
+
def initialize(output = nil)
|
10
|
+
@output = output
|
11
|
+
super()
|
12
|
+
end
|
13
|
+
|
14
|
+
# RubyLex prompts unconditionally once the prompt is first set (not very reset-friendly), so we need to fix that.
|
15
|
+
def set_prompt(p = nil, &block)
|
16
|
+
if p.nil? && !block_given?
|
17
|
+
@prompt = nil # this will go back to NOT prompting
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
# overriding this method because we don't want to prompt
|
23
|
+
# def each_top_level_statement
|
24
|
+
# initialize_input
|
25
|
+
# catch(:TERM_INPUT) do
|
26
|
+
# loop do
|
27
|
+
# begin
|
28
|
+
# @continue = false
|
29
|
+
# prompt
|
30
|
+
# unless l = lex
|
31
|
+
# throw :TERM_INPUT if @line == ''
|
32
|
+
# else
|
33
|
+
# #p l
|
34
|
+
# @line.concat l
|
35
|
+
# if @ltype or @continue or @indent > 0
|
36
|
+
# next
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
# if @line != "\n"
|
40
|
+
# yield @line, @exp_line_no
|
41
|
+
# end
|
42
|
+
# break unless l
|
43
|
+
# @line = ''
|
44
|
+
# @exp_line_no = @line_no
|
45
|
+
#
|
46
|
+
# @indent = 0
|
47
|
+
# @indent_stack = []
|
48
|
+
# prompt
|
49
|
+
# rescue TerminateLineInput
|
50
|
+
# initialize_input
|
51
|
+
# prompt
|
52
|
+
# get_readed
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Rink
|
2
|
+
module LineProcessor
|
3
|
+
# The Line Processor takes partial lines and performs operations on them. This is usually triggered by some special
|
4
|
+
# character or combination of characters, such as TAB, ARROW UP, ARROW DOWN, and so forth.
|
5
|
+
#
|
6
|
+
class Base
|
7
|
+
attr_reader :source
|
8
|
+
|
9
|
+
def initialize(source = nil)
|
10
|
+
@source = source
|
11
|
+
end
|
12
|
+
|
13
|
+
# Autocomplete is usually triggered by a TAB character and generally involves looking at the beginning of a line
|
14
|
+
# and finding the command the user is most likely trying to type. This saves typing for the user and creates a more
|
15
|
+
# intuitive interface.
|
16
|
+
#
|
17
|
+
# This method returns either a single String or an array of Strings.
|
18
|
+
def autocomplete(line, namespace)
|
19
|
+
raise NotImplementedError, "autocomplete"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module Rink
|
2
|
+
module LineProcessor
|
3
|
+
# Performs autocompletion based on method names of objects used. This algorithm is identical to that of IRB.
|
4
|
+
class PureRuby < Rink::LineProcessor::Base
|
5
|
+
OPERATORS = ["%", "&", "*", "**", "+", "-", "/", "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
|
6
|
+
"[]", "[]=", "^"
|
7
|
+
] unless defined?(OPERATORS)
|
8
|
+
|
9
|
+
RESERVED_WORDS = [ "BEGIN", "END", "alias", "and", "begin", "break", "case", "class", "def", "defined", "do",
|
10
|
+
"else", "elsif", "end", "ensure", "false", "for", "if", "in", "module", "next", "nil", "not",
|
11
|
+
"or", "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless",
|
12
|
+
"until", "when", "while", "yield"
|
13
|
+
] unless defined?(RESERVED_WORDS)
|
14
|
+
|
15
|
+
def autocomplete_for_regexp(receiver, message)
|
16
|
+
candidates = Regexp.instance_methods(true)
|
17
|
+
select_message(receiver, message, candidates)
|
18
|
+
end
|
19
|
+
|
20
|
+
def autocomplete_for_array(receiver, message)
|
21
|
+
candidates = Array.instance_methods(true)
|
22
|
+
select_message(receiver, message, candidates)
|
23
|
+
end
|
24
|
+
|
25
|
+
def autocomplete_for_proc_or_hash(receiver, message)
|
26
|
+
candidates = Proc.instance_methods(true) | Hash.instance_methods(true)
|
27
|
+
select_message(receiver, message, candidates)
|
28
|
+
end
|
29
|
+
|
30
|
+
def autocomplete_for_symbol(sym)
|
31
|
+
if Symbol.respond_to?(:all_symbols)
|
32
|
+
candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name}
|
33
|
+
candidates.grep(/^#{sym}/)
|
34
|
+
else
|
35
|
+
[]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def autocomplete_for_absolute_constant_or_class_methods(receiver)
|
40
|
+
candidates = Object.constants
|
41
|
+
candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
|
42
|
+
end
|
43
|
+
|
44
|
+
def autocomplete_for_constant_or_class_methods(receiver, message)
|
45
|
+
begin
|
46
|
+
candidates = eval("#{receiver}.constants | #{receiver}.methods", bind)
|
47
|
+
rescue Exception
|
48
|
+
candidates = []
|
49
|
+
end
|
50
|
+
candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e}
|
51
|
+
end
|
52
|
+
|
53
|
+
def autocomplete_for_symbol_method(receiver, message)
|
54
|
+
candidates = Symbol.instance_methods(true)
|
55
|
+
select_message(receiver, message, candidates)
|
56
|
+
end
|
57
|
+
|
58
|
+
def autocomplete_for_numeric(receiver, message)
|
59
|
+
begin
|
60
|
+
candidates = eval(receiver, bind).methods
|
61
|
+
rescue Exception
|
62
|
+
candidates = []
|
63
|
+
end
|
64
|
+
select_message(receiver, message, candidates)
|
65
|
+
end
|
66
|
+
|
67
|
+
def autocomplete_for_hex_numeric(receiver, message)
|
68
|
+
begin
|
69
|
+
candidates = eval(receiver, bind).methods
|
70
|
+
rescue Exception
|
71
|
+
candidates = []
|
72
|
+
end
|
73
|
+
select_message(receiver, message, candidates)
|
74
|
+
end
|
75
|
+
|
76
|
+
def autocomplete_for_global_variable(obj)
|
77
|
+
global_variables.grep(Regexp.new(obj))
|
78
|
+
end
|
79
|
+
|
80
|
+
def autocomplete_for_variable(receiver, message)
|
81
|
+
gv = eval("global_variables", bind)
|
82
|
+
lv = eval("local_variables", bind)
|
83
|
+
cv = eval("self.class.constants", bind)
|
84
|
+
|
85
|
+
if (gv | lv | cv).include?(receiver)
|
86
|
+
# foo.func and foo is local var.
|
87
|
+
candidates = eval("#{receiver}.methods", bind)
|
88
|
+
elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
|
89
|
+
# Foo::Bar.func
|
90
|
+
begin
|
91
|
+
candidates = eval("#{receiver}.methods", bind)
|
92
|
+
rescue Exception
|
93
|
+
candidates = []
|
94
|
+
end
|
95
|
+
else
|
96
|
+
# func1.func2
|
97
|
+
candidates = []
|
98
|
+
ObjectSpace.each_object(Module){|m|
|
99
|
+
begin
|
100
|
+
name = m.name
|
101
|
+
rescue Exception
|
102
|
+
name = ""
|
103
|
+
end
|
104
|
+
next if name != "IRB::Context" and
|
105
|
+
/^(IRB|SLex|RubyLex|RubyToken)/ =~ name
|
106
|
+
candidates.concat m.instance_methods(false)
|
107
|
+
}
|
108
|
+
candidates.sort!
|
109
|
+
candidates.uniq!
|
110
|
+
end
|
111
|
+
select_message(receiver, message, candidates)
|
112
|
+
end
|
113
|
+
|
114
|
+
def autocomplete_for_string(message)
|
115
|
+
receiver = ""
|
116
|
+
candidates = String.instance_methods(true)
|
117
|
+
select_message(receiver, message, candidates)
|
118
|
+
end
|
119
|
+
|
120
|
+
def autocomplete(line, namespace)
|
121
|
+
# Borrowed from irb/completion.rb
|
122
|
+
case line
|
123
|
+
when /^(\/[^\/]*\/)\.([^.]*)$/
|
124
|
+
autocomplete_for_regexp($1, Regexp.quote($2))
|
125
|
+
|
126
|
+
when /^([^\]]*\])\.([^.]*)$/
|
127
|
+
autocomplete_for_array($1, Regexp.quote($2))
|
128
|
+
|
129
|
+
when /^([^\}]*\})\.([^.]*)$/
|
130
|
+
autocomplete_for_proc_or_hash($1, Regexp.quote($2))
|
131
|
+
|
132
|
+
when /^(:[^:.]*)$/
|
133
|
+
autocomplete_for_symbol($1)
|
134
|
+
|
135
|
+
when /^::([A-Z][^:\.\(]*)$/
|
136
|
+
autocomplete_for_absolute_constant_or_class_methods($1)
|
137
|
+
|
138
|
+
when /^(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/
|
139
|
+
autocomplete_for_constant_or_class_methods($1, Regexp.quote($4))
|
140
|
+
|
141
|
+
when /^(:[^:.]+)\.([^.]*)$/
|
142
|
+
autocomplete_for_symbol_method($1, Regexp.quote($2))
|
143
|
+
|
144
|
+
when /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)\.([^.]*)$/
|
145
|
+
autocomplete_for_numeric($1, Regexp.quote($5))
|
146
|
+
|
147
|
+
when /^(-?0x[0-9a-fA-F_]+)\.([^.]*)$/
|
148
|
+
autocomplete_for_hex_numeric($1, Regexp.quote($2))
|
149
|
+
|
150
|
+
when /^(\$[^.]*)$/
|
151
|
+
autocomplete_for_global_variable(Regexp.quote($1))
|
152
|
+
|
153
|
+
# when /^(\$?(\.?[^.]+)+)\.([^.]*)$/
|
154
|
+
when /^((\.?[^.]+)+)\.([^.]*)$/
|
155
|
+
autocomplete_for_variable($1, Regexp.quote($3))
|
156
|
+
|
157
|
+
when /^\.([^.]*)$/
|
158
|
+
# unknown(maybe String)
|
159
|
+
autocomplete_for_string(Regexp.quote($1))
|
160
|
+
else
|
161
|
+
candidates = eval("methods | private_methods | local_variables | self.class.constants", namespace.send(:binding))
|
162
|
+
(candidates|RESERVED_WORDS).grep(/^#{Regexp.quote(line)}/)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
def select_message(receiver, message, candidates)
|
168
|
+
candidates.grep(/^#{message}/).collect do |e|
|
169
|
+
case e
|
170
|
+
when /^[a-zA-Z_]/
|
171
|
+
receiver + "." + e
|
172
|
+
when /^[0-9]/
|
173
|
+
when *OPERATORS
|
174
|
+
#receiver + " " + e
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rink
|
2
|
+
module OutputMethod
|
3
|
+
class Base
|
4
|
+
attr_writer :silenced
|
5
|
+
|
6
|
+
def output
|
7
|
+
raise NotImplementedError, "output"
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(silenced = false)
|
11
|
+
@silenced = silenced
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(*args)
|
15
|
+
print(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def puts(*args)
|
19
|
+
print args.join("\n"), "\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
def print(*args)
|
23
|
+
raise NotImplementedError, "print" unless silenced?
|
24
|
+
end
|
25
|
+
|
26
|
+
def silenced?
|
27
|
+
@silenced
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Rink
|
2
|
+
module OutputMethod
|
3
|
+
class IO < Rink::OutputMethod::Base
|
4
|
+
attr_accessor :io
|
5
|
+
|
6
|
+
def initialize(io)
|
7
|
+
super()
|
8
|
+
@io = io
|
9
|
+
end
|
10
|
+
|
11
|
+
def output
|
12
|
+
@io
|
13
|
+
end
|
14
|
+
|
15
|
+
def print(*args)
|
16
|
+
return if silenced?
|
17
|
+
args = args.flatten.join
|
18
|
+
@io.print(*args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/rink.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#require 'sc-ansi'
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "rink/delegation"))
|
4
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "rink/lexer"))
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'rink/io_methods'))
|
6
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "rink/line_processor/base"))
|
7
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "rink/line_processor/pure_ruby"))
|
8
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "rink/console"))
|
9
|
+
|
10
|
+
module Rink
|
11
|
+
|
12
|
+
end
|