Class: Ratch::Console

Inherits:
Object show all
Defined in:
lib/ratch/console.rb

Overview

Ratch Shell Console

NOTE: Console class is still a work in progress.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConsole

Set up the user’s environment, including a pure binding into which env.rb and commands.rb are mixed.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/ratch/console.rb', line 12

def initialize
    require 'readline'
	#root = Rush::Dir.new('/')
	#home = Rush::Dir.new(ENV['HOME']) if ENV['HOME']
	#pwd = Rush::Dir.new(ENV['PWD']) if ENV['PWD']

	#@config = Rush::Config.new

	@config.load_history.each do |item|
		Readline::HISTORY.push(item)
	end

	Readline.basic_word_break_characters = ""
	Readline.completion_append_character = nil
	Readline.completion_proc = completion_proc

	@shell = Ratch::Shell.new

	@pure_binding = @shell.instance_eval("binding")

	$last_res = nil

	#eval @config.load_env, @pure_binding

	#commands = @config.load_commands
	#Rush::Dir.class_eval commands
	#Array.class_eval commands
end

Instance Attribute Details

#suppress_outputObject

Returns the value of attribute suppress_output.



8
9
10
# File 'lib/ratch/console.rb', line 8

def suppress_output
  @suppress_output
end

Instance Method Details

#complete_method(receiver, dot, partial_name, pre) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
# File 'lib/ratch/console.rb', line 132

def complete_method(receiver, dot, partial_name, pre)
	path = eval("#{receiver}.full_path", @pure_binding) rescue nil
	box = eval("#{receiver}.box", @pure_binding) rescue nil
	if path and box
		(box[path].methods - Object.methods).select do |e|
			e.match(/^#{Regexp.escape(partial_name)}/)
		end.map do |e|
			(pre || '') + receiver + dot + e
		end
	end
end

#complete_path(possible_var, accessor, quote, partial_path, pre) ⇒ Object

:nodoc:



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/ratch/console.rb', line 144

def complete_path(possible_var, accessor, quote, partial_path, pre)		# :nodoc:
	original_var, fixed_path = possible_var, ''
	if /^(.+\/)([^\/]*)$/ === partial_path
		fixed_path, partial_path = $~.captures
		possible_var += "['#{fixed_path}']"
	end
	full_path = eval("#{possible_var}.full_path", @pure_binding) rescue nil
	box = eval("#{possible_var}.box", @pure_binding) rescue nil
	if full_path and box
		Rush::Dir.new(full_path, box).entries.select do |e|
			e.name.match(/^#{Regexp.escape(partial_path)}/)
		end.map do |e|
			(pre || '') + original_var + accessor + quote + fixed_path + e.name + (e.dir? ? "/" : "")
		end
	end
end

#complete_variable(partial_name, pre) ⇒ Object



161
162
163
164
165
166
167
168
169
170
# File 'lib/ratch/console.rb', line 161

def complete_variable(partial_name, pre)
	lvars = eval('local_variables', @pure_binding)
	gvars = eval('global_variables', @pure_binding)
	ivars = eval('instance_variables', @pure_binding)
	(lvars + gvars + ivars).select do |e|
		e.match(/^#{Regexp.escape(partial_name)}/)
	end.map do |e|
		(pre || '') + e
	end
end

#completion_procObject

Try to do tab completion on dir square brackets and slash accessors.

Example:

dir[‘subd # presing tab here will produce dir[’subdir/ if subdir exists dir/‘subd # presing tab here will produce dir/’subdir/ if subdir exists

This isn’t that cool yet, because it can’t do multiple levels of subdirs. It does work remotely, though, which is pretty sweet.



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/ratch/console.rb', line 181

def completion_proc
	proc do |input|
		receiver, accessor, *rest = path_parts(input)
		if receiver
			case accessor
			when /^[\[\/]$/
				complete_path(receiver, accessor, *rest)
			when /^\.$/
				complete_method(receiver, accessor, *rest)
			when nil
				complete_variable(receiver, *rest)
			end
		end
	end
end

#execute(cmd) ⇒ Object

Run a single command.



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/ratch/console.rb', line 57

def execute(cmd)
	res = eval(cmd, @pure_binding)
	$last_res = res
	eval("_ = $last_res", @pure_binding)
	print_result(res)
#rescue Rush::Exception => e
#	puts "Exception #{e.class} -> #{e.message}"
rescue ::Exception => e
	puts "Exception #{e.class} -> #{e.message}"
	e.backtrace.each do |t|
		puts "   #{::File.expand_path(t)}"
	end
end

#finishObject

Save history to ~/.config/ratch/history when the shell exists.



72
73
74
75
76
# File 'lib/ratch/console.rb', line 72

def finish
  @config.save_history(Readline::HISTORY.to_a)
  puts
  exit
end

#path_parts(input) ⇒ Object

:nodoc:



119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/ratch/console.rb', line 119

def path_parts(input)		# :nodoc:
	case input
	when /((?:@{1,2}|\$|)\w+(?:\[[^\]]+\])*)([\[\/])(['"])([^\3]*)$/
		$~.to_a.slice(1, 4).push($~.pre_match)
	when /((?:@{1,2}|\$|)\w+(?:\[[^\]]+\])*)(\.)(\w*)$/
		$~.to_a.slice(1, 3).push($~.pre_match)
	when /((?:@{1,2}|\$|)\w+)$/
		$~.to_a.slice(1, 1).push(nil).push($~.pre_match)
	else
		[ nil, nil, nil ]
	end
end

Nice printing of different return types, particularly Rush::SearchResults.



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
115
116
117
# File 'lib/ratch/console.rb', line 81

def print_result(res)
	return if self.suppress_output
	if res.kind_of? String
		puts res
	elsif res.kind_of? Rush::SearchResults
		widest = res.entries.map { |k| k.full_path.length }.max
		res.entries_with_lines.each do |entry, lines|
			print entry.full_path
			print ' ' * (widest - entry.full_path.length + 2)
			print "=> "
			print res.colorize(lines.first.strip.head(30))
			print "..." if lines.first.strip.length > 30
			if lines.size > 1
				print " (plus #{lines.size - 1} more matches)"
			end
			print "\n"
		end
		puts "#{res.entries.size} matching files with #{res.lines.size} matching lines"
	elsif res.respond_to? :each
		counts = {}
		res.each do |item|
			puts item
			counts[item.class] ||= 0
			counts[item.class] += 1
		end
		if counts == {}
			puts "=> (empty set)"
		else
			count_s = counts.map do |klass, count|
				"#{count} x #{klass}"
			end.join(', ')
			puts "=> #{count_s}"
		end
	else
		puts "=> #{res.inspect}"
	end
end

#runObject

Run the interactive shell using readline.



42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/ratch/console.rb', line 42

def run
  loop do
    cmd = Readline.readline('ratch> ')
 
    finish if cmd.nil? or cmd == 'exit'

    next if cmd == ""

    Readline::HISTORY.push(cmd)
 
    execute(cmd)
  end
end