File: string_splitter.rb

package info (click to toggle)
ruby-hamlit 2.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,576 kB
  • ctags: 1,122
  • sloc: ruby: 10,667; ansic: 517; sh: 23; makefile: 8
file content (88 lines) | stat: -rw-r--r-- 2,340 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
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
40
41
42
43
44
45
46
47
48
49
50
51
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
require 'ripper'
require 'hamlit/ruby_expression'

module Hamlit
  class StringSplitter < Temple::Filter
    class << self
      # `code` param must be valid string literal
      def compile(code)
        [].tap do |exps|
          tokens = Ripper.lex(code.strip)
          tokens.pop while tokens.last && %i[on_comment on_sp].include?(tokens.last[1])

          if tokens.size < 2
            raise Hamlit::InternalError.new("Expected token size >= 2 but got: #{tokens.size}")
          end
          compile_tokens!(exps, tokens)
        end
      end

      private

      def strip_quotes!(tokens)
        _, type, beg_str = tokens.shift
        if type != :on_tstring_beg
          raise Hamlit::InternalError.new("Expected :on_tstring_beg but got: #{type}")
        end

        _, type, end_str = tokens.pop
        if type != :on_tstring_end
          raise Hamlit::InternalError.new("Expected :on_tstring_end but got: #{type}")
        end

        [beg_str, end_str]
      end

      def compile_tokens!(exps, tokens)
        beg_str, end_str = strip_quotes!(tokens)

        until tokens.empty?
          _, type, str = tokens.shift

          case type
          when :on_tstring_content
            exps << [:static, eval("#{beg_str}#{str}#{end_str}")]
          when :on_embexpr_beg
            embedded = shift_balanced_embexpr(tokens)
            exps << [:dynamic, embedded] unless embedded.empty?
          end
        end
      end

      def shift_balanced_embexpr(tokens)
        String.new.tap do |embedded|
          embexpr_open = 1

          until tokens.empty?
            _, type, str = tokens.shift
            case type
            when :on_embexpr_beg
              embexpr_open += 1
            when :on_embexpr_end
              embexpr_open -= 1
              break if embexpr_open == 0
            end

            embedded << str
          end
        end
      end
    end

    def on_dynamic(code)
      return [:dynamic, code] unless RubyExpression.string_literal?(code)
      return [:dynamic, code] if code.include?("\n")

      temple = [:multi]
      StringSplitter.compile(code).each do |type, content|
        case type
        when :static
          temple << [:static, content]
        when :dynamic
          temple << on_dynamic(content)
        end
      end
      temple
    end
  end
end