Class: RDF::Literal
- Inherits:
-
Object
- Object
- RDF::Literal
- Includes:
- Term
- Defined in:
- lib/rdf/model/literal.rb,
lib/rdf/model/literal/date.rb,
lib/rdf/model/literal/time.rb,
lib/rdf/model/literal/token.rb,
lib/rdf/model/literal/double.rb,
lib/rdf/model/literal/boolean.rb,
lib/rdf/model/literal/decimal.rb,
lib/rdf/model/literal/integer.rb,
lib/rdf/model/literal/numeric.rb,
lib/rdf/model/literal/datetime.rb
Overview
An RDF literal.
Subclasses of Literal should define DATATYPE and GRAMMAR constants, which are used for identifying the appropriate class to use for a datatype URI and to perform lexical matching on the value.
Literal comparison with other Value instances call Value#type_error, which, returns false. Implementations wishing to have TypeError raised should mix-in TypeCheck. This is required for strict SPARQL conformance.
Specific typed literals may have behavior different from the default implementation. See the following defined sub-classes for specific documentation. Additional sub-classes may be defined, and will interoperate by defining ‘DATATYPE` and `GRAMMAR` constants, in addition other required overrides of RDF::Literal behavior.
In RDF 1.1, all literals are typed, including plain literals and language tagged literals. Internally, plain literals are given the ‘xsd:string` datatype and language tagged literals are given the `rdf:langString` datatype. Creating a plain literal, without a datatype or language, will automatically provide the `xsd:string` datatype; similar for language tagged literals. Note that most serialization formats will remove this datatype. Code which depends on a literal having the `xsd:string` datatype being different from a plain literal (formally, without a datatype) may break. However note that the `#has_datatype?` will continue to return `false` for plain or language-tagged literals.
Defined Under Namespace
Classes: Boolean, Date, DateTime, Decimal, Double, Integer, Numeric, Time, Token
Constant Summary collapse
Instance Attribute Summary collapse
-
#datatype ⇒ URI
The XML Schema datatype URI (optional).
-
#language ⇒ Symbol
The language tag (optional).
Class Method Summary collapse
-
.datatype_map ⇒ Object
Return Hash mapping from datatype URI to class.
-
.datatyped_class(uri) ⇒ Object
Return datatype class for uri, or nil if none is found.
- .new(value, language: nil, datatype: nil, lexical: nil, validate: false, canonicalize: false, **options) ⇒ Object
Instance Method Summary collapse
-
#<=>(other) ⇒ Integer
Compares ‘self` to `other` for sorting purposes (with type check).
-
#==(other) ⇒ Boolean
(also: #===)
Returns ‘true` if this literal is equivalent to `other` (with type check).
-
#canonicalize! ⇒ RDF::Literal
Converts this literal into its canonical lexical representation.
-
#compatible?(other) ⇒ Boolean
Term compatibility according to SPARQL.
-
#comperable_datatype2?(other) ⇒ Boolean
Returns ‘true` if the literals are comperable.
-
#comperable_datatype?(other) ⇒ Boolean
Returns ‘true` if the literal has a datatype and the comparison should return false instead of raise a type error.
-
#datatype? ⇒ Boolean
(also: #has_datatype?, #typed?, #datatyped?)
Returns ‘true` if this is a datatyped literal.
-
#eql?(other) ⇒ Boolean
Determins if ‘self` is the same term as `other`.
-
#escape(string) ⇒ String
Escape a literal using ECHAR escapes.
- #freeze ⇒ Object
-
#hash ⇒ Integer
Returns a hash code for this literal.
-
#humanize(lang = :en) ⇒ String
Returns a human-readable value for the literal.
-
#initialize(value, language: nil, datatype: nil, lexical: nil, validate: false, canonicalize: false, **options) ⇒ Literal
constructor
Literals without a datatype are given either xsd:string or rdf:langString depending on if there is language.
-
#inspect ⇒ String
Returns a developer-friendly representation of ‘self`.
-
#language? ⇒ Boolean
(also: #has_language?)
Returns ‘true` if this is a language-tagged literal.
-
#literal? ⇒ Boolean
Returns ‘true`.
- #object ⇒ Object
-
#plain? ⇒ Boolean
Returns ‘true` if this is a plain literal.
-
#simple? ⇒ Boolean
Returns ‘true` if this is a simple literal.
-
#squish(*other_string) ⇒ RDF::Literal
Returns the literal, first removing all whitespace on both ends of the value, and then changing remaining consecutive whitespace groups into one space each.
-
#squish! ⇒ Object
Performs a destructive #squish.
-
#to_s ⇒ String
Returns the value as a string.
-
#valid? ⇒ Boolean
Returns ‘true` if the value adheres to the defined grammar of the datatype.
-
#validate! ⇒ RDF::Literal
Validates the value using Value#valid?, raising an error if the value is invalid.
-
#value ⇒ String
Returns the value as a string.
-
#value_hash ⇒ Integer
Returns a hash code for the value.
Methods included from Term
#term?, #terms, #to_base, #to_term
Methods included from Value
#anonymous?, #canonicalize, #constant?, #graph?, #inspect!, #invalid?, #iri?, #list?, #node?, #resource?, #start_with?, #statement?, #term?, #to_nquads, #to_ntriples, #to_rdf, #to_term, #type_error, #uri?, #variable?
Constructor Details
#initialize(value, language: nil, datatype: nil, lexical: nil, validate: false, canonicalize: false, **options) ⇒ Literal
Literals without a datatype are given either xsd:string or rdf:langString depending on if there is language
165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/rdf/model/literal.rb', line 165 def initialize(value, language: nil, datatype: nil, lexical: nil, validate: false, canonicalize: false, **) @object = value.freeze @string = lexical if lexical @string = value if !defined?(@string) && value.is_a?(String) @string = @string.encode(Encoding::UTF_8).freeze if instance_variable_defined?(:@string) @object = @string if instance_variable_defined?(:@string) && @object.is_a?(String) @language = language.to_s.downcase.to_sym if language @datatype = RDF::URI(datatype).freeze if datatype @datatype ||= self.class.const_get(:DATATYPE) if self.class.const_defined?(:DATATYPE) @datatype ||= instance_variable_defined?(:@language) && @language ? RDF.langString : RDF::URI("http://www.w3.org/2001/XMLSchema#string") end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
Instance Attribute Details
#datatype ⇒ URI
Returns The XML Schema datatype URI (optional).
144 145 146 |
# File 'lib/rdf/model/literal.rb', line 144 def datatype @datatype end |
#language ⇒ Symbol
Returns The language tag (optional).
141 142 143 |
# File 'lib/rdf/model/literal.rb', line 141 def language @language end |
Class Method Details
.datatype_map ⇒ Object
Return Hash mapping from datatype URI to class
90 91 92 93 94 95 96 |
# File 'lib/rdf/model/literal.rb', line 90 def self.datatype_map @@datatype_map ||= Hash[ @@subclasses .select {|klass| klass.const_defined?(:DATATYPE)} .map {|klass| [klass.const_get(:DATATYPE).to_s, klass]} ] end |
.datatyped_class(uri) ⇒ Object
Return datatype class for uri, or nil if none is found
101 102 103 |
# File 'lib/rdf/model/literal.rb', line 101 def self.datatyped_class(uri) datatype_map[uri] end |
.new(value, language: nil, datatype: nil, lexical: nil, validate: false, canonicalize: false, **options) ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/rdf/model/literal.rb', line 107 def self.new(value, language: nil, datatype: nil, lexical: nil, validate: false, canonicalize: false, **) raise ArgumentError, "datatype with language must be rdf:langString" if language && (datatype || RDF.langString).to_s != RDF.langString.to_s klass = case when !self.equal?(RDF::Literal) self # subclasses can be directly constructed without type dispatch when typed_literal = datatyped_class(datatype.to_s) typed_literal else case value when ::TrueClass then RDF::Literal::Boolean when ::FalseClass then RDF::Literal::Boolean when ::Integer then RDF::Literal::Integer when ::Float then RDF::Literal::Double when ::BigDecimal then RDF::Literal::Decimal when ::Rational then RDF::Literal::Double when ::DateTime then RDF::Literal::DateTime when ::Time then RDF::Literal::DateTime when ::Date then RDF::Literal::Date when ::Symbol then RDF::Literal::Token else self end end literal = klass.allocate literal.send(:initialize, value, language: language, datatype: datatype, **) literal.validate! if validate literal.canonicalize! if canonicalize literal end |
Instance Method Details
#<=>(other) ⇒ Integer
Compares ‘self` to `other` for sorting purposes (with type check).
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/rdf/model/literal.rb', line 316 def <=>(other) case other when Literal case when self.eql?(other) 0 when self.language? && other.language? # Literals with languages can compare if languages are identical self.to_s <=> other.to_s when self.simple? && other.simple? self.to_s <=> other.to_s when !self.valid? type_error("#{self.inspect} is invalid") || 0 when !other.valid? type_error("#{other.inspect} is invalid") || 0 when self.comperable_datatype2?(other) self.object <=> other.object else type_error("#{self.inspect} and #{other.inspect} are not comperable") || 0 end when String self.simple? && self.value <=> other else 1 end end |
#==(other) ⇒ Boolean Also known as: ===
Returns ‘true` if this literal is equivalent to `other` (with type check).
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/rdf/model/literal.rb', line 286 def ==(other) case other when Literal case when self.eql?(other) true when self.language? && self.language.to_s == other.language.to_s # Literals with languages can compare if languages are identical self.value_hash == other.value_hash && self.value == other.value when self.simple? && other.simple? self.value_hash == other.value_hash && self.value == other.value when other.comperable_datatype?(self) || self.comperable_datatype?(other) # Comoparing plain with undefined datatypes does not generate an error, but returns false # From data-r2/expr-equal/eq-2-2. false else type_error("unable to determine whether #{self.inspect} and #{other.inspect} are equivalent") end when String self.simple? && self.value.eql?(other) else false end end |
#canonicalize! ⇒ RDF::Literal
Converts this literal into its canonical lexical representation.
Subclasses should override this as needed and appropriate.
460 461 462 |
# File 'lib/rdf/model/literal.rb', line 460 def canonicalize! self end |
#compatible?(other) ⇒ Boolean
Term compatibility according to SPARQL
Compatibility of two arguments is defined as:
-
The arguments are simple literals or literals typed as xsd:string
-
The arguments are plain literals with identical language tags
-
The first argument is a plain literal with language tag and the second argument is a simple literal or literal typed as xsd:string
222 223 224 225 226 227 228 229 230 231 |
# File 'lib/rdf/model/literal.rb', line 222 def compatible?(other) return false unless other.literal? && plain? && other.plain? # * The arguments are simple literals or literals typed as xsd:string # * The arguments are plain literals with identical language tags # * The first argument is a plain literal with language tag and the second argument is a simple literal or literal typed as xsd:string language? ? (language == other.language || other.datatype == RDF::URI("http://www.w3.org/2001/XMLSchema#string")) : other.datatype == RDF::URI("http://www.w3.org/2001/XMLSchema#string") end |
#comperable_datatype2?(other) ⇒ Boolean
Returns ‘true` if the literals are comperable.
Used for <=> operator.
439 440 441 442 443 444 445 446 447 448 449 450 451 |
# File 'lib/rdf/model/literal.rb', line 439 def comperable_datatype2?(other) case self when RDF::Literal::Numeric, RDF::Literal::Boolean case other when RDF::Literal::Numeric, RDF::Literal::Boolean true else false end else self.datatype == other.datatype end end |
#comperable_datatype?(other) ⇒ Boolean
Returns ‘true` if the literal has a datatype and the comparison should return false instead of raise a type error.
This behavior is intuited from SPARQL data-r2/expr-equal/eq-2-2
419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/rdf/model/literal.rb', line 419 def comperable_datatype?(other) return false unless self.plain? || self.language? case other when RDF::Literal::Numeric, RDF::Literal::Boolean, RDF::Literal::Date, RDF::Literal::Time, RDF::Literal::DateTime # Invald types can be compared without raising a TypeError if literal has a language (open-eq-08) !other.valid? && self.language? else # An unknown datatype may not be used for comparison, unless it has a language? (open-eq-8) self.language? end end |
#datatype? ⇒ Boolean Also known as: has_datatype?, typed?, datatyped?
Returns ‘true` if this is a datatyped literal.
For historical reasons, this excludes xsd:string and rdf:langString
381 382 383 |
# File 'lib/rdf/model/literal.rb', line 381 def datatype? !plain? && !language? end |
#eql?(other) ⇒ Boolean
Determins if ‘self` is the same term as `other`.
266 267 268 269 270 271 272 273 |
# File 'lib/rdf/model/literal.rb', line 266 def eql?(other) self.equal?(other) || (self.class.eql?(other.class) && self.value_hash == other.value_hash && self.value.eql?(other.value) && self.language.to_s.eql?(other.language.to_s) && self.datatype.eql?(other.datatype)) end |
#escape(string) ⇒ String
N-Triples only requires ‘"nr’ to be escaped.
Escape a literal using ECHAR escapes.
ECHAR ::= '\' [tbnrf"'\]
498 499 500 501 502 503 504 505 506 507 |
# File 'lib/rdf/model/literal.rb', line 498 def escape(string) string.gsub('\\', '\\\\'). gsub("\t", '\\t'). gsub("\b", '\\b'). gsub("\n", '\\n'). gsub("\r", '\\r'). gsub("\f", '\\f'). gsub('"', '\\"'). freeze end |
#freeze ⇒ Object
252 253 254 255 256 |
# File 'lib/rdf/model/literal.rb', line 252 def freeze hash.freeze value_hash.freeze super end |
#hash ⇒ Integer
Returns a hash code for this literal.
237 238 239 |
# File 'lib/rdf/model/literal.rb', line 237 def hash @hash ||= [to_s, datatype, language].hash end |
#humanize(lang = :en) ⇒ String
Returns a human-readable value for the literal
522 523 524 |
# File 'lib/rdf/model/literal.rb', line 522 def humanize(lang = :en) to_s.freeze end |
#inspect ⇒ String
Returns a developer-friendly representation of ‘self`.
530 531 532 |
# File 'lib/rdf/model/literal.rb', line 530 def inspect sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, RDF::NTriples.serialize(self)) end |
#language? ⇒ Boolean Also known as: has_language?
Returns ‘true` if this is a language-tagged literal.
369 370 371 |
# File 'lib/rdf/model/literal.rb', line 369 def language? datatype == RDF.langString end |
#literal? ⇒ Boolean
Returns ‘true`.
195 196 197 |
# File 'lib/rdf/model/literal.rb', line 195 def literal? true end |
#object ⇒ Object
187 188 189 |
# File 'lib/rdf/model/literal.rb', line 187 def object defined?(@object) ? @object : value end |
#plain? ⇒ Boolean
Returns ‘true` if this is a plain literal. A plain literal may have a language, but may not have a datatype. For all practical purposes, this includes xsd:string literals too.
350 351 352 |
# File 'lib/rdf/model/literal.rb', line 350 def plain? [RDF.langString, RDF::URI("http://www.w3.org/2001/XMLSchema#string")].include?(datatype) end |
#simple? ⇒ Boolean
Returns ‘true` if this is a simple literal. A simple literal has no datatype or language.
360 361 362 |
# File 'lib/rdf/model/literal.rb', line 360 def simple? datatype == RDF::URI("http://www.w3.org/2001/XMLSchema#string") end |
#squish(*other_string) ⇒ RDF::Literal
Returns the literal, first removing all whitespace on both ends of the value, and then changing remaining consecutive whitespace groups into one space each.
Note that it handles both ASCII and Unicode whitespace.
471 472 473 |
# File 'lib/rdf/model/literal.rb', line 471 def squish(*other_string) self.dup.squish! end |
#squish! ⇒ Object
Performs a destructive #squish.
480 481 482 483 484 485 486 |
# File 'lib/rdf/model/literal.rb', line 480 def squish! @string = value. gsub(/\A[[:space:]]+/, ''). gsub(/[[:space:]]+\z/, ''). gsub(/[[:space:]]+/, ' ') self end |
#to_s ⇒ String
Returns the value as a string.
513 514 515 |
# File 'lib/rdf/model/literal.rb', line 513 def to_s @object.to_s.freeze end |
#valid? ⇒ Boolean
Returns ‘true` if the value adheres to the defined grammar of the datatype.
394 395 396 397 398 399 |
# File 'lib/rdf/model/literal.rb', line 394 def valid? return false if language? && language.to_s !~ /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/ return false if datatype? && datatype.invalid? grammar = self.class.const_get(:GRAMMAR) rescue nil grammar.nil? || value.match?(grammar) end |
#validate! ⇒ RDF::Literal
Validates the value using Value#valid?, raising an error if the value is invalid.
408 409 410 411 |
# File 'lib/rdf/model/literal.rb', line 408 def validate! raise ArgumentError, "#{to_s.inspect} is not a valid <#{datatype.to_s}> literal" if invalid? self end |
#value ⇒ String
Returns the value as a string.
181 182 183 |
# File 'lib/rdf/model/literal.rb', line 181 def value instance_variable_defined?(:@string) && @string || to_s end |
#value_hash ⇒ Integer
Returns a hash code for the value.
246 247 248 |
# File 'lib/rdf/model/literal.rb', line 246 def value_hash @value_hash ||= value.hash end |