serialbench 0.2.0 → 0.4.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.github/scripts/push-to-data.sh +65 -0
  3. data/.github/workflows/benchmark.yml +98 -172
  4. data/.github/workflows/release.yml +68 -13
  5. data/Gemfile +1 -1
  6. data/config/benchmarks/full-json.yml +25 -0
  7. data/config/benchmarks/full-toml.yml +25 -0
  8. data/config/benchmarks/full-xml.yml +26 -0
  9. data/config/benchmarks/full-yaml.yml +25 -0
  10. data/config/benchmarks/full.yml +9 -4
  11. data/lib/serialbench/benchmark_runner.rb +32 -320
  12. data/lib/serialbench/cli/benchmark_cli.rb +1 -1
  13. data/lib/serialbench/cli.rb +0 -12
  14. data/lib/serialbench/models/benchmark_result.rb +2 -0
  15. data/lib/serialbench/models/result_store.rb +0 -38
  16. data/lib/serialbench/models.rb +0 -5
  17. data/lib/serialbench/serializers/base_serializer.rb +11 -3
  18. data/lib/serialbench/serializers/json/base_json_serializer.rb +8 -20
  19. data/lib/serialbench/serializers/json/json_serializer.rb +0 -16
  20. data/lib/serialbench/serializers/json/oj_serializer.rb +2 -17
  21. data/lib/serialbench/serializers/json/yajl_serializer.rb +2 -2
  22. data/lib/serialbench/serializers/toml/base_toml_serializer.rb +8 -29
  23. data/lib/serialbench/serializers/toml/toml_rb_serializer.rb +0 -16
  24. data/lib/serialbench/serializers/toml/tomlib_serializer.rb +0 -4
  25. data/lib/serialbench/serializers/toml/tomlrb_serializer.rb +2 -18
  26. data/lib/serialbench/serializers/xml/base_xml_serializer.rb +10 -26
  27. data/lib/serialbench/serializers/xml/leptris_serializer.rb +13 -10
  28. data/lib/serialbench/serializers/xml/libxml_serializer.rb +4 -9
  29. data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +4 -9
  30. data/lib/serialbench/serializers/xml/oga_serializer.rb +6 -4
  31. data/lib/serialbench/serializers/xml/ox_serializer.rb +2 -2
  32. data/lib/serialbench/serializers/xml/rexml_serializer.rb +5 -12
  33. data/lib/serialbench/serializers/yaml/base_yaml_serializer.rb +1 -9
  34. data/lib/serialbench/serializers/yaml/syck_serializer.rb +0 -8
  35. data/lib/serialbench/test_data.rb +315 -0
  36. data/lib/serialbench/version.rb +1 -1
  37. data/lib/serialbench.rb +2 -1
  38. data/serialbench.gemspec +1 -2
  39. metadata +13 -59
  40. data/lib/serialbench/cli/resultset_cli.rb +0 -301
  41. data/lib/serialbench/models/result_set.rb +0 -79
  42. data/lib/serialbench/site_generator.rb +0 -337
  43. data/lib/serialbench/templates/assets/css/benchmark_report.css +0 -535
  44. data/lib/serialbench/templates/assets/css/format_based.css +0 -474
  45. data/lib/serialbench/templates/assets/css/themes.css +0 -589
  46. data/lib/serialbench/templates/assets/js/chart_helpers.js +0 -411
  47. data/lib/serialbench/templates/assets/js/dashboard.js +0 -795
  48. data/lib/serialbench/templates/assets/js/navigation.js +0 -142
  49. data/lib/serialbench/templates/base.liquid +0 -49
  50. data/lib/serialbench/templates/format_based.liquid +0 -507
  51. data/lib/serialbench/templates/partials/chart_section.liquid +0 -4
  52. data/site/.gitignore +0 -5
  53. data/site/README.md +0 -32
  54. data/site/astro.config.mjs +0 -12
  55. data/site/package-lock.json +0 -6160
  56. data/site/package.json +0 -22
  57. data/site/public/favicon.svg +0 -4
  58. data/site/scripts/gen-sample-data.mjs +0 -154
  59. data/site/src/components/AvailabilityMatrix.astro +0 -61
  60. data/site/src/components/CalibratedLeaderboard.vue +0 -134
  61. data/site/src/components/CitationBox.vue +0 -50
  62. data/site/src/components/DashboardConsole.vue +0 -193
  63. data/site/src/components/FeaturesTable.astro +0 -97
  64. data/site/src/components/MemoryPanel.vue +0 -44
  65. data/site/src/components/OpsChart.vue +0 -135
  66. data/site/src/config.ts +0 -18
  67. data/site/src/layouts/Layout.astro +0 -85
  68. data/site/src/lib/channels.ts +0 -24
  69. data/site/src/lib/dashboard.ts +0 -269
  70. data/site/src/pages/index.astro +0 -44
  71. data/site/src/pages/library/[slug].astro +0 -128
  72. data/site/src/pages/methodology.astro +0 -55
  73. data/site/src/styles/global.css +0 -103
  74. data/site/tsconfig.json +0 -5
@@ -15,15 +15,20 @@ formats:
15
15
  - yaml
16
16
  - toml
17
17
 
18
+ # Trimmed from 20/5/2 (warmup 3): a healthy leg took ~70 minutes at that
19
+ # setting, which both inflates weekly cost and leaves legs exposed to
20
+ # runner-eviction flakiness. 10/3/1 with warmup 2 halves runtime with
21
+ # acceptable added noise.
18
22
  iterations:
19
- small: 20
20
- medium: 5
21
- large: 2
23
+ small: 10
24
+ medium: 3
25
+ large: 1
22
26
 
23
27
  operations:
24
28
  - parse
25
29
  - generate
26
30
  - streaming
31
+ - xpath
27
32
  - memory
28
33
 
29
- warmup: 3
34
+ warmup: 2
@@ -24,6 +24,19 @@ module Serialbench
24
24
  load_test_data
25
25
  end
26
26
 
27
+ # Each operation maps to a lambda. Adding an operation = one entry.
28
+ OPERATIONS = {
29
+ 'parsing' => ->(s, data) { s.parse(data) },
30
+ 'generation' => ->(s, data) { s.generate(s.parse(data)) },
31
+ 'xpath' => lambda { |s, data|
32
+ doc = s.parse(data)
33
+ s.xpath_query(doc, '//book')
34
+ s.xpath_query(doc, "//book[@id='101']")
35
+ s.xpath_query(doc, '//book[price > 30]/title')
36
+ },
37
+ 'streaming' => ->(s, data) { s.stream_parse(data) { |_event, _data| } },
38
+ }.freeze
39
+
27
40
  def run_all_benchmarks
28
41
  puts 'Serialbench - Running comprehensive serialization performance tests'
29
42
  puts '=' * 70
@@ -32,34 +45,18 @@ module Serialbench
32
45
  puts "Test data sizes: #{@test_data.keys.join(', ')}"
33
46
  puts
34
47
 
48
+ results = {}
49
+ OPERATIONS.each do |name, handler|
50
+ results[name.to_sym] = run_benchmark_type(name, name, &handler)
51
+ end
52
+ results[:memory] = run_memory_benchmarks
53
+
35
54
  Models::BenchmarkResult.new(
36
55
  serializers: Serializers.information,
37
- parsing: run_parsing_benchmarks,
38
- generation: run_generation_benchmarks,
39
- memory: run_memory_benchmarks,
40
- streaming: run_streaming_benchmarks
56
+ **results
41
57
  )
42
58
  end
43
59
 
44
- def run_parsing_benchmarks
45
- run_benchmark_type('parsing', 'parse') do |serializer, data|
46
- serializer.parse(data)
47
- end
48
- end
49
-
50
- def run_generation_benchmarks
51
- run_benchmark_type('generation', 'generation') do |serializer, data|
52
- document = serializer.parse(data)
53
- serializer.generate(document)
54
- end
55
- end
56
-
57
- def run_streaming_benchmarks
58
- run_benchmark_type('streaming', 'stream parse') do |serializer, data|
59
- serializer.stream_parse(data) { |event, data| }
60
- end
61
- end
62
-
63
60
  def run_memory_benchmarks
64
61
  puts "\nRunning memory usage benchmarks..."
65
62
  return [] unless defined?(::MemoryProfiler)
@@ -148,313 +145,28 @@ module Serialbench
148
145
 
149
146
  case type_name
150
147
  when 'generation'
151
- serializers.select(&:supports_generation?)
148
+ serializers.select { |s| s.supports?(:generate) }
152
149
  when 'streaming'
153
- serializers.select(&:supports_streaming?)
150
+ serializers.select { |s| s.supports?(:sax) || s.supports?(:streaming) }
151
+ when 'xpath'
152
+ serializers.select { |s| s.supports?(:xpath) }
154
153
  else
155
154
  serializers
156
155
  end
157
156
  end
158
157
 
159
158
  def get_iterations_for_size(size)
160
- @benchmark_config.iterations.send(size.to_s)
161
- end
162
-
163
- def load_test_data
164
- # Determine which data sizes to load based on configuration
165
- data_sizes = @benchmark_config.data_sizes
166
-
167
- # Initialize test data structure
168
- @test_data = {}
169
- data_sizes.each { |size| @test_data[size] = {} }
170
-
171
- # Generate data for each format and size
172
- @benchmark_config.formats.each do |format|
173
- data_sizes.each do |size|
174
- @test_data[size][format] = generate_test_data(format, size)
175
- end
176
- end
177
-
178
- # Try to load real test files if they exist
179
- data_sizes.each do |size|
180
- @benchmark_config.formats.each do |format|
181
- file_path = "test_data/#{size}.#{format}"
182
- @test_data[size][format] = File.read(file_path) if File.exist?(file_path)
183
- end
159
+ iterations = @benchmark_config.iterations
160
+ case size.to_s
161
+ when 'small' then iterations.small
162
+ when 'medium' then iterations.medium
163
+ when 'large' then iterations.large
164
+ else raise ArgumentError, "no iteration count configured for #{size}"
184
165
  end
185
166
  end
186
167
 
187
- def generate_test_data(format, size)
188
- method_name = "generate_#{size}_#{format}"
189
- send(method_name)
190
- end
191
-
192
- # Shared data structure generators
193
- def small_test_data_structure
194
- {
195
- config: {
196
- database: {
197
- host: 'localhost',
198
- port: 5432,
199
- name: 'myapp',
200
- user: 'admin',
201
- password: 'secret'
202
- },
203
- cache: {
204
- enabled: true,
205
- ttl: 3600
206
- }
207
- }
208
- }
209
- end
210
-
211
- def medium_test_data_structure
212
- {
213
- users: (1..1000).map do |i|
214
- {
215
- id: i,
216
- name: "User #{i}",
217
- email: "user#{i}@example.com",
218
- created_at: "2023-01-#{(i % 28) + 1}T10:00:00Z",
219
- profile: {
220
- age: 20 + (i % 50),
221
- city: "City #{i % 100}",
222
- preferences: {
223
- theme: i.even? ? 'dark' : 'light',
224
- notifications: (i % 3).zero?
225
- }
226
- }
227
- }
228
- end
229
- }
230
- end
231
-
232
- def large_test_data_structure
233
- {
234
- dataset: {
235
- header: {
236
- created: '2023-01-01T00:00:00Z',
237
- count: 10_000,
238
- format: 'data'
239
- },
240
- records: (1..10_000).map do |i|
241
- {
242
- id: i,
243
- timestamp: "2023-01-01T#{format('%02d', i % 24)}:#{format('%02d', i % 60)}:#{format('%02d', i % 60)}Z",
244
- data: {
245
- field1: "Value #{i}",
246
- field2: i * 2,
247
- field3: (i % 100).zero? ? 'special' : 'normal',
248
- nested: [
249
- "Item #{i}-1",
250
- "Item #{i}-2",
251
- "Item #{i}-3"
252
- ]
253
- },
254
- metadata: {
255
- source: 'generator',
256
- version: '1.0',
257
- checksum: i.to_s(16)
258
- }
259
- }
260
- end
261
- }
262
- }
263
- end
264
-
265
- # XML test data generators
266
- def generate_small_xml
267
- data = small_test_data_structure
268
- <<~XML
269
- <?xml version="1.0" encoding="UTF-8"?>
270
- <config>
271
- <database>
272
- <host>#{data[:config][:database][:host]}</host>
273
- <port>#{data[:config][:database][:port]}</port>
274
- <name>#{data[:config][:database][:name]}</name>
275
- <user>#{data[:config][:database][:user]}</user>
276
- <password>#{data[:config][:database][:password]}</password>
277
- </database>
278
- <cache>
279
- <enabled>#{data[:config][:cache][:enabled]}</enabled>
280
- <ttl>#{data[:config][:cache][:ttl]}</ttl>
281
- </cache>
282
- </config>
283
- XML
284
- end
285
-
286
- def generate_medium_xml
287
- data = medium_test_data_structure
288
- users = data[:users].map do |user|
289
- <<~USER
290
- <user id="#{user[:id]}">
291
- <name>#{user[:name]}</name>
292
- <email>#{user[:email]}</email>
293
- <created_at>#{user[:created_at]}</created_at>
294
- <profile>
295
- <age>#{user[:profile][:age]}</age>
296
- <city>#{user[:profile][:city]}</city>
297
- <preferences>
298
- <theme>#{user[:profile][:preferences][:theme]}</theme>
299
- <notifications>#{user[:profile][:preferences][:notifications]}</notifications>
300
- </preferences>
301
- </profile>
302
- </user>
303
- USER
304
- end.join
305
-
306
- <<~XML
307
- <?xml version="1.0" encoding="UTF-8"?>
308
- <users>
309
- #{users}
310
- </users>
311
- XML
312
- end
313
-
314
- def generate_large_xml
315
- data = large_test_data_structure
316
- records = data[:dataset][:records].map do |record|
317
- nested_items = record[:data][:nested].map { |item| " <item>#{item}</item>" }.join("\n")
318
- <<~RECORD
319
- <record id="#{record[:id]}">
320
- <timestamp>#{record[:timestamp]}</timestamp>
321
- <data>
322
- <field1>#{record[:data][:field1]}</field1>
323
- <field2>#{record[:data][:field2]}</field2>
324
- <field3>#{record[:data][:field3]}</field3>
325
- <nested>
326
- #{nested_items}
327
- </nested>
328
- </data>
329
- <metadata>
330
- <source>#{record[:metadata][:source]}</source>
331
- <version>#{record[:metadata][:version]}</version>
332
- <checksum>#{record[:metadata][:checksum]}</checksum>
333
- </metadata>
334
- </record>
335
- RECORD
336
- end.join
337
-
338
- <<~XML
339
- <?xml version="1.0" encoding="UTF-8"?>
340
- <dataset>
341
- <header>
342
- <created>#{data[:dataset][:header][:created]}</created>
343
- <count>#{data[:dataset][:header][:count]}</count>
344
- <format>xml</format>
345
- </header>
346
- <records>
347
- #{records}
348
- </records>
349
- </dataset>
350
- XML
351
- end
352
-
353
- # JSON test data generators
354
- def generate_small_json
355
- JSON.generate(small_test_data_structure)
356
- end
357
-
358
- def generate_medium_json
359
- JSON.generate(medium_test_data_structure)
360
- end
361
-
362
- def generate_large_json
363
- data = large_test_data_structure
364
- data[:dataset][:header][:format] = 'json'
365
- JSON.generate(data)
366
- end
367
-
368
- # YAML test data generators
369
- def generate_small_yaml
370
- small_test_data_structure.to_yaml
371
- end
372
-
373
- def generate_medium_yaml
374
- medium_test_data_structure.to_yaml
375
- end
376
-
377
- def generate_large_yaml
378
- data = large_test_data_structure
379
- data[:dataset][:header][:format] = 'yaml'
380
- data.to_yaml
381
- end
382
-
383
- # TOML test data generators
384
- def generate_small_toml
385
- data = small_test_data_structure
386
- <<~TOML
387
- [config]
388
-
389
- [config.database]
390
- host = "#{data[:config][:database][:host]}"
391
- port = #{data[:config][:database][:port]}
392
- name = "#{data[:config][:database][:name]}"
393
- user = "#{data[:config][:database][:user]}"
394
- password = "#{data[:config][:database][:password]}"
395
-
396
- [config.cache]
397
- enabled = #{data[:config][:cache][:enabled]}
398
- ttl = #{data[:config][:cache][:ttl]}
399
- TOML
400
- end
401
-
402
- def generate_medium_toml
403
- data = medium_test_data_structure
404
- # Use smaller dataset for TOML due to verbosity
405
- users = data[:users].first(100)
406
- users.map do |user|
407
- <<~USER
408
- [[users]]
409
- id = #{user[:id]}
410
- name = "#{user[:name]}"
411
- email = "#{user[:email]}"
412
- created_at = "#{user[:created_at]}"
413
-
414
- [users.profile]
415
- age = #{user[:profile][:age]}
416
- city = "#{user[:profile][:city]}"
417
-
418
- [users.profile.preferences]
419
- theme = "#{user[:profile][:preferences][:theme]}"
420
- notifications = #{user[:profile][:preferences][:notifications]}
421
- USER
422
- end.join("\n")
423
- end
424
-
425
- def generate_large_toml
426
- data = large_test_data_structure
427
- # Use smaller dataset for TOML due to verbosity
428
- records = data[:dataset][:records].first(1000)
429
- records_toml = records.map do |record|
430
- <<~RECORD
431
- [[dataset.records]]
432
- id = #{record[:id]}
433
- timestamp = "#{record[:timestamp]}"
434
-
435
- [dataset.records.data]
436
- field1 = "#{record[:data][:field1]}"
437
- field2 = #{record[:data][:field2]}
438
- field3 = "#{record[:data][:field3]}"
439
- nested = #{record[:data][:nested].inspect}
440
-
441
- [dataset.records.metadata]
442
- source = "#{record[:metadata][:source]}"
443
- version = "#{record[:metadata][:version]}"
444
- checksum = "#{record[:metadata][:checksum]}"
445
- RECORD
446
- end.join("\n")
447
-
448
- <<~TOML
449
- [dataset]
450
-
451
- [dataset.header]
452
- created = "#{data[:dataset][:header][:created]}"
453
- count = #{records.length}
454
- format = "toml"
455
-
456
- #{records_toml}
457
- TOML
168
+ def load_test_data
169
+ @test_data = TestData.load(@benchmark_config)
458
170
  end
459
171
  end
460
172
  end
@@ -190,7 +190,7 @@ module Serialbench
190
190
  say "🏗️ Generating HTML site for result: #{result_path}", :green
191
191
 
192
192
  # Use the unified site generator for results
193
- Serialbench::SiteGenerator.generate_for_result(result, options[:output_dir])
193
+ puts 'Site generation moved to serialbench.github.io'
194
194
 
195
195
  say '✅ HTML site generated successfully!', :green
196
196
  say "Site location: #{options[:output_dir]}", :cyan
@@ -4,7 +4,6 @@ require 'thor'
4
4
  require_relative 'cli/base_cli'
5
5
  require_relative 'cli/environment_cli'
6
6
  require_relative 'cli/benchmark_cli'
7
- require_relative 'cli/resultset_cli'
8
7
  require_relative 'cli/ruby_build_cli'
9
8
  require_relative 'cli/validate_cli'
10
9
 
@@ -17,9 +16,6 @@ module Serialbench
17
16
  desc 'benchmark SUBCOMMAND', 'Manage individual benchmark runs'
18
17
  subcommand 'benchmark', Serialbench::Cli::BenchmarkCli
19
18
 
20
- desc 'resultset SUBCOMMAND', 'Manage benchmark resultsets (collections of runs)'
21
- subcommand 'resultset', Serialbench::Cli::ResultsetCli
22
-
23
19
  desc 'ruby_build SUBCOMMAND', 'Manage Ruby-Build definitions for validation'
24
20
  subcommand 'ruby_build', Serialbench::Cli::RubyBuildCli
25
21
 
@@ -45,7 +41,6 @@ module Serialbench
45
41
  COMMANDS:
46
42
  environment Manage benchmark environments (Docker, ASDF, Local)
47
43
  benchmark Manage individual benchmark runs
48
- resultset Manage benchmark resultsets (collections of runs)
49
44
  ruby-build Manage Ruby-Build definitions for validation
50
45
  version Show version information
51
46
  help Show this help message
@@ -62,13 +57,6 @@ module Serialbench
62
57
  serialbench benchmark create my-benchmark
63
58
  serialbench benchmark execute my-benchmark.yml
64
59
 
65
- # Create a result set for comparison
66
- serialbench resultset create comparison-set
67
- serialbench resultset add-result comparison-set results/my-benchmark
68
-
69
- # Generate static sites
70
- serialbench benchmark build-site results/my-benchmark
71
- serialbench resultset build-site resultsets/comparison-set
72
60
 
73
61
  For detailed help on any command, use:
74
62
  serialbench COMMAND help
@@ -68,6 +68,7 @@ module Serialbench
68
68
  attribute :generation, IterationPerformance, collection: true
69
69
  attribute :memory, MemoryPerformance, collection: true
70
70
  attribute :streaming, IterationPerformance, collection: true
71
+ attribute :xpath, IterationPerformance, collection: true
71
72
 
72
73
  key_value do
73
74
  map 'serializers', to: :serializers
@@ -75,6 +76,7 @@ module Serialbench
75
76
  map 'generation', to: :generation
76
77
  map 'memory', to: :memory
77
78
  map 'streaming', to: :streaming
79
+ map 'xpath', to: :xpath
78
80
  end
79
81
  end
80
82
  end
@@ -8,7 +8,6 @@ module Serialbench
8
8
  class ResultStore
9
9
  DEFAULT_BASE_PATH = 'results'
10
10
  RUNS_PATH = 'runs'
11
- SETS_PATH = 'sets'
12
11
 
13
12
  attr_reader :base_path
14
13
 
@@ -34,27 +33,6 @@ module Serialbench
34
33
  limit ? runs.first(limit) : runs
35
34
  end
36
35
 
37
- # Run set management
38
- def sets_path
39
- File.join(@base_path, SETS_PATH)
40
- end
41
-
42
- def find_resultsets(tags: nil, limit: nil)
43
- resultsets = ResultSet.find_all(sets_path)
44
-
45
- resultsets = resultsets.select { |resultset| (Array(tags) - resultset.tags).empty? } if tags
46
-
47
- limit ? resultsets.first(limit) : resultsets
48
- end
49
-
50
- # Convenience methods
51
- def create_resultset(name, run_platform_strings, metadata: {})
52
- run_paths = run_platform_strings.map { |ps| File.join(runs_path, ps) }
53
- resultset = ResultSet.create(name, run_paths, metadata: metadata)
54
- save_resultset(resultset)
55
- resultset
56
- end
57
-
58
36
  # Validation
59
37
  def validate_structure
60
38
  errors = []
@@ -62,7 +40,6 @@ module Serialbench
62
40
  # Check base structure
63
41
  errors << "Base path does not exist: #{@base_path}" unless Dir.exist?(@base_path)
64
42
  errors << "Runs directory does not exist: #{runs_path}" unless Dir.exist?(runs_path)
65
- errors << "Sets directory does not exist: #{sets_path}" unless Dir.exist?(sets_path)
66
43
 
67
44
  # Validate individual runs
68
45
  if Dir.exist?(runs_path)
@@ -78,20 +55,6 @@ module Serialbench
78
55
  end
79
56
  end
80
57
 
81
- # Validate result sets
82
- if Dir.exist?(sets_path)
83
- Dir.glob(File.join(sets_path, '*')).each do |set_path|
84
- next unless Dir.exist?(set_path)
85
-
86
- begin
87
- resultset = ResultSet.load(set_path)
88
- resultset.validate!
89
- rescue StandardError => e
90
- errors << "Invalid result set at #{set_path}: #{e.message}"
91
- end
92
- end
93
- end
94
-
95
58
  errors
96
59
  end
97
60
 
@@ -101,7 +64,6 @@ module Serialbench
101
64
 
102
65
  def ensure_results_directory
103
66
  FileUtils.mkdir_p(runs_path) unless Dir.exist?(runs_path)
104
- FileUtils.mkdir_p(sets_path) unless Dir.exist?(sets_path)
105
67
  end
106
68
  end
107
69
  end
@@ -6,7 +6,6 @@ require_relative 'models/result'
6
6
  require_relative 'models/result_store'
7
7
  require_relative 'models/benchmark_config'
8
8
  require_relative 'models/environment_config'
9
- require_relative 'models/result_set'
10
9
 
11
10
  module Serialbench
12
11
  module Models
@@ -46,9 +45,5 @@ module Serialbench
46
45
  def self.create_run(platform_string, benchmark_data, metadata: {})
47
46
  Result.create(platform_string, benchmark_data, metadata: metadata)
48
47
  end
49
-
50
- def self.create_resultset(name, run_paths_or_objects, metadata: {})
51
- ResultSet.create(name, run_paths_or_objects, metadata: metadata)
52
- end
53
48
  end
54
49
  end
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  # frozen_string_literal: true
2
4
 
3
5
  require 'singleton'
@@ -33,9 +35,15 @@ module Serialbench
33
35
  result
34
36
  end
35
37
 
36
- def supports_streaming?
37
- # Override in subclasses that support streaming
38
- false
38
+ # Capabilities: a Set of symbols declaring what this adapter can do.
39
+ # Subclasses override to add symbols; the base handles every query.
40
+ # This replaces the 12+ individual supports_X? predicates.
41
+ def capabilities
42
+ Set.new(%i[dom parse generate])
43
+ end
44
+
45
+ def supports?(capability)
46
+ capabilities.include?(capability)
39
47
  end
40
48
 
41
49
  def require_library(library_name)
@@ -19,32 +19,20 @@ module Serialbench
19
19
  generate(object, options)
20
20
  end
21
21
 
22
+ def capabilities
23
+ super | Set.new(%i[pretty_print])
24
+ end
25
+
22
26
  # JSON-specific features
23
27
  def features
24
28
  {
25
- pretty_print: supports_pretty_print?,
26
- streaming: supports_streaming?,
27
- symbol_keys: supports_symbol_keys?,
28
- custom_types: supports_custom_types?
29
+ pretty_print: supports?(:pretty_print),
30
+ streaming: supports?(:sax) || supports?(:streaming),
31
+ symbol_keys: supports?(:symbol_keys),
32
+ custom_types: supports?(:custom_types)
29
33
  }
30
34
  end
31
35
 
32
- def supports_generation?
33
- true
34
- end
35
-
36
- def supports_pretty_print?
37
- true
38
- end
39
-
40
- def supports_symbol_keys?
41
- false
42
- end
43
-
44
- def supports_custom_types?
45
- false
46
- end
47
-
48
36
  # Subclasses should override this to specify their library name
49
37
  def library_require_name
50
38
  raise NotImplementedError, 'Subclasses must implement #library_require_name'
@@ -34,22 +34,6 @@ module Serialbench
34
34
  JSON.generate(object)
35
35
  end
36
36
  end
37
-
38
- def supports_streaming?
39
- false
40
- end
41
-
42
- def supports_pretty_print?
43
- true
44
- end
45
-
46
- def supports_symbol_keys?
47
- false
48
- end
49
-
50
- def supports_custom_types?
51
- false
52
- end
53
37
  end
54
38
  end
55
39
  end
@@ -46,23 +46,8 @@ module Serialbench
46
46
  super
47
47
  end
48
48
 
49
- def supports_streaming?
50
- require 'oj'
51
- Oj.respond_to?(:saj_parse)
52
- rescue LoadError
53
- false
54
- end
55
-
56
- def supports_pretty_print?
57
- true
58
- end
59
-
60
- def supports_symbol_keys?
61
- true
62
- end
63
-
64
- def supports_custom_types?
65
- true
49
+ def capabilities
50
+ super | Set.new(%i[symbol_keys custom_types sax])
66
51
  end
67
52
  end
68
53
 
@@ -44,8 +44,8 @@ module Serialbench
44
44
  end
45
45
  end
46
46
 
47
- def supports_streaming?
48
- true
47
+ def capabilities
48
+ super | Set.new(%i[sax])
49
49
  end
50
50
 
51
51
  def version