lib/watir/generator/base/visitor.rb in watir-6.13.0 vs lib/watir/generator/base/visitor.rb in watir-6.14.0

- old
+ new

@@ -1,162 +1,162 @@ module Watir module Generator - class Base::Visitor < WebIDL::RubySexpVisitor + module Base + class Visitor < WebIDL::RubySexpVisitor + STRING_TYPES = ['WindowProxy', 'ValidityState', 'TimeRanges', 'Location', + 'Any', 'TimedTrackArray', 'TimedTrack', 'TextTrackArray', 'TextTrack', + /Media.+/, 'TextTrackKind', 'Function', /.*EventHandler$/, + 'Document', 'DocumentFragment', 'DOMTokenList', 'DOMSettableTokenList', + 'DOMStringMap', 'HTMLPropertiesCollection', /HTML.*Element/, /HTML.*Collection/, + 'CSSStyleDeclaration', /.+List$/, 'Date', 'Element', /DOM.+ReadOnly/, + /SVGAnimated.+/, /SVG.*Element/, /SVG.*Collection/, 'SVGViewSpec', + 'Object', 'USVString'].freeze + def initialize + super - def initialize - super + # When an interface has multiple IDL definitions in the spec, the inheritance is sometimes + # not repeated. So we'll keep track ourselves. + @inheritance_map = {} - # When an interface has multiple IDL definitions in the spec, the inheritance is sometimes - # not repeated. So we'll keep track ourselves. - @inheritance_map = {} + @already_defined = [] + end - @already_defined = [] - end + # + # WebIDL visitor interface + # - # - # WebIDL visitor interface - # + def visit_interface(interface) + name = interface.name + parent = interface.inherits.first - def visit_interface(interface) - name = interface.name - parent = interface.inherits.first + warn name + return if name !~ interface_regexp || name =~ /(Collection|Document)$/ - $stderr.puts name - return if name !~ interface_regexp || name =~ /(Collection|Document)$/ + parent = if force_inheritance.key?(name) + force_inheritance[name] + else + @inheritance_map[name] ||= parent&.name + return unless @inheritance_map[name] - if force_inheritance.keys.include?(name) - parent = force_inheritance[name] - elsif parent - @inheritance_map[name] ||= parent.name - parent = parent.name - else - parent = @inheritance_map[name] || return - end + @inheritance_map[name] + end - [ :scope, - [:block, + [:scope, + [:block, element_class(interface.name, extract_attributes(interface), parent), - collection_class(interface.name) - ] - ] - end + collection_class(interface.name)]] + end - def visit_module(mod) - # ignored - end + def visit_module(mod) + # ignored + end - def visit_implements_statement(stmt) - # ignored - end + def visit_implements_statement(stmt) + # ignored + end - # TODO: do everything in the visitor somehow? - # problem is we lack the tag name info while walking the interface AST - # # - # # Watir generator visitor interface - # # - # - # def visit_tag(tag_name, interface_name) - # tag_string = tag.inspect - # singular = Util.paramify(classify_regexp, tag) - # plural = singular.pluralize - # element_class = Util.classify(classify_regexp, interfaces.first.name) - # collection_class = "#{element_class}Collection" - # - # [:defn, - # :a, - # [:args, :"*args"], - # [:scope, - # [:block, - # [:call, - # [:const, :Anchor], - # :new, - # [:arglist, - # [:self], - # [:call, - # [:call, nil, :extract_selector, [:arglist, [:lvar, :args]]], - # :merge, - # [:arglist, [:hash, [:lit, :tag_name], [:str, "a"]]]]]]]]] - # end + # TODO: do everything in the visitor somehow? + # problem is we lack the tag name info while walking the interface AST + # # + # # Watir generator visitor interface + # # + # + # def visit_tag(tag_name, interface_name) + # tag_string = tag.inspect + # singular = Util.paramify(classify_regexp, tag) + # plural = singular.pluralize + # element_class = Util.classify(classify_regexp, interfaces.first.name) + # collection_class = "#{element_class}Collection" + # + # [:defn, + # :a, + # [:args, :"*args"], + # [:scope, + # [:block, + # [:call, + # [:const, :Anchor], + # :new, + # [:arglist, + # [:self], + # [:call, + # [:call, nil, :extract_selector, [:arglist, [:lvar, :args]]], + # :merge, + # [:arglist, [:hash, [:lit, :tag_name], [:str, "a"]]]]]]]]] + # end - private + private - def element_class(name, attributes, parent) - [:class, Util.classify(classify_regexp, name), [:const, Util.classify(classify_regexp, parent)], - *attribute_calls(attributes) - ] - end + def element_class(name, attributes, parent) + [:class, Util.classify(classify_regexp, name), [:const, Util.classify(classify_regexp, parent)], + *attribute_calls(attributes)] + end - def extract_attributes(interface) - members = interface.members - members += interface.implements.flat_map(&:members) + def extract_attributes(interface) + members = interface.members + members += interface.implements.flat_map(&:members) + members += interface.includes.flat_map(&:members) - members.select { |e| e.kind_of?(WebIDL::Ast::Attribute) }.uniq(&:name) - end + members.select { |e| e.is_a?(WebIDL::Ast::Attribute) }.uniq(&:name) + end - def collection_class(name) - return if @already_defined.include?(name) - @already_defined << name - name = Util.classify(classify_regexp, name) + def collection_class(name) + return if @already_defined.include?(name) - [:class, "#{name}Collection", [:const, :ElementCollection]] - end + @already_defined << name + name = Util.classify(classify_regexp, name) - def attribute_calls(attributes) - attributes.map do |attribute| - call(:attribute, [ - [:lit, ruby_type_for(attribute.type)], - [:lit, ruby_method_name_for(attribute)], - [:lit, attribute.name.to_sym] - ]) + [:class, "#{name}Collection", %i[const ElementCollection]] end - end - def call(name, args) - [:call, nil, name.to_sym, [:arglist] + args] - end - - def ruby_method_name_for(attribute) - str = if %w(httpEquiv contentEditable acceptCharset isContentEditable).include? attribute.name - attribute.name.snake_case - else - attribute.name.downcase + def attribute_calls(attributes) + attributes.map do |attribute| + call(:attribute, [ + [:lit, ruby_type_for(attribute.type)], + [:lit, ruby_method_name_for(attribute)], + [:lit, attribute.name.to_sym] + ]) + end end - if attribute.type.name == :Boolean - str = $1 if str =~ /^is_(.+)/ - str << '?' + def call(name, args) + [:call, nil, name.to_sym, [:arglist] + args] end - str = 'for' if str == 'htmlfor' + def ruby_method_name_for(attribute) + str = if %w[httpEquiv contentEditable acceptCharset isContentEditable].include? attribute.name + attribute.name.snake_case + else + attribute.name.downcase + end - str.to_sym - end + if attribute.type.name == :Boolean + str = Regexp.last_match(1) if str =~ /^is_(.+)/ + str << '?' + end - def ruby_type_for(type) - case type.name.to_s - when 'DOMString', 'any' - String - when 'UnsignedLong', 'Long', 'Integer', 'Short', 'UnsignedShort', - 'SVGAnimatedLength' - Integer - when 'Float', /.*Double$/ - Float - when 'Boolean' - 'Boolean' - when 'WindowProxy', 'ValidityState', 'TimeRanges', 'Location', - 'Any', 'TimedTrackArray', 'TimedTrack', 'TextTrackArray', 'TextTrack', - /Media.+/, 'TextTrackKind', 'Function', /.*EventHandler$/, - 'Document', 'DocumentFragment', 'DOMTokenList', 'DOMSettableTokenList', - 'DOMStringMap', 'HTMLPropertiesCollection', /HTML.*Element/, /HTML.*Collection/, - 'CSSStyleDeclaration', /.+List$/, 'Date', 'Element', /DOM.+ReadOnly/, - /SVGAnimated.+/, /SVG.*Element/, /SVG.*Collection/, 'SVGViewSpec', - 'Object', 'USVString' - # probably completely wrong. - String - else - raise "unknown type: #{type.name}" + str = 'for' if str == 'htmlfor' + + str.to_sym end - end - end # Visitor + def ruby_type_for(type) + case type.name.to_s + when 'DOMString', 'any' + String + when 'UnsignedLong', 'Long', 'Integer', 'Short', 'UnsignedShort', + 'SVGAnimatedLength' + Integer + when 'Float', /.*Double$/ + Float + when 'Boolean' + 'Boolean' + when *STRING_TYPES + # probably completely wrong. + String + else + raise "unknown type: #{type.name}" + end + end + end # Visitor + end # Base end # Generator end # Watir