From 2f30f137431388b6b773e8e72c6454d1b32b1fae Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Mon, 5 Jun 2023 13:21:25 +1000 Subject: [PATCH 1/6] Spec SemanticProperty --- .rspec | 2 + .../semantizer/semantic_property_spec.rb | 13 +++ spec/spec_helper.rb | 98 +++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 .rspec create mode 100644 spec/lib/virtual_assembly/semantizer/semantic_property_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..8ef7776 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--require spec_helper +--require virtual_assembly/semantizer diff --git a/spec/lib/virtual_assembly/semantizer/semantic_property_spec.rb b/spec/lib/virtual_assembly/semantizer/semantic_property_spec.rb new file mode 100644 index 0000000..1b44505 --- /dev/null +++ b/spec/lib/virtual_assembly/semantizer/semantic_property_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +describe VirtualAssembly::Semantizer::SemanticProperty do + it 'has a name' do + property = described_class.new('http://example.net/property5') + expect(property.name).to eq 'http://example.net/property5' + end + + it 'stores a getter' do + property = described_class.new('@id') { 'person/42' } + expect(property.value).to eq 'person/42' + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..1d4048f --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + + # The settings below are suggested to provide a good initial experience + # with RSpec, but feel free to customize to your heart's content. + # # This allows you to limit a spec run to individual examples or groups + # # you care about by tagging them with `:focus` metadata. When nothing + # # is tagged with `:focus`, all examples get run. RSpec also provides + # # aliases for `it`, `describe`, and `context` that include `:focus` + # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + # config.filter_run_when_matching :focus + # + # # Allows RSpec to persist some state between runs in order to support + # # the `--only-failures` and `--next-failure` CLI options. We recommend + # # you configure your source control system to ignore this file. + # config.example_status_persistence_file_path = "spec/examples.txt" + # + # # Limits the available syntax to the non-monkey patched syntax that is + # # recommended. For more details, see: + # # https://relishapp.com/rspec/rspec-core/docs/configuration/zero-monkey-patching-mode + # config.disable_monkey_patching! + # + # # This setting enables warnings. It's recommended, but in some cases may + # # be too noisy due to issues in dependencies. + # config.warnings = true + # + # # Many RSpec users commonly either run the entire suite or an individual + # # file, and it's useful to allow more verbose output when running an + # # individual spec file. + # if config.files_to_run.one? + # # Use the documentation formatter for detailed output, + # # unless a formatter has already been configured + # # (e.g. via a command-line flag). + # config.default_formatter = "doc" + # end + # + # # Print the 10 slowest examples and example groups at the + # # end of the spec run, to help surface which specs are running + # # particularly slow. + # config.profile_examples = 10 + # + # # Run specs in random order to surface order dependencies. If you find an + # # order dependency and want to debug it, you can fix the order by providing + # # the seed, which is printed after each run. + # # --seed 1234 + # config.order = :random + # + # # Seed global randomization in this process using the `--seed` CLI option. + # # Setting this allows you to use `--seed` to deterministically reproduce + # # test failures related to randomization by passing the same `--seed` value + # # as the one that triggered the failure. + # Kernel.srand config.seed +end From 09f54091c68f4544baef9f81d6ce53d806c262a5 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Mon, 5 Jun 2023 13:23:04 +1000 Subject: [PATCH 2/6] Style SemanticProperty with rubocop --- .../semantizer/semantic_property.rb | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/lib/virtual_assembly/semantizer/semantic_property.rb b/lib/virtual_assembly/semantizer/semantic_property.rb index 0c0fb71..a29de42 100644 --- a/lib/virtual_assembly/semantizer/semantic_property.rb +++ b/lib/virtual_assembly/semantizer/semantic_property.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Copyright © 2023 Maxime Lecoq, # # Permission is hereby granted, free of charge, to any person obtaining a copy of this software @@ -15,15 +17,15 @@ # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# The SemanticPropety class is designed to turn properties of +# The SemanticPropety class is designed to turn properties of # objects into linked data. # # A SemanticProperty has a name and a corresponding value that # can be fetched later (so its value would be up to date). # -# This class is intented to be used through the SemanticObject +# This class is intented to be used through the SemanticObject # class. -# +# # For instance, we can tell that the name of a Person object refers # to the linked data concept "name" from the FOAF project. The name # of the property would be the uri of the FOAF:name property while the @@ -31,33 +33,35 @@ # # You should use a block to pass the value like so: # SemanticProperty.new("http://xmlns.com/foaf/0.1/name") {self.name} -class VirtualAssembly::Semantizer::SemanticProperty - - # The name of the property. It generally points to an uri - # like "http://xmlns.com/foaf/0.1/name" or it is used to - # define a reserved linked data property like "@id". - # - # This should be a String. - attr_accessor :name +module VirtualAssembly + module Semantizer + class SemanticProperty + # The name of the property. It generally points to an uri + # like "http://xmlns.com/foaf/0.1/name" or it is used to + # define a reserved linked data property like "@id". + # + # This should be a String. + attr_accessor :name - # The function to call when the value is requested. - # - # This should be a Proc passed as a Block. - attr_accessor :valueGetter + # The function to call when the value is requested. + # + # This should be a Proc passed as a Block. + attr_accessor :valueGetter - # @param name The name of the property, like - # "http://xmlns.com/foaf/0.1/name" or "@id" for instance. - # - # @param valueGetter A Proc used to retrieve the value of the - # property when requested. - def initialize(name, &valueGetter) + # @param name The name of the property, like + # "http://xmlns.com/foaf/0.1/name" or "@id" for instance. + # + # @param valueGetter A Proc used to retrieve the value of the + # property when requested. + def initialize(name, &valueGetter) @name = name @valueGetter = valueGetter - end + end - # Fetch and returns the value associated to this property. - def value - return @valueGetter.call + # Fetch and returns the value associated to this property. + def value + @valueGetter.call + end end - -end \ No newline at end of file + end +end From 11a64f698a89d0ff079f2e1b1d5015036f926ea6 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Mon, 5 Jun 2023 13:35:03 +1000 Subject: [PATCH 3/6] Allow to provide a setter for each property --- lib/virtual_assembly/semantizer/semantic_property.rb | 10 ++++++++++ .../semantizer/semantic_property_spec.rb | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/virtual_assembly/semantizer/semantic_property.rb b/lib/virtual_assembly/semantizer/semantic_property.rb index a29de42..c7d259d 100644 --- a/lib/virtual_assembly/semantizer/semantic_property.rb +++ b/lib/virtual_assembly/semantizer/semantic_property.rb @@ -48,6 +48,11 @@ class SemanticProperty # This should be a Proc passed as a Block. attr_accessor :valueGetter + # The function to call to store a new value. + # + # This should be a Proc + attr_accessor :valueSetter + # @param name The name of the property, like # "http://xmlns.com/foaf/0.1/name" or "@id" for instance. # @@ -62,6 +67,11 @@ def initialize(name, &valueGetter) def value @valueGetter.call end + + # Stores a new value for this property. + def value=(new_value) + @valueSetter.call(new_value) + end end end end diff --git a/spec/lib/virtual_assembly/semantizer/semantic_property_spec.rb b/spec/lib/virtual_assembly/semantizer/semantic_property_spec.rb index 1b44505..be261da 100644 --- a/spec/lib/virtual_assembly/semantizer/semantic_property_spec.rb +++ b/spec/lib/virtual_assembly/semantizer/semantic_property_spec.rb @@ -10,4 +10,15 @@ property = described_class.new('@id') { 'person/42' } expect(property.value).to eq 'person/42' end + + it 'can store a setter' do + weather = "rain" + + property = described_class.new("weather") { weather } + property.valueSetter = -> (value) { weather = value } + + expect { property.value = "sunshine" } + .to change { property.value } + .from("rain").to("sunshine") + end end From 346418e67c19487ef47bc3a247d5dcb10625d17d Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Mon, 5 Jun 2023 15:40:14 +1000 Subject: [PATCH 4/6] Style SemanticObject with rubocop --- .../semantizer/semantic_object.rb | 258 +++++++++--------- 1 file changed, 129 insertions(+), 129 deletions(-) diff --git a/lib/virtual_assembly/semantizer/semantic_object.rb b/lib/virtual_assembly/semantizer/semantic_object.rb index 7d1c303..e2312e2 100644 --- a/lib/virtual_assembly/semantizer/semantic_object.rb +++ b/lib/virtual_assembly/semantizer/semantic_object.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Copyright © 2023 Maxime Lecoq, # # Permission is hereby granted, free of charge, to any person obtaining a copy of this software @@ -23,153 +25,151 @@ # A semanticObject holds semantic properties (SemanticProperty) # that refers to linked data concepts. # -# For example, a Person object including this module could register +# For example, a Person object including this module could register # in its initializer method a semantic property for its name like: # Person.registerSemanticProperty("http://xmlns.com/foaf/0.1/name") {self.name} -module VirtualAssembly::Semantizer::SemanticObject - - # The semantic ID implements the concept of linked data ID. - # - # This ID is an uri pointing to the location of the object - # on the web like "https://mywebsite/myobject" for instance. - # - # If a SemanticObject doesn't define its ID, it - # will be considered as a blank node. - # - # This should be a String or nil. - attr_accessor :semanticId - - # The semantic type implements the concept of linked data type - # (also called class). - # - # This type is an uri pointing to the location of the linked - # data concept on the web like "http://xmlns.com/foaf/0.1/Person" - # for instance. - # - # This should be a String or nil. - attr_accessor :semanticType - - # This Array stores the semantic properties of the object. - # To append a SemanticProperty, use the dedicated - # registerSemanticProperty method. You should pass the value - # of the property as a block (callback) like so: - # registerSemanticProperty("http://xmlns.com/foaf/0.1/name") {self.name}. - attr_reader :semanticProperties - - # If the semanticId is nil, the object will be treated as a blank node. - def initialize(semanticId = nil, semanticType = nil) - @semanticProperties = Array.new - +module VirtualAssembly + module Semantizer + module SemanticObject + # The semantic ID implements the concept of linked data ID. + # + # This ID is an uri pointing to the location of the object + # on the web like "https://mywebsite/myobject" for instance. + # + # If a SemanticObject doesn't define its ID, it + # will be considered as a blank node. + # + # This should be a String or nil. + attr_accessor :semanticId + + # The semantic type implements the concept of linked data type + # (also called class). + # + # This type is an uri pointing to the location of the linked + # data concept on the web like "http://xmlns.com/foaf/0.1/Person" + # for instance. + # + # This should be a String or nil. + attr_accessor :semanticType + + # This Array stores the semantic properties of the object. + # To append a SemanticProperty, use the dedicated + # registerSemanticProperty method. You should pass the value + # of the property as a block (callback) like so: + # registerSemanticProperty("http://xmlns.com/foaf/0.1/name") {self.name}. + attr_reader :semanticProperties + + # If the semanticId is nil, the object will be treated as a blank node. + def initialize(semanticId = nil, semanticType = nil) + @semanticProperties = [] + # This Hash allows us to find a property using its name. # # Hash # # The key store the name of a property (String). - # The value store the index of the property in the + # The value store the index of the property in the # semanticProperties array (Integer). - @semanticPropertiesNameIndex = Hash.new + @semanticPropertiesNameIndex = {} # Ensure to call the setter methods self.semanticId = semanticId self.semanticType = semanticType - end + end - def hasSemanticProperty?(name) - return @semanticPropertiesNameIndex.include?(name) - end + def hasSemanticProperty?(name) + @semanticPropertiesNameIndex.include?(name) + end - def isBlankNode? - return @semanticId == nil || @semanticId == "" - end + def isBlankNode? + @semanticId.nil? || @semanticId == '' + end - # Given the name of the property, it returns the value - # associated to a property of this object. - def semanticPropertyValue(name) + # Given the name of the property, it returns the value + # associated to a property of this object. + def semanticPropertyValue(name) index = @semanticPropertiesNameIndex.fetch(name, nil) - return index != nil ? @semanticProperties[index].value : nil; - end + !index.nil? ? @semanticProperties[index].value : nil + end - # Use this method to append a semantic property to this object. - # The value of the property should be passed as a block so its - # value would be up to date when we will access it. - def registerSemanticProperty(name, &valueGetter) + # Use this method to append a semantic property to this object. + # The value of the property should be passed as a block so its + # value would be up to date when we will access it. + def registerSemanticProperty(name, &valueGetter) createOrUpdateSemanticProperty(name, valueGetter) - end - - # Sets the semantic id of the object and registers the - # corresponding semantic property. - # - # The semantic ID implements the concept of linked data ID. - # - # This ID is an uri pointing to the location of the object - # on the web like "https://mywebsite/myobject" for instance. - # - # If a SemanticObject doesn't define its ID, it - # will be considered as a blank node. - # - # This should be a String or nil. - def semanticId=(uri) + end + + # Sets the semantic id of the object and registers the + # corresponding semantic property. + # + # The semantic ID implements the concept of linked data ID. + # + # This ID is an uri pointing to the location of the object + # on the web like "https://mywebsite/myobject" for instance. + # + # If a SemanticObject doesn't define its ID, it + # will be considered as a blank node. + # + # This should be a String or nil. + def semanticId=(uri) @semanticId = uri - registerSemanticProperty("@id") {self.semanticId} - end - - # Sets the semantic type of the object and registers the - # corresponding semantic property. - # - # The semantic type implements the concept of linked data type - # (also called class). - # - # This type is an uri pointing to the location of the linked - # data concept on the web like "http://xmlns.com/foaf/0.1/Person" - # for instance. - # - # This should be a String or nil. - def semanticType=(type) + registerSemanticProperty('@id') { semanticId } + end + + # Sets the semantic type of the object and registers the + # corresponding semantic property. + # + # The semantic type implements the concept of linked data type + # (also called class). + # + # This type is an uri pointing to the location of the linked + # data concept on the web like "http://xmlns.com/foaf/0.1/Person" + # for instance. + # + # This should be a String or nil. + def semanticType=(type) @semanticType = type - registerSemanticProperty("@type") {self.semanticType} - end - - # Serialize all the semantic properties of this object - # to an output format. - # - # You could use the HashSerializer to export as a Hash. - # This Hash should be then exported to JSON for instance. - def serialize(serializer) - return serializer.process(self) - end - - protected - - # If the semantic property already exist in this object, this - # method will simply update the valueGetter of the property. - # - # If this object does not holds the property, the new property - # will be added into the semanticProperties Array of this object. - def createOrUpdateSemanticProperty(name, valueGetter) - # Update - if (hasSemanticProperty?(name)) - semanticProperty = findSemanticProperty(name) - if (semanticProperty != nil) - semanticProperty.valueGetter = valueGetter - end - - # Create - else - @semanticProperties.push(VirtualAssembly::Semantizer::SemanticProperty.new(name, &valueGetter)) - index = @semanticProperties.count - 1 - @semanticPropertiesNameIndex.store(name, index); - end - end - - # Given its name, returns the corresponding SemanticProperty - # stored by this object or nil if the property does not exist. - def findSemanticProperty(name) - begin - index = @semanticPropertiesNameIndex.fetch(name) - return @semanticProperties.at(index) - rescue - return nil - end + registerSemanticProperty('@type') { semanticType } + end + + # Serialize all the semantic properties of this object + # to an output format. + # + # You could use the HashSerializer to export as a Hash. + # This Hash should be then exported to JSON for instance. + def serialize(serializer) + serializer.process(self) + end + + protected + + # If the semantic property already exist in this object, this + # method will simply update the valueGetter of the property. + # + # If this object does not holds the property, the new property + # will be added into the semanticProperties Array of this object. + def createOrUpdateSemanticProperty(name, valueGetter) + # Update + if hasSemanticProperty?(name) + semanticProperty = findSemanticProperty(name) + semanticProperty.valueGetter = valueGetter unless semanticProperty.nil? + + # Create + else + @semanticProperties.push(VirtualAssembly::Semantizer::SemanticProperty.new(name, &valueGetter)) + index = @semanticProperties.count - 1 + @semanticPropertiesNameIndex.store(name, index) end - -end \ No newline at end of file + end + + # Given its name, returns the corresponding SemanticProperty + # stored by this object or nil if the property does not exist. + def findSemanticProperty(name) + index = @semanticPropertiesNameIndex.fetch(name) + @semanticProperties.at(index) + rescue StandardError + nil + end + end + end +end From e5aa14744e552f40d90527152104500e8787956e Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Mon, 5 Jun 2023 16:47:21 +1000 Subject: [PATCH 5/6] Allow public access to properties for writing --- .../semantizer/semantic_object.rb | 33 ++++++++++--------- .../semantizer/semantic_object_spec.rb | 30 +++++++++++++++++ 2 files changed, 48 insertions(+), 15 deletions(-) create mode 100644 spec/lib/virtual_assembly/semantizer/semantic_object_spec.rb diff --git a/lib/virtual_assembly/semantizer/semantic_object.rb b/lib/virtual_assembly/semantizer/semantic_object.rb index e2312e2..a9b62c9 100644 --- a/lib/virtual_assembly/semantizer/semantic_object.rb +++ b/lib/virtual_assembly/semantizer/semantic_object.rb @@ -88,8 +88,16 @@ def isBlankNode? # Given the name of the property, it returns the value # associated to a property of this object. def semanticPropertyValue(name) - index = @semanticPropertiesNameIndex.fetch(name, nil) - !index.nil? ? @semanticProperties[index].value : nil + semanticProperty(name)&.value + end + + # Given its name, returns the corresponding SemanticProperty + # stored by this object or nil if the property does not exist. + def semanticProperty(name) + index = @semanticPropertiesNameIndex.fetch(name) + @semanticProperties.at(index) + rescue StandardError + nil end # Use this method to append a semantic property to this object. @@ -113,7 +121,8 @@ def registerSemanticProperty(name, &valueGetter) # This should be a String or nil. def semanticId=(uri) @semanticId = uri - registerSemanticProperty('@id') { semanticId } + property = registerSemanticProperty('@id') { semanticId } + property.valueSetter = ->(value) { @semanticId = value } end # Sets the semantic type of the object and registers the @@ -129,7 +138,8 @@ def semanticId=(uri) # This should be a String or nil. def semanticType=(type) @semanticType = type - registerSemanticProperty('@type') { semanticType } + property = registerSemanticProperty('@type') { semanticType } + property.valueSetter = ->(value) { @semanticType = value } end # Serialize all the semantic properties of this object @@ -151,24 +161,17 @@ def serialize(serializer) def createOrUpdateSemanticProperty(name, valueGetter) # Update if hasSemanticProperty?(name) - semanticProperty = findSemanticProperty(name) + semanticProperty = semanticProperty(name) semanticProperty.valueGetter = valueGetter unless semanticProperty.nil? # Create else - @semanticProperties.push(VirtualAssembly::Semantizer::SemanticProperty.new(name, &valueGetter)) + semanticProperty = VirtualAssembly::Semantizer::SemanticProperty.new(name, &valueGetter) + @semanticProperties.push(semanticProperty) index = @semanticProperties.count - 1 @semanticPropertiesNameIndex.store(name, index) end - end - - # Given its name, returns the corresponding SemanticProperty - # stored by this object or nil if the property does not exist. - def findSemanticProperty(name) - index = @semanticPropertiesNameIndex.fetch(name) - @semanticProperties.at(index) - rescue StandardError - nil + semanticProperty end end end diff --git a/spec/lib/virtual_assembly/semantizer/semantic_object_spec.rb b/spec/lib/virtual_assembly/semantizer/semantic_object_spec.rb new file mode 100644 index 0000000..2ea7d1d --- /dev/null +++ b/spec/lib/virtual_assembly/semantizer/semantic_object_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +describe VirtualAssembly::Semantizer::SemanticObject do + subject(:object) do + Class.new(Object) do + include VirtualAssembly::Semantizer::SemanticObject + end.new + end + + it 'has a semantic id' do + expect { object.semanticId = 'five' } + .to change { object.semanticId }.from(nil).to('five') + end + + it 'has semantic properties' do + expect(object.hasSemanticProperty?('@id')).to eq true + end + + it 'allow to register properties' do + property = subject.registerSemanticProperty('smokes') + expect(property.name).to eq 'smokes' + end + + it 'allows to access properties' do + object.semanticId = 'five' + + expect { object.semanticProperty('@id').value = 'six' } + .to change { object.semanticPropertyValue('@id') }.from('five').to('six') + end +end From 2d77b93d516f542ab3ebd25f0a0daecf9405f3b0 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Mon, 5 Jun 2023 17:01:31 +1000 Subject: [PATCH 6/6] Simplify storage of semantic properties --- .../semantizer/semantic_object.rb | 46 +++++++------------ 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/lib/virtual_assembly/semantizer/semantic_object.rb b/lib/virtual_assembly/semantizer/semantic_object.rb index a9b62c9..c70492c 100644 --- a/lib/virtual_assembly/semantizer/semantic_object.rb +++ b/lib/virtual_assembly/semantizer/semantic_object.rb @@ -52,33 +52,26 @@ module SemanticObject # This should be a String or nil. attr_accessor :semanticType - # This Array stores the semantic properties of the object. - # To append a SemanticProperty, use the dedicated - # registerSemanticProperty method. You should pass the value - # of the property as a block (callback) like so: - # registerSemanticProperty("http://xmlns.com/foaf/0.1/name") {self.name}. - attr_reader :semanticProperties - # If the semanticId is nil, the object will be treated as a blank node. def initialize(semanticId = nil, semanticType = nil) - @semanticProperties = [] - - # This Hash allows us to find a property using its name. - # - # Hash - # - # The key store the name of a property (String). - # The value store the index of the property in the - # semanticProperties array (Integer). - @semanticPropertiesNameIndex = {} + @semanticPropertiesMap = {} # Ensure to call the setter methods self.semanticId = semanticId self.semanticType = semanticType end + # This Array stores the semantic properties of the object. + # To append a SemanticProperty, use the dedicated + # registerSemanticProperty method. You should pass the value + # of the property as a block (callback) like so: + # registerSemanticProperty("http://xmlns.com/foaf/0.1/name") {self.name}. + def semanticProperties + @semanticPropertiesMap.values + end + def hasSemanticProperty?(name) - @semanticPropertiesNameIndex.include?(name) + @semanticPropertiesMap.key?(name) end def isBlankNode? @@ -94,10 +87,7 @@ def semanticPropertyValue(name) # Given its name, returns the corresponding SemanticProperty # stored by this object or nil if the property does not exist. def semanticProperty(name) - index = @semanticPropertiesNameIndex.fetch(name) - @semanticProperties.at(index) - rescue StandardError - nil + @semanticPropertiesMap[name] end # Use this method to append a semantic property to this object. @@ -161,17 +151,15 @@ def serialize(serializer) def createOrUpdateSemanticProperty(name, valueGetter) # Update if hasSemanticProperty?(name) - semanticProperty = semanticProperty(name) - semanticProperty.valueGetter = valueGetter unless semanticProperty.nil? + property = semanticProperty(name) + property&.valueGetter = valueGetter # Create else - semanticProperty = VirtualAssembly::Semantizer::SemanticProperty.new(name, &valueGetter) - @semanticProperties.push(semanticProperty) - index = @semanticProperties.count - 1 - @semanticPropertiesNameIndex.store(name, index) + property = VirtualAssembly::Semantizer::SemanticProperty.new(name, &valueGetter) + @semanticPropertiesMap[name] = property end - semanticProperty + property end end end