Class: Leptris::XML::SAX::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/leptris/xml/sax/parser.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(handler = Leptris::XML::SAX::Document.new, encoding = nil) ⇒ Parser

Returns a new instance of Parser.



11
12
13
14
# File 'lib/leptris/xml/sax/parser.rb', line 11

def initialize(handler = Leptris::XML::SAX::Document.new, encoding = nil)
  @document = handler
  @encoding = encoding
end

Instance Attribute Details

#documentObject

Returns the value of attribute document.



9
10
11
# File 'lib/leptris/xml/sax/parser.rb', line 9

def document
  @document
end

#encodingObject (readonly)

Returns the value of attribute encoding.



9
10
11
# File 'lib/leptris/xml/sax/parser.rb', line 9

def encoding
  @encoding
end

Instance Method Details

#handler_structObject

The handler struct (eleven FFI::Function callbacks + the C struct) is built once per handler and reused across parses; the memoized struct is anchored against GC by the instance itself.



26
27
28
# File 'lib/leptris/xml/sax/parser.rb', line 26

def handler_struct
  @handler_struct ||= build_handler_struct
end

#parse(input) ⇒ Object

Parse a string, IO, or file path. Dispatches to parse_memory / parse_io / parse_file based on the argument type.



32
33
34
35
36
37
38
39
# File 'lib/leptris/xml/sax/parser.rb', line 32

def parse(input)
  case input
  when String                then parse_memory(input)
  when ->(x) { x.respond_to?(:read) } then parse_io(input)
  else
    raise ArgumentError, "SAX parser expects a String or IO, got #{input.class}"
  end
end

#parse_file(path) ⇒ Object



79
80
81
# File 'lib/leptris/xml/sax/parser.rb', line 79

def parse_file(path)
  File.open(path, "r") { |f| parse_io(f) }
end

#parse_io(io) ⇒ Object



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
# File 'lib/leptris/xml/sax/parser.rb', line 53

def parse_io(io)
  handler_struct = self.handler_struct
  parser_ptr = Leptris::XML::FFI.leptris_sax_parser_create(
    handler_struct.pointer, nil)
  if parser_ptr.null?
    raise Leptris::XML::Error, "leptris_sax_parser_create failed"
  end
  begin
    while (chunk = io.read(CHUNK_SIZE))
      rc = Leptris::XML::FFI.leptris_sax_parser_feed(
        parser_ptr, chunk, chunk.bytesize, 0)
      if rc != 0
        raise Leptris::XML::ParseError, "leptris_sax_parser_feed failed (rc=#{rc})"
      end
    end
    # Final flush
    rc = Leptris::XML::FFI.leptris_sax_parser_feed(parser_ptr, "", 0, 1)
    if rc != 0
      raise Leptris::XML::ParseError, "leptris_sax_parser_feed (final) failed (rc=#{rc})"
    end
  ensure
    Leptris::XML::FFI.leptris_sax_parser_free(parser_ptr)
  end
  self
end

#parse_memory(string) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/leptris/xml/sax/parser.rb', line 41

def parse_memory(string)
  string = string.dup.force_encoding("UTF-8")
  handler_struct = self.handler_struct
  rc = Leptris::XML::FFI.leptris_sax_parse(
    string, string.bytesize, handler_struct.pointer, nil)
  if rc != 0
    raise Leptris::XML::ParseError,
      "leptris_sax_parse failed (rc=#{rc})"
  end
  self
end