lib/dbd/fact/factory.rb
module Dbd
class Fact
module Factory
class << self
##
# @return [Class] the top class for which instances are created here.
def top_class
Fact
end
##
# @return [String] A new subject string.
def new_subject
top_class::Subject.new_subject
end
##
# @return [String] A new id string.
def new_id
top_class::ID.new_id
end
##
# Constructs a Fact or ContextFact from a string values array
# (e.g. pulled from a CSV row).
#
# @param [Array] string_values Required : the array with values, organized as in attributes
# @return [Fact, Context] the constructed fact
def from_string_values(string_values, options={})
string_hash = string_hash_from_values(string_values)
validate_string_hash(string_hash) if options[:validate]
fact_from_values_hash(values_hash(string_hash))
end
##
# Formats for checking CSV fields
# the predicate, object_type and object are tested in the initializer
def attribute_formats
{
id: [true, Fact::ID.valid_regexp],
time_stamp: [true, TimeStamp.valid_regexp],
context_subject: [false, Fact::Subject.valid_regexp],
subject: [true, Fact::Subject.valid_regexp]
}
end
private
def unescaped_string_values(string_values)
string_values.map{ |string_value| unescaped_string(string_value) }
end
def unescaped_string(string)
r = %r{(\\\\|\\n)}
repl = {
"\\\\" => "\\", # double backslash => single backslash
"\\n" => "\n"} # backslash n => newline
string.gsub(r, repl)
end
def string_hash_from_values(string_values)
unescaped_values = unescaped_string_values(string_values)
attributes_strings_array = [top_class.attributes, unescaped_values].transpose
# Remove empty values (e.g. the context_subject for a ContextFact).
attributes_strings_array.delete_if{ |_, v| v == '' }
Hash[attributes_strings_array]
end
def values_hash(string_hash)
string_hash.tap do |h|
h[:time_stamp] = TimeStamp.new(time: h[:time_stamp])
end
end
def fact_from_values_hash(values_hash)
if values_hash[:context_subject]
Fact.new(values_hash)
else
ContextFact.new(values_hash)
end
end
def validate_string_hash(string_hash)
attribute_formats.each do |attr, validation|
string = string_hash[attr]
mandatory, format = validation
validate_string_by_regexp(mandatory, string, format)
end
end
def validate_string_by_regexp(mandatory, string, format)
if (mandatory || string) && (string !~ format)
report_invalid_entry(string)
end
end
def report_invalid_entry(string)
raise FactError, "invalid entry found : #{string}"
end
end
end
end
end