Completed
Push — master ( dc4b6d...04cf1c )
by Kacper
04:06
created

Ruby::getIdentifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
1
<?php
2
/**
3
 * Highlighter
4
 *
5
 * Copyright (C) 2016, Some right reserved.
6
 *
7
 * @author Kacper "Kadet" Donat <[email protected]>
8
 *
9
 * Contact with author:
10
 * Xmpp: [email protected]
11
 * E-mail: [email protected]
12
 *
13
 * From Kadet with love.
14
 */
15
16
namespace Kadet\Highlighter\Language;
17
18
19
use Kadet\Highlighter\Matcher\CommentMatcher;
20
use Kadet\Highlighter\Matcher\RegexMatcher;
21
use Kadet\Highlighter\Matcher\WordMatcher;
22
use Kadet\Highlighter\Parser\CloseRule;
23
use Kadet\Highlighter\Parser\OpenRule;
24
use Kadet\Highlighter\Parser\Rule;
25
use Kadet\Highlighter\Parser\Token\ContextualToken;
26
use Kadet\Highlighter\Parser\Token\LanguageToken;
27
use Kadet\Highlighter\Parser\TokenFactory;
28
29
class Ruby extends GreedyLanguage
30
{
31
32
    /**
33
     * Tokenization rules setup
34
     */
35
    public function setupRules()
36
    {
37
        $function = '[a-z]\w*[!?]?';
38
        $this->rules->addMany([
39
            'comment' => [
40
                new Rule(new CommentMatcher(['#']), ['context' => ['!string.regex', '!string']]),
41
                'doc' => [
42
                    new OpenRule(new RegexMatcher('/^(=begin)/m')),
43
                    new CloseRule(new RegexMatcher('/^(=end)/m')),
44
                ]
45
            ],
46
            'keyword' => new Rule(new WordMatcher([
47
                'BEGIN', 'class', 'ensure', 'when', 'END', 'def', 'not', 'super', 'while',
48
                'alias', 'defined', 'for', 'or', 'then', 'yield', 'and', 'do', 'if', 'redo', 'begin', 'else',
49
                'in', 'rescue', 'undef', 'break', 'elsif', 'module', 'retry', 'unless', 'case', 'end', 'next', 'return',
50
                'until',
51
            ], ['case-sensitivity' => true])),
52
            'string' => [
53
                CommonFeatures::strings(
54
                    ['single' => '\'', 'double' => '"'],
55
                    ['context' => ['!operator.escape', '!comment', '!string', '!expression']]
56
                ),
57
                'generalized' => [
58
                    // TODO: Generalized strings
59
                ]
60
            ],
61
            'operator.escape' => new Rule(new RegexMatcher('/(\\\.)/'), [
62
                'context' => ['string']
63
            ]),
64
            'constant' => [
65
                new Rule(new RegexMatcher('/(?:[a-z_])?::([a-z_]\w*)/i')),
66
                'special' => new Rule(new WordMatcher(['self', 'nil', 'true', 'false', '__FILE__', '__LINE__']))
67
            ],
68
            'variable' => [
69
                'global'   => new Rule(new RegexMatcher('/(?:[^\\\]|^)(\$\w*)/i')),
70
                'property' => new Rule(new RegexMatcher('/(?:[^\\\]|^)(@{1,2}\w*)/i')),
71
            ],
72
            // JS + Perl = Ruby?
73
            'string.regex' => [
74
                new OpenRule(new RegexMatcher('#(?>[\[=(?:+,!~]|^|return|=>|&&|\|\|)\s*(/).*?/#sm'), [
75
                    'context' => ['!comment']
76
                ]),
77
                new Rule(new RegexMatcher('#(?=\/.*?(/[mixounse]*))#sm'), [
78
                    'priority' => 2,
79
                    'factory'  => new TokenFactory(ContextualToken::class),
80
                    'context'  => ['!operator.escape', 'string.regex']
81
                ])
82
            ],
83
            'call' => [
84
                new Rule(new RegexMatcher("/($function)\\s*\\(/i"), ['priority' => 2]),
85
                new Rule(new RegexMatcher(
86
                    // fixme: expression handling smth[blah].func
87
                    "/(?<![^\\\\]\\\\)(?<=\\n|\\{|\\(|\\}|\\|\\||or|&&|and|=|;)\\s*(?:\\w+(?:::|\\.))?($function)(?:[\\h\r]*\$|\\h+['\":\\w])/im"
88
                ), ['priority' => 0]),
89
            ],
90
            'symbol' => [
91
                'symbol'   => new Rule(new RegexMatcher('/[^\B:](:[a-z_]\w*)/i')),
92
                'class'    => new Rule(new RegexMatcher('/class\s+([a-z_]\w*)/i')),
93
                'function' => new Rule(new RegexMatcher('/def\s+(?:\[\]\s*|\*\s*|\w+\.){0,2}([a-z_]\w*)/i')),
94
            ],
95
            'expression.in-string' => new Rule(new RegexMatcher('/(?=(\#\{((?>[^\#{}]+|(?1))+)\}))/x'), [
96
                'context' => ['string.double'],
97
                'factory' => new TokenFactory(LanguageToken::class),
98
                'inject'  => $this
99
            ]),
100
101
            'number'    => new Rule(new RegexMatcher('/((?:-|\b)(?:0[0-7]+|0[xX][0-9a-fA-F]+|0b[01]+|\d+))/')),
102
        ]);
103
    }
104
105
    /**
106
     * Unique language identifier, for example 'php'
107
     *
108
     * @return string
109
     */
110 2
    public function getIdentifier()
111
    {
112 2
        return 'ruby';
113
    }
114
115 View Code Duplication
    public static function getMetadata()
116
    {
117
        return [
118
            'name'      => ['ruby'],
119
            'mime'      => ['text/x-ruby', 'application/x-ruby'],
120
            'extension' => ['*.rb', '*.rbw', 'Rakefile', '*.rake', '*.gemspec', '*.rbx', '*.duby', 'Gemfile'],
121
        ];
122
    }
123
}
124