tomlib 0.1.0

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: 16903f85ce6caa68598bf97a4e631d2f69312a7019cb0901d668c40fafa24fb6
4
+ data.tar.gz: 8fc0cf9b86b65dc8e3a455ffdbca94151a1ca74b1252e72600edcb872338de06
5
+ SHA512:
6
+ metadata.gz: ddd0190b6aa540128cafa6fdf20bcd16b7a7e0d6c4eaa1cbb65f993708388bedea553f0deda33884b26cb93996dd7ddc4825c7bc36b2223eb21eb43fcae6b2aa
7
+ data.tar.gz: 65e1c88710a7a3f5ca65ca75026e59b64a525d5232c063359c976259ab8e7b10eac503a6aa665d7a2cbe21f7106a8573b9a3faf361b88a121c6a3af46269a744
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## [0.1.0] - 2022-08-02
2
+
3
+ Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Kamil Giszczak
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # Tomlib
2
+
3
+ Tomlib is a TOML parser and generator for Ruby. It is fast and standards-compliant by relying
4
+ on native [tomlc99](https://github.com/cktan/tomlc99) parser.
5
+
6
+ Tomlib is TOML v1.0 compliant.
7
+
8
+ ## Installation
9
+
10
+ Tomlib supports Ruby (MRI) 2.7+
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'tomlib'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ ```
21
+ $ bundle install
22
+ ```
23
+
24
+ Or install it yourself as:
25
+
26
+ ```
27
+ $ gem install tomlib
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ To parse a TOML document use:
33
+
34
+ ```ruby
35
+ require 'tomlib'
36
+
37
+ Tomlib.parse(<<~TOML)
38
+ firstName = "John"
39
+ lastName = "Doe"
40
+ hobbies = [ "Singing", "Dancing" ]
41
+
42
+ [address]
43
+ firstName = "John"
44
+ lastName = "Doe"
45
+ hobbies = [ "Singing", "Dancing" ]
46
+
47
+ [address]
48
+ city = "London"
49
+ zip = "E1 6AN"
50
+
51
+ [address.street]
52
+ name = "Oxford Street"
53
+ TOML
54
+
55
+ # =>
56
+ #
57
+ # {
58
+ # "firstName" => "John",
59
+ # "lastName" => "Doe",
60
+ # "hobbies" => ["Singing", "Dancing"],
61
+ # "address" => {
62
+ # "city"=>"London",
63
+ # "zip"=>"E1 6AN",
64
+ # "street"=>{ "name"=>"Oxford Street" }
65
+ # }
66
+ # }
67
+ ```
68
+
69
+ To generate a TOML document from Ruby Hash use:
70
+
71
+ ```ruby
72
+ require 'tomlib'
73
+
74
+ Tomlib.dump({
75
+ "firstName" => "John",
76
+ "lastName" => "Doe",
77
+ "hobbies" => ["Singing", "Dancing"],
78
+ "address" => {
79
+ "city"=>"London",
80
+ "zip"=>"E1 6AN",
81
+ "street"=>{ "name"=>"Oxford Street" }
82
+ }
83
+ })
84
+
85
+ # =>
86
+ #
87
+ # firstName = "John"
88
+ # lastName = "Doe"
89
+ # hobbies = [ "Singing", "Dancing" ]
90
+ #
91
+ # [address]
92
+ # city = "London"
93
+ # zip = "E1 6AN"
94
+ #
95
+ # [address.street]
96
+ # name = "Oxford Street"
97
+ ```
98
+
99
+ If you don't need indentation use:
100
+
101
+ ```ruby
102
+ require 'tomlib'
103
+
104
+ Tomlib.dump(hash, indent: false)
105
+
106
+ # =>
107
+ #
108
+ # firstName = "John"
109
+ # lastName = "Doe"
110
+ # hobbies = [ "Singing", "Dancing" ]
111
+ #
112
+ # [address]
113
+ # city = "London"
114
+ # zip = "E1 6AN"
115
+ #
116
+ # [address.street]
117
+ # name = "Oxford Street"
118
+ ```
119
+
120
+ ## Performance
121
+
122
+ `Tomlib` parsing is ~300x faster than `toml-rb` and ~15x faster than `Tomlrb`
123
+ for usual use case (~5KB TOML document size).
124
+
125
+ Generating TOML document is about 1.7x faster than `toml-rb`.
126
+
127
+ For full comparison take a look at
128
+ [benchmarks](https://github.com/kgiszczak/tomlib/tree/master/benchmarks)
129
+
130
+ ## Contributing
131
+
132
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kgiszczak/tomlib.
133
+
134
+ ## License
135
+
136
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mkmf'
4
+
5
+ CONFIG['warnflags'].slice!(/ -Wshorten-64-to-32/)
6
+
7
+ create_makefile('tomlib/tomlib')
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'bigdecimal'
4
+ require 'date'
5
+ require 'time'
6
+
7
+ require_relative 'error'
8
+
9
+ module Tomlib
10
+ # TOML generator
11
+ #
12
+ # @api private
13
+ class Dumper
14
+ # Indent characters
15
+ # @api private
16
+ INDENT = ' '.freeze
17
+
18
+ # Representation of Infinity in TOML
19
+ # @api private
20
+ INF_POSITIVE = 'inf'.freeze
21
+
22
+ # Representation of negative Infinity in TOML
23
+ # @api private
24
+ INF_NEGATIVE = '-inf'.freeze
25
+
26
+ # Representation of NaN in TOML
27
+ # @api private
28
+ NAN = 'nan'.freeze
29
+
30
+ # Generate TOML string from ruby Hash
31
+ #
32
+ # @param [Hash] hash
33
+ # @param [String, nil] base_key
34
+ # @param [String] indent
35
+ # @param [true, false] use_indent
36
+ #
37
+ # @return [String]
38
+ #
39
+ # @api private
40
+ def dump(hash, base_key = nil, indent = '', use_indent: true)
41
+ header = ''
42
+ footer = ''
43
+
44
+ hash.each do |key, value|
45
+ toml_key = to_toml_key(key)
46
+
47
+ if value.is_a?(Hash)
48
+ compound_key = to_toml_compound_key(base_key, toml_key)
49
+ next_indent = use_indent && base_key ? indent + INDENT : indent
50
+
51
+ footer << "\n".freeze << next_indent << '['.freeze << compound_key << "]\n".freeze
52
+ footer << dump(value, compound_key, next_indent, use_indent: use_indent)
53
+ elsif value.is_a?(Array) && value.all? { |e| e.is_a?(Hash) }
54
+ compound_key = to_toml_compound_key(base_key, toml_key)
55
+ next_indent = use_indent && base_key ? indent + INDENT : indent
56
+
57
+ value.each do |el|
58
+ footer << "\n".freeze << next_indent << '[['.freeze << compound_key << "]]\n".freeze
59
+ footer << dump(el, compound_key, next_indent, use_indent: use_indent)
60
+ end
61
+ else
62
+ header << indent << toml_key << ' = '.freeze << to_toml_value(value) << "\n".freeze
63
+ end
64
+ end
65
+
66
+ footer.gsub!(/\A\n/, ''.freeze) if header.empty?
67
+ header << footer
68
+ end
69
+
70
+ private
71
+
72
+ # Generate TOML key from Hash key
73
+ #
74
+ # @param [String] key
75
+ # @param [true, false] use_indent
76
+ #
77
+ # @return [String]
78
+ #
79
+ # @api private
80
+ def to_toml_key(key)
81
+ raise DumpError, "'nil' can't be used as a key" if key.nil?
82
+
83
+ key = key.to_s
84
+
85
+ case key_type(key)
86
+ when :quoted
87
+ key.inspect
88
+ when :escape
89
+ key.dump.gsub('\n', '\\\\\n')
90
+ else
91
+ key
92
+ end
93
+ end
94
+
95
+ # Concatenate key with base_key
96
+ #
97
+ # @param [String, nil] base_key
98
+ # @param [String] key
99
+ #
100
+ # @return [String]
101
+ #
102
+ # @api private
103
+ def to_toml_compound_key(base, key)
104
+ return key unless base
105
+
106
+ '' << base << '.'.freeze << key
107
+ end
108
+
109
+ # Generate TOML value from Ruby object
110
+ #
111
+ # @param [Object] value
112
+ #
113
+ # @return [String]
114
+ #
115
+ # @api private
116
+ def to_toml_value(value)
117
+ case value
118
+ when String
119
+ value.inspect
120
+ when Float, BigDecimal
121
+ to_toml_float(value)
122
+ when Time, DateTime
123
+ value.iso8601(3)
124
+ when Date
125
+ value.iso8601
126
+ when Hash
127
+ "{ #{value.map { |k, v| "#{to_toml_key(k)} = #{to_toml_value(v)}" }.join(', ')} }"
128
+ when Array
129
+ "[ #{value.map { |e| to_toml_value(e) }.join(', ')} ]"
130
+ when nil
131
+ '""'.freeze
132
+ else
133
+ value.to_s
134
+ end
135
+ end
136
+
137
+ # Generate TOML float value from Ruby Float or BigDecimal
138
+ #
139
+ # @param [Float, BigDecimal] value
140
+ #
141
+ # @return [String]
142
+ #
143
+ # @api private
144
+ def to_toml_float(value)
145
+ return INF_POSITIVE if value.infinite? && value.positive?
146
+ return INF_NEGATIVE if value.infinite? && value.negative?
147
+ return NAN if value.nan?
148
+
149
+ value.to_s
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: false
2
+
3
+ module Tomlib
4
+ # Error during TOML document generation
5
+ #
6
+ # @api private
7
+ class DumpError < StandardError
8
+ end
9
+ end
Binary file
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tomlib
4
+ # @api private
5
+ VERSION = '0.1.0'
6
+ end
data/lib/tomlib.rb ADDED
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'tomlib/dumper'
4
+ require_relative 'tomlib/tomlib'
5
+ require_relative 'tomlib/version'
6
+
7
+ # Main library namespace
8
+ #
9
+ # @example parsing TOML data into Ruby Hash
10
+ #
11
+ # puts Tomlib.load(<<~TOML)
12
+ # firstName = "John"
13
+ # lastName = "Doe"
14
+ # TOML
15
+ #
16
+ # # => { 'firstName' => 'John', 'lastName' => 'Doe' }
17
+ #
18
+ # @example generating TOML from Ruby Hash
19
+ #
20
+ # puts Tomlib.dump({ 'firstName' => 'John', 'lastName' => 'Doe' })
21
+ #
22
+ # # =>
23
+ # firstName = "John"
24
+ # lastName = "Doe"
25
+ #
26
+ # @api public
27
+ module Tomlib
28
+ # Dump Ruby Hash into TOML format
29
+ #
30
+ # @param [Hash] hash
31
+ # @param [true, false] indent (default: true)
32
+ #
33
+ # @return [String]
34
+ #
35
+ # @example
36
+ # puts Tomlib.dump({ 'firstName' => 'John', 'lastName' => 'Doe' })
37
+ # # =>
38
+ # firstName = "John"
39
+ # lastName = "Doe"
40
+ #
41
+ # @api public
42
+ def self.dump(hash, indent: true)
43
+ Dumper.new.dump(hash, use_indent: indent)
44
+ end
45
+ end
data/tomlib.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/tomlib/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'tomlib'
7
+ spec.version = Tomlib::VERSION
8
+ spec.authors = ['Kamil Giszczak']
9
+ spec.email = ['beerkg@gmail.com']
10
+
11
+ spec.summary = 'Fast TOML parser and generator with native extension.'
12
+ spec.description = 'Fast TOML parser and generator with native extension.'
13
+ spec.homepage = 'https://github.com/kgiszczak/tomlib'
14
+ spec.license = 'MIT'
15
+
16
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
17
+
18
+ spec.metadata['homepage_uri'] = 'https://github.com/kgiszczak/tomlib'
19
+ spec.metadata['source_code_uri'] = 'https://github.com/kgiszczak/tomlib'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/kgiszczak/tomlib/blob/master/CHANGELOG.md'
21
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/kgiszczak/tomlib/issues'
22
+
23
+ spec.files = Dir['CHANGELOG.md', 'LICENSE.txt', 'README.md', 'tomlib.gemspec', 'lib/**/*']
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.extensions = ['ext/tomlib/extconf.rb']
27
+
28
+ spec.required_ruby_version = '>= 2.7.0'
29
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tomlib
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kamil Giszczak
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-08-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Fast TOML parser and generator with native extension.
14
+ email:
15
+ - beerkg@gmail.com
16
+ executables: []
17
+ extensions:
18
+ - ext/tomlib/extconf.rb
19
+ extra_rdoc_files: []
20
+ files:
21
+ - CHANGELOG.md
22
+ - LICENSE.txt
23
+ - README.md
24
+ - ext/tomlib/extconf.rb
25
+ - lib/tomlib.rb
26
+ - lib/tomlib/dumper.rb
27
+ - lib/tomlib/error.rb
28
+ - lib/tomlib/tomlib.bundle
29
+ - lib/tomlib/version.rb
30
+ - tomlib.gemspec
31
+ homepage: https://github.com/kgiszczak/tomlib
32
+ licenses:
33
+ - MIT
34
+ metadata:
35
+ allowed_push_host: https://rubygems.org
36
+ homepage_uri: https://github.com/kgiszczak/tomlib
37
+ source_code_uri: https://github.com/kgiszczak/tomlib
38
+ changelog_uri: https://github.com/kgiszczak/tomlib/blob/master/CHANGELOG.md
39
+ bug_tracker_uri: https://github.com/kgiszczak/tomlib/issues
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 2.7.0
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubygems_version: 3.3.7
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: Fast TOML parser and generator with native extension.
59
+ test_files: []