" Constructor: " ============ function! sj#argparser#ruby#Construct(start_index, end_index, line) let parser = sj#argparser#common#Construct(a:start_index, a:end_index, a:line) call extend(parser, { \ 'hash_type': '', \ 'cursor_arg': 0, \ 'cursor_col': col('.'), \ \ 'Process': function('sj#argparser#ruby#Process'), \ 'PushArg': function('sj#argparser#ruby#PushArg'), \ 'AtFunctionEnd': function('sj#argparser#ruby#AtFunctionEnd'), \ 'ExpandOptionHash': function('sj#argparser#ruby#ExpandOptionHash'), \ 'MarkOptionArg': function('sj#argparser#ruby#MarkOptionArg'), \ }) return parser endfunction " Methods: " ======== function! sj#argparser#ruby#Process() dict while !self.Finished() if self.body[0] == ',' call self.PushArg() call self.Next() continue elseif self.AtFunctionEnd() break elseif self.body[0] =~ '[''"]' call self.JumpPair("'\"", "'\"") " Example: 'some key': value if len(self.body) > 1 && self.body[1] == ':' call self.MarkOptionArg('new') endif elseif self.body[0] =~ "[{\[`(/]" call self.JumpPair("{[`(/", "}]`)/") elseif self.body[0] == '%' call self.PushChar() if self.body[0] =~ '[qQrswWx]' call self.PushChar() endif let delimiter = self.body[0] if delimiter =~ '[[({<]' call self.JumpPair('[({<', '])}>') else call self.JumpPair(delimiter, delimiter) endif elseif self.body =~ '^=>' " Example: 'some key' => value call self.MarkOptionArg('classic') elseif self.body =~ '^\(\k\|[?!]\):[^:]' " Example: some_key: value call self.MarkOptionArg('new') endif call self.PushChar() endwhile if len(self.current_arg) > 0 call self.PushArg() endif endfunction " Pushes the current argument either to the args or opts stack and initializes " a new one. function! sj#argparser#ruby#PushArg() dict if self.current_arg_type == 'option' call add(self.opts, sj#Trim(self.current_arg)) else call add(self.args, sj#Trim(self.current_arg)) endif let self.current_arg = '' let self.current_arg_type = 'normal' if self.cursor_col > self.index + 1 " cursor is after the current argument let self.cursor_arg += 1 endif endfunction " If the last argument is a hash and no options have been parsed, splits the " last argument and fills the options with it. function! sj#argparser#ruby#ExpandOptionHash() dict if len(self.opts) <= 0 && len(self.args) > 0 " then try parsing the last parameter let last = self.args[-1] let hash_pattern = '^{\(.*\(=>\|\k:\|[''"]:\).*\)}$' if last =~ hash_pattern " then it seems to be a hash, expand it call remove(self.args, -1) let hash = sj#ExtractRx(last, hash_pattern, '\1') let [_from, _to, _args, opts, hash_type, _cursor_arg] = \ sj#argparser#ruby#ParseArguments(0, -1, hash, { 'expand_options': 1 }) call extend(self.opts, opts) let self.hash_type = hash_type endif endif endfunction " Returns true if the parser is at the function's end, either because of a " closing brace, a "do" clause or a "%>". function! sj#argparser#ruby#AtFunctionEnd() dict if self.body[0] == ')' return 1 elseif self.body =~ '\v^\s*do(\s*\|.*\|)?(\s*-?\%\>\s*)?$' return 1 elseif self.body =~ '^\s*-\?%>' return 1 endif return 0 endfunction " Public functions: " ================= function! sj#argparser#ruby#LocateFunction() return sj#argparser#common#LocateRubylikeFunction( \ '\k\+[?!]\=', \ ['rubyInterpolationDelimiter', 'rubyString'] \ ) endfunction function! sj#argparser#ruby#MarkOptionArg(type) dict let self.current_arg_type = 'option' if a:type == 'new' && sj#BlankString(self.hash_type) let self.hash_type = 'new' elseif a:type == 'classic' && sj#BlankString(self.hash_type) let self.hash_type = 'classic' elseif a:type != self.hash_type let self.hash_type = 'mixed' endif endfunction function! sj#argparser#ruby#LocateHash() return sj#LocateBracesOnLine('{', '}', ['rubyInterpolationDelimiter', 'rubyString']) endfunction function! sj#argparser#ruby#ParseArguments(start_index, end_index, line, options) let parser = sj#argparser#ruby#Construct(a:start_index, a:end_index, a:line) call parser.Process() if a:options.expand_options call parser.ExpandOptionHash() endif return [ a:start_index, parser.index, parser.args, parser.opts, parser.hash_type, parser.cursor_arg ] endfunction