serialbench 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 +7 -0
- data/.github/workflows/benchmark.yml +125 -0
- data/.github/workflows/ci.yml +74 -0
- data/.rspec +4 -0
- data/Gemfile +34 -0
- data/README.adoc +592 -0
- data/Rakefile +63 -0
- data/exe/serialbench +6 -0
- data/lib/serialbench/benchmark_runner.rb +540 -0
- data/lib/serialbench/chart_generator.rb +821 -0
- data/lib/serialbench/cli.rb +438 -0
- data/lib/serialbench/memory_profiler.rb +31 -0
- data/lib/serialbench/result_formatter.rb +182 -0
- data/lib/serialbench/result_merger.rb +1201 -0
- data/lib/serialbench/serializers/base_serializer.rb +63 -0
- data/lib/serialbench/serializers/json/base_json_serializer.rb +67 -0
- data/lib/serialbench/serializers/json/json_serializer.rb +58 -0
- data/lib/serialbench/serializers/json/oj_serializer.rb +102 -0
- data/lib/serialbench/serializers/json/yajl_serializer.rb +67 -0
- data/lib/serialbench/serializers/toml/base_toml_serializer.rb +76 -0
- data/lib/serialbench/serializers/toml/toml_rb_serializer.rb +55 -0
- data/lib/serialbench/serializers/toml/tomlib_serializer.rb +50 -0
- data/lib/serialbench/serializers/xml/base_parser.rb +69 -0
- data/lib/serialbench/serializers/xml/base_xml_serializer.rb +71 -0
- data/lib/serialbench/serializers/xml/libxml_parser.rb +98 -0
- data/lib/serialbench/serializers/xml/libxml_serializer.rb +127 -0
- data/lib/serialbench/serializers/xml/nokogiri_parser.rb +111 -0
- data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +118 -0
- data/lib/serialbench/serializers/xml/oga_parser.rb +85 -0
- data/lib/serialbench/serializers/xml/oga_serializer.rb +125 -0
- data/lib/serialbench/serializers/xml/ox_parser.rb +64 -0
- data/lib/serialbench/serializers/xml/ox_serializer.rb +88 -0
- data/lib/serialbench/serializers/xml/rexml_parser.rb +129 -0
- data/lib/serialbench/serializers/xml/rexml_serializer.rb +121 -0
- data/lib/serialbench/serializers.rb +62 -0
- data/lib/serialbench/version.rb +5 -0
- data/lib/serialbench.rb +42 -0
- data/serialbench.gemspec +51 -0
- metadata +239 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_parser'
|
4
|
+
|
5
|
+
module Serialbench
|
6
|
+
module Parsers
|
7
|
+
class OxParser < BaseParser
|
8
|
+
def parse_dom(xml_string)
|
9
|
+
require 'ox'
|
10
|
+
Ox.parse(xml_string)
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_sax(xml_string, handler = nil)
|
14
|
+
require 'ox'
|
15
|
+
require 'stringio'
|
16
|
+
handler ||= OxSaxHandler.new
|
17
|
+
Ox.sax_parse(handler, StringIO.new(xml_string))
|
18
|
+
handler
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate_xml(document, options = {})
|
22
|
+
require 'ox'
|
23
|
+
indent = options.fetch(:indent, 0)
|
24
|
+
Ox.dump(document, indent: indent)
|
25
|
+
end
|
26
|
+
|
27
|
+
def supports_streaming?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
# SAX handler for Ox
|
32
|
+
class OxSaxHandler < (defined?(::Ox) ? ::Ox::Sax : Object)
|
33
|
+
attr_reader :elements_processed, :text_nodes_processed
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@elements_processed = 0
|
37
|
+
@text_nodes_processed = 0
|
38
|
+
end
|
39
|
+
|
40
|
+
def start_element(name)
|
41
|
+
@elements_processed += 1
|
42
|
+
end
|
43
|
+
|
44
|
+
def end_element(name)
|
45
|
+
# Process end element
|
46
|
+
end
|
47
|
+
|
48
|
+
def text(value)
|
49
|
+
@text_nodes_processed += 1 unless value.strip.empty?
|
50
|
+
end
|
51
|
+
|
52
|
+
def attr(name, value)
|
53
|
+
# Process attribute
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def library_require_name
|
60
|
+
'ox'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_xml_serializer'
|
4
|
+
|
5
|
+
module Serialbench
|
6
|
+
module Serializers
|
7
|
+
module Xml
|
8
|
+
class OxSerializer < BaseXmlSerializer
|
9
|
+
def name
|
10
|
+
'ox'
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(xml_string)
|
14
|
+
require 'ox'
|
15
|
+
Ox.parse(xml_string)
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate(data)
|
19
|
+
require 'ox'
|
20
|
+
Ox.dump(data, indent: 2)
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_streaming(xml_string, &block)
|
24
|
+
require 'ox'
|
25
|
+
require 'stringio'
|
26
|
+
|
27
|
+
handler = StreamingHandler.new(&block)
|
28
|
+
Ox.sax_parse(handler, StringIO.new(xml_string))
|
29
|
+
handler.elements_processed
|
30
|
+
end
|
31
|
+
|
32
|
+
def supports_streaming?
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def version
|
37
|
+
return 'unknown' unless available?
|
38
|
+
|
39
|
+
require 'ox'
|
40
|
+
Ox::VERSION
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def library_require_name
|
46
|
+
'ox'
|
47
|
+
end
|
48
|
+
|
49
|
+
# SAX handler for streaming
|
50
|
+
class StreamingHandler < (defined?(::Ox) ? ::Ox::Sax : Object)
|
51
|
+
attr_reader :elements_processed
|
52
|
+
|
53
|
+
def initialize(&block)
|
54
|
+
@block = block
|
55
|
+
@elements_processed = 0
|
56
|
+
@current_element = nil
|
57
|
+
@element_stack = []
|
58
|
+
end
|
59
|
+
|
60
|
+
def start_element(name)
|
61
|
+
@elements_processed += 1
|
62
|
+
@current_element = { name: name, attributes: {}, children: [], text: '' }
|
63
|
+
@element_stack.push(@current_element)
|
64
|
+
end
|
65
|
+
|
66
|
+
def end_element(name)
|
67
|
+
element = @element_stack.pop
|
68
|
+
if @element_stack.empty?
|
69
|
+
@block&.call(element) if @block
|
70
|
+
else
|
71
|
+
@element_stack.last[:children] << element
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def text(value)
|
76
|
+
return if value.strip.empty?
|
77
|
+
|
78
|
+
@element_stack.last[:text] += value if @element_stack.any?
|
79
|
+
end
|
80
|
+
|
81
|
+
def attr(name, value)
|
82
|
+
@element_stack.last[:attributes][name] = value if @element_stack.any?
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_parser'
|
4
|
+
|
5
|
+
module Serialbench
|
6
|
+
module Parsers
|
7
|
+
class RexmlParser < BaseParser
|
8
|
+
def parse_dom(xml_string)
|
9
|
+
require 'rexml/document'
|
10
|
+
REXML::Document.new(xml_string)
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_sax(xml_string, handler = nil)
|
14
|
+
require 'rexml/parsers/sax2parser'
|
15
|
+
handler ||= DefaultSaxHandler.new
|
16
|
+
parser = REXML::Parsers::SAX2Parser.new(xml_string)
|
17
|
+
parser.listen(handler)
|
18
|
+
parser.parse
|
19
|
+
handler
|
20
|
+
rescue LoadError
|
21
|
+
# Fallback if SAX2 is not available
|
22
|
+
require 'rexml/document'
|
23
|
+
doc = REXML::Document.new(xml_string)
|
24
|
+
handler ||= DefaultSaxHandler.new
|
25
|
+
# Simulate SAX events by walking the document
|
26
|
+
doc.root.each_recursive do |element|
|
27
|
+
if element.is_a?(REXML::Element)
|
28
|
+
handler.start_element(nil, element.name, element.name, element.attributes)
|
29
|
+
handler.end_element(nil, element.name, element.name)
|
30
|
+
elsif element.is_a?(REXML::Text)
|
31
|
+
handler.characters(element.to_s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
handler
|
35
|
+
end
|
36
|
+
|
37
|
+
def generate_xml(document, options = {})
|
38
|
+
require 'rexml/document'
|
39
|
+
indent = options.fetch(:indent, 0)
|
40
|
+
output = String.new
|
41
|
+
if indent > 0
|
42
|
+
document.write(output, indent)
|
43
|
+
else
|
44
|
+
document.write(output)
|
45
|
+
end
|
46
|
+
output
|
47
|
+
end
|
48
|
+
|
49
|
+
def supports_streaming?
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
def library_require_name
|
56
|
+
'rexml/document'
|
57
|
+
end
|
58
|
+
|
59
|
+
def detect_version
|
60
|
+
require 'rexml/rexml'
|
61
|
+
REXML::VERSION
|
62
|
+
rescue LoadError, NameError
|
63
|
+
'built-in'
|
64
|
+
end
|
65
|
+
|
66
|
+
def supports_xpath?
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
def supports_namespaces?
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def supports_validation?
|
75
|
+
false
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Default SAX handler for REXML - only define if REXML SAX is available
|
80
|
+
begin
|
81
|
+
require 'rexml/sax2listener'
|
82
|
+
|
83
|
+
class DefaultSaxHandler
|
84
|
+
include ::REXML::SAX2Listener
|
85
|
+
|
86
|
+
attr_reader :elements_processed, :text_nodes_processed
|
87
|
+
|
88
|
+
def initialize
|
89
|
+
@elements_processed = 0
|
90
|
+
@text_nodes_processed = 0
|
91
|
+
end
|
92
|
+
|
93
|
+
def start_element(uri, localname, qname, attributes)
|
94
|
+
@elements_processed += 1
|
95
|
+
end
|
96
|
+
|
97
|
+
def characters(text)
|
98
|
+
@text_nodes_processed += 1 unless text.strip.empty?
|
99
|
+
end
|
100
|
+
|
101
|
+
def end_element(uri, localname, qname)
|
102
|
+
# Element processing complete
|
103
|
+
end
|
104
|
+
end
|
105
|
+
rescue LoadError
|
106
|
+
# SAX2Listener not available, define a simple handler
|
107
|
+
class DefaultSaxHandler
|
108
|
+
attr_reader :elements_processed, :text_nodes_processed
|
109
|
+
|
110
|
+
def initialize
|
111
|
+
@elements_processed = 0
|
112
|
+
@text_nodes_processed = 0
|
113
|
+
end
|
114
|
+
|
115
|
+
def start_element(uri, localname, qname, attributes)
|
116
|
+
@elements_processed += 1
|
117
|
+
end
|
118
|
+
|
119
|
+
def characters(text)
|
120
|
+
@text_nodes_processed += 1 unless text.strip.empty?
|
121
|
+
end
|
122
|
+
|
123
|
+
def end_element(uri, localname, qname)
|
124
|
+
# Element processing complete
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_xml_serializer'
|
4
|
+
|
5
|
+
module Serialbench
|
6
|
+
module Serializers
|
7
|
+
module Xml
|
8
|
+
class RexmlSerializer < BaseXmlSerializer
|
9
|
+
def available?
|
10
|
+
require_library('rexml/document')
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
'rexml'
|
15
|
+
end
|
16
|
+
|
17
|
+
def version
|
18
|
+
require 'rexml/rexml'
|
19
|
+
REXML::VERSION
|
20
|
+
rescue LoadError, NameError
|
21
|
+
'built-in'
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse(xml_string)
|
25
|
+
require 'rexml/document'
|
26
|
+
REXML::Document.new(xml_string)
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate(document, options = {})
|
30
|
+
require 'rexml/document'
|
31
|
+
indent = options.fetch(:indent, 0)
|
32
|
+
output = String.new
|
33
|
+
if indent > 0
|
34
|
+
document.write(output, indent)
|
35
|
+
else
|
36
|
+
document.write(output)
|
37
|
+
end
|
38
|
+
output
|
39
|
+
end
|
40
|
+
|
41
|
+
def stream_parse(xml_string, &block)
|
42
|
+
require 'rexml/parsers/sax2parser'
|
43
|
+
handler = SaxHandler.new(&block)
|
44
|
+
parser = REXML::Parsers::SAX2Parser.new(xml_string)
|
45
|
+
parser.listen(handler)
|
46
|
+
parser.parse
|
47
|
+
handler.result
|
48
|
+
rescue LoadError
|
49
|
+
# Fallback if SAX2 is not available
|
50
|
+
require 'rexml/document'
|
51
|
+
doc = REXML::Document.new(xml_string)
|
52
|
+
handler = SaxHandler.new(&block)
|
53
|
+
# Simulate SAX events by walking the document
|
54
|
+
doc.root.each_recursive do |element|
|
55
|
+
if element.is_a?(REXML::Element)
|
56
|
+
handler.start_element(nil, element.name, element.name, element.attributes)
|
57
|
+
handler.end_element(nil, element.name, element.name)
|
58
|
+
elsif element.is_a?(REXML::Text)
|
59
|
+
handler.characters(element.to_s)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
handler.result
|
63
|
+
end
|
64
|
+
|
65
|
+
def supports_streaming?
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
def supports_xpath?
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
def supports_namespaces?
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
def supports_validation?
|
80
|
+
false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# SAX handler for REXML streaming
|
85
|
+
class SaxHandler
|
86
|
+
attr_reader :result, :elements_processed, :text_nodes_processed
|
87
|
+
|
88
|
+
def initialize(&block)
|
89
|
+
@block = block
|
90
|
+
@elements_processed = 0
|
91
|
+
@text_nodes_processed = 0
|
92
|
+
@result = nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def start_element(uri, localname, qname, attributes)
|
96
|
+
@elements_processed += 1
|
97
|
+
@block&.call(:start_element, { name: qname, attributes: attributes })
|
98
|
+
end
|
99
|
+
|
100
|
+
def characters(text)
|
101
|
+
return if text.strip.empty?
|
102
|
+
|
103
|
+
@text_nodes_processed += 1
|
104
|
+
@block&.call(:text, text)
|
105
|
+
end
|
106
|
+
|
107
|
+
def end_element(uri, localname, qname)
|
108
|
+
@block&.call(:end_element, { name: qname })
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Include SAX2Listener if available
|
113
|
+
begin
|
114
|
+
require 'rexml/sax2listener'
|
115
|
+
SaxHandler.include(::REXML::SAX2Listener)
|
116
|
+
rescue LoadError
|
117
|
+
# SAX2Listener not available, handler works without it
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'serializers/base_serializer'
|
4
|
+
|
5
|
+
# XML Serializers
|
6
|
+
require_relative 'serializers/xml/base_xml_serializer'
|
7
|
+
require_relative 'serializers/xml/rexml_serializer'
|
8
|
+
require_relative 'serializers/xml/ox_serializer'
|
9
|
+
require_relative 'serializers/xml/nokogiri_serializer'
|
10
|
+
require_relative 'serializers/xml/oga_serializer'
|
11
|
+
require_relative 'serializers/xml/libxml_serializer'
|
12
|
+
|
13
|
+
# JSON Serializers
|
14
|
+
require_relative 'serializers/json/base_json_serializer'
|
15
|
+
require_relative 'serializers/json/json_serializer'
|
16
|
+
require_relative 'serializers/json/oj_serializer'
|
17
|
+
require_relative 'serializers/json/yajl_serializer'
|
18
|
+
|
19
|
+
# TOML Serializers
|
20
|
+
require_relative 'serializers/toml/base_toml_serializer'
|
21
|
+
require_relative 'serializers/toml/toml_rb_serializer'
|
22
|
+
require_relative 'serializers/toml/tomlib_serializer'
|
23
|
+
|
24
|
+
module Serialbench
|
25
|
+
module Serializers
|
26
|
+
# Registry of all available serializers
|
27
|
+
SERIALIZERS = {
|
28
|
+
xml: [
|
29
|
+
Xml::RexmlSerializer,
|
30
|
+
Xml::OxSerializer,
|
31
|
+
Xml::NokogiriSerializer,
|
32
|
+
Xml::OgaSerializer,
|
33
|
+
Xml::LibxmlSerializer
|
34
|
+
],
|
35
|
+
json: [
|
36
|
+
Json::JsonSerializer,
|
37
|
+
Json::OjSerializer,
|
38
|
+
Json::YajlSerializer
|
39
|
+
],
|
40
|
+
toml: [
|
41
|
+
Toml::TomlRbSerializer,
|
42
|
+
Toml::TomlibSerializer
|
43
|
+
]
|
44
|
+
}.freeze
|
45
|
+
|
46
|
+
def self.all
|
47
|
+
SERIALIZERS.values.flatten
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.for_format(format)
|
51
|
+
SERIALIZERS[format.to_sym] || []
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.available_for_format(format)
|
55
|
+
for_format(format).select { |serializer_class| serializer_class.new.available? }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.available
|
59
|
+
all.select { |serializer_class| serializer_class.new.available? }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/serialbench.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'serialbench/version'
|
4
|
+
require_relative 'serialbench/serializers'
|
5
|
+
require_relative 'serialbench/benchmark_runner'
|
6
|
+
require_relative 'serialbench/result_merger'
|
7
|
+
require_relative 'serialbench/cli'
|
8
|
+
require_relative 'serialbench/result_formatter'
|
9
|
+
require_relative 'serialbench/chart_generator'
|
10
|
+
require_relative 'serialbench/memory_profiler'
|
11
|
+
|
12
|
+
module Serialbench
|
13
|
+
class Error < StandardError; end
|
14
|
+
|
15
|
+
# Supported serialization formats
|
16
|
+
FORMATS = %i[xml json toml].freeze
|
17
|
+
|
18
|
+
def self.run_benchmarks(formats: FORMATS, options: {})
|
19
|
+
runner = BenchmarkRunner.new(formats: formats, **options)
|
20
|
+
runner.run_all_benchmarks
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.available_serializers(format = nil)
|
24
|
+
runner = BenchmarkRunner.new
|
25
|
+
if format
|
26
|
+
runner.serializers_for_format(format)
|
27
|
+
else
|
28
|
+
runner.all_serializers
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.generate_reports(results)
|
33
|
+
result_merger = Serialbench::ResultMerger.new
|
34
|
+
result_merger.generate_all_reports(results)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.generate_reports_from_data(data_file)
|
38
|
+
require 'json'
|
39
|
+
data = JSON.parse(File.read(data_file), symbolize_names: true)
|
40
|
+
generate_reports(data)
|
41
|
+
end
|
42
|
+
end
|
data/serialbench.gemspec
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/serialbench/version'
|
4
|
+
|
5
|
+
all_files_in_git = Dir.chdir(File.expand_path(__dir__)) do
|
6
|
+
`git ls-files -z`.split("\x0")
|
7
|
+
end
|
8
|
+
|
9
|
+
Gem::Specification.new do |spec|
|
10
|
+
spec.name = 'serialbench'
|
11
|
+
spec.version = Serialbench::VERSION
|
12
|
+
spec.authors = ['Ribose']
|
13
|
+
spec.email = ['open.source@ribose.com']
|
14
|
+
|
15
|
+
spec.summary = 'Comprehensive serialization benchmarking tool for Ruby'
|
16
|
+
spec.description = 'A benchmarking suite for comparing performance of various serialization libraries in Ruby, including XML, JSON, and TOML parsers/generators.'
|
17
|
+
spec.homepage = 'https://github.com/metanorma/serialbench'
|
18
|
+
spec.license = 'BSD-2-Clause'
|
19
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
|
20
|
+
|
21
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
22
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
23
|
+
spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"
|
24
|
+
|
25
|
+
# Specify which files should be added to the gem when it is released.
|
26
|
+
spec.files = all_files_in_git
|
27
|
+
.reject { |f| f.match(%r{\A(?:spec|features|bin|\.)/}) }
|
28
|
+
|
29
|
+
spec.bindir = 'exe'
|
30
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ['lib']
|
32
|
+
|
33
|
+
# Runtime dependencies
|
34
|
+
spec.add_dependency 'benchmark-ips', '~> 2.10'
|
35
|
+
spec.add_dependency 'memory_profiler', '~> 1.0'
|
36
|
+
spec.add_dependency 'thor', '~> 1.2'
|
37
|
+
|
38
|
+
# XML serializers (optional)
|
39
|
+
spec.add_dependency 'libxml-ruby', '~> 4.0'
|
40
|
+
spec.add_dependency 'nokogiri', '~> 1.15'
|
41
|
+
spec.add_dependency 'oga', '~> 3.4'
|
42
|
+
spec.add_dependency 'ox', '~> 2.14'
|
43
|
+
|
44
|
+
# JSON serializers (optional)
|
45
|
+
spec.add_dependency 'oj', '~> 3.13'
|
46
|
+
spec.add_dependency 'yajl-ruby', '~> 1.4'
|
47
|
+
|
48
|
+
# TOML serializers (optional)
|
49
|
+
spec.add_dependency 'tomlib', '~> 0.6'
|
50
|
+
spec.add_dependency 'toml-rb', '~> 2.2'
|
51
|
+
end
|