Skip to content

Commit 4b6ffbf

Browse files
authored
Merge pull request #225 from xml4r/dev
Dev
2 parents cf6b176 + fe9f7cd commit 4b6ffbf

File tree

84 files changed

+12954
-12721
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+12954
-12721
lines changed

.github/workflows/mri.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: CI
22

33
on:
44
push:
5-
branches: [ master ]
5+
branches: [ master, dev ]
66
pull_request:
77
branches: [ master ]
88

@@ -21,7 +21,7 @@ jobs:
2121
fail-fast: false
2222
matrix:
2323
os: [ubuntu-latest, macos-latest, windows-latest]
24-
ruby: ['3.2', '3.3', '3.4']
24+
ruby: ['3.2', '3.3', '3.4', '4.0']
2525
steps:
2626
- uses: actions/checkout@v4
2727
- name: Set up Ruby

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ ext/libxml/libxml_ruby.bundle
1919
/ext/vc/*.suo
2020
Gemfile.lock
2121
lib/*/libxml_ruby.so
22+
/ext/vc/libxml_ruby/x64
23+
/ext/vc/libxml_ruby/libxml_ruby.vcxproj.user

HISTORY

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
= Release History
22

3+
== 5.0.6 / 2026-04-03
4+
* Test fix - Make the memory leak test threshold more generous to avoid false positives
5+
* Test fix - Call get_handler on Error class instead of module
6+
* Fix XML::Writer.string buffer leak
7+
* Update assertion to comply with minitest deprecations
8+
* Allow libdir to match Rubies with double digit patch numbers
9+
310
== 5.0.5 / 2025-07-30
411
* Try to fix broken documentation link in Ruby Gems website
512
* Update history file

Rakefile

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,6 @@ Rake::ExtensionTask.new do |ext|
2121
ext.name = SO_NAME
2222
ext.ext_dir = "ext/libxml"
2323
ext.lib_dir = "lib/#{RUBY_VERSION.sub(/\.\d+$/, '')}"
24-
if RUBY_PLATFORM.match(/mswin|mingw/)
25-
ext.config_options <<
26-
if (dir = ENV['WINDOWS_XML2_INCLUDE'])
27-
"--with-xml2-include=#{dir}"
28-
else
29-
case RUBY_PLATFORM
30-
when 'i386-mingw32'
31-
'--with-xml2-include=C:/msys64/mingw32/include/libxml2'
32-
when 'x64-mingw32'
33-
'--with-xml2-include=C:/msys64/mingw64/include/libxml2'
34-
when 'x64-mingw-ucrt'
35-
'--with-xml2-include=C:/msys64/ucrt64/include/libxml2'
36-
else
37-
raise "Unknown Windows Ruby, please set ENV['WINDOWS_XML2_INCLUDE']"
38-
end
39-
end
40-
else
41-
ext.config_options << '--with-xml2-include=/usr/include/libxml2'
42-
end
4324
end
4425

4526
# Setup generic gem
@@ -49,21 +30,20 @@ Gem::PackageTask.new(spec) do |pkg|
4930
end
5031

5132
# Setup Windows Gem
52-
if RUBY_PLATFORM.match(/mswin|mingw/)
53-
binaries = (FileList['lib/**/*.so',
54-
'lib/**/*dll'])
33+
if RUBY_PLATFORM.match(/mingw/)
34+
binaries = (FileList['lib/**/*.so'])
5535

5636
# Windows specification
57-
win_spec = spec.clone
58-
win_spec.platform = Gem::Platform::CURRENT
59-
win_spec.files += binaries.to_a
60-
win_spec.instance_variable_set(:@cache_file, nil)
37+
mingw_spec = spec.clone
38+
mingw_spec.platform = Gem::Platform::CURRENT
39+
mingw_spec.files += binaries.to_a
40+
mingw_spec.instance_variable_set(:@cache_file, nil)
6141

6242
# Unset extensions
63-
win_spec.extensions = nil
43+
mingw_spec.extensions = nil
6444

6545
# Rake task to build the windows package
66-
Gem::PackageTask.new(win_spec) do |pkg|
46+
Gem::PackageTask.new(mingw_spec) do |pkg|
6747
pkg.package_dir = 'pkg'
6848
pkg.need_tar = false
6949
end

ext/libxml/extconf.rb

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,46 @@ def crash(str)
2323
end
2424
else
2525
dir_config('xml2')
26+
pkg_config('libxml-2.0')
2627
end
2728

28-
found_header = find_header('libxml/xmlversion.h',
29-
'/opt/include/libxml2',
30-
'/opt/local/include/libxml2',
31-
'/opt/homebrew/opt/libxml2/include/libxml2',
32-
'/usr/local/include/libxml2',
33-
'/usr/include/libxml2',
34-
'/usr/local/include',
35-
'/usr/local/opt/libxml2/include/libxml2')
29+
include_dirs = []
30+
lib_dirs = []
31+
32+
if (msystem_prefix = ENV['MSYSTEM_PREFIX']) && !msystem_prefix.empty?
33+
include_dirs.concat([
34+
"#{msystem_prefix}/include/libxml2",
35+
"#{msystem_prefix}/include"
36+
])
37+
lib_dirs << "#{msystem_prefix}/lib"
38+
end
39+
40+
include_dirs.concat([
41+
'/opt/include/libxml2',
42+
'/opt/local/include/libxml2',
43+
'/opt/homebrew/opt/libxml2/include/libxml2',
44+
'/usr/local/include/libxml2',
45+
'/usr/include/libxml2',
46+
'/usr/local/include',
47+
'/usr/local/opt/libxml2/include/libxml2'
48+
])
49+
50+
lib_dirs.concat([
51+
'/opt/lib',
52+
'/opt/local/lib',
53+
'/opt/homebrew/opt/libxml2/lib',
54+
'/usr/lib',
55+
'/usr/local/lib',
56+
'/usr/local/opt/libxml2/lib'
57+
])
58+
59+
found_header = find_header('libxml/xmlversion.h', *include_dirs)
3660

3761
found_lib = find_library('xml2', 'xmlParseDoc',
38-
'/opt/lib',
39-
'/opt/local/lib',
40-
'/opt/homebrew/opt/libxml2/lib',
41-
'/usr/lib',
42-
'/usr/local/lib',
43-
'/usr/local/opt/libxml2/lib')
62+
*lib_dirs)
4463

4564
found_lib ||= find_library('libxml2', 'xmlParseDoc',
46-
'/opt/lib',
47-
'/opt/local/lib',
48-
'/opt/homebrew/opt/libxml2/lib',
49-
'/usr/lib',
50-
'/usr/local/lib',
51-
'/usr/local/opt/libxml2/lib')
65+
*lib_dirs)
5266

5367
if !found_header || !found_lib
5468
crash(<<~EOL)

ext/libxml/ruby_xml_attr.c

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,29 @@
3232

3333
VALUE cXMLAttr;
3434

35-
void rxml_attr_mark(xmlAttrPtr xattr)
35+
static void rxml_attr_mark(void *data)
3636
{
37+
xmlAttrPtr xattr = (xmlAttrPtr) data;
3738
/* This can happen if Ruby does a GC run after creating the
3839
new attribute but before initializing it. */
3940
if (xattr != NULL)
4041
rxml_node_mark((xmlNodePtr) xattr);
4142
}
4243

44+
const rb_data_type_t rxml_attr_type = {
45+
"LibXML::XML::Attr",
46+
{rxml_attr_mark, NULL, 0},
47+
&rxml_node_data_type, 0, RUBY_TYPED_FREE_IMMEDIATELY
48+
};
49+
4350
VALUE rxml_attr_wrap(xmlAttrPtr xattr)
4451
{
45-
return Data_Wrap_Struct(cXMLAttr, rxml_attr_mark, NULL, xattr);
52+
return TypedData_Wrap_Struct(cXMLAttr, &rxml_attr_type, xattr);
4653
}
4754

4855
static VALUE rxml_attr_alloc(VALUE klass)
4956
{
50-
return Data_Wrap_Struct(klass, rxml_attr_mark, NULL, NULL);
57+
return TypedData_Wrap_Struct(klass, &rxml_attr_type, NULL);
5158
}
5259

5360
/*
@@ -78,7 +85,7 @@ static VALUE rxml_attr_initialize(int argc, VALUE *argv, VALUE self)
7885
Check_Type(name, T_STRING);
7986
Check_Type(value, T_STRING);
8087

81-
Data_Get_Struct(node, xmlNode, xnode);
88+
TypedData_Get_Struct(node, xmlNode, &rxml_node_data_type, xnode);
8289

8390
if (xnode->type != XML_ELEMENT_NODE)
8491
rb_raise(rb_eArgError, "Attributes can only be created on element nodes.");
@@ -90,14 +97,14 @@ static VALUE rxml_attr_initialize(int argc, VALUE *argv, VALUE self)
9097
else
9198
{
9299
xmlNsPtr xns;
93-
Data_Get_Struct(ns, xmlNs, xns);
100+
TypedData_Get_Struct(ns, xmlNs, &rxml_namespace_type, xns);
94101
xattr = xmlNewNsProp(xnode, xns, (xmlChar*)StringValuePtr(name), (xmlChar*)StringValuePtr(value));
95102
}
96103

97104
if (!xattr)
98105
rb_raise(rb_eRuntimeError, "Could not create attribute.");
99106

100-
DATA_PTR( self) = xattr;
107+
RTYPEDDATA_DATA( self) = xattr;
101108
return self;
102109
}
103110

@@ -110,7 +117,7 @@ static VALUE rxml_attr_initialize(int argc, VALUE *argv, VALUE self)
110117
static VALUE rxml_attr_child_get(VALUE self)
111118
{
112119
xmlAttrPtr xattr;
113-
Data_Get_Struct(self, xmlAttr, xattr);
120+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
114121
if (xattr->children == NULL)
115122
return Qnil;
116123
else
@@ -129,7 +136,7 @@ static VALUE rxml_attr_child_get(VALUE self)
129136
static VALUE rxml_attr_doc_get(VALUE self)
130137
{
131138
xmlAttrPtr xattr;
132-
Data_Get_Struct(self, xmlAttr, xattr);
139+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
133140
if (xattr->doc == NULL)
134141
return Qnil;
135142
else
@@ -145,7 +152,7 @@ static VALUE rxml_attr_doc_get(VALUE self)
145152
static VALUE rxml_attr_last_get(VALUE self)
146153
{
147154
xmlAttrPtr xattr;
148-
Data_Get_Struct(self, xmlAttr, xattr);
155+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
149156
if (xattr->last == NULL)
150157
return Qnil;
151158
else
@@ -161,7 +168,7 @@ static VALUE rxml_attr_last_get(VALUE self)
161168
static VALUE rxml_attr_name_get(VALUE self)
162169
{
163170
xmlAttrPtr xattr;
164-
Data_Get_Struct(self, xmlAttr, xattr);
171+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
165172

166173
if (xattr->name == NULL)
167174
return Qnil;
@@ -178,7 +185,7 @@ static VALUE rxml_attr_name_get(VALUE self)
178185
static VALUE rxml_attr_next_get(VALUE self)
179186
{
180187
xmlAttrPtr xattr;
181-
Data_Get_Struct(self, xmlAttr, xattr);
188+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
182189
if (xattr->next == NULL)
183190
return Qnil;
184191
else
@@ -194,7 +201,7 @@ static VALUE rxml_attr_next_get(VALUE self)
194201
static VALUE rxml_attr_node_type(VALUE self)
195202
{
196203
xmlAttrPtr xattr;
197-
Data_Get_Struct(self, xmlAttr, xattr);
204+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
198205
return INT2NUM(xattr->type);
199206
}
200207

@@ -207,7 +214,7 @@ static VALUE rxml_attr_node_type(VALUE self)
207214
static VALUE rxml_attr_ns_get(VALUE self)
208215
{
209216
xmlAttrPtr xattr;
210-
Data_Get_Struct(self, xmlAttr, xattr);
217+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
211218
if (xattr->ns == NULL)
212219
return Qnil;
213220
else
@@ -223,7 +230,7 @@ static VALUE rxml_attr_ns_get(VALUE self)
223230
static VALUE rxml_attr_parent_get(VALUE self)
224231
{
225232
xmlAttrPtr xattr;
226-
Data_Get_Struct(self, xmlAttr, xattr);
233+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
227234
if (xattr->parent == NULL)
228235
return Qnil;
229236
else
@@ -239,7 +246,7 @@ static VALUE rxml_attr_parent_get(VALUE self)
239246
static VALUE rxml_attr_prev_get(VALUE self)
240247
{
241248
xmlAttrPtr xattr;
242-
Data_Get_Struct(self, xmlAttr, xattr);
249+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
243250
if (xattr->prev == NULL)
244251
return Qnil;
245252
else
@@ -258,12 +265,10 @@ static VALUE rxml_attr_prev_get(VALUE self)
258265
static VALUE rxml_attr_remove_ex(VALUE self)
259266
{
260267
xmlAttrPtr xattr;
261-
Data_Get_Struct(self, xmlAttr, xattr);
268+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
262269
xmlRemoveProp(xattr);
263270

264-
RDATA(self)->data = NULL;
265-
RDATA(self)->dfree = NULL;
266-
RDATA(self)->dmark = NULL;
271+
RTYPEDDATA_DATA(self) = NULL;
267272

268273
return Qnil;
269274
}
@@ -280,7 +285,7 @@ VALUE rxml_attr_value_get(VALUE self)
280285
xmlChar *value;
281286
VALUE result = Qnil;
282287

283-
Data_Get_Struct(self, xmlAttr, xattr);
288+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
284289
value = xmlNodeGetContent((xmlNodePtr)xattr);
285290

286291
if (value != NULL)
@@ -302,7 +307,7 @@ VALUE rxml_attr_value_set(VALUE self, VALUE val)
302307
xmlAttrPtr xattr;
303308

304309
Check_Type(val, T_STRING);
305-
Data_Get_Struct(self, xmlAttr, xattr);
310+
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
306311

307312
if (xattr->ns)
308313
xmlSetNsProp(xattr->parent, xattr->ns, xattr->name,

ext/libxml/ruby_xml_attr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#define __RXML_ATTR__
55

66
extern VALUE cXMLAttr;
7+
extern const rb_data_type_t rxml_attr_type;
78

89
void rxml_init_attr(void);
910
VALUE rxml_attr_wrap(xmlAttrPtr xattr);

0 commit comments

Comments
 (0)