Class: RailsHttpLab::Bruno::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_http_lab/bruno/parser.rb

Overview

Parses Bruno .bru files into a Document of ordered Blocks.

Two content modes:

- :kv  — every line is "  key: value" (2-space indent), one pair per line.
- :raw — opaque body, preserved verbatim. Used for body:json, body:text,
         body:xml, body:graphql, body:graphql:vars, body:sparql,
         script:pre-request, script:post-response, tests, docs.

Round-trip property: Serializer.dump(Parser.parse(s)) == s for files written by Bruno itself (see spec/bruno/round_trip_spec.rb).

Constant Summary collapse

RAW_BLOCK_NAMES =
%w[
  body:json
  body:text
  body:xml
  body:sparql
  body:graphql
  body:graphql:vars
  script:pre-request
  script:post-response
  tests
  docs
].freeze
BLOCK_OPEN_RE =

name = letters/digits/_/- with optional colon-delimited variants

/\A([a-zA-Z][\w-]*(?::[\w-]+)*)\s*\{\s*\z/

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source) ⇒ Parser

Returns a new instance of Parser.



37
38
39
40
41
42
# File 'lib/rails_http_lab/bruno/parser.rb', line 37

def initialize(source)
  @source = source
  # Split keeping line content; the last element may be "" if source ends with \n.
  @lines = source.split("\n", -1)
  @i     = 0
end

Class Method Details

.parse(source) ⇒ Object



33
34
35
# File 'lib/rails_http_lab/bruno/parser.rb', line 33

def self.parse(source)
  new(source).parse
end

Instance Method Details

#parseObject



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
# File 'lib/rails_http_lab/bruno/parser.rb', line 44

def parse
  blocks = []
  leading_blanks = 0

  # Count leading blank lines.
  while @i < @lines.length && blank?(@lines[@i])
    leading_blanks += 1
    @i += 1
  end

  while @i < @lines.length
    line = @lines[@i]

    if blank?(line)
      @i += 1
      next
    end

    if (m = line.match(BLOCK_OPEN_RE))
      name = m[1]
      @i += 1
      if RAW_BLOCK_NAMES.include?(name)
        blocks << parse_raw_block(name)
      else
        blocks << parse_kv_block(name)
      end
    else
      # If we got here we hit something we don't understand. To stay forgiving,
      # skip it; alternatively raise. We raise so callers know their file is off.
      raise ParseError, "unexpected line outside of any block (line #{@i + 1}): #{line.inspect}"
    end
  end

  # Trailing newline preserved iff source ends with \n (then @lines's last entry is "").
  trailing_newline = @source.end_with?("\n")

  Document.new(
    blocks: blocks,
    leading_blank_lines: leading_blanks,
    trailing_newline: trailing_newline
  )
end