Skip to content

Commit 803045f

Browse files
committed
Add add_pg method to Header class and corresponding tests
1 parent 095329e commit 803045f

2 files changed

Lines changed: 87 additions & 0 deletions

File tree

lib/hts/bam/header.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,23 @@ def get_tid(name)
111111
name2tid(name)
112112
end
113113

114+
# Add a @PG (program) line to the header
115+
# @param program_name [String] Name of the program
116+
# @param options [Hash] Key-value pairs for @PG tags (ID, PN, VN, CL, PP, etc.)
117+
# @return [Integer] 0 on success, -1 on failure
118+
#
119+
# This is a convenience wrapper around sam_hdr_add_pg that automatically:
120+
# - Generates a unique ID if the specified one clashes
121+
# - Manages PP (previous program) chains automatically
122+
#
123+
# @example
124+
# header.add_pg("bwa", VN: "0.7.17", CL: "bwa mem ref.fa read.fq")
125+
# header.add_pg("samtools", VN: "1.15", PP: "bwa")
126+
def add_pg(program_name, **options)
127+
args = options.flat_map { |k, v| [:string, k.to_s, :string, v.to_s] }
128+
LibHTS.sam_hdr_add_pg(@sam_hdr, program_name, *args, :pointer, FFI::Pointer::NULL)
129+
end
130+
114131
private
115132

116133
def name2tid(name)

test/header_test.rb

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "test_helper"
4+
5+
class HeaderTest < Minitest::Test
6+
def setup
7+
@bam = HTS::Bam.open(Fixtures["poo.sort.bam"])
8+
@header = @bam.header
9+
end
10+
11+
def teardown
12+
@bam&.close
13+
end
14+
15+
def test_add_pg
16+
# Test basic @PG line addition
17+
result = @header.add_pg("test_program", VN: "1.0.0", CL: "test_program input.bam")
18+
assert_equal 0, result
19+
20+
# Check that the @PG line was added
21+
header_text = @header.to_s
22+
assert_match(/@PG\t.*PN:test_program/, header_text)
23+
assert_match(/VN:1.0.0/, header_text)
24+
assert_match(/CL:test_program input.bam/, header_text)
25+
end
26+
27+
def test_add_pg_with_pp
28+
# Add first program
29+
@header.add_pg("program1", VN: "1.0")
30+
31+
# Add second program with PP reference
32+
result = @header.add_pg("program2", VN: "2.0", PP: "program1")
33+
assert_equal 0, result
34+
35+
header_text = @header.to_s
36+
assert_match(/@PG\t.*PN:program1/, header_text)
37+
assert_match(/@PG\t.*PN:program2/, header_text)
38+
assert_match(/PP:program1/, header_text)
39+
end
40+
41+
def test_add_pg_auto_id_generation
42+
# Add multiple programs with the same name
43+
# sam_hdr_add_pg should automatically generate unique IDs
44+
@header.add_pg("samtools")
45+
@header.add_pg("samtools")
46+
@header.add_pg("samtools")
47+
48+
header_text = @header.to_s
49+
# Should have multiple @PG lines with samtools
50+
pg_lines = header_text.scan(/@PG\t.*PN:samtools/)
51+
assert_operator pg_lines.size, :>=, 3
52+
end
53+
54+
def test_add_pg_with_id
55+
result = @header.add_pg("myprogram", ID: "custom_id", VN: "0.1")
56+
assert_equal 0, result
57+
58+
header_text = @header.to_s
59+
assert_match(/ID:custom_id/, header_text)
60+
assert_match(/PN:myprogram/, header_text)
61+
end
62+
63+
def test_add_pg_empty_options
64+
result = @header.add_pg("simple_program")
65+
assert_equal 0, result
66+
67+
header_text = @header.to_s
68+
assert_match(/@PG\t.*PN:simple_program/, header_text)
69+
end
70+
end

0 commit comments

Comments
 (0)