/**
 * Ruby patterns
 *
 * @author Matthew King
 * @author Jesse Farmer <jesse@20bits.com>
 * @author actsasflinn
 * @version 1.0.5
 */

Rainbow.extend('ruby', [
    /**
     * Strings
     *   1. No support for multi-line strings
     */
    {
        'name': 'string',
        'matches': {
            1: 'string.open',
            2: {
                'name': 'string.keyword',
                'pattern': /(\#\{.*?\})/g
            },
            3: 'string.close'
        },
        'pattern': /("|`)(.*?[^\\\1])?(\1)/g
    },
    {
        'name': 'string',
        'pattern': /('|"|`)([^\\\1\n]|\\.)*\1/g
    },
    {
        'name': 'string',
        'pattern': /%[qQ](?=(\(|\[|\{|&lt;|.)(.*?)(?:'|\)|\]|\}|&gt;|\1))(?:\(\2\)|\[\2\]|\{\2\}|\&lt;\2&gt;|\1\2\1)/g
    },
    /**
     * Heredocs
     * Heredocs of the form `<<'HTML' ... HTML` are unsupported.
     */
    {
        'matches': {
            1: 'string',
            2: 'string',
            3: 'string'
        },
        'pattern': /(&lt;&lt;)(\w+).*?$([\s\S]*?^\2)/gm
    },
    {
        'matches': {
            1: 'string',
            2: 'string',
            3: 'string'
        },
        'pattern': /(&lt;&lt;\-)(\w+).*?$([\s\S]*?\2)/gm
    },
    /**
     * Regular expressions
     * Escaped delimiter (`/\//`) is unsupported.
     */
    {
        'name': 'string.regexp',
        'matches': {
            1: 'string.regexp',
            2: {
                'name': 'string.regexp',
                'pattern': /\\(.){1}/g
            },
            3: 'string.regexp',
            4: 'string.regexp'
        },
        'pattern': /(\/)(.*?)(\/)([a-z]*)/g
    },
    {
        'name': 'string.regexp',
        'matches': {
            1: 'string.regexp',
            2: {
                'name': 'string.regexp',
                'pattern': /\\(.){1}/g
            },
            3: 'string.regexp',
            4: 'string.regexp'
        },
        'pattern': /%r(?=(\(|\[|\{|&lt;|.)(.*?)('|\)|\]|\}|&gt;|\1))(?:\(\2\)|\[\2\]|\{\2\}|\&lt;\2&gt;|\1\2\1)([a-z]*)/g
    },
    /**
     * Comments
     */
    {
        'name': 'comment',
        'pattern': /#.*$/gm
    },
    {
        'name': 'comment',
        'pattern': /^\=begin[\s\S]*?\=end$/gm
    },
    /**
     * Symbols
     */
    {
        'matches': {
            1: 'constant'
        },
        'pattern': /(\w+:)[^:]/g
    },
    {
        'matches': {
            1: 'constant.symbol'
        },
        'pattern': /[^:](:(?:\w+|(?=['"](.*?)['"])(?:"\2"|'\2')))/g
    },
    {
        'name': 'constant.numeric',
        'pattern': /\b(0x[\da-f]+|\d+)\b/g
    },
    {
        'name': 'support.class',
        'pattern': /\b[A-Z]\w*(?=((\.|::)[A-Za-z]|\[))/g
    },
    {
        'name': 'constant',
        'pattern': /\b[A-Z]\w*\b/g
    },
    /**
     * Keywords, variables, constants, and operators
     *   In Ruby some keywords are valid method names, e.g., MyClass#yield
     *   Don't mark those instances as "keywords"
     */
    {
        'matches': {
            1: 'storage.class',
            2: 'entity.name.class',
            3: 'entity.other.inherited-class'
        },
        'pattern': /\s*(class)\s+((?:(?:::)?[A-Z]\w*)+)(?:\s+&lt;\s+((?:(?:::)?[A-Z]\w*)+))?/g
    },
    {
        'matches': {
            1: 'storage.module',
            2: 'entity.name.class'
        },
        'pattern': /\s*(module)\s+((?:(?:::)?[A-Z]\w*)+)/g
    },
    {
        'name': 'variable.global',
        'pattern': /\$([a-zA-Z_]\w*)\b/g
    },
    {
        'name': 'variable.class',
        'pattern': /@@([a-zA-Z_]\w*)\b/g
    },
    {
        'name': 'variable.instance',
        'pattern': /@([a-zA-Z_]\w*)\b/g
    },
    {
        'matches': {
            1: 'keyword.control'
        },
        'pattern': /[^\.]\b(BEGIN|begin|case|class|do|else|elsif|END|end|ensure|for|if|in|module|rescue|then|unless|until|when|while)\b(?![?!])/g
    },
    {
        'matches': {
            1: 'keyword.control.pseudo-method'
        },
        'pattern': /[^\.]\b(alias|alias_method|break|next|redo|retry|return|super|undef|yield)\b(?![?!])|\bdefined\?|\bblock_given\?/g
    },
    {
        'matches': {
            1: 'constant.language'
        },
        'pattern': /\b(nil|true|false)\b(?![?!])/g
    },
    {
        'matches': {
            1: 'variable.language'
        },
        'pattern': /\b(__(FILE|LINE)__|self)\b(?![?!])/g
    },
    {
        'matches': {
            1: 'keyword.special-method'
        },
        'pattern': /\b(require|gem|initialize|new|loop|include|extend|raise|attr_reader|attr_writer|attr_accessor|attr|catch|throw|private|module_function|public|protected)\b(?![?!])/g
    },
    {
        'name': 'keyword.operator',
        'pattern': /\s\?\s|=|&lt;&lt;|&lt;&lt;=|%=|&=|\*=|\*\*=|\+=|\-=|\^=|\|{1,2}=|&lt;&lt;|&lt;=&gt;|&lt;(?!&lt;|=)|&gt;(?!&lt;|=|&gt;)|&lt;=|&gt;=|===|==|=~|!=|!~|%|&amp;|\*\*|\*|\+|\-|\/|\||~|&gt;&gt;/g
    },
    {
        'matches': {
            1: 'keyword.operator.logical'
        },
        'pattern': /[^\.]\b(and|not|or)\b/g
    },

    /**
    * Functions
    *   1. No support for marking function parameters
    */
    {
        'matches': {
            1: 'storage.function',
            2: 'entity.name.function'
        },
        'pattern': /(def)\s(.*?)(?=(\s|\())/g
    }
], true);
