Class: Utopia::XNode::Scanner

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

Constant Summary collapse

CDATA =
/[^<]+/m
TAG_PARAMETER =
/\s*([^\s=\/>]*)=((['"])(.*?)\3)/um

Instance Method Summary collapse

Constructor Details

#initialize(callback, string) ⇒ Scanner

Returns a new instance of Scanner.



31
32
33
34
# File 'lib/utopia/xnode/scanner.rb', line 31

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

Instance Method Details

#calculate_line_number(at = pos) ⇒ Object



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

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



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

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



89
90
91
92
93
# File 'lib/utopia/xnode/scanner.rb', line 89

def scan_attributes
	while scan(TAG_PARAMETER)
		@callback.attribute(self[1], self[4])
	end
end

#scan_cdataObject



67
68
69
70
71
# File 'lib/utopia/xnode/scanner.rb', line 67

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

#scan_tagObject



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

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



121
122
123
124
125
126
127
# File 'lib/utopia/xnode/scanner.rb', line 121

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



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/utopia/xnode/scanner.rb', line 129

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



145
146
147
148
149
# File 'lib/utopia/xnode/scanner.rb', line 145

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

#scan_tag_normal(begin_tag_type = OPENED_TAG) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/utopia/xnode/scanner.rb', line 95

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