Class: Utopia::XNode::Scanner

Inherits:
StringScanner
  • Object
show all
Defined in:
lib/utopia/xnode/scanner.rb

Constant Summary collapse

CDATA =
/[^<]+/m
ATTRIBUTE_NAME =

Parse an attribute in the form of key=“value” or key.

/\s*([^\s=\/>]+)/um
ATTRIBUTE_VALUE =
/=((['"])(.*?)\2)/um

Instance Method Summary collapse

Constructor Details

#initialize(callback, string) ⇒ Scanner

Returns a new instance of Scanner.



33
34
35
36
# File 'lib/utopia/xnode/scanner.rb', line 33

def initialize(callback, string)
	@callback = callback
	super(string)
end

Instance Method Details

#calculate_line_number(at = pos) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/utopia/xnode/scanner.rb', line 38

def calculate_line_number(at = pos)
	line_no = 1
	line_offset = offset = 0
	
	string.lines.each do |line|
		line_offset = offset
		offset += line.size
		
		if offset >= at
			return [line_no, line_offset, at - line_offset, offset, line]
		end
		
		line_no += 1
	end
	
	return nil
end

#parseObject



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/utopia/xnode/scanner.rb', line 56

def parse
	until eos?
		pos = self.pos

		scan_cdata
		scan_tag

		if pos == self.pos
			raise ScanError.new("Scanner didn't move", self)
		end
	end
end

#scan_attributesObject



91
92
93
94
95
96
97
98
99
100
# File 'lib/utopia/xnode/scanner.rb', line 91

def scan_attributes
	while scan(ATTRIBUTE_NAME)
		name = self[1]
		if scan(ATTRIBUTE_VALUE)
			@callback.attribute(name, self[3])
		else
			@callback.attribute(name, nil)
		end
	end
end

#scan_cdataObject



69
70
71
72
73
# File 'lib/utopia/xnode/scanner.rb', line 69

def scan_cdata
	if scan(CDATA)
		@callback.cdata(matched)
	end
end

#scan_tagObject



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/utopia/xnode/scanner.rb', line 75

def scan_tag
	if scan(/</)
		if scan(/\//)
			scan_tag_normal(CLOSED_TAG)
		elsif scan(/!\[CDATA\[/)
			scan_tag_cdata
		elsif scan(/!/)
			scan_tag_comment
		elsif scan(/\?/)
			scan_tag_instruction
		else
			scan_tag_normal
		end
	end
end

#scan_tag_cdataObject



128
129
130
131
132
133
134
# File 'lib/utopia/xnode/scanner.rb', line 128

def scan_tag_cdata
	if scan_until(/(.*?)\]\]>/m)
		@callback.cdata(self[1].to_html)
	else
		raise ScanError.new("CDATA tag is not closed!", self)
	end
end

#scan_tag_commentObject



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/utopia/xnode/scanner.rb', line 136

def scan_tag_comment
	if scan(/--/)
		if scan_until(/(.*?)-->/m)
			@callback.comment("--" + self[1] + "--")
		else
			raise ScanError.new("Comment is not closed!", self)
		end
	else
		if scan_until(/(.*?)>/)
			@callback.comment(self[1])
		else
			raise ScanError.new("Comment is not closed!", self)
		end
	end
end

#scan_tag_instructionObject



152
153
154
155
156
# File 'lib/utopia/xnode/scanner.rb', line 152

def scan_tag_instruction
	if scan_until(/(.*)\?>/)
		@callback.instruction(self[1])
	end
end

#scan_tag_normal(begin_tag_type = OPENED_TAG) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/utopia/xnode/scanner.rb', line 102

def scan_tag_normal(begin_tag_type = OPENED_TAG)
	if scan(/[^\s\/>]+/)
		@callback.begin_tag(matched, begin_tag_type)
	
		scan(/\s*/)
	
		scan_attributes
	
		scan(/\s*/)
	
		if scan(/\/>/)
			if begin_tag_type == CLOSED_TAG
				raise ScanError.new("Tag cannot be closed at both ends!", self)
			else
				@callback.finish_tag(begin_tag_type, CLOSED_TAG)
			end
		elsif scan(/>/)
			@callback.finish_tag(begin_tag_type, OPENED_TAG)
		else
			raise ScanError.new("Invalid characters in tag!", self)
		end
	else
		raise ScanError.new("Invalid tag!", self)
	end
end