Class: RSQL::Commands
- Inherits:
-
Object
- Object
- RSQL::Commands
- Defined in:
- lib/rsql/commands.rb
Overview
A wrapper to parse and handle commands
Defined Under Namespace
Classes: Command
Constant Summary collapse
- SEPARATORS =
Split commands on these characters.
';|!'
Instance Method Summary collapse
- #add_command(content, bangs, is_ruby, separator = nil) ⇒ Object private
- #concat(other) ⇒ Object
- #empty? ⇒ Boolean
-
#initialize(input, default_displayer) ⇒ Commands
constructor
Split on separators, allowing for escaping;.
- #last ⇒ Object
- #run!(eval_context) ⇒ Object
- #run_command(cmd, last_results, eval_context) ⇒ Object private
Constructor Details
#initialize(input, default_displayer) ⇒ Commands
Split on separators, allowing for escaping;
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/rsql/commands.rb', line 52 def initialize(input, default_displayer) @default_displayer = default_displayer @cmds = [] esc = '' bangs = {} match_before_bang = nil in_pipe_arg = false next_is_ruby = false input.scan(/[^#{SEPARATORS}]+.?/) do |match| orig_match = match if i = SEPARATORS.index(match[-1]) sep = SEPARATORS[i] match.chop! if match[-1] == ?\\ # unescape the separator and save the content away esc << match[0..-2] << sep next end else sep = nil end unless esc.empty? esc << match match = esc esc = '' end found_maps = false if match_before_bang new_bangs = {} match.split(/\s*,\s*/).each do |ent| (key,val) = ent.split(/\s*=>\s*/) unless key && val # they are using a bang but have no maps # so we assume this is a != or something # similar and let it go through unmapped match = match_before_bang + '!' + match match_before_bang = nil else found_maps = true if val.strip == 'nil' new_bangs[key.strip] = nil else new_bangs[key.strip] = val.to_sym end end end if found_maps next unless match_before_bang match = match_before_bang match_before_bang = nil bangs.merge!(new_bangs) end end if sep == ?! match_before_bang = match next end if sep == ?| # we've split on a pipe so we need to handle the # case where ruby code is declaring a block with # arguments (e.g. {|x| p x} or do |x| p x end) if in_pipe_arg in_pipe_arg = false esc << match << '|' next elsif orig_match =~ /\{\s*|do\s*/ in_pipe_arg = true esc << match << '|' next end end add_command(match, bangs, next_is_ruby, sep) bangs = {} next_is_ruby = sep == ?| end add_command(esc, bangs, next_is_ruby) end |
Instance Method Details
#add_command(content, bangs, is_ruby, separator = nil) ⇒ Object (private)
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/rsql/commands.rb', line 183 def add_command(content, bangs, is_ruby, separator=nil) content.strip! case content[0] when ?. content.slice!(0) declarator = :ruby else declarator = is_ruby ? :ruby : nil end if content.end_with?('\G') # emulate mysql's \G output content.slice!(-2,2) displayer = :display_by_line elsif separator == ?| displayer = :pipe else displayer = @default_displayer end unless content.empty? @cmds << Command.new(content, bangs, declarator, displayer) return true end return false end |
#concat(other) ⇒ Object
144 145 146 |
# File 'lib/rsql/commands.rb', line 144 def concat(other) @cmds.concat(other) end |
#empty? ⇒ Boolean
140 141 142 |
# File 'lib/rsql/commands.rb', line 140 def empty? return @cmds.empty? end |
#last ⇒ Object
148 149 150 |
# File 'lib/rsql/commands.rb', line 148 def last @cmds.last end |
#run!(eval_context) ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/rsql/commands.rb', line 152 def run!(eval_context) last_results = nil while @cmds.any? cmd = @cmds.shift results = run_command(cmd, last_results, eval_context) return :done if results == :done if cmd.displayer == :pipe last_results = results elsif MySQLResults === results last_results = nil results.send(cmd.displayer) elsif EvalResults === results last_results = nil if MySQLResults === results.value # This happens if their recipe returns MySQL # results...just display it like above. results.value.send(cmd.displayer) else if results.stdout && 0 < results.stdout.size puts results.stdout.string end puts "=> #{results.value.inspect}" if results.value end end end end |
#run_command(cmd, last_results, eval_context) ⇒ Object (private)
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/rsql/commands.rb', line 212 def run_command(cmd, last_results, eval_context) eval_context.bangs = cmd.bangs if cmd.declarator stdout = cmd.displayer == :pipe ? StringIO.new : nil value = eval_context.safe_eval(cmd.content, last_results, stdout) if String === value cmds = Commands.new(value, cmd.displayer) unless cmds.empty? # need to carry along the bangs into the # last command so we don't lose them if cmds.last.bangs.empty? && cmd.bangs.any? cmds.last.bangs = cmd.bangs end @cmds = cmds.concat(@cmds) end return end else value = cmd.content end return :done if value == 'exit' || value == 'quit' if String === value begin last_results = MySQLResults.query(value, eval_context) rescue MySQLResults::MaxRowsException => ex $stderr.puts "refusing to process #{ex.rows} rows (max: #{ex.max})--" << "consider raising this via set_max_rows" rescue Mysql::Error => ex $stderr.puts ex. rescue Exception => ex $stderr.puts ex.inspect raise end else last_results = EvalResults.new(value, stdout) end return last_results end |