# Copyright (c) 2012 MaxMedia and Travis Warlick # Licensed under the MIT License (see LICENSE) class Module # Defines a singleton-class attribute writer that ensures the value is always converted to the # given type by using the method in the options or creating a new instance of the `type` class # and passing the value to its initializer. # # @overload class_attr_writer_typed(type, *names) # @param type [Class] class to ensure the value is # @param names [*Symbol] names of attributes # # @overload class_attr_writer_typed(type, *names, opts={}) # @param type [Class] class to ensure the value is # @param names [*Symbol] names of attributes # @param opts [Hash] options # @option opts [Symbol] :method method name to use to convert the values def class_attr_writer_typed(type, *names) options = names.extract_options! names.each do |name| class_eval <<-EOC, __FILE__, __LINE__+1 def self.#{name}=(val) obj = #{options[:method] ? "val.#{options[:method]}" : "val"} @#{name} = (obj.is_a?(#{type}) ? obj : #{type}.new(obj)) end EOC end end # Defines a singleton-class attribute reader that has ensured the value has been converted to the # given type. # # @param type [Class] class to ensure the value is # @param names [*Symbol] names of attributes # @return [Object] value will be of type defined in the parameters # @raise [TypeError] if the value has been modified and is no longer of the proper type def class_attr_reader_typed(type, *names) options = names.extract_options! names.each do |name| class_eval <<-EOC, __FILE__, __LINE__+1 def self.#{name} unless @#{name}.is_a?(#{type}) raise TypeError, "Expected #{name} to be a #{type}" end @#{name} end EOC end end # Defines a singleton-class attribute reader and writer that ensures the value is always # converted to the given type. # # @see #class_attr_writer_typed # @see #class_attr_reader_typed def class_attr_accessor_typed(type, *names) options = names.extract_options! class_attr_reader_typed type, *names class_attr_writer_typed type, *names end end