serialbench 0.1.1 → 0.1.3

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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/benchmark.yml +273 -220
  3. data/.github/workflows/rake.yml +26 -0
  4. data/.github/workflows/windows-debug.yml +171 -0
  5. data/.gitignore +32 -0
  6. data/.rubocop.yml +1 -0
  7. data/.rubocop_todo.yml +274 -0
  8. data/Gemfile +14 -1
  9. data/README.adoc +292 -1118
  10. data/Rakefile +0 -55
  11. data/config/benchmarks/full.yml +29 -0
  12. data/config/benchmarks/short.yml +26 -0
  13. data/config/environments/asdf-ruby-3.2.yml +8 -0
  14. data/config/environments/asdf-ruby-3.3.yml +8 -0
  15. data/config/environments/docker-ruby-3.0.yml +9 -0
  16. data/config/environments/docker-ruby-3.1.yml +9 -0
  17. data/config/environments/docker-ruby-3.2.yml +9 -0
  18. data/config/environments/docker-ruby-3.3.yml +9 -0
  19. data/config/environments/docker-ruby-3.4.yml +9 -0
  20. data/data/schemas/result.yml +29 -0
  21. data/docker/Dockerfile.alpine +33 -0
  22. data/docker/{Dockerfile.benchmark → Dockerfile.ubuntu} +4 -3
  23. data/docker/README.md +2 -2
  24. data/docs/PLATFORM_VALIDATION_FIX.md +79 -0
  25. data/docs/SYCK_YAML_FIX.md +91 -0
  26. data/docs/WEBSITE_COMPLETION_PLAN.md +440 -0
  27. data/docs/WINDOWS_LIBXML_FIX.md +136 -0
  28. data/docs/WINDOWS_SETUP.md +122 -0
  29. data/exe/serialbench +1 -1
  30. data/lib/serialbench/benchmark_runner.rb +261 -423
  31. data/lib/serialbench/cli/base_cli.rb +51 -0
  32. data/lib/serialbench/cli/benchmark_cli.rb +453 -0
  33. data/lib/serialbench/cli/environment_cli.rb +181 -0
  34. data/lib/serialbench/cli/resultset_cli.rb +261 -0
  35. data/lib/serialbench/cli/ruby_build_cli.rb +225 -0
  36. data/lib/serialbench/cli/validate_cli.rb +88 -0
  37. data/lib/serialbench/cli.rb +61 -600
  38. data/lib/serialbench/config_manager.rb +129 -0
  39. data/lib/serialbench/models/benchmark_config.rb +75 -0
  40. data/lib/serialbench/models/benchmark_result.rb +81 -0
  41. data/lib/serialbench/models/environment_config.rb +72 -0
  42. data/lib/serialbench/models/platform.rb +111 -0
  43. data/lib/serialbench/models/result.rb +80 -0
  44. data/lib/serialbench/models/result_set.rb +79 -0
  45. data/lib/serialbench/models/result_store.rb +108 -0
  46. data/lib/serialbench/models.rb +54 -0
  47. data/lib/serialbench/ruby_build_manager.rb +149 -0
  48. data/lib/serialbench/runners/asdf_runner.rb +296 -0
  49. data/lib/serialbench/runners/base.rb +32 -0
  50. data/lib/serialbench/runners/docker_runner.rb +140 -0
  51. data/lib/serialbench/runners/local_runner.rb +71 -0
  52. data/lib/serialbench/serializers/base_serializer.rb +9 -17
  53. data/lib/serialbench/serializers/json/base_json_serializer.rb +4 -4
  54. data/lib/serialbench/serializers/json/json_serializer.rb +0 -2
  55. data/lib/serialbench/serializers/json/oj_serializer.rb +0 -2
  56. data/lib/serialbench/serializers/json/rapidjson_serializer.rb +1 -1
  57. data/lib/serialbench/serializers/json/yajl_serializer.rb +0 -2
  58. data/lib/serialbench/serializers/toml/base_toml_serializer.rb +5 -5
  59. data/lib/serialbench/serializers/toml/toml_rb_serializer.rb +1 -3
  60. data/lib/serialbench/serializers/toml/tomlib_serializer.rb +1 -3
  61. data/lib/serialbench/serializers/toml/tomlrb_serializer.rb +56 -0
  62. data/lib/serialbench/serializers/xml/base_xml_serializer.rb +4 -9
  63. data/lib/serialbench/serializers/xml/libxml_serializer.rb +4 -10
  64. data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +2 -4
  65. data/lib/serialbench/serializers/xml/oga_serializer.rb +4 -10
  66. data/lib/serialbench/serializers/xml/ox_serializer.rb +2 -4
  67. data/lib/serialbench/serializers/xml/rexml_serializer.rb +3 -5
  68. data/lib/serialbench/serializers/yaml/base_yaml_serializer.rb +5 -1
  69. data/lib/serialbench/serializers/yaml/psych_serializer.rb +1 -1
  70. data/lib/serialbench/serializers/yaml/syck_serializer.rb +60 -23
  71. data/lib/serialbench/serializers.rb +23 -6
  72. data/lib/serialbench/site_generator.rb +283 -0
  73. data/lib/serialbench/templates/assets/css/benchmark_report.css +535 -0
  74. data/lib/serialbench/templates/assets/css/format_based.css +474 -0
  75. data/lib/serialbench/templates/assets/css/themes.css +589 -0
  76. data/lib/serialbench/templates/assets/js/chart_helpers.js +411 -0
  77. data/lib/serialbench/templates/assets/js/dashboard.js +795 -0
  78. data/lib/serialbench/templates/assets/js/navigation.js +142 -0
  79. data/lib/serialbench/templates/base.liquid +49 -0
  80. data/lib/serialbench/templates/format_based.liquid +507 -0
  81. data/lib/serialbench/templates/partials/chart_section.liquid +4 -0
  82. data/lib/serialbench/version.rb +1 -1
  83. data/lib/serialbench/yaml_validator.rb +36 -0
  84. data/lib/serialbench.rb +2 -31
  85. data/serialbench.gemspec +15 -3
  86. metadata +106 -25
  87. data/.github/workflows/ci.yml +0 -74
  88. data/.github/workflows/docker.yml +0 -246
  89. data/config/ci.yml +0 -22
  90. data/config/full.yml +0 -30
  91. data/docker/run-benchmarks.sh +0 -356
  92. data/lib/serialbench/chart_generator.rb +0 -821
  93. data/lib/serialbench/result_formatter.rb +0 -182
  94. data/lib/serialbench/result_merger.rb +0 -1201
  95. data/lib/serialbench/serializers/xml/base_parser.rb +0 -69
  96. data/lib/serialbench/serializers/xml/libxml_parser.rb +0 -98
  97. data/lib/serialbench/serializers/xml/nokogiri_parser.rb +0 -111
  98. data/lib/serialbench/serializers/xml/oga_parser.rb +0 -85
  99. data/lib/serialbench/serializers/xml/ox_parser.rb +0 -64
  100. data/lib/serialbench/serializers/xml/rexml_parser.rb +0 -129
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'json'
5
+ require_relative '../ruby_build_manager'
6
+ require_relative 'base'
7
+
8
+ module Serialbench
9
+ module Runners
10
+ # Handles Docker-based benchmark execution
11
+ class DockerRunner < Base
12
+ class DockerError < StandardError; end
13
+
14
+ def initialize(environment_config, environment_config_path)
15
+ super
16
+
17
+ @docker_image = @environment_config.docker&.image
18
+ raise 'docker.image is required' unless @docker_image
19
+
20
+ # Handle dockerfile path relative to environment file
21
+ dockerfile_path = @environment_config.docker&.dockerfile
22
+ raise 'docker.dockerfile path is required' unless dockerfile_path
23
+
24
+ @dockerfile = Pathname.new(environment_config_path).dirname.join(dockerfile_path).to_s
25
+ raise "path '#{@dockerfile}' specified in docker.dockerfile is not found" unless File.exist?(@dockerfile)
26
+
27
+ validate_docker_available
28
+ end
29
+
30
+ # Build Docker image for this environment
31
+ def prepare
32
+ puts "🐳 Preparing Docker image for #{@name}..."
33
+
34
+ puts " 🐍 Using Docker image: #{base_image_string}"
35
+ puts " 🔨 Building Docker image: #{docker_image_string}"
36
+
37
+ cmd = [
38
+ 'docker', 'build',
39
+ '--build-arg', "BASE_IMAGE=#{base_image_string}",
40
+ '-t', docker_image_string,
41
+ '-f', @dockerfile,
42
+ '.'
43
+ ]
44
+
45
+ # Show command being run
46
+ puts " 🔧 Running command: #{cmd.join(' ')}"
47
+ success = system(*cmd)
48
+
49
+ raise DockerError, "Failed to build Docker image '#{docker_image_string}'" unless success
50
+
51
+ puts "✅ Docker image prepared successfully for #{docker_image_string}"
52
+ end
53
+
54
+ def base_image_string
55
+ @environment_config.docker.image
56
+ end
57
+
58
+ def docker_image_string
59
+ "serialbench:#{@environment_config.ruby_build_tag}"
60
+ end
61
+
62
+ # Run benchmark for this environment
63
+ def run_benchmark(benchmark_config, benchmark_config_path, result_dir)
64
+ puts "🚀 Running benchmark at #{@environment_config_path}..."
65
+
66
+ FileUtils.mkdir_p(result_dir)
67
+
68
+ # Build image if not already built
69
+ prepare unless image_exists?
70
+
71
+ # Run the benchmark
72
+ run_benchmark_in_container(benchmark_config, benchmark_config_path, result_dir)
73
+
74
+ puts "✅ Benchmark completed for #{@environment_config_path}"
75
+ end
76
+
77
+ private
78
+
79
+ # Validate Docker is available
80
+ def validate_docker_available
81
+ raise DockerError, 'Docker is not installed or not available in PATH' unless system('docker --version > /dev/null 2>&1')
82
+
83
+ return if system('docker info > /dev/null 2>&1')
84
+
85
+ raise DockerError, 'Docker daemon is not running'
86
+ end
87
+
88
+ # Check if Docker image exists
89
+ def image_exists?
90
+ image_name = "serialbench:#{@name}"
91
+ system("docker image inspect #{image_name} > /dev/null 2>&1")
92
+ end
93
+
94
+ # Run benchmark in container
95
+ def run_benchmark_in_container(_benchmark_config, benchmark_config_path, result_dir)
96
+ puts '🏃 Running benchmark in Docker container...'
97
+ puts " 📁 Results will be saved to: #{result_dir}"
98
+ puts " 🐳 Using Docker image: #{docker_image_string}"
99
+
100
+ benchmark_log = File.join(result_dir, 'benchmark.log')
101
+
102
+ cmd = [
103
+ 'docker', 'run', '--rm',
104
+ '-v', "#{File.expand_path(result_dir)}:/app/results",
105
+ '-v', "#{File.expand_path(@environment_config_path)}:/app/environment.yml",
106
+ '-v', "#{File.expand_path(benchmark_config_path)}:/app/benchmark_config.yml",
107
+ # TODO: do not hard code this path in the docker image
108
+ '-v', "#{RubyBuildManager::CACHE_FILE}:/root/.serialbench/ruby-build-definitions.yaml",
109
+ docker_image_string,
110
+ 'benchmark',
111
+ '_docker_execute',
112
+ '--result_dir=/app/results',
113
+ '/app/environment.yml',
114
+ '/app/benchmark_config.yml'
115
+ ]
116
+
117
+ puts " 🔧 Running command: #{cmd.join(' ')}"
118
+ puts " 📝 Benchmark output will be logged to: #{benchmark_log}"
119
+ puts ' ⏳ This may take several minutes...'
120
+
121
+ success = system("#{cmd.join(' ')} > #{benchmark_log} 2>&1")
122
+ puts " ✅ Command executed with status: #{success ? 'success' : 'failure'}"
123
+ puts " 📊 Checking if results saved to: #{File.join(result_dir, 'results.yaml')}"
124
+
125
+ if success && File.exist?(File.join(result_dir, 'results.yaml'))
126
+ puts '✅ Benchmark completed successfully'
127
+ puts " 📊 Results saved to: #{File.join(result_dir, 'results.yaml')}"
128
+ else
129
+ puts "❌ Benchmark failed (see #{benchmark_log})"
130
+ puts " 🔍 Check log file for details: #{benchmark_log}"
131
+ if File.exist?(benchmark_log)
132
+ puts ' 📄 Last few lines of log:'
133
+ system("tail -10 #{benchmark_log} | sed 's/^/ /'")
134
+ end
135
+ raise DockerError, 'Benchmark execution failed'
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require_relative 'base'
5
+ require_relative '../benchmark_runner'
6
+ require_relative '../models/result'
7
+ require_relative '../models/platform'
8
+
9
+ module Serialbench
10
+ module Runners
11
+ # Handles local benchmark execution using the current Ruby environment
12
+ class LocalRunner < Base
13
+ def prepare
14
+ # For local environments, no preparation is needed
15
+ # The current Ruby environment is already set up
16
+ puts "✅ Local environment ready (using current Ruby: #{RUBY_VERSION})"
17
+ end
18
+
19
+ def run_benchmark(benchmark_config, benchmark_config_path, result_dir)
20
+ puts "🏠 Running benchmark locally with Ruby #{RUBY_VERSION}..."
21
+ puts " 📁 Results will be saved to: #{result_dir}"
22
+
23
+ FileUtils.mkdir_p(result_dir)
24
+
25
+ # Run the benchmark
26
+ runner = Serialbench::BenchmarkRunner.new(
27
+ environment_config: @environment_config,
28
+ benchmark_config: benchmark_config
29
+ )
30
+
31
+ results = runner.run_all_benchmarks
32
+
33
+ # Get platform information with correct Ruby version from environment config
34
+ platform = Serialbench::Models::Platform.current_local(
35
+ ruby_version: @environment_config.ruby_build_tag
36
+ )
37
+
38
+ # Create metadata
39
+ metadata = Models::RunMetadata.new(
40
+ benchmark_config_path: benchmark_config_path,
41
+ environment_config_path: @environment_config_path,
42
+ tags: [
43
+ 'local',
44
+ platform.os,
45
+ platform.arch,
46
+ "ruby-#{@environment_config.ruby_build_tag}"
47
+ ]
48
+ )
49
+
50
+ # Save results
51
+ results_model = Models::Result.new(
52
+ platform: platform,
53
+ metadata: metadata,
54
+ environment_config: @environment_config,
55
+ benchmark_config: benchmark_config,
56
+ benchmark_result: results
57
+ )
58
+
59
+ # Restore YAML to use Psych for output, otherwise lutaml-model's to_yaml
60
+ # will have no output (Syck gem overrides YAML constant)
61
+ Object.const_set(:YAML, Psych)
62
+
63
+ results_file = File.join(result_dir, 'results.yaml')
64
+ results_model.to_file(results_file)
65
+
66
+ puts "✅ Benchmark completed successfully"
67
+ puts " 📊 Results saved to: #{results_file}"
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,26 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'singleton'
4
+
3
5
  module Serialbench
4
6
  module Serializers
5
7
  class BaseSerializer
8
+ include Singleton
9
+
6
10
  def initialize
7
11
  # Override in subclasses
8
12
  end
9
13
 
10
- def available?
11
- raise NotImplementedError, 'Subclasses must implement #available?'
12
- end
13
-
14
- def name
15
- raise NotImplementedError, 'Subclasses must implement #name'
16
- end
17
-
18
- def version
19
- raise NotImplementedError, 'Subclasses must implement #version'
20
- end
21
-
22
- def format
23
- raise NotImplementedError, 'Subclasses must implement #format'
14
+ %w[name version format library_require_name available?].each do |method_name|
15
+ define_method(method_name) do
16
+ self.class.send(method_name)
17
+ end
24
18
  end
25
19
 
26
20
  def parse(data)
@@ -31,7 +25,7 @@ module Serialbench
31
25
  raise NotImplementedError, 'Subclasses must implement #generate'
32
26
  end
33
27
 
34
- def stream_parse(data, &block)
28
+ def stream_parse(data)
35
29
  # Default implementation falls back to regular parsing
36
30
  # Override in subclasses that support streaming
37
31
  result = parse(data)
@@ -44,8 +38,6 @@ module Serialbench
44
38
  false
45
39
  end
46
40
 
47
- protected
48
-
49
41
  def require_library(library_name)
50
42
  require library_name
51
43
  true
@@ -6,7 +6,7 @@ module Serialbench
6
6
  module Serializers
7
7
  module Json
8
8
  class BaseJsonSerializer < BaseSerializer
9
- def format
9
+ def self.format
10
10
  :json
11
11
  end
12
12
 
@@ -29,7 +29,9 @@ module Serialbench
29
29
  }
30
30
  end
31
31
 
32
- protected
32
+ def supports_generation?
33
+ true
34
+ end
33
35
 
34
36
  def supports_pretty_print?
35
37
  true
@@ -48,8 +50,6 @@ module Serialbench
48
50
  raise NotImplementedError, 'Subclasses must implement #library_require_name'
49
51
  end
50
52
 
51
- public
52
-
53
53
  # Check if the JSON library is available
54
54
  def available?
55
55
  return @available if defined?(@available)
@@ -39,8 +39,6 @@ module Serialbench
39
39
  false
40
40
  end
41
41
 
42
- protected
43
-
44
42
  def supports_pretty_print?
45
43
  true
46
44
  end
@@ -53,8 +53,6 @@ module Serialbench
53
53
  false
54
54
  end
55
55
 
56
- protected
57
-
58
56
  def supports_pretty_print?
59
57
  true
60
58
  end
@@ -27,7 +27,7 @@ module Serialbench
27
27
  RapidJSON.parse(json_string)
28
28
  end
29
29
 
30
- def generate(object, options = {})
30
+ def generate(object, _options = {})
31
31
  require 'rapidjson'
32
32
  RapidJSON.dump(object)
33
33
  end
@@ -60,8 +60,6 @@ module Serialbench
60
60
  end
61
61
  end
62
62
 
63
- protected
64
-
65
63
  def library_require_name
66
64
  'yajl'
67
65
  end
@@ -6,7 +6,7 @@ module Serialbench
6
6
  module Serializers
7
7
  module Toml
8
8
  class BaseTomlSerializer < BaseSerializer
9
- def format
9
+ def self.format
10
10
  :toml
11
11
  end
12
12
 
@@ -29,13 +29,15 @@ module Serialbench
29
29
  }
30
30
  end
31
31
 
32
+ def supports_generation?
33
+ true
34
+ end
35
+
32
36
  def supports_streaming?
33
37
  # TOML is typically not streamed due to its structure
34
38
  false
35
39
  end
36
40
 
37
- protected
38
-
39
41
  def supports_comments?
40
42
  false
41
43
  end
@@ -57,8 +59,6 @@ module Serialbench
57
59
  raise NotImplementedError, 'Subclasses must implement #library_require_name'
58
60
  end
59
61
 
60
- public
61
-
62
62
  # Check if the TOML library is available
63
63
  def available?
64
64
  return @available if defined?(@available)
@@ -27,13 +27,11 @@ module Serialbench
27
27
  TomlRB.parse(toml_string)
28
28
  end
29
29
 
30
- def generate(object, options = {})
30
+ def generate(object, _options = {})
31
31
  require 'toml-rb'
32
32
  TomlRB.dump(object)
33
33
  end
34
34
 
35
- protected
36
-
37
35
  def supports_comments?
38
36
  false
39
37
  end
@@ -24,7 +24,7 @@ module Serialbench
24
24
  # TOML doesn't typically support streaming parsing
25
25
  # Parse the entire document and yield it
26
26
  result = parse(toml_string)
27
- block&.call(result) if block
27
+ block&.call(result)
28
28
  1 # Return 1 document processed
29
29
  end
30
30
 
@@ -39,8 +39,6 @@ module Serialbench
39
39
  Tomlib::VERSION
40
40
  end
41
41
 
42
- protected
43
-
44
42
  def library_require_name
45
43
  'tomlib'
46
44
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_toml_serializer'
4
+
5
+ module Serialbench
6
+ module Serializers
7
+ module Toml
8
+ class TomlrbSerializer < BaseTomlSerializer
9
+ def available?
10
+ require_library('tomlrb')
11
+ end
12
+
13
+ def name
14
+ 'tomlrb'
15
+ end
16
+
17
+ def version
18
+ require 'tomlrb'
19
+ # tomlrb doesn't expose a VERSION constant, so we'll use gem version
20
+ Gem.loaded_specs['tomlrb']&.version&.to_s || 'unknown'
21
+ rescue LoadError, NameError
22
+ 'unknown'
23
+ end
24
+
25
+ def parse(toml_string)
26
+ require 'tomlrb'
27
+ Tomlrb.parse(toml_string)
28
+ end
29
+
30
+ def generate(object, options = {})
31
+ raise NotImplementedError, 'tomlrb gem does not support TOML generation/dumping'
32
+ end
33
+
34
+ def supports_generation?
35
+ false
36
+ end
37
+
38
+ def supports_comments?
39
+ false
40
+ end
41
+
42
+ def supports_arrays_of_tables?
43
+ true
44
+ end
45
+
46
+ def supports_inline_tables?
47
+ true
48
+ end
49
+
50
+ def supports_multiline_strings?
51
+ true
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -6,7 +6,7 @@ module Serialbench
6
6
  module Serializers
7
7
  module Xml
8
8
  class BaseXmlSerializer < BaseSerializer
9
- def format
9
+ def self.format
10
10
  :xml
11
11
  end
12
12
 
@@ -33,7 +33,9 @@ module Serialbench
33
33
  }
34
34
  end
35
35
 
36
- protected
36
+ def supports_generation?
37
+ true
38
+ end
37
39
 
38
40
  def supports_xpath?
39
41
  false
@@ -47,13 +49,6 @@ module Serialbench
47
49
  false
48
50
  end
49
51
 
50
- # Subclasses should override this to specify their library name
51
- def library_require_name
52
- raise NotImplementedError, 'Subclasses must implement #library_require_name'
53
- end
54
-
55
- public
56
-
57
52
  # Check if the XML library is available
58
53
  def available?
59
54
  return @available if defined?(@available)
@@ -49,8 +49,6 @@ module Serialbench
49
49
  LibXML::XML::VERSION
50
50
  end
51
51
 
52
- protected
53
-
54
52
  def library_require_name
55
53
  'libxml'
56
54
  end
@@ -60,26 +58,22 @@ module Serialbench
60
58
  def build_xml_from_data(data, name = 'root')
61
59
  require 'libxml'
62
60
 
61
+ element = LibXML::XML::Node.new(name.to_s)
63
62
  case data
64
63
  when Hash
65
- element = LibXML::XML::Node.new(name.to_s)
66
64
  data.each do |key, value|
67
65
  child = build_xml_from_data(value, key.to_s)
68
66
  element << child
69
67
  end
70
- element
71
68
  when Array
72
- element = LibXML::XML::Node.new(name.to_s)
73
69
  data.each_with_index do |item, index|
74
70
  child = build_xml_from_data(item, "item_#{index}")
75
71
  element << child
76
72
  end
77
- element
78
73
  else
79
- element = LibXML::XML::Node.new(name.to_s)
80
74
  element.content = data.to_s
81
- element
82
75
  end
76
+ element
83
77
  end
84
78
 
85
79
  # SAX handler for streaming
@@ -102,10 +96,10 @@ module Serialbench
102
96
  @element_stack.push(@current_element)
103
97
  end
104
98
 
105
- def on_end_element(element)
99
+ def on_end_element(_element)
106
100
  element_data = @element_stack.pop
107
101
  if @element_stack.empty?
108
- @block&.call(element_data) if @block
102
+ @block&.call(element_data)
109
103
  else
110
104
  @element_stack.last[:children] << element_data
111
105
  end
@@ -49,8 +49,6 @@ module Serialbench
49
49
  Nokogiri::VERSION
50
50
  end
51
51
 
52
- protected
53
-
54
52
  def library_require_name
55
53
  'nokogiri'
56
54
  end
@@ -111,10 +109,10 @@ module Serialbench
111
109
  @element_stack.push(@current_element)
112
110
  end
113
111
 
114
- def end_element(name)
112
+ def end_element(_name)
115
113
  element = @element_stack.pop
116
114
  if @element_stack.empty?
117
- @block&.call(element) if @block
115
+ @block&.call(element)
118
116
  else
119
117
  @element_stack.last[:children] << element
120
118
  end
@@ -49,8 +49,6 @@ module Serialbench
49
49
  Oga::VERSION
50
50
  end
51
51
 
52
- protected
53
-
54
52
  def library_require_name
55
53
  'oga'
56
54
  end
@@ -60,27 +58,23 @@ module Serialbench
60
58
  def build_xml_from_data(data, name = 'root')
61
59
  require 'oga'
62
60
 
61
+ element = Oga::XML::Element.new(name: name)
63
62
  case data
64
63
  when Hash
65
- element = Oga::XML::Element.new(name: name)
66
64
  data.each do |key, value|
67
65
  child = build_xml_from_data(value, key.to_s)
68
66
  element.children << child
69
67
  end
70
- element
71
68
  when Array
72
- element = Oga::XML::Element.new(name: name)
73
69
  data.each_with_index do |item, index|
74
70
  child = build_xml_from_data(item, "item_#{index}")
75
71
  element.children << child
76
72
  end
77
- element
78
73
  else
79
- element = Oga::XML::Element.new(name: name)
80
74
  text_node = Oga::XML::Text.new(text: data.to_s)
81
75
  element.children << text_node
82
- element
83
76
  end
77
+ element
84
78
  end
85
79
 
86
80
  # SAX handler for streaming
@@ -110,10 +104,10 @@ module Serialbench
110
104
  @element_stack.last[:text] += text if @element_stack.any?
111
105
  end
112
106
 
113
- def after_element(namespace, name)
107
+ def after_element(_namespace, _name)
114
108
  element = @element_stack.pop
115
109
  if @element_stack.empty?
116
- @block&.call(element) if @block
110
+ @block&.call(element)
117
111
  else
118
112
  @element_stack.last[:children] << element
119
113
  end
@@ -40,8 +40,6 @@ module Serialbench
40
40
  Ox::VERSION
41
41
  end
42
42
 
43
- protected
44
-
45
43
  def library_require_name
46
44
  'ox'
47
45
  end
@@ -63,10 +61,10 @@ module Serialbench
63
61
  @element_stack.push(@current_element)
64
62
  end
65
63
 
66
- def end_element(name)
64
+ def end_element(_name)
67
65
  element = @element_stack.pop
68
66
  if @element_stack.empty?
69
- @block&.call(element) if @block
67
+ @block&.call(element)
70
68
  else
71
69
  @element_stack.last[:children] << element
72
70
  end
@@ -41,7 +41,7 @@ module Serialbench
41
41
 
42
42
  indent = options.fetch(:indent, 0)
43
43
  output = String.new
44
- if indent > 0
44
+ if indent.positive?
45
45
  document.write(output, indent)
46
46
  else
47
47
  document.write(output)
@@ -77,8 +77,6 @@ module Serialbench
77
77
  false
78
78
  end
79
79
 
80
- protected
81
-
82
80
  def supports_xpath?
83
81
  true
84
82
  end
@@ -122,7 +120,7 @@ module Serialbench
122
120
  @result = nil
123
121
  end
124
122
 
125
- def start_element(uri, localname, qname, attributes)
123
+ def start_element(_uri, _localname, qname, attributes)
126
124
  @elements_processed += 1
127
125
  @block&.call(:start_element, { name: qname, attributes: attributes })
128
126
  end
@@ -134,7 +132,7 @@ module Serialbench
134
132
  @block&.call(:text, text)
135
133
  end
136
134
 
137
- def end_element(uri, localname, qname)
135
+ def end_element(_uri, _localname, qname)
138
136
  @block&.call(:end_element, { name: qname })
139
137
  end
140
138
  end