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