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.
@@ -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