lib/axiom/attribute.rb in axiom-0.1.0 vs lib/axiom/attribute.rb in axiom-0.1.1

- old
+ new

@@ -4,26 +4,27 @@ # Abstract base class representing a type of data in a relation tuple class Attribute extend Aliasable, DescendantsTracker include AbstractType, ::Comparable, Visitable - include Equalizer.new(:name, :required?) + include Equalizer.new(:name, :type, :required?) + abstract_singleton_method :type + # The attribute name # # @return [Symbol] # # @api private attr_reader :name - # The attribute options + # The attribute type # - # @return [Hash] + # @return [Class<Types::Object>] # # @api private - attr_reader :options - private :options + attr_reader :type # Coerce an object into an Attribute # # @param [Attribute, #to_ary, #to_sym] object # the object to coerce @@ -64,16 +65,14 @@ # # @return [Class<Attribute>] # # @api private def self.infer_type(operand) - case operand - when Attribute, Function, Aggregate then operand.type - when FalseClass then Boolean + if operand.respond_to?(:type) + operand.type else - type = operand.class - descendants.detect { |descendant| type <= descendant.primitive } + Types::Type.descendants.detect { |type| type.include?(operand) } end end # Initialize an Attribute # @@ -87,12 +86,12 @@ # @return [undefined] # # @api private def initialize(name, options = EMPTY_HASH) @name = name.to_sym - @options = freeze_object(options) - @required = @options.fetch(:required, true) + @required = options.fetch(:required, true) + @type = self.class.type end # Extract the value corresponding to this attribute from a tuple # # @example @@ -120,22 +119,17 @@ # # @todo Make this have the same API as functions # # @api public def rename(new_name) - name.equal?(new_name) ? self : self.class.new(new_name, options) + if name.equal?(new_name) + self + else + self.class.new(new_name, required: required?) + end end - # Return the type returned from #call - # - # @return [Class<Attribute>] - # - # @api public - def type - self.class - end - # Test if the attribute is required # # @example # attribute.required? # => true or false # @@ -144,38 +138,35 @@ # @api public def required? @required end - # Test if a value is the correct primitive type + # Test if the attribute is optional # # @example - # attribute.valid_primitive?(value) # => true or false + # attribute.optional? # => true or false # - # @param [Object] value - # the value to test - # # @return [Boolean] # # @api public - def valid_primitive?(value) - value.kind_of?(self.class.primitive) + def optional? + ! required? end # Test if the value matches the attribute constraints # # @example - # attribute.valid_value?(value) # => true or false + # attribute.include?(value) # => true or false # # @param [Object] value # the value to test # # @return [Boolean] # # @api public - def valid_value?(value) - valid_or_optional?(value) { valid_primitive?(value) } + def include?(value) + valid_or_optional?(value, &type.method(:include?)) end private # Test that the value is either valid or optional @@ -187,10 +178,10 @@ # # @return [Boolean] # # @api private def valid_or_optional?(value) - value.nil? ? ! required? : yield + value.nil? ? optional? : yield(value) end # Coerce the object into an Attribute # # @param [Array] args