virtual_assembly-semantizer 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cbd44cbccb6f557aebdb7ef2cb5ed9119ae53839dba26f0a9540794a4fa447a5
4
+ data.tar.gz: 973105f42f81b44ae526b34c822c05898bcd29d8b5a94edbf99b189c4381970e
5
+ SHA512:
6
+ metadata.gz: d032ce8d8eee24379cb6babc939ffdb6243187f7347f7f2d151c742acb5f62cdeb8e0d5d07216131aaced9d518edc26b854e83bc36da11283de011f6c57e349d
7
+ data.tar.gz: 1c55b2707feb65c622a080c27ec6af6d26cf9abc9c9fe556dfd1a4b4c32ebaf2b6197c730cfadfcafaa5b04958919e0deae40c96b53d17222b6aa97af1f5d6f4
@@ -0,0 +1,99 @@
1
+ # Copyright © 2023 Maxime Lecoq, <maxime@lecoqlibre.fr>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4
+ # and associated documentation files (the “Software”), to deal in the Software without
5
+ # restriction, including without limitation the rights to use, copy, modify, merge, publish,
6
+ # distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
7
+ # Software is furnished to do so, subject to the following conditions:
8
+ #
9
+ # The above copyright notice and this permission notice shall be included in all copies or
10
+ # substantial portions of the Software.
11
+
12
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13
+ # BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15
+ # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
16
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+
18
+ # The HashSerializer turns all the semantic properties of a SemanticObject into a Hash.
19
+ #
20
+ # Lets consider the following SemanticObject with a single semantic property like:
21
+ # - name: "http://xmlns.com/foaf/0.1/name"
22
+ # - value: "John"
23
+ #
24
+ # The HashSerializer will return the following Hash:
25
+ # {"http://xmlns.com/foaf/0.1/name" => "John"}.
26
+ class Semantizer::HashSerializer
27
+
28
+ # This is the main method to begin the serialization.
29
+ #
30
+ # The subject should be a SemanticObject.
31
+ def process(subject)
32
+ result = {}
33
+
34
+ # We iterate over all the semantic properties of the subject.
35
+ subject.semanticProperties.each do |property|
36
+ name = property.name
37
+ value = property.value
38
+
39
+ if (value == nil)
40
+ next
41
+ end
42
+
43
+ # In case the property is a primitive, we simply get its value.
44
+ if ([ String, Integer, Float, TrueClass, FalseClass ].include?(value.class))
45
+ result[name] = value
46
+
47
+ # In case the property is a SemanticObject, we get its semanticId
48
+ # or we process it if it is a blank node.
49
+ elsif (value.is_a? SemanticObject)
50
+ if (value.isBlankNode?)
51
+ result[name] = process(value)
52
+ else
53
+ result[name] = value.semanticId
54
+ end
55
+
56
+ # In case the property is an Array, we export each item.
57
+ elsif (value.class == Array)
58
+ result[name] = exportCollection(value)
59
+
60
+ else
61
+ raise "The type of the property '" + name + "' is '" + value.class.to_s + "' but a primitive, a SemanticObject or an Array is required."
62
+ end
63
+ end
64
+
65
+ return result;
66
+ end
67
+
68
+ private
69
+
70
+ # Serialize a collection of values.
71
+ def exportCollection(values)
72
+ collection = []
73
+
74
+ if (!values.empty?)
75
+ type = values.at(0).class
76
+
77
+ # If the collection contains only primitives, we simply return it.
78
+ if ([ String, Integer, Float, TrueClass, FalseClass ].include?(type))
79
+ collection = values
80
+
81
+ # In case the collection contains SemanticObject we have to process
82
+ # the blank nodes or return the semantic id.
83
+ elsif type == SemanticObject
84
+ values.each do |item|
85
+ if (item.isBlankNode?)
86
+ collection.push(process(item))
87
+ else
88
+ collection.push(item.semanticId)
89
+ end
90
+ end
91
+ else
92
+ raise "Elements of the collection are not primitive nor SemanticObject."
93
+ end
94
+ end
95
+
96
+ return collection;
97
+ end
98
+
99
+ end
@@ -0,0 +1,173 @@
1
+ # Copyright © 2023 Maxime Lecoq, <maxime@lecoqlibre.fr>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4
+ # and associated documentation files (the “Software”), to deal in the Software without
5
+ # restriction, including without limitation the rights to use, copy, modify, merge, publish,
6
+ # distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
7
+ # Software is furnished to do so, subject to the following conditions:
8
+ #
9
+ # The above copyright notice and this permission notice shall be included in all copies or
10
+ # substantial portions of the Software.
11
+
12
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13
+ # BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15
+ # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
16
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+
18
+ require 'virtual_assembly/semantizer/semantic_property'
19
+
20
+ # The SemanticObject module is designed to add linked data
21
+ # to classical objects.
22
+ #
23
+ # A semanticObject holds semantic properties (SemanticProperty)
24
+ # that refers to linked data concepts.
25
+ #
26
+ # For example, a Person object including this module could register
27
+ # in its initializer method a semantic property for its name like:
28
+ # Person.registerSemanticProperty("http://xmlns.com/foaf/0.1/name") {self.name}
29
+ module Semantizer::SemanticObject
30
+
31
+ # The semantic ID implements the concept of linked data ID.
32
+ #
33
+ # This ID is an uri pointing to the location of the object
34
+ # on the web like "https://mywebsite/myobject" for instance.
35
+ #
36
+ # If a SemanticObject doesn't define its ID, it
37
+ # will be considered as a blank node.
38
+ #
39
+ # This should be a String or nil.
40
+ attr_accessor :semanticId
41
+
42
+ # The semantic type implements the concept of linked data type
43
+ # (also called class).
44
+ #
45
+ # This type is an uri pointing to the location of the linked
46
+ # data concept on the web like "http://xmlns.com/foaf/0.1/Person"
47
+ # for instance.
48
+ #
49
+ # This should be a String or nil.
50
+ attr_accessor :semanticType
51
+
52
+ # This Array stores the semantic properties of the object.
53
+ # To append a SemanticProperty, use the dedicated
54
+ # registerSemanticProperty method. You should pass the value
55
+ # of the property as a block (callback) like so:
56
+ # registerSemanticProperty("http://xmlns.com/foaf/0.1/name") {self.name}.
57
+ attr_reader :semanticProperties
58
+
59
+ # If the semanticId is nil, the object will be treated as a blank node.
60
+ def initialize(semanticId = nil, semanticType = nil)
61
+ @semanticId = semanticId
62
+ @semanticType = semanticType
63
+ @semanticProperties = Array.new
64
+
65
+ # This Hash allows us to find a property using its name.
66
+ #
67
+ # Hash<String, Integer>
68
+ #
69
+ # The key store the name of a property (String).
70
+ # The value store the index of the property in the
71
+ # semanticProperties array (Integer).
72
+ @semanticPropertiesNameIndex = Hash.new
73
+ end
74
+
75
+ def hasSemanticProperty?(name)
76
+ return @semanticPropertiesNameIndex.include?(name)
77
+ end
78
+
79
+ def isBlankNode?
80
+ return @semanticId == nil || @semanticId == ""
81
+ end
82
+
83
+ # Given the name of the property, it returns the value
84
+ # associated to a property of this object.
85
+ def semanticPropertyValue(name)
86
+ index = @semanticPropertiesNameIndex.fetch(name, nil)
87
+ return index != nil ? @semanticProperties[index].value : nil;
88
+ end
89
+
90
+ # Use this method to append a semantic property to this object.
91
+ # The value of the property should be passed as a block so its
92
+ # value would be up to date when we will access it.
93
+ def registerSemanticProperty(name, &valueGetter)
94
+ createOrUpdateSemanticProperty(name, valueGetter)
95
+ end
96
+
97
+ # Sets the semantic id of the object and registers the
98
+ # corresponding semantic property.
99
+ #
100
+ # The semantic ID implements the concept of linked data ID.
101
+ #
102
+ # This ID is an uri pointing to the location of the object
103
+ # on the web like "https://mywebsite/myobject" for instance.
104
+ #
105
+ # If a SemanticObject doesn't define its ID, it
106
+ # will be considered as a blank node.
107
+ #
108
+ # This should be a String or nil.
109
+ def semanticId=(uri)
110
+ @semanticId = uri
111
+ registerSemanticProperty("@id") {self.semanticId}
112
+ end
113
+
114
+ # Sets the semantic type of the object and registers the
115
+ # corresponding semantic property.
116
+ #
117
+ # The semantic type implements the concept of linked data type
118
+ # (also called class).
119
+ #
120
+ # This type is an uri pointing to the location of the linked
121
+ # data concept on the web like "http://xmlns.com/foaf/0.1/Person"
122
+ # for instance.
123
+ #
124
+ # This should be a String or nil.
125
+ def semanticType=(type)
126
+ @semanticType = type
127
+ registerSemanticProperty("@type") {self.semanticType}
128
+ end
129
+
130
+ # Serialize all the semantic properties of this object
131
+ # to an output format.
132
+ #
133
+ # You could use the HashSerializer to export as a Hash.
134
+ # This Hash should be then exported to JSON for instance.
135
+ def serialize(serializer)
136
+ return serializer.process(self)
137
+ end
138
+
139
+ protected
140
+
141
+ # If the semantic property already exist in this object, this
142
+ # method will simply update the valueGetter of the property.
143
+ #
144
+ # If this object does not holds the property, the new property
145
+ # will be added into the semanticProperties Array of this object.
146
+ def createOrUpdateSemanticProperty(name, valueGetter)
147
+ # Update
148
+ if (hasSemanticProperty?(name))
149
+ semanticProperty = findSemanticProperty(name)
150
+ if (semanticProperty != nil)
151
+ semanticProperty.valueGetter = valueGetter
152
+ end
153
+
154
+ # Create
155
+ else
156
+ @semanticProperties.push(Semantizer::SemanticProperty.new(name, &valueGetter))
157
+ index = @semanticProperties.count - 1
158
+ @semanticPropertiesNameIndex.store(name, index);
159
+ end
160
+ end
161
+
162
+ # Given its name, returns the corresponding SemanticProperty
163
+ # stored by this object or nil if the property does not exist.
164
+ def findSemanticProperty(name)
165
+ begin
166
+ index = @semanticPropertiesNameIndex.fetch(name)
167
+ return @semanticProperties.at(index)
168
+ rescue
169
+ return nil
170
+ end
171
+ end
172
+
173
+ end
@@ -0,0 +1,63 @@
1
+ # Copyright © 2023 Maxime Lecoq, <maxime@lecoqlibre.fr>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4
+ # and associated documentation files (the “Software”), to deal in the Software without
5
+ # restriction, including without limitation the rights to use, copy, modify, merge, publish,
6
+ # distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
7
+ # Software is furnished to do so, subject to the following conditions:
8
+ #
9
+ # The above copyright notice and this permission notice shall be included in all copies or
10
+ # substantial portions of the Software.
11
+
12
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13
+ # BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15
+ # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
16
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+
18
+ # The SemanticPropety class is designed to turn properties of
19
+ # objects into linked data.
20
+ #
21
+ # A SemanticProperty has a name and a corresponding value that
22
+ # can be fetched later (so its value would be up to date).
23
+ #
24
+ # This class is intented to be used through the SemanticObject
25
+ # class.
26
+ #
27
+ # For instance, we can tell that the name of a Person object refers
28
+ # to the linked data concept "name" from the FOAF project. The name
29
+ # of the property would be the uri of the FOAF:name property while the
30
+ # value would be the attribute reader of the name of the Person object.
31
+ #
32
+ # You should use a block to pass the value like so:
33
+ # SemanticProperty.new("http://xmlns.com/foaf/0.1/name") {self.name}
34
+ class Semantizer::SemanticProperty
35
+
36
+ # The name of the property. It generally points to an uri
37
+ # like "http://xmlns.com/foaf/0.1/name" or it is used to
38
+ # define a reserved linked data property like "@id".
39
+ #
40
+ # This should be a String.
41
+ attr_accessor :name
42
+
43
+ # The function to call when the value is requested.
44
+ #
45
+ # This should be a Proc passed as a Block.
46
+ attr_accessor :valueGetter
47
+
48
+ # @param name The name of the property, like
49
+ # "http://xmlns.com/foaf/0.1/name" or "@id" for instance.
50
+ #
51
+ # @param valueGetter A Proc used to retrieve the value of the
52
+ # property when requested.
53
+ def initialize(name, &valueGetter)
54
+ @name = name
55
+ @valueGetter = valueGetter
56
+ end
57
+
58
+ # Fetch and returns the value associated to this property.
59
+ def value
60
+ return @valueGetter.call
61
+ end
62
+
63
+ end
@@ -0,0 +1,5 @@
1
+ class Semantizer
2
+ require 'virtual_assembly/semantizer/semantic_object'
3
+ require 'virtual_assembly/semantizer/semantic_property'
4
+ require 'virtual_assembly/semantizer/hash_serializer'
5
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: virtual_assembly-semantizer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Maxime Lecoq
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-01-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A library to add linked data to your models
14
+ email: maxime@lecoqlibre.fr
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/virtual_assembly/semantizer.rb
20
+ - lib/virtual_assembly/semantizer/hash_serializer.rb
21
+ - lib/virtual_assembly/semantizer/semantic_object.rb
22
+ - lib/virtual_assembly/semantizer/semantic_property.rb
23
+ homepage: https://github.com/assemblee-virtuelle/semantizer-ruby/
24
+ licenses:
25
+ - MIT
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubygems_version: 3.3.25
43
+ signing_key:
44
+ specification_version: 4
45
+ summary: Semantizer
46
+ test_files: []