241: def initialize(selector, *values)
242: raise ArgumentError, "CSS expression cannot be empty" if selector.empty?
243: @source = ""
244: values = values[0] if values.size == 1 and values[0].is_a?(Array)
245:
246:
247: statement = selector.strip.dup
248:
249: simple_selector(statement, values).each { |name, value| instance_variable_set("@#{name}", value) }
250:
251:
252: if statement.sub!(/^\s*,\s*/, "")
253: second = Selector.new(statement, values)
254: (@alternates ||= []) << second
255:
256: if alternates = second.instance_variable_get(:@alternates)
257: second.instance_variable_set(:@alternates, nil)
258: @alternates.concat alternates
259: end
260: @source << " , " << second.to_s
261:
262:
263: elsif statement.sub!(/^\s*\+\s*/, "")
264: second = next_selector(statement, values)
265: @depends = lambda do |element, first|
266: if element = next_element(element)
267: second.match(element, first)
268: end
269: end
270: @source << " + " << second.to_s
271:
272:
273: elsif statement.sub!(/^\s*~\s*/, "")
274: second = next_selector(statement, values)
275: @depends = lambda do |element, first|
276: matches = []
277: while element = next_element(element)
278: if subset = second.match(element, first)
279: if first && !subset.empty?
280: matches << subset.first
281: break
282: else
283: matches.concat subset
284: end
285: end
286: end
287: matches.empty? ? nil : matches
288: end
289: @source << " ~ " << second.to_s
290:
291:
292: elsif statement.sub!(/^\s*>\s*/, "")
293: second = next_selector(statement, values)
294: @depends = lambda do |element, first|
295: matches = []
296: element.children.each do |child|
297: if child.tag? and subset = second.match(child, first)
298: if first && !subset.empty?
299: matches << subset.first
300: break
301: else
302: matches.concat subset
303: end
304: end
305: end
306: matches.empty? ? nil : matches
307: end
308: @source << " > " << second.to_s
309:
310:
311: elsif statement =~ /^\s+\S+/ and statement != selector
312: second = next_selector(statement, values)
313: @depends = lambda do |element, first|
314: matches = []
315: stack = element.children.reverse
316: while node = stack.pop
317: next unless node.tag?
318: if subset = second.match(node, first)
319: if first && !subset.empty?
320: matches << subset.first
321: break
322: else
323: matches.concat subset
324: end
325: elsif children = node.children
326: stack.concat children.reverse
327: end
328: end
329: matches.empty? ? nil : matches
330: end
331: @source << " " << second.to_s
332: else
333:
334:
335: unless statement.empty? or statement.strip.empty?
336: raise ArgumentError, "Invalid selector: #{statement}"
337: end
338: end
339: end