# encoding: utf-8
module Watir
module HTML
class Generator
IGNORED_ATTRIBUTES = %w(cells elements hash rows span text)
def generate(spec_url, io = StringIO.new)
@spec_url, @io = spec_url, io
extract_spec
cleanup_spec
write_header
write_class_defs
write_container_methods
write_footer
io
end
private
def generator
@generator ||= WebIDL::Generator.new(visitor)
end
def visitor
@visitor ||= Visitor.new
end
def extractor
@extractor ||= SpecExtractor.new(@spec_url)
end
def extract_spec
@tag2interfaces = extractor.process
@sorted_interfaces = extractor.sorted_interfaces
if extractor.errors.any?
raise "error extracting spec: #{extractor.errors.join("\n")}"
end
end
def cleanup_spec
# ignore the link element for now
@tag2interfaces.delete("link")
@sorted_interfaces.reject! { |intf| intf.name == "HTMLLinkElement" }
# frame is implemented manually, see https://github.com/watir/watir-webdriver/issues/204
@sorted_interfaces.reject! { |intf| intf.name == "HTMLFrameElement" }
# cleanup attributes
@sorted_interfaces.each do |intf|
intf.members.delete_if { |member| IGNORED_ATTRIBUTES.include?(member.name) }
end
end
def write_header
@io.puts "# Autogenerated from the HTML5 specification. Edits may be lost."
@io.puts "module Watir"
end
def write_class_defs
@sorted_interfaces.each do |interface|
interface = generator.generate(interface)
unless interface.empty?
interface.gsub!(/^\s+\n/, '') # remove empty lines
@io.puts indent(interface)
end
end
end
def write_container_methods
@io.puts "\n\n"
@io.puts indent("module Container")
@tag2interfaces.sort.each do |tag, interfaces|
raise "multiple interfaces for tag #{tag.inspect}" unless interfaces.map { |e| e.name }.uniq.size == 1
tag_string = tag.inspect
singular = Util.paramify(tag)
plural = singular.pluralize
element_class = Util.classify(interfaces.first.name)
collection_class = "#{element_class}Collection"
# visitor.visit_tag(tag, interfaces.first.name) !?
@io.puts indent(<<-CODE, 3)
#
# @return [#{element_class}]
#
def #{singular}(*args)
#{element_class}.new(self, extract_selector(args).merge(:tag_name => #{tag_string}))
end
#
# @return [#{collection_class}]
#
def #{plural}(*args)
#{collection_class}.new(self, extract_selector(args).merge(:tag_name => #{tag_string}))
end
Watir.tag_to_class[#{tag.to_sym.inspect}] = #{element_class}
CODE
end
@io.puts indent("end # Container")
end
def write_footer
@io.puts "end # Watir"
end
def indent(code, indent = 1)
indent_string = " " * indent
code.split("\n").map { |line| line.empty? ? line : indent_string + line }.join("\n")
end
end # Generator
end # HTML5
end # Watir