rdf-borsh 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8d3f80cf1f9a45652da775024fabd5c00d460f3d02c3ee34ed7ec355829a50f4
4
+ data.tar.gz: c631076d5c4d8a9c57e2add7c937feb492699c3a5187ea735c06200713e9a03b
5
+ SHA512:
6
+ metadata.gz: 1c45cf0db32119a5532825e288630b50d08634f72f8ef2e3c9d49719ca03aeaa2c3b52d03af4639163555ac90a17ff2f123eaaa01b1362fd28877b9c0a2dc13a
7
+ data.tar.gz: ffc8a1a577fb3f8b0f0253de890dbb93366e7af112aab10af327ff27ce38e683462b2678027d6044c5fbb7106ceffc47768f7268bb71ef863e8108a807330b6d
data/AUTHORS ADDED
@@ -0,0 +1 @@
1
+ * Arto Bendiken <arto@bendiken.net>
data/CHANGES.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## 1.0.0 - 2025-01-07
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # RDF/Borsh for Ruby
2
+
3
+ [![License](https://img.shields.io/badge/license-Public%20Domain-blue.svg)](https://unlicense.org)
4
+ [![Compatibility](https://img.shields.io/badge/ruby-3.0%2B-blue)](https://rubygems.org/gems/rdf-borsh)
5
+ [![Package](https://img.shields.io/gem/v/rdf-borsh)](https://rubygems.org/gems/rdf-borsh)
6
+
7
+ A Ruby library for encoding and decoding RDF data using the [Borsh]
8
+ binary serialization format.
9
+
10
+ [Borsh]: https://borsh.io
11
+
12
+ ## 🛠️ Prerequisites
13
+
14
+ - [Ruby](https://ruby-lang.org) 3.0+
15
+
16
+ ## ⬇️ Installation
17
+
18
+ ### Installation via RubyGems
19
+
20
+ ```bash
21
+ gem install rdf-borsh
22
+ ```
23
+
24
+ ## 👉 Examples
25
+
26
+ ### Importing the library
27
+
28
+ ```ruby
29
+ require 'rdf/borsh'
30
+ ```
31
+
32
+ ## 👨‍💻 Development
33
+
34
+ ```bash
35
+ git clone https://github.com/ruby-rdf/rdf-borsh.git
36
+ ```
37
+
38
+ - - -
39
+
40
+ [![Share on Twitter](https://img.shields.io/badge/share%20on-twitter-03A9F4?logo=twitter)](https://twitter.com/share?url=https://github.com/ruby-rdf/rdf-borsh&text=RDF%2FBorsh+for+Ruby)
41
+ [![Share on Reddit](https://img.shields.io/badge/share%20on-reddit-red?logo=reddit)](https://reddit.com/submit?url=https://github.com/ruby-rdf/rdf-borsh&title=RDF%2FBorsh+for+Ruby)
42
+ [![Share on Hacker News](https://img.shields.io/badge/share%20on-hacker%20news-orange?logo=ycombinator)](https://news.ycombinator.com/submitlink?u=https://github.com/ruby-rdf/rdf-borsh&t=RDF%2FBorsh+for+Ruby)
43
+ [![Share on Facebook](https://img.shields.io/badge/share%20on-facebook-1976D2?logo=facebook)](https://www.facebook.com/sharer/sharer.php?u=https://github.com/ruby-rdf/rdf-borsh)
data/UNLICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org/>
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,21 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require 'rdf/format'
4
+
5
+ module RDF::Borsh
6
+ class Format < RDF::Format
7
+ content_type 'application/x-rdf+borsh', extension: :borsh
8
+ reader { RDF::Borsh::Reader }
9
+ writer { RDF::Borsh::Writer }
10
+
11
+ MAGIC = 'RDFB'.freeze
12
+ VERSION = '1'.ord
13
+ FLAGS = 0b00000111
14
+
15
+ def self.name; "RDF/Borsh"; end
16
+
17
+ def self.detect(sample)
18
+ sample[0..4] == [MAGIC, VERSION].pack('a4C')
19
+ end
20
+ end # Format
21
+ end # RDF::Borsh
@@ -0,0 +1,90 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require 'extlz4'
4
+ require 'rdf'
5
+ require 'stringio'
6
+
7
+ module RDF::Borsh
8
+ class Reader < RDF::Reader
9
+ format RDF::Borsh::Format
10
+
11
+ MAGIC = RDF::Borsh::Format::MAGIC
12
+ VERSION = RDF::Borsh::Format::VERSION
13
+ FLAGS = RDF::Borsh::Format::FLAGS
14
+
15
+ def initialize(input = $stdin, **options, &block)
16
+ super(input, **options) do
17
+ input = @input
18
+ @version, @flags, @quad_count = self.read_header
19
+
20
+ input_size = input.read(4).unpack('V').first
21
+ @input = StringIO.new(self.decompress(input.read(input_size)), 'rb')
22
+ @terms = [nil] + self.read_terms
23
+
24
+ input_size = input.read(4).unpack('V').first
25
+ @input = StringIO.new(self.decompress(input.read(input_size)), 'rb')
26
+ _ = @input.read(4).unpack('V').first
27
+
28
+ if block_given?
29
+ case block.arity
30
+ when 0 then self.instance_eval(&block)
31
+ else block.call(self)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def read_statement
38
+ quad_data = @input.read(8) or raise EOFError
39
+ g, s, p, o = quad_data.unpack('v4').map! { |term_id| @terms[term_id] }
40
+ RDF::Statement.new(s, p, o, graph_name: g)
41
+ end
42
+
43
+ def read_quad; self.read_statement.to_quad; end
44
+ def read_triple; self.read_statement.to_triple; end
45
+
46
+ ##
47
+ # Reads the compressed terms dictionary.
48
+ def read_terms
49
+ term_count = @input.read(4).unpack('V').first
50
+ term_count.times.map do
51
+ term_kind, term_string_size = @input.read(5).unpack('CV')
52
+ term_string = @input.read(term_string_size)
53
+
54
+ case term_kind
55
+ when 1 then RDF::URI(term_string)
56
+ when 2 then RDF::Node(term_string)
57
+ when 3 then RDF::Literal(term_string)
58
+ when 4
59
+ term_datatype_size = @input.read(4).unpack('V')
60
+ RDF::Literal(term_string, datatype: @input.read(term_datatype_size))
61
+ when 5
62
+ term_language_size = @input.read(4).unpack('V')
63
+ RDF::Literal(term_string, language: @input.read(term_language_size))
64
+ else
65
+ raise RDF::ReaderError, "unknown RDF/Borsh term type: #{term_kind}"
66
+ end
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Reads the uncompressed header.
72
+ def read_header
73
+ magic = @input.read(4).unpack('a4').first
74
+ raise RDF::ReaderError, "invalid RDF/Borsh header: #{magic.inspect}" if magic != MAGIC
75
+
76
+ version = @input.read(1).unpack('C').first
77
+ raise RDF::ReaderError, "invalid RDF/Borsh version: #{version}" if version != VERSION
78
+
79
+ flags = @input.read(1).unpack('C').first
80
+ raise RDF::ReaderError, "invalid RDF/Borsh flags: #{flags}" if flags != FLAGS
81
+
82
+ quad_count = @input.read(4).unpack('V').first
83
+ [version, flags, quad_count]
84
+ end
85
+
86
+ def decompress(data)
87
+ LZ4::BlockDecoder.new.decode(data)
88
+ end
89
+ end # Reader
90
+ end # RDF::Borsh
@@ -0,0 +1 @@
1
+ # This is free and unencumbered software released into the public domain.
@@ -0,0 +1,123 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require 'extlz4'
4
+ require 'rdf'
5
+ require 'sorted_set'
6
+ require 'stringio'
7
+
8
+ module RDF::Borsh
9
+ class Writer < RDF::Writer
10
+ format RDF::Borsh::Format
11
+
12
+ MAGIC = RDF::Borsh::Format::MAGIC
13
+ VERSION = RDF::Borsh::Format::VERSION
14
+ FLAGS = RDF::Borsh::Format::FLAGS
15
+ LZ4HC_CLEVEL_MAX = 12
16
+
17
+ def initialize(output = $stdout, **options, &block)
18
+ @terms_dict, @terms_map = [], {}
19
+ @quads_set = SortedSet.new
20
+
21
+ super(output, **options) do
22
+ if block_given?
23
+ case block.arity
24
+ when 0 then self.instance_eval(&block)
25
+ else block.call(self)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def write_triple(subject, predicate, object)
32
+ self.write_quad(subject, predicate, object, nil)
33
+ end
34
+
35
+ def write_quad(subject, predicate, object, context)
36
+ s = self.intern_term(subject)
37
+ p = self.intern_term(predicate)
38
+ o = self.intern_term(object)
39
+ g = self.intern_term(context)
40
+ @quads_set << [g, s, p, o]
41
+ end
42
+
43
+ def flush
44
+ self.finish
45
+ super
46
+ end
47
+
48
+ def finish
49
+ self.write_header
50
+ self.write_terms
51
+ self.write_quads
52
+ end
53
+
54
+ # Writes the uncompressed header.
55
+ def write_header
56
+ @output.write([MAGIC, VERSION, FLAGS].pack('a4CC'))
57
+ @output.write([@quads_set.size].pack('V'))
58
+ end
59
+
60
+ # Writes the compressed terms dictionary.
61
+ def write_terms
62
+ buffer = StringIO.open do |output|
63
+ output.binmode
64
+ output.write([@terms_dict.size].pack('V'))
65
+ @terms_dict.each do |term|
66
+ output.write(case
67
+ when term.iri?
68
+ string = term.to_s
69
+ [1, string.bytesize, string].pack('CVa*')
70
+ when term.node?
71
+ string = term.id.to_s
72
+ [2, string.bytesize, string].pack('CVa*')
73
+ when term.literal? && term.plain?
74
+ string = term.value.to_s
75
+ [3, string.bytesize, string].pack('CVa*')
76
+ when term.literal? && term.datatype?
77
+ string = term.value.to_s
78
+ datatype = term.datatype.to_s
79
+ [4, string.bytesize, string, datatype.bytesize, datatype].pack('CVa*Va*')
80
+ when term.literal? && term.language?
81
+ string = term.value.to_s
82
+ language = term.language.to_s
83
+ [5, string.bytesize, string, datatype.language, language].pack('CVa*Va*')
84
+ else
85
+ raise RDF::WriterError, "unsupported RDF/Borsh term type: #{term.inspect}"
86
+ end)
87
+ end
88
+ self.compress(output.string)
89
+ end
90
+ @output.write([buffer.size].pack('V'))
91
+ @output.write(buffer)
92
+ end
93
+
94
+ def write_quads
95
+ buffer = StringIO.open do |output|
96
+ output.binmode
97
+ output.write([@quads_set.size].pack('V'))
98
+ @quads_set.each do |quad|
99
+ output.write(quad.pack('v4'))
100
+ end
101
+ self.compress(output.string)
102
+ end
103
+ @output.write([buffer.size].pack('V'))
104
+ @output.write(buffer)
105
+ end
106
+
107
+ # @return [Integer]
108
+ def intern_term(term)
109
+ return 0 if term.nil? # for the default graph
110
+ term_id = @terms_map[term]
111
+ if !term_id
112
+ term_id = @terms_dict.size + 1
113
+ @terms_dict << term
114
+ @terms_map[term] = term_id
115
+ end
116
+ term_id
117
+ end
118
+
119
+ def compress(data)
120
+ LZ4::BlockEncoder.new(LZ4HC_CLEVEL_MAX).encode(data)
121
+ end
122
+ end # Writer
123
+ end # RDF::Borsh
data/lib/rdf/borsh.rb ADDED
@@ -0,0 +1,13 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ module RDF
4
+ ##
5
+ # RDF/Borsh.
6
+ module Borsh
7
+ autoload :Format, 'rdf/borsh/format'
8
+ autoload :Reader, 'rdf/borsh/reader'
9
+ autoload :Writer, 'rdf/borsh/writer'
10
+ end
11
+ end
12
+
13
+ require 'rdf/borsh/version'
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rdf-borsh
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Arto Bendiken
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-01-07 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: extlz4
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.3'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.3'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rdf
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.3'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.3'
40
+ - !ruby/object:Gem::Dependency
41
+ name: sorted_set
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rdf-spec
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.3'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.3'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rspec
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.12'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.12'
82
+ - !ruby/object:Gem::Dependency
83
+ name: yard
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.9'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.9'
96
+ description: A Ruby library for encoding and decoding RDF data using the Borsh binary
97
+ serialization format.
98
+ email: public-rdf-ruby@w3.org
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - AUTHORS
104
+ - CHANGES.md
105
+ - README.md
106
+ - UNLICENSE
107
+ - VERSION
108
+ - lib/rdf/borsh.rb
109
+ - lib/rdf/borsh/format.rb
110
+ - lib/rdf/borsh/reader.rb
111
+ - lib/rdf/borsh/version.rb
112
+ - lib/rdf/borsh/writer.rb
113
+ homepage: https://github.com/ruby-rdf/rdf-borsh
114
+ licenses:
115
+ - Unlicense
116
+ metadata:
117
+ bug_tracker_uri: https://github.com/ruby-rdf/rdf-borsh/issues
118
+ changelog_uri: https://github.com/ruby-rdf/rdf-borsh/blob/master/CHANGES.md
119
+ documentation_uri: https://github.com/ruby-rdf/rdf-borsh/blob/master/README.md
120
+ homepage_uri: https://github.com/ruby-rdf/rdf-borsh
121
+ source_code_uri: https://github.com/ruby-rdf/rdf-borsh
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '3.0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubygems_version: 3.6.2
137
+ specification_version: 4
138
+ summary: RDF/Borsh for Ruby
139
+ test_files: []