rblade 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +4 -0
- data/CHANGELOG.md +4 -0
- data/README.md +52 -0
- data/Rakefile +1 -1
- data/do +10 -10
- data/lib/rblade/compiler/compiles_comments.rb +1 -1
- data/lib/rblade/compiler/compiles_components.rb +2 -2
- data/lib/rblade/compiler/statements/compiles_component_helpers.rb +0 -2
- data/lib/rblade/compiler/tokenizes_statements.rb +136 -126
- data/lib/rblade/component_store.rb +1 -1
- data/lib/rblade/helpers/regular_expressions.rb +135 -0
- data/lib/rblade/railtie.rb +16 -6
- data/rblade.gemspec +2 -2
- metadata +5 -5
- data/lib/rblade/helpers/tokenizer.rb +0 -65
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 565a823219a85db94f6fa31e42de52cab5d1de562c89c42243a0105d54eab581
         | 
| 4 | 
            +
              data.tar.gz: 484ca84492233eabd1c61a534be991cfdb489273751e4e43a1b5ac400965b867
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a3fa94d7c7c3f19f3671dd346bffedbee1fdaaf3b93ce0928cba1b6bb7d24a7c7da83c016863df9aa8c5cbdd0d5519d65efef7aa18a59a77a7861764e8188f03
         | 
| 7 | 
            +
              data.tar.gz: 29325e82f35eb1e6b949b49684ea5c78cea910ffeeacf18ef012c39ff6cbe2a73e26bd47d1753734cc712421b19a958dab54224c024c25ca580b53b34b6dcb9a
         | 
    
        data/.github/workflows/ruby.yml
    CHANGED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,7 @@ | |
| 1 | 
            +
            ## 3.1.0 [2025-04-02]
         | 
| 2 | 
            +
            - Add ability to use slots in dynamic components and the component view helper method
         | 
| 3 | 
            +
            - Change statement matching to use regular expressions to improve compile performance
         | 
| 4 | 
            +
             | 
| 1 5 | 
             
            ## 3.0.1 [2025-03-18]
         | 
| 2 6 | 
             
            - Fix dynamic components not working when `RBlade.component_helper_method_name` is set
         | 
| 3 7 |  | 
    
        data/README.md
    CHANGED
    
    | @@ -62,6 +62,7 @@ For a quick overview of RBlade's capabilities, refer to the [reference file](REF | |
| 62 62 | 
             
                + [Method Field](#method-field)
         | 
| 63 63 | 
             
              * [Stacks](#stacks)
         | 
| 64 64 | 
             
              * [Integrating RBlade With Other Templates](#rblade-integration)
         | 
| 65 | 
            +
              * [Limitations](#limitations)
         | 
| 65 66 |  | 
| 66 67 | 
             
            <a name="displaying-data"></a>
         | 
| 67 68 | 
             
            ## Displaying Data
         | 
| @@ -984,6 +985,18 @@ You might want to use RBlade components within other templates, e.g. if you are | |
| 984 985 | 
             
            <% end %>
         | 
| 985 986 | 
             
            ```
         | 
| 986 987 |  | 
| 988 | 
            +
            The component method also passes a proc that can be used to specify slots:
         | 
| 989 | 
            +
             | 
| 990 | 
            +
            ```erb
         | 
| 991 | 
            +
            <%= component "card" do |slot| %>
         | 
| 992 | 
            +
              <%# The "class" attribute and the contents of the block will be passed in as the "heading" attribute to the card component %>
         | 
| 993 | 
            +
              <% slot :heading, class: "font-bold" do %>
         | 
| 994 | 
            +
                Heading
         | 
| 995 | 
            +
              <% end %>
         | 
| 996 | 
            +
              Content
         | 
| 997 | 
            +
            <% end %>
         | 
| 998 | 
            +
            ```
         | 
| 999 | 
            +
             | 
| 987 1000 | 
             
            If preferred, the `component` method can be renamed using the `RBlade.component_helper_method_name` option:
         | 
| 988 1001 |  | 
| 989 1002 | 
             
            ```ruby
         | 
| @@ -1017,3 +1030,42 @@ Once enabled, RBlade components can be used as layouts for ERB templates, or ren | |
| 1017 1030 |  | 
| 1018 1031 | 
             
            > [!NOTE]  
         | 
| 1019 1032 | 
             
            > Using the `component` helper instead of RBlade's component syntax does not take advantage of RBlade's component caching
         | 
| 1033 | 
            +
             | 
| 1034 | 
            +
             | 
| 1035 | 
            +
            <a name="limitations"></a>
         | 
| 1036 | 
            +
            ## Limitations
         | 
| 1037 | 
            +
             | 
| 1038 | 
            +
            ### Regular expressions in RBlade directives
         | 
| 1039 | 
            +
             | 
| 1040 | 
            +
            Regular expression literals may cause improper bracket matching in RBlade directive. To work around this, use the `%r` percent literal syntax.
         | 
| 1041 | 
            +
             | 
| 1042 | 
            +
            ```rblade
         | 
| 1043 | 
            +
            {{-- Parentheses in regular expressions may cause incorrect matching --}}
         | 
| 1044 | 
            +
            @ruby(/\)/)
         | 
| 1045 | 
            +
             | 
| 1046 | 
            +
            {{-- A workaround is to use the alternative %r syntax --}}
         | 
| 1047 | 
            +
            @ruby(%r/\)/)
         | 
| 1048 | 
            +
            ```
         | 
| 1049 | 
            +
             | 
| 1050 | 
            +
            ### `<<` in RBlade directives
         | 
| 1051 | 
            +
             | 
| 1052 | 
            +
            The append operator is assumed to be a HEREDOC if followed immediately by a word character (a-z, A-Z, _), `-` or `~`.
         | 
| 1053 | 
            +
             | 
| 1054 | 
            +
            ```rblade
         | 
| 1055 | 
            +
            {{-- If using `<<` to append, add a space after the operator --}}
         | 
| 1056 | 
            +
            @ruby(string << "extra")
         | 
| 1057 | 
            +
            ```
         | 
| 1058 | 
            +
             | 
| 1059 | 
            +
            ### End brackets in print statements
         | 
| 1060 | 
            +
             | 
| 1061 | 
            +
            Print statements cannot contain their end bracket in strings or other literals:
         | 
| 1062 | 
            +
             | 
| 1063 | 
            +
            ```rblade
         | 
| 1064 | 
            +
            # These examples will cause a syntax error
         | 
| 1065 | 
            +
            {{ '}}' }}
         | 
| 1066 | 
            +
            <%= 'foo%>' %>
         | 
| 1067 | 
            +
             | 
| 1068 | 
            +
            # A workaround is to use the alternative syntax
         | 
| 1069 | 
            +
            <%= 'foo}}' %>
         | 
| 1070 | 
            +
            {{ 'foo%>' }}
         | 
| 1071 | 
            +
            ```
         | 
    
        data/Rakefile
    CHANGED
    
    
    
        data/do
    CHANGED
    
    | @@ -43,36 +43,36 @@ fi | |
| 43 43 |  | 
| 44 44 | 
             
            if [ "$1" == "run" ] || [ "$1" == "r" ]
         | 
| 45 45 | 
             
            then
         | 
| 46 | 
            -
                echo Running: ${DOCKER_COMPOSE_COMMAND} run blade ${@:2}
         | 
| 47 | 
            -
                ${DOCKER_COMPOSE_COMMAND} run blade "${@:2}"
         | 
| 46 | 
            +
                echo Running: ${DOCKER_COMPOSE_COMMAND} run --remove-orphans --rm blade ${@:2}
         | 
| 47 | 
            +
                ${DOCKER_COMPOSE_COMMAND} run --remove-orphans --rm blade "${@:2}"
         | 
| 48 48 | 
             
                exit 0
         | 
| 49 49 | 
             
            fi
         | 
| 50 50 |  | 
| 51 51 | 
             
            if [ "$1" == "rake" ] || [ "$1" == "rk" ]
         | 
| 52 52 | 
             
            then
         | 
| 53 | 
            -
                echo Running: ${DOCKER_COMPOSE_COMMAND} run blade rake ${@:2}
         | 
| 54 | 
            -
                ${DOCKER_COMPOSE_COMMAND} run blade rake "${@:2}"
         | 
| 53 | 
            +
                echo Running: ${DOCKER_COMPOSE_COMMAND} run --remove-orphans --rm blade rake ${@:2}
         | 
| 54 | 
            +
                ${DOCKER_COMPOSE_COMMAND} run --remove-orphans --rm blade rake "${@:2}"
         | 
| 55 55 | 
             
                exit 0
         | 
| 56 56 | 
             
            fi
         | 
| 57 57 |  | 
| 58 58 | 
             
            if [ "$1" == "cs" ] || [ "$1" == "c" ]
         | 
| 59 59 | 
             
            then
         | 
| 60 | 
            -
                echo Running: ${DOCKER_COMPOSE_COMMAND} run blade rubocop "${@:2}"
         | 
| 61 | 
            -
                ${DOCKER_COMPOSE_COMMAND} run blade rubocop "${@:2}"
         | 
| 60 | 
            +
                echo Running: ${DOCKER_COMPOSE_COMMAND} run --remove-orphans --rm blade rubocop "${@:2}"
         | 
| 61 | 
            +
                ${DOCKER_COMPOSE_COMMAND} run --remove-orphans --rm blade rubocop "${@:2}"
         | 
| 62 62 | 
             
                exit 0
         | 
| 63 63 | 
             
            fi
         | 
| 64 64 |  | 
| 65 65 | 
             
            if [ "$1" == "cs:fix" ]
         | 
| 66 66 | 
             
            then
         | 
| 67 | 
            -
                echo Running: ${DOCKER_COMPOSE_COMMAND} run blade rubocop --autocorrect "${@:2}"
         | 
| 68 | 
            -
                ${DOCKER_COMPOSE_COMMAND} run blade rubocop --autocorrect "${@:2}"
         | 
| 67 | 
            +
                echo Running: ${DOCKER_COMPOSE_COMMAND} run --remove-orphans --rm blade rubocop --autocorrect "${@:2}"
         | 
| 68 | 
            +
                ${DOCKER_COMPOSE_COMMAND} run --remove-orphans --rm blade rubocop --autocorrect "${@:2}"
         | 
| 69 69 | 
             
                exit 0
         | 
| 70 70 | 
             
            fi
         | 
| 71 71 |  | 
| 72 72 | 
             
            if [ "$1" == "test" ] || [ "$1" == "t" ]
         | 
| 73 73 | 
             
            then
         | 
| 74 | 
            -
                echo Running: ${DOCKER_COMPOSE_COMMAND} run blade rake test "${@:2}"
         | 
| 75 | 
            -
                ${DOCKER_COMPOSE_COMMAND} run blade rake test "${@:2}"
         | 
| 74 | 
            +
                echo Running: ${DOCKER_COMPOSE_COMMAND} run --remove-orphans --rm blade rake test "${@:2}"
         | 
| 75 | 
            +
                ${DOCKER_COMPOSE_COMMAND} run --remove-orphans --rm blade rake test "${@:2}"
         | 
| 76 76 | 
             
                exit 0
         | 
| 77 77 | 
             
            fi
         | 
| 78 78 |  | 
| @@ -45,7 +45,7 @@ module RBlade | |
| 45 45 | 
             
                  attributes = compile_attributes token.value[:attributes]
         | 
| 46 46 |  | 
| 47 47 | 
             
                  if component[:name].start_with? "slot::"
         | 
| 48 | 
            -
                    "_slot.call(:'#{RBlade.escape_quotes(component[:name].delete_prefix("slot::"))}', {#{attributes.join(",")}}) do;"
         | 
| 48 | 
            +
                    "_slot.call(:'#{RBlade.escape_quotes(component[:name].delete_prefix("slot::"))}', **{#{attributes.join(",")}}) do;"
         | 
| 49 49 | 
             
                  else
         | 
| 50 50 | 
             
                    "#{@component_store.component(component[:name])}(RBlade::AttributesManager.new({#{attributes.join(",")}})) do |_slot|;"
         | 
| 51 51 | 
             
                  end
         | 
| @@ -67,7 +67,7 @@ module RBlade | |
| 67 67 |  | 
| 68 68 | 
             
                  attributes = compile_attributes token.value[:attributes]
         | 
| 69 69 |  | 
| 70 | 
            -
                  "@output_buffer.raw_buffer<<#{RBlade.component_helper_method_name}(#{component_value}, '#{RBlade.escape_quotes(@component_store.current_view_name)}', #{attributes.join ","}) do | 
| 70 | 
            +
                  "@output_buffer.raw_buffer<<#{RBlade.component_helper_method_name}(#{component_value}, '#{RBlade.escape_quotes(@component_store.current_view_name)}', #{attributes.join ","}) do |_slot|;"
         | 
| 71 71 | 
             
                end
         | 
| 72 72 |  | 
| 73 73 | 
             
                def compile_token_end(token)
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require "rblade/helpers/ | 
| 3 | 
            +
            require "rblade/helpers/regular_expressions"
         | 
| 4 4 | 
             
            require "ripper"
         | 
| 5 5 |  | 
| 6 6 | 
             
            module RBlade
         | 
| @@ -9,161 +9,171 @@ module RBlade | |
| 9 9 | 
             
                  tokens.map! do |token|
         | 
| 10 10 | 
             
                    next(token) if token.type != :unprocessed
         | 
| 11 11 |  | 
| 12 | 
            -
                     | 
| 13 | 
            -
             | 
| 12 | 
            +
                    current_match_id = nil
         | 
| 13 | 
            +
                    segments = []
         | 
| 14 | 
            +
                    token.value.split(/
         | 
| 15 | 
            +
                      \s?(?<!\w|@)
         | 
| 14 16 | 
             
                      (?:
         | 
| 15 17 | 
             
                        (?:
         | 
| 16 | 
            -
                          ( | 
| 17 | 
            -
                          ( | 
| 18 | 
            +
                          (?<escaped_at>@@)
         | 
| 19 | 
            +
                          (?=\w++[!\?]?(?!\w))
         | 
| 18 20 | 
             
                        )
         | 
| 19 21 | 
             
                        |
         | 
| 20 22 | 
             
                        (?:
         | 
| 21 | 
            -
                           | 
| 22 | 
            -
                          ( | 
| 23 | 
            -
                          ( | 
| 24 | 
            -
             | 
| 23 | 
            +
                          @
         | 
| 24 | 
            +
                          (?# Statement name )
         | 
| 25 | 
            +
                          (?<statement_name>\w++[!\?]?)
         | 
| 26 | 
            +
                          (?# Optional parameters )
         | 
| 27 | 
            +
                          (?:
         | 
| 28 | 
            +
                            [ \t]*+
         | 
| 29 | 
            +
                            (?# Matched parentheses )
         | 
| 30 | 
            +
                            (?<statement_arguments>
         | 
| 31 | 
            +
                              \(
         | 
| 32 | 
            +
                                (?:
         | 
| 33 | 
            +
                                  [^()#{RegularExpressions::RUBY_STRING_CHARACTERS}]++
         | 
| 34 | 
            +
                                  |
         | 
| 35 | 
            +
                                  #{RegularExpressions::RUBY_STRING}
         | 
| 36 | 
            +
                                  |
         | 
| 37 | 
            +
                                  \g<statement_arguments>
         | 
| 38 | 
            +
                                )*+
         | 
| 39 | 
            +
                              \)
         | 
| 40 | 
            +
                            )
         | 
| 25 41 | 
             
                          )?
         | 
| 26 42 | 
             
                        )
         | 
| 27 43 | 
             
                      )
         | 
| 28 | 
            -
                       | 
| 29 | 
            -
                    / | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
                    # The @ symbol is used to escape blade directives so we return it unprocessed
         | 
| 43 | 
            -
                    if segment == "@@"
         | 
| 44 | 
            -
                      segments[i] = Token.new(type: :unprocessed, value: segment[1..] + segments[i + 1])
         | 
| 45 | 
            -
                      segments.delete_at i + 1
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                      i += 1
         | 
| 48 | 
            -
                    elsif segment == "@"
         | 
| 49 | 
            -
                      statement_handle = segments[i + 1].downcase.tr "_", ""
         | 
| 50 | 
            -
                      if CompilesStatements.has_handler(statement_handle)
         | 
| 51 | 
            -
                        tokenize_statement! statement_handle, segments, i
         | 
| 52 | 
            -
                        handle_special_cases! segments, i
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                        segments.delete_at(i + 1) if segments[i + 1]&.match?(/\A\s\z/)
         | 
| 55 | 
            -
                        if segments[i - 1].is_a?(Token) && segments[i - 1].type == :unprocessed && segments[i - 1].value.match?(/\A\s\z/)
         | 
| 56 | 
            -
                          segments.delete_at i - 1
         | 
| 57 | 
            -
                          i -= 1
         | 
| 44 | 
            +
                      \s?
         | 
| 45 | 
            +
                    /xo) do |before_match|
         | 
| 46 | 
            +
                      next if current_match_id == $~.object_id
         | 
| 47 | 
            +
                      current_match_id = $~.object_id
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                      # Add the current string to the segment list
         | 
| 50 | 
            +
                      unless before_match == ""
         | 
| 51 | 
            +
                        # Skip output between case and when statements
         | 
| 52 | 
            +
                        unless segments.last&.type == :statement && segments.last&.value&.[](:name) == "case"
         | 
| 53 | 
            +
                          if segments.last && segments.last.type == :unprocessed
         | 
| 54 | 
            +
                            segments.last.value << before_match
         | 
| 55 | 
            +
                          else
         | 
| 56 | 
            +
                            segments << Token.new(type: :unprocessed, value: before_match)
         | 
| 57 | 
            +
                          end
         | 
| 58 58 | 
             
                        end
         | 
| 59 | 
            -
                       | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
                         | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
                          segments. | 
| 59 | 
            +
                      end
         | 
| 60 | 
            +
                      next if $~.nil?
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                      # Skip escaped statements
         | 
| 63 | 
            +
                      if $~&.[](:escaped_at) == "@@"
         | 
| 64 | 
            +
                        segment = $&
         | 
| 65 | 
            +
                        # Remove the first or second @, depending on whether there is whitespace
         | 
| 66 | 
            +
                        segment.slice!(1).inspect
         | 
| 67 | 
            +
                        if segments.last && segments.last.type == :unprocessed
         | 
| 68 | 
            +
                          segments.last.value << segment
         | 
| 69 | 
            +
                        else
         | 
| 70 | 
            +
                          segments << Token.new(type: :unprocessed, value: segment)
         | 
| 71 71 | 
             
                        end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                        next
         | 
| 72 74 | 
             
                      end
         | 
| 73 75 |  | 
| 74 | 
            -
                       | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 76 | 
            +
                      statement_handle = $~[:statement_name].downcase.tr("_", "")
         | 
| 77 | 
            +
                      unless CompilesStatements.has_handler(statement_handle)
         | 
| 78 | 
            +
                        if segments.last && segments.last.type == :unprocessed
         | 
| 79 | 
            +
                          segments.last.value << $&
         | 
| 80 | 
            +
                        else
         | 
| 81 | 
            +
                          segments << Token.new(type: :unprocessed, value: $&)
         | 
| 82 | 
            +
                        end
         | 
| 77 83 |  | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
                      segments.delete_at i
         | 
| 81 | 
            -
                    end
         | 
| 82 | 
            -
                  end
         | 
| 84 | 
            +
                        next
         | 
| 85 | 
            +
                      end
         | 
| 83 86 |  | 
| 84 | 
            -
             | 
| 85 | 
            -
                end
         | 
| 87 | 
            +
                      statement_data = {name: statement_handle}
         | 
| 86 88 |  | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
                  statement_data = {name: handle}
         | 
| 89 | 
            +
                      unless $~[:statement_arguments].blank?
         | 
| 90 | 
            +
                        arguments = tokenize_arguments! statement_handle, $~[:statement_arguments]
         | 
| 90 91 |  | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
                  end
         | 
| 92 | 
            +
                        unless arguments.nil?
         | 
| 93 | 
            +
                          statement_data[:arguments] = arguments
         | 
| 94 | 
            +
                        end
         | 
| 95 95 |  | 
| 96 | 
            -
             | 
| 97 | 
            -
                    arguments = tokenize_arguments! handle, segments, i + 1
         | 
| 96 | 
            +
                      end
         | 
| 98 97 |  | 
| 99 | 
            -
             | 
| 100 | 
            -
                      statement_data[:arguments] = arguments
         | 
| 98 | 
            +
                      segments << Token.new(type: :statement, value: statement_data)
         | 
| 101 99 | 
             
                    end
         | 
| 102 | 
            -
                  end
         | 
| 103 100 |  | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
                def handle_special_cases!(segments, i)
         | 
| 108 | 
            -
                  if segments[i][:value][:name] == "case"
         | 
| 109 | 
            -
                    # Remove any whitespace before a when statement
         | 
| 110 | 
            -
                    until segments[i + 1].nil? || segments[i + 1] == "@"
         | 
| 111 | 
            -
                      segments.delete_at i + 1
         | 
| 112 | 
            -
                    end
         | 
| 113 | 
            -
                  end
         | 
| 101 | 
            +
                    segments
         | 
| 102 | 
            +
                  end.flatten!
         | 
| 114 103 | 
             
                end
         | 
| 115 104 |  | 
| 116 | 
            -
                 | 
| 117 | 
            -
                  success = expand_segment_to_end_parenthesis! segments, segment_index
         | 
| 118 | 
            -
             | 
| 119 | 
            -
                  # If no matching parentheses were found, so we combine the argument string with the next segment
         | 
| 120 | 
            -
                  unless success
         | 
| 121 | 
            -
                    unless segments[segment_index + 1].nil?
         | 
| 122 | 
            -
                      segments[segment_index] <<= segments[segment_index + 1]
         | 
| 123 | 
            -
                      segments.delete_at segment_index + 1
         | 
| 124 | 
            -
                    end
         | 
| 125 | 
            -
             | 
| 126 | 
            -
                    return nil
         | 
| 127 | 
            -
                  end
         | 
| 105 | 
            +
                private
         | 
| 128 106 |  | 
| 129 | 
            -
             | 
| 130 | 
            -
                  argument_string  | 
| 107 | 
            +
                def tokenize_arguments!(statement_handle, argument_string)
         | 
| 108 | 
            +
                  argument_string.delete_prefix! "("
         | 
| 109 | 
            +
                  argument_string.delete_suffix! ")"
         | 
| 131 110 |  | 
| 132 | 
            -
                  # Special case for the props statement: remove the wrapping braces if they exist
         | 
| 133 111 | 
             
                  if statement_handle == "props"
         | 
| 134 | 
            -
                    if  | 
| 135 | 
            -
             | 
| 136 | 
            -
                     | 
| 112 | 
            +
                    # Special case for the props statement: remove wrapping braces if they exist
         | 
| 113 | 
            +
                    argument_string.delete_prefix! "{"
         | 
| 114 | 
            +
                    argument_string.delete_suffix! "}"
         | 
| 137 115 | 
             
                  end
         | 
| 138 116 |  | 
| 139 | 
            -
                   | 
| 140 | 
            -
                   | 
| 141 | 
            -
             | 
| 142 | 
            -
                  arguments
         | 
| 143 | 
            -
                end
         | 
| 144 | 
            -
             | 
| 145 | 
            -
                def expand_segment_to_end_parenthesis!(segments, segment_index)
         | 
| 146 | 
            -
                  parentheses_difference = 0
         | 
| 147 | 
            -
             | 
| 148 | 
            -
                  loop do
         | 
| 149 | 
            -
                    tokens = Ripper.lex(segments[segment_index]).map { |token| token[1] }
         | 
| 150 | 
            -
                    parentheses_difference = tokens.count(:on_lparen) - tokens.count(:on_rparen)
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                    break if parentheses_difference.zero? || segments[segment_index + 1].nil?
         | 
| 153 | 
            -
             | 
| 154 | 
            -
                    index = segments[segment_index + 1].each_char.find_index { |c| c == ")" && (parentheses_difference -= 1).zero? }
         | 
| 117 | 
            +
                  argument_string.strip!
         | 
| 118 | 
            +
                  return nil if argument_string == ""
         | 
| 155 119 |  | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
                     | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 120 | 
            +
                  current_match_id = nil
         | 
| 121 | 
            +
                  arguments = []
         | 
| 122 | 
            +
                  argument_string.split(/
         | 
| 123 | 
            +
                    \G
         | 
| 124 | 
            +
                    (?<argument>
         | 
| 125 | 
            +
                      (?:
         | 
| 126 | 
            +
                        [^,\(\{\[#{RegularExpressions::RUBY_STRING_CHARACTERS}]++
         | 
| 127 | 
            +
                        |
         | 
| 128 | 
            +
                        #{RegularExpressions::RUBY_STRING}
         | 
| 129 | 
            +
                        |
         | 
| 130 | 
            +
                        (?<parentheses>
         | 
| 131 | 
            +
                          \(
         | 
| 132 | 
            +
                            (?:
         | 
| 133 | 
            +
                              [^\(\)#{RegularExpressions::RUBY_STRING_CHARACTERS}]++
         | 
| 134 | 
            +
                              |
         | 
| 135 | 
            +
                              \g<string>
         | 
| 136 | 
            +
                              |
         | 
| 137 | 
            +
                              \g<parentheses>
         | 
| 138 | 
            +
                            )*+
         | 
| 139 | 
            +
                          \)
         | 
| 140 | 
            +
                        )
         | 
| 141 | 
            +
                        |
         | 
| 142 | 
            +
                        (?<brackets>
         | 
| 143 | 
            +
                          \[
         | 
| 144 | 
            +
                            (?:
         | 
| 145 | 
            +
                              [^\[\]#{RegularExpressions::RUBY_STRING_CHARACTERS}]++
         | 
| 146 | 
            +
                              |
         | 
| 147 | 
            +
                              \g<string>
         | 
| 148 | 
            +
                              |
         | 
| 149 | 
            +
                              \g<brackets>
         | 
| 150 | 
            +
                            )*+
         | 
| 151 | 
            +
                          \]
         | 
| 152 | 
            +
                        )
         | 
| 153 | 
            +
                        |
         | 
| 154 | 
            +
                        (?<braces>
         | 
| 155 | 
            +
                          \{
         | 
| 156 | 
            +
                            (?:
         | 
| 157 | 
            +
                              [^\{\}#{RegularExpressions::RUBY_STRING_CHARACTERS}]++
         | 
| 158 | 
            +
                              |
         | 
| 159 | 
            +
                              \g<string>
         | 
| 160 | 
            +
                              |
         | 
| 161 | 
            +
                              \g<braces>
         | 
| 162 | 
            +
                            )*+
         | 
| 163 | 
            +
                          \}
         | 
| 164 | 
            +
                        )
         | 
| 165 | 
            +
                      )*+
         | 
| 166 | 
            +
                    )
         | 
| 167 | 
            +
                    ,
         | 
| 168 | 
            +
                  /xmo, -1) do |x|
         | 
| 169 | 
            +
                    next if current_match_id == $~.object_id
         | 
| 170 | 
            +
                    current_match_id = $~.object_id
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                    argument = ($~&.[](:argument) || x).strip
         | 
| 173 | 
            +
                    arguments << argument unless argument == ""
         | 
| 164 174 | 
             
                  end
         | 
| 165 175 |  | 
| 166 | 
            -
                   | 
| 176 | 
            +
                  arguments
         | 
| 167 177 | 
             
                end
         | 
| 168 178 | 
             
              end
         | 
| 169 179 | 
             
            end
         | 
| @@ -86,7 +86,7 @@ module RBlade | |
| 86 86 |  | 
| 87 87 | 
             
                  compiled_component = RBlade::Compiler.compile_string(template, self)
         | 
| 88 88 |  | 
| 89 | 
            -
                  @component_definitions << "def self._rblade_component_#{escaped_name}(attributes,&);slot=if block_given?;RBlade::SlotManager.new(@output_buffer.capture(->(name, slot_attributes, &slot_block)do;attributes[name]=RBlade::SlotManager.new(@output_buffer.capture(&slot_block), slot_attributes);end,&));end;_stacks=[];@output_buffer.raw_buffer<<@output_buffer.capture do;#{compiled_component}@output_buffer.raw_buffer.prepend(@_rblade_stack_manager.get(_stacks));end;end;"
         | 
| 89 | 
            +
                  @component_definitions << "def self._rblade_component_#{escaped_name}(attributes,&);slot=if block_given?;RBlade::SlotManager.new(@output_buffer.capture(->(name, **slot_attributes, &slot_block)do;attributes[name]=RBlade::SlotManager.new(@output_buffer.capture(&slot_block), slot_attributes);end,&));end;slot.nil?;_stacks=[];@output_buffer.raw_buffer<<@output_buffer.capture do;#{compiled_component}@output_buffer.raw_buffer.prepend(@_rblade_stack_manager.get(_stacks));end;end;"
         | 
| 90 90 |  | 
| 91 91 | 
             
                  @component_method_names[name] = "_rblade_component_#{escaped_name}"
         | 
| 92 92 | 
             
                end
         | 
| @@ -0,0 +1,135 @@ | |
| 1 | 
            +
            module RBlade::RegularExpressions
         | 
| 2 | 
            +
              RUBY_STRING_CHARACTERS = "\"'%?<"
         | 
| 3 | 
            +
              RUBY_STRING = /
         | 
| 4 | 
            +
                (?<string>
         | 
| 5 | 
            +
                (?# Interpolated strings )
         | 
| 6 | 
            +
                "
         | 
| 7 | 
            +
                  (?:
         | 
| 8 | 
            +
                    [^#"\\]++
         | 
| 9 | 
            +
                    |
         | 
| 10 | 
            +
                    \#(?<curly>\{
         | 
| 11 | 
            +
                      (?:
         | 
| 12 | 
            +
                        [^"'{}?%]++
         | 
| 13 | 
            +
                        |
         | 
| 14 | 
            +
                        \g<string>
         | 
| 15 | 
            +
                        |
         | 
| 16 | 
            +
                        \g<curly>
         | 
| 17 | 
            +
                      )*+
         | 
| 18 | 
            +
                    \})
         | 
| 19 | 
            +
                    |
         | 
| 20 | 
            +
                    \\.
         | 
| 21 | 
            +
                    |
         | 
| 22 | 
            +
                    (?!\#\{)\#[@$]?
         | 
| 23 | 
            +
                  )*+
         | 
| 24 | 
            +
                "
         | 
| 25 | 
            +
                |
         | 
| 26 | 
            +
                (?# Non interpolated strings )
         | 
| 27 | 
            +
                '
         | 
| 28 | 
            +
                  (?:
         | 
| 29 | 
            +
                    [^'\\]++
         | 
| 30 | 
            +
                    |
         | 
| 31 | 
            +
                    \\.
         | 
| 32 | 
            +
                  )*+
         | 
| 33 | 
            +
                '
         | 
| 34 | 
            +
                |
         | 
| 35 | 
            +
                (?# Non interpolated percent expressions )
         | 
| 36 | 
            +
                %[qwis]
         | 
| 37 | 
            +
                  (?:
         | 
| 38 | 
            +
                    (?<ni_parentheses> \( (?: [^()\\]++ | \\. | \g<ni_parentheses> )*+ \) )
         | 
| 39 | 
            +
                    |
         | 
| 40 | 
            +
                    (?<ni_brackets> \[ (?: [^\[\]\\]++ | \\. | \g<ni_brackets> )*+ \] )
         | 
| 41 | 
            +
                    |
         | 
| 42 | 
            +
                    (?<ni_crocs> < (?: [^<>\\]++ | \\. | \g<ni_crocs> )*+ > )
         | 
| 43 | 
            +
                    |
         | 
| 44 | 
            +
                    (?<ni_braces> \{ (?: [^{}\\]++ | \\. | \g<ni_braces> )*+ \} )
         | 
| 45 | 
            +
                    |
         | 
| 46 | 
            +
                    (?<percent_delimiter>[\x00-\x7F&&[^a-zA-Z0-9(\[{<]])
         | 
| 47 | 
            +
                    (?:
         | 
| 48 | 
            +
                      [a-zA-Z0-9(\[{<[^\x00-\x7F]]++
         | 
| 49 | 
            +
                      |
         | 
| 50 | 
            +
                      \\.
         | 
| 51 | 
            +
                      |
         | 
| 52 | 
            +
                      (?!\k<percent_delimiter>)[^\\]
         | 
| 53 | 
            +
                    )*?
         | 
| 54 | 
            +
                    \k<percent_delimiter>
         | 
| 55 | 
            +
                  )
         | 
| 56 | 
            +
                |
         | 
| 57 | 
            +
                (?# Interpolated percent expressions )
         | 
| 58 | 
            +
                %[QWIrx]?
         | 
| 59 | 
            +
                  (?:
         | 
| 60 | 
            +
                    (?<i_parentheses> \( (?: [^()\\#]++ | \#\g<curly> | \\. | \g<i_parentheses> )*+ \) )
         | 
| 61 | 
            +
                    |
         | 
| 62 | 
            +
                    (?<i_brackets> \[ (?: [^\[\]\\#]++ | \#\g<curly> | \\. | \g<i_brackets> )*+ \] )
         | 
| 63 | 
            +
                    |
         | 
| 64 | 
            +
                    (?<i_crocs> < (?: [^<>\\#]++ | \#\g<curly> | \\. | \g<i_crocs> )*+ > )
         | 
| 65 | 
            +
                    |
         | 
| 66 | 
            +
                    (?<i_braces> \{ (?: [^{}\\#]++ | \#\g<curly> | \\. | \g<i_braces> )*+ \} )
         | 
| 67 | 
            +
                    |
         | 
| 68 | 
            +
                    \g<percent_delimiter>
         | 
| 69 | 
            +
                    (?:
         | 
| 70 | 
            +
                      [a-zA-Z0-9(\[{<[^\x00-\x7F]]++
         | 
| 71 | 
            +
                      |
         | 
| 72 | 
            +
                      \#\g<curly>
         | 
| 73 | 
            +
                      |
         | 
| 74 | 
            +
                      \\.
         | 
| 75 | 
            +
                      |
         | 
| 76 | 
            +
                      (?!\k<percent_delimiter>)[^\\#]
         | 
| 77 | 
            +
                      |
         | 
| 78 | 
            +
                      (?!\#\{)\#[@$]?+
         | 
| 79 | 
            +
                    )*?
         | 
| 80 | 
            +
                    (?!\#\{)\k<percent_delimiter>
         | 
| 81 | 
            +
                  )
         | 
| 82 | 
            +
                |
         | 
| 83 | 
            +
                (?# Interpolated HEREDOC)
         | 
| 84 | 
            +
                <<(?:(?<heredoc_delimiter>[a-zA-Z_]\w*+)|"\g<heredoc_delimiter>")[^\n]*+\n
         | 
| 85 | 
            +
                (?:
         | 
| 86 | 
            +
                  (?!\k<heredoc_delimiter>$)[^\#\n]++
         | 
| 87 | 
            +
                  |
         | 
| 88 | 
            +
                  \#\g<curly>
         | 
| 89 | 
            +
                  |
         | 
| 90 | 
            +
                  (?!\#\{)\#[^\#\n]++
         | 
| 91 | 
            +
                  |
         | 
| 92 | 
            +
                  \n
         | 
| 93 | 
            +
                )*?
         | 
| 94 | 
            +
                \n\k<heredoc_delimiter>$
         | 
| 95 | 
            +
                |
         | 
| 96 | 
            +
                (?# Interpolated HEREDOC with leading spaces)
         | 
| 97 | 
            +
                <<[-~](?:\g<heredoc_delimiter>|"\g<heredoc_delimiter>")[^\n]*+\n
         | 
| 98 | 
            +
                (?:
         | 
| 99 | 
            +
                  (?!\k<heredoc_delimiter>$)[^\#\n]++
         | 
| 100 | 
            +
                  |
         | 
| 101 | 
            +
                  \#\g<curly>
         | 
| 102 | 
            +
                  |
         | 
| 103 | 
            +
                  (?!\#\{)\#[^\#\n]++
         | 
| 104 | 
            +
                  |
         | 
| 105 | 
            +
                  \n
         | 
| 106 | 
            +
                )*?
         | 
| 107 | 
            +
                \n\s*+\k<heredoc_delimiter>$
         | 
| 108 | 
            +
                |
         | 
| 109 | 
            +
                (?# Non-interpolated HEREDOC)
         | 
| 110 | 
            +
                <<'\g<heredoc_delimiter>'[^\n]*+\n
         | 
| 111 | 
            +
                (?:
         | 
| 112 | 
            +
                  (?!\k<heredoc_delimiter>$)[^\n]*+\n
         | 
| 113 | 
            +
                )*+
         | 
| 114 | 
            +
                \k<heredoc_delimiter>$
         | 
| 115 | 
            +
                |
         | 
| 116 | 
            +
                (?# Non-interpolated HEREDOC with leading spaces)
         | 
| 117 | 
            +
                <<[-~]'\g<heredoc_delimiter>'[^\n]*+\n
         | 
| 118 | 
            +
                (?:
         | 
| 119 | 
            +
                  (?!\s*\k<heredoc_delimiter>$)[^\n]*+\n
         | 
| 120 | 
            +
                )*+
         | 
| 121 | 
            +
                \s*\k<heredoc_delimiter>$
         | 
| 122 | 
            +
                |
         | 
| 123 | 
            +
                (?<!\w)\?.
         | 
| 124 | 
            +
                |
         | 
| 125 | 
            +
                (?# Consume characters that aren't string literals)
         | 
| 126 | 
            +
                (?<=\w)\?
         | 
| 127 | 
            +
                |
         | 
| 128 | 
            +
                (?# A percentage sign that's not a percent literal)
         | 
| 129 | 
            +
                %(?![qwisQWIrx]?+\g<percent_delimiter>)
         | 
| 130 | 
            +
                )
         | 
| 131 | 
            +
                |
         | 
| 132 | 
            +
                (?# Consume angled brackets that aren't HEREDOCs)
         | 
| 133 | 
            +
                <(?!<[~-]?['"a-zA-Z_])
         | 
| 134 | 
            +
              /mx
         | 
| 135 | 
            +
            end
         | 
    
        data/lib/rblade/railtie.rb
    CHANGED
    
    | @@ -23,7 +23,7 @@ module RBlade | |
| 23 23 | 
             
                end
         | 
| 24 24 |  | 
| 25 25 | 
             
                def setup_component_view_helper(mod)
         | 
| 26 | 
            -
                  mod.send(:define_method, RBlade.component_helper_method_name) do |component_name, current_view = nil, **attributes, &block|
         | 
| 26 | 
            +
                  mod.send(:define_method, RBlade.component_helper_method_name) do |component_name, current_view = nil, slot: "", **attributes, &block|
         | 
| 27 27 | 
             
                    # If this is a relative path, prepend with the previous component name's base
         | 
| 28 28 | 
             
                    if !current_view.nil? && component_name.start_with?(".")
         | 
| 29 29 | 
             
                      component_name = current_view.sub(/[^\.]++\z/, "") + component_name.delete_prefix(".")
         | 
| @@ -37,12 +37,22 @@ module RBlade | |
| 37 37 | 
             
                    end
         | 
| 38 38 | 
             
                    path.sub!(/(?:\.[^.]++)?\.rblade\z/, "")
         | 
| 39 39 |  | 
| 40 | 
            -
                     | 
| 41 | 
            -
                      slot: block.nil? ? attributes.delete(:slot) || -"" : capture(&block),
         | 
| 42 | 
            -
                      attributes: RBlade::AttributesManager.new(attributes),
         | 
| 43 | 
            -
                    }
         | 
| 40 | 
            +
                    attributes = RBlade::AttributesManager.new(attributes)
         | 
| 44 41 |  | 
| 45 | 
            -
                     | 
| 42 | 
            +
                    unless block.nil?
         | 
| 43 | 
            +
                      value = nil
         | 
| 44 | 
            +
                      slot = @output_buffer.capture do
         | 
| 45 | 
            +
                        value = block.call(->(name, **slot_attributes, &slot_block) do
         | 
| 46 | 
            +
                          attributes[name] = RBlade::SlotManager.new(@output_buffer.capture(&slot_block), slot_attributes)
         | 
| 47 | 
            +
                        end)
         | 
| 48 | 
            +
                      end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                      if slot.blank?
         | 
| 51 | 
            +
                        slot = value || ""
         | 
| 52 | 
            +
                      end
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    render template: path, locals: {slot: RBlade::SlotManager.new(slot), attributes:}
         | 
| 46 56 | 
             
                  end
         | 
| 47 57 | 
             
                end
         | 
| 48 58 | 
             
              end
         | 
    
        data/rblade.gemspec
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Gem::Specification.new do |s|
         | 
| 2 2 | 
             
              s.name = "rblade"
         | 
| 3 | 
            -
              s.version = "3.0 | 
| 3 | 
            +
              s.version = "3.1.0"
         | 
| 4 4 | 
             
              s.summary = "A component-first templating engine for Rails"
         | 
| 5 5 | 
             
              s.description = "RBlade is a simple, yet powerful templating engine for Ruby on Rails, inspired by Laravel Blade."
         | 
| 6 6 | 
             
              s.authors = ["Simon J"]
         | 
| @@ -14,7 +14,7 @@ Gem::Specification.new do |s| | |
| 14 14 |  | 
| 15 15 | 
             
              s.add_development_dependency "minitest", "~> 5.0"
         | 
| 16 16 | 
             
              s.add_development_dependency "minitest-reporters", "~> 1.1"
         | 
| 17 | 
            -
              s.add_development_dependency "standard", ">= 1. | 
| 17 | 
            +
              s.add_development_dependency "standard", ">= 1.35.1"
         | 
| 18 18 | 
             
              s.add_development_dependency "rubocop", ">= 1.73"
         | 
| 19 19 | 
             
              s.add_development_dependency "rails", ">= 7.0"
         | 
| 20 20 | 
             
              s.add_development_dependency "benchmark-ips"
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: rblade
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3.0 | 
| 4 | 
            +
              version: 3.1.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Simon J
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2025- | 
| 11 | 
            +
            date: 2025-04-02 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: minitest
         | 
| @@ -44,14 +44,14 @@ dependencies: | |
| 44 44 | 
             
                requirements:
         | 
| 45 45 | 
             
                - - ">="
         | 
| 46 46 | 
             
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            -
                    version:  | 
| 47 | 
            +
                    version: 1.35.1
         | 
| 48 48 | 
             
              type: :development
         | 
| 49 49 | 
             
              prerelease: false
         | 
| 50 50 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 51 | 
             
                requirements:
         | 
| 52 52 | 
             
                - - ">="
         | 
| 53 53 | 
             
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            -
                    version:  | 
| 54 | 
            +
                    version: 1.35.1
         | 
| 55 55 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 56 56 | 
             
              name: rubocop
         | 
| 57 57 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -154,10 +154,10 @@ files: | |
| 154 154 | 
             
            - lib/rblade/component_store.rb
         | 
| 155 155 | 
             
            - lib/rblade/helpers/attributes_manager.rb
         | 
| 156 156 | 
             
            - lib/rblade/helpers/class_manager.rb
         | 
| 157 | 
            +
            - lib/rblade/helpers/regular_expressions.rb
         | 
| 157 158 | 
             
            - lib/rblade/helpers/slot_manager.rb
         | 
| 158 159 | 
             
            - lib/rblade/helpers/stack_manager.rb
         | 
| 159 160 | 
             
            - lib/rblade/helpers/style_manager.rb
         | 
| 160 | 
            -
            - lib/rblade/helpers/tokenizer.rb
         | 
| 161 161 | 
             
            - lib/rblade/rails_template.rb
         | 
| 162 162 | 
             
            - lib/rblade/railtie.rb
         | 
| 163 163 | 
             
            - rblade.gemspec
         | 
| @@ -1,65 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module RBlade
         | 
| 4 | 
            -
              class Tokenizer
         | 
| 5 | 
            -
                def self.extract_comma_separated_values(segment)
         | 
| 6 | 
            -
                  unless segment.match?(/,\s*+\z/)
         | 
| 7 | 
            -
                    # Add a comma to the end to delimit the end of the last argument
         | 
| 8 | 
            -
                    segment += ","
         | 
| 9 | 
            -
                  end
         | 
| 10 | 
            -
                  segment_lines = segment.lines
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                  tokens = Ripper.lex segment
         | 
| 13 | 
            -
                  arguments = []
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                  current_line = 1
         | 
| 16 | 
            -
                  current_index = 0
         | 
| 17 | 
            -
                  bracket_count = {
         | 
| 18 | 
            -
                    "[]": 0,
         | 
| 19 | 
            -
                    "{}": 0,
         | 
| 20 | 
            -
                    "()": 0,
         | 
| 21 | 
            -
                  }
         | 
| 22 | 
            -
                  tokens.each do |token|
         | 
| 23 | 
            -
                    case token[1]
         | 
| 24 | 
            -
                    when :on_lbracket
         | 
| 25 | 
            -
                      bracket_count[:[]] += 1
         | 
| 26 | 
            -
                    when :on_rbracket
         | 
| 27 | 
            -
                      bracket_count[:[]] -= 1
         | 
| 28 | 
            -
                    when :on_lbrace
         | 
| 29 | 
            -
                      bracket_count[:"{}"] += 1
         | 
| 30 | 
            -
                    when :on_rbrace
         | 
| 31 | 
            -
                      bracket_count[:"{}"] -= 1
         | 
| 32 | 
            -
                    when :on_lparen
         | 
| 33 | 
            -
                      bracket_count[:"()"] += 1
         | 
| 34 | 
            -
                    when :on_rparen
         | 
| 35 | 
            -
                      bracket_count[:"()"] -= 1
         | 
| 36 | 
            -
                    when :on_comma
         | 
| 37 | 
            -
                      if bracket_count[:[]] != 0 || bracket_count[:"{}"] != 0 || bracket_count[:"()"] != 0
         | 
| 38 | 
            -
                        next
         | 
| 39 | 
            -
                      end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                      argument = +""
         | 
| 42 | 
            -
             | 
| 43 | 
            -
                      # Concatenate all lines up to this token's line, including the tail end of the current line
         | 
| 44 | 
            -
                      if token[0][0] != current_line
         | 
| 45 | 
            -
                        (current_line...token[0][0]).each do |i|
         | 
| 46 | 
            -
                          argument << (segment_lines[i - 1].slice(current_index..-1) || "")
         | 
| 47 | 
            -
                          current_index = 0
         | 
| 48 | 
            -
                        end
         | 
| 49 | 
            -
                        current_line = token[0][0]
         | 
| 50 | 
            -
                      end
         | 
| 51 | 
            -
                      argument << segment_lines[current_line - 1].slice(current_index...token[0][1])
         | 
| 52 | 
            -
                      argument.strip!
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                      arguments.push argument
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                      current_index = token[0][1] + 1
         | 
| 57 | 
            -
                    end
         | 
| 58 | 
            -
                  end
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                  return nil if arguments.count == 1 && arguments[0] == ""
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                  arguments
         | 
| 63 | 
            -
                end
         | 
| 64 | 
            -
              end
         | 
| 65 | 
            -
            end
         |