lib/frodata/property.rb
module FrOData
# FrOData::Property represents an abstract property, defining the basic
# interface and required methods, with some default implementations. All
# supported property types should be implemented under the FrOData::Properties
# namespace.
class Property
# The property's name
attr_reader :name
# The property's value
attr_accessor :value
# The property's options
attr_reader :options
# Default intialization for a property with a name, value and options.
# @param name [to_s]
# @param value [to_s,nil]
# @param options [Hash]
def initialize(name, value, options = {})
@name = name.to_s
@value = value.nil? ? nil : value.to_s
@options = default_options.merge(options)
end
# Abstract implementation, should return property type, based on
# FrOData::Service metadata in proper implementation.
# @raise NotImplementedError
def type
raise NotImplementedError
end
# Provides for value-based equality checking.
# @param other [value] object for comparison
# @return [Boolean]
def ==(other)
self.value == other.value
end
# Whether the property permits a nil value.
# (Default=true)
# @return [Boolean]
def allows_nil?
options[:allows_nil]
end
# Whether the property uses strict validation.
# (Default=false)
# @return [Boolean]
def strict?
if options.key? :strict
options[:strict]
elsif service
service.options[:strict]
else
true
end
end
# The configured concurrency mode for the property.
# @return [String]
def concurrency_mode
@concurrency_mode ||= options[:concurrency_mode]
end
# Value to be used in XML.
# @return [String]
def xml_value
@value
end
# Value to be used in JSON.
# @return [*]
def json_value
value
end
# Value to be used in URLs.
# @return [String]
def url_value
@value
end
# Returns the XML representation of the property to the supplied XML
# builder.
# @param xml_builder [Nokogiri::XML::Builder]
def to_xml(xml_builder)
attributes = {
'metadata:type' => type,
}
if value.nil?
attributes['metadata:null'] = 'true'
xml_builder['data'].send(name.to_sym, attributes)
else
xml_builder['data'].send(name.to_sym, attributes, xml_value)
end
end
# Creates a new property instance from an XML element
# @param property_xml [Nokogiri::XML::Element]
# @param options [Hash]
# @return [FrOData::Property]
def self.from_xml(property_xml, options = {})
if property_xml.attributes['null'].andand.value == 'true'
content = nil
else
content = property_xml.content
end
new(property_xml.name, content, options)
end
protected
def default_options
{
allows_nil: true,
concurrency_mode: :none
}
end
def service
options[:service]
end
def logger
# Use a dummy logger if service is not available (-> unit tests)
@logger ||= service.andand.logger || Logger.new('/dev/null')
end
def validation_error(message)
if strict?
raise ArgumentError, "#{name}: #{message}"
else
logger.warn "#{name}: #{message}"
nil
end
end
end
end