=begin Generate replacement initialize() methods that use keyword-argument style hash arguments instead of positional arguments. Known problems (due to overloaded constructors): * FXCursor * FXQuat{d,f} * FXRange{d,f} * FXRecentFiles * FXRectangle * FXSphere{d,f} =end CLASSES_TO_SKIP = %w{FX4Splitter FXCursor FXDCWindow FXExtentd FXExtentf FXFont FXGLCanvas FXGLShape FXGLViewer FXDockBar FXMenuBar FXToolBar FXQuatd FXQuatf FXRanged FXRangef FXRecentFiles FXRectangle FXRegion FXSize FXSphered FXSpheref FXSplitter FXVec2d FXVec2f FXVec3d FXVec3f FXVec4d FXVec4f FXWindow} class Arg attr_reader :name attr_reader :value def initialize(name, value) @name = name @value = value end end class MethodDescription attr_accessor :method_name attr_accessor :required_args attr_accessor :optional_args def initialize @method_name = nil @required_args = [] @optional_args = [] end def generate_alias " alias old_#{method_name} #{method_name}\n" end def generate_body argument_names = optional_args.map { |arg| arg.name } defaults_hash = optional_args.map { |arg| ":#{arg.name} => #{arg.value}"} defaults_hash = "{ #{defaults_hash.join(', ')} }" required = required_args.join(", ") optional = optional_args.map { |arg| "params[:#{arg.name}]"} optional = optional.join(", ") buffer = "" buffer << " def #{method_name}(#{required}#{required_args.length > 0 ? ', ' : ''}*args#{expects_block? ? ', &blk' : ''})\n" buffer << " argument_names = %w{#{argument_names.join(' ')}}\n" buffer << " default_params = #{defaults_hash}\n" buffer << " params = {}\n" buffer << " params = args.pop if args.last.is_a? Hash\n" buffer << " args.each_with_index { |e, i| params[argument_names[i].intern] = e }\n" if optional_args.any? { |arg| arg.name == "padLeft" } buffer << " if params.key? :padding\n" buffer << " value = params.delete(:padding)\n" buffer << " [:padLeft, :padRight, :padTop, :padBottom].each { |s| params[s] ||= value }\n" buffer << " end\n" end buffer << " params.keys.each { |key| raise ArgumentError, \"Unrecognized parameter \#{key}\" unless default_params.keys.include?(key) }\n" buffer << " params = default_params.merge(params)\n" buffer << " old_#{method_name}(#{required}#{(required_args.length > 0) && (optional_args.length > 0) ? ', ' : ''}#{optional}#{expects_block? ? ', &blk' : ''})\n" buffer << " end\n" buffer end def expects_block? method_name == "initialize" end end class ClassDescription attr_accessor :class_name attr_accessor :method_descriptions def initialize @class_name = nil @method_descriptions = [] end def generate_class_initializer buffer = "" buffer << " class #{class_name}\n" method_descriptions.each do |method_description| buffer << method_description.generate_alias buffer << method_description.generate_body end buffer << " end\n\n" buffer end def has_methods_with_optional_arguments? method_descriptions.each do |m| return true if m.optional_args.length > 0 end false end end class Generator def initialize @known_classes = {} end def generate_preamble(out) out.puts <<-END require 'fox16' old_verbose = $VERBOSE; $VERBOSE = nil module Fox END out.puts(DATA.read) end def go(filenames, output_filename) out = File.new(output_filename, "w") class_descriptions = [] filenames.each { |filename| class_descriptions += scan_for_descriptions(filename) } generate_preamble(out) class_descriptions.each do |class_description| out.puts class_description.generate_class_initializer if class_description.has_methods_with_optional_arguments? end generate_closing(out) end def generate_closing(out) out.puts "end" out.puts "" out.puts "$VERBOSE = old_verbose" end def scan_for_descriptions(filename) class_description = nil class_descriptions = [] IO.foreach(filename) do |str| if str =~ /^ class\s*(\w+).*$/ class_description = ClassDescription.new class_description.class_name = $1 elsif str =~ /def (initialize|findText)\((.*)\)/ method_description = MethodDescription.new method_description.method_name = $1 # args = $2.split(',').map { |x| x.strip } args = $2.split(', ').map { |x| x.strip } args.each do |arg| if arg =~ /(.*)=(.*)/ method_description.optional_args << Arg.new($1, $2) elsif method_description.required_args << arg end end if @known_classes.has_key? class_description.class_name warn "Overloaded initialize method for class: #{class_description.class_name}" end @known_classes[class_description.class_name] = 1 class_description.method_descriptions << method_description elsif str =~ /^ end/ class_descriptions << class_description unless skip?(class_description.class_name) class_description = nil end end class_descriptions end def skip?(name) CLASSES_TO_SKIP.include? name end end if __FILE__ == $0 Generator.new.go(Dir.glob('rdoc-sources/*.rb'), 'lib/fox16/kwargs.rb') end __END__ class FX4Splitter alias old_initialize initialize def initialize(p, *args, &blk) argument_names = %w{opts x y width height} default_params = { :opts => FOURSPLITTER_NORMAL, :x => 0, :y => 0, :width => 0, :height => 0 } params = {} params = args.pop if args.last.is_a? Hash if args.length > 0 && (args.first.nil? || args.first.is_a?(FXObject)) tgt, sel = args[0], args[1] args.each_with_index { |e, i| params[argument_names[i-2].intern] = e if i >= 2 } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, tgt, sel, params[:opts], params[:x], params[:y], params[:width], params[:height], &blk) else args.each_with_index { |e, i| params[argument_names[i].intern] = e } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, params[:opts], params[:x], params[:y], params[:width], params[:height], &blk) end end end class FXDockBar alias old_initialize initialize def initialize(p, *args, &blk) argument_names = %w{opts x y width height padLeft padRight padTop padBottom hSpacing vSpacing} default_params = { :opts => LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FILL_X, :x => 0, :y => 0, :width => 0, :height => 0, :padLeft => 3, :padRight => 3, :padTop => 2, :padBottom => 2, :hSpacing => DEFAULT_SPACING, :vSpacing => DEFAULT_SPACING } params = {} params = args.pop if args.last.is_a? Hash if args.length > 0 && (args.first.nil? || args.first.is_a?(FXComposite)) q = args[0] args.each_with_index { |e, i| params[argument_names[i-1].intern] = e if i >= 1 } if params.key? :padding value = params.delete(:padding) [:padLeft, :padRight, :padTop, :padBottom].each { |s| params[s] ||= value } end params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, q, params[:opts], params[:x], params[:y], params[:width], params[:height], params[:padLeft], params[:padRight], params[:padTop], params[:padBottom], params[:hSpacing], params[:vSpacing], &blk) else args.each_with_index { |e, i| params[argument_names[i].intern] = e } if params.key? :padding value = params.delete(:padding) [:padLeft, :padRight, :padTop, :padBottom].each { |s| params[s] ||= value } end params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, params[:opts], params[:x], params[:y], params[:width], params[:height], params[:padLeft], params[:padRight], params[:padTop], params[:padBottom], params[:hSpacing], params[:vSpacing], &blk) end end end class FXFont alias old_initialize initialize def initialize(a, arg1, *args, &blk) if args.length > 0 face, size = arg1, args[0] argument_names = %w{weight slant encoding setWidth hints} default_params = { :weight => FXFont::Normal, :slant => FXFont::Straight, :encoding => FONTENCODING_DEFAULT, :setWidth => FXFont::NonExpanded, :hints => 0 } params = {} params = args.pop if args.last.is_a? Hash args.each_with_index { |e, i| params[argument_names[i-1].intern] = e if i >= 1 } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(a, face, size, params[:weight], params[:slant], params[:encoding], params[:setWidth], params[:hints], &blk) else old_initialize(a, arg1, &blk) end end class << self alias old_listFonts listFonts end def FXFont.listFonts(face, *args) argument_names = %w{weight slant setWidth encoding hints} default_params = { :weight => 0, :slant => 0, :setWidth => 0, :encoding => 0, :hints => 0 } params = {} params = args.pop if args.last.is_a? Hash args.each_with_index { |e, i| params[argument_names[i].intern] = e } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_listFonts(face, params[:weight], params[:slant], params[:setWidth], params[:encoding], params[:hints]) end end class FXGLCanvas alias old_initialize initialize def initialize(parent, vis, *args, &blk) argument_names = %w{target selector opts x y width height} default_params = { :target => nil, :selector => 0, :opts => 0, :x => 0, :y => 0, :width => 0, :height => 0 } params = {} params = args.pop if args.last.is_a? Hash if args.length > 0 && (args[0].is_a?(FXGLCanvas)) sharegroup = args[0] args.each_with_index { |e, i| params[argument_names[i-1].intern] = e if i >= 1 } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(parent, vis, sharegroup, params[:target], params[:selector], params[:opts], params[:x], params[:y], params[:width], params[:height], &blk) else args.each_with_index { |e, i| params[argument_names[i].intern] = e } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(parent, vis, params[:target], params[:selector], params[:opts], params[:x], params[:y], params[:width], params[:height], &blk) end end end class FXGLViewer alias old_initialize initialize def initialize(parent, vis, *args, &blk) argument_names = %w{target selector opts x y width height} default_params = { :target => nil, :selector => 0, :opts => 0, :x => 0, :y => 0, :width => 0, :height => 0 } params = {} params = args.pop if args.last.is_a? Hash if args.length > 0 && (args[0].is_a?(FXGLViewer)) sharegroup = args[0] args.each_with_index { |e, i| params[argument_names[i-1].intern] = e if i >= 1 } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(parent, vis, sharegroup, params[:target], params[:selector], params[:opts], params[:x], params[:y], params[:width], params[:height], &blk) else args.each_with_index { |e, i| params[argument_names[i].intern] = e } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(parent, vis, params[:target], params[:selector], params[:opts], params[:x], params[:y], params[:width], params[:height], &blk) end end end class FXMenuBar alias old_initialize initialize def initialize(p, *args, &blk) argument_names = %w{opts x y width height padLeft padRight padTop padBottom hSpacing vSpacing} default_params = { :opts => LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FILL_X, :x => 0, :y => 0, :width => 0, :height => 0, :padLeft => 3, :padRight => 3, :padTop => 2, :padBottom => 2, :hSpacing => DEFAULT_SPACING, :vSpacing => DEFAULT_SPACING } params = {} params = args.pop if args.last.is_a? Hash if args.length > 0 && (args[0].nil? || args[0].is_a?(FXComposite)) q = args[0] args.each_with_index { |e, i| params[argument_names[i-1].intern] = e if i >= 1 } if params.key? :padding value = params.delete(:padding) [:padLeft, :padRight, :padTop, :padBottom].each { |s| params[s] ||= value } end params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, q, params[:opts], params[:x], params[:y], params[:width], params[:height], params[:padLeft], params[:padRight], params[:padTop], params[:padBottom], params[:hSpacing], params[:vSpacing], &blk) else args.each_with_index { |e, i| params[argument_names[i].intern] = e } if params.key? :padding value = params.delete(:padding) [:padLeft, :padRight, :padTop, :padBottom].each { |s| params[s] ||= value } end params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, params[:opts], params[:x], params[:y], params[:width], params[:height], params[:padLeft], params[:padRight], params[:padTop], params[:padBottom], params[:hSpacing], params[:vSpacing], &blk) end end end class FXSplitter alias old_initialize initialize def initialize(p, *args, &blk) argument_names = %w{opts x y width height} default_params = { :opts => SPLITTER_NORMAL, :x => 0, :y => 0, :width => 0, :height => 0 } params = {} params = args.pop if args.last.is_a? Hash if args.length > 0 && (args.first.nil? || args.first.is_a?(FXObject)) tgt, sel = args[0], args[1] args.each_with_index { |e, i| params[argument_names[i-2].intern] = e if i >= 2 } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, tgt, sel, params[:opts], params[:x], params[:y], params[:width], params[:height], &blk) else args.each_with_index { |e, i| params[argument_names[i].intern] = e } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, params[:opts], params[:x], params[:y], params[:width], params[:height], &blk) end end end class FXToolBar alias old_initialize initialize def initialize(p, *args, &blk) argument_names = %w{opts x y width height padLeft padRight padTop padBottom hSpacing vSpacing} default_params = { :opts => LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FILL_X, :x => 0, :y => 0, :width => 0, :height => 0, :padLeft => 3, :padRight => 3, :padTop => 2, :padBottom => 2, :hSpacing => DEFAULT_SPACING, :vSpacing => DEFAULT_SPACING } params = {} params = args.pop if args.last.is_a? Hash if args.length > 0 && (args[0].nil? || args[0].is_a?(FXComposite)) q = args[0] args.each_with_index { |e, i| params[argument_names[i-1].intern] = e if i >= 1 } if params.key? :padding value = params.delete(:padding) [:padLeft, :padRight, :padTop, :padBottom].each { |s| params[s] ||= value } end params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, q, params[:opts], params[:x], params[:y], params[:width], params[:height], params[:padLeft], params[:padRight], params[:padTop], params[:padBottom], params[:hSpacing], params[:vSpacing], &blk) else args.each_with_index { |e, i| params[argument_names[i].intern] = e } if params.key? :padding value = params.delete(:padding) [:padLeft, :padRight, :padTop, :padBottom].each { |s| params[s] ||= value } end params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, params[:opts], params[:x], params[:y], params[:width], params[:height], params[:padLeft], params[:padRight], params[:padTop], params[:padBottom], params[:hSpacing], params[:vSpacing], &blk) end end end class FXWindow alias old_initialize initialize def initialize(p, *args, &blk) if p.is_a? FXApp old_initialize(p, *args, &blk) else argument_names = %w{opts x y width height} default_params = { :opts => 0, :x => 0, :y => 0, :width => 0, :height => 0 } params = {} params = args.pop if args.last.is_a? Hash args.each_with_index { |e, i| params[argument_names[i].intern] = e } params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } params = default_params.merge(params) old_initialize(p, params[:opts], params[:x], params[:y], params[:width], params[:height], &blk) end end end