Skip to content
Merged

Dev #225

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/mri.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: CI

on:
push:
branches: [ master ]
branches: [ master, dev ]
pull_request:
branches: [ master ]

Expand All @@ -21,7 +21,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
ruby: ['3.2', '3.3', '3.4']
ruby: ['3.2', '3.3', '3.4', '4.0']
steps:
- uses: actions/checkout@v4
- name: Set up Ruby
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ ext/libxml/libxml_ruby.bundle
/ext/vc/*.suo
Gemfile.lock
lib/*/libxml_ruby.so
/ext/vc/libxml_ruby/x64
/ext/vc/libxml_ruby/libxml_ruby.vcxproj.user
7 changes: 7 additions & 0 deletions HISTORY
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
= Release History

== 5.0.6 / 2026-04-03
* Test fix - Make the memory leak test threshold more generous to avoid false positives
* Test fix - Call get_handler on Error class instead of module
* Fix XML::Writer.string buffer leak
* Update assertion to comply with minitest deprecations
* Allow libdir to match Rubies with double digit patch numbers

== 5.0.5 / 2025-07-30
* Try to fix broken documentation link in Ruby Gems website
* Update history file
Expand Down
36 changes: 8 additions & 28 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,6 @@ Rake::ExtensionTask.new do |ext|
ext.name = SO_NAME
ext.ext_dir = "ext/libxml"
ext.lib_dir = "lib/#{RUBY_VERSION.sub(/\.\d+$/, '')}"
if RUBY_PLATFORM.match(/mswin|mingw/)
ext.config_options <<
if (dir = ENV['WINDOWS_XML2_INCLUDE'])
"--with-xml2-include=#{dir}"
else
case RUBY_PLATFORM
when 'i386-mingw32'
'--with-xml2-include=C:/msys64/mingw32/include/libxml2'
when 'x64-mingw32'
'--with-xml2-include=C:/msys64/mingw64/include/libxml2'
when 'x64-mingw-ucrt'
'--with-xml2-include=C:/msys64/ucrt64/include/libxml2'
else
raise "Unknown Windows Ruby, please set ENV['WINDOWS_XML2_INCLUDE']"
end
end
else
ext.config_options << '--with-xml2-include=/usr/include/libxml2'
end
end

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

# Setup Windows Gem
if RUBY_PLATFORM.match(/mswin|mingw/)
binaries = (FileList['lib/**/*.so',
'lib/**/*dll'])
if RUBY_PLATFORM.match(/mingw/)
binaries = (FileList['lib/**/*.so'])

# Windows specification
win_spec = spec.clone
win_spec.platform = Gem::Platform::CURRENT
win_spec.files += binaries.to_a
win_spec.instance_variable_set(:@cache_file, nil)
mingw_spec = spec.clone
mingw_spec.platform = Gem::Platform::CURRENT
mingw_spec.files += binaries.to_a
mingw_spec.instance_variable_set(:@cache_file, nil)

# Unset extensions
win_spec.extensions = nil
mingw_spec.extensions = nil

# Rake task to build the windows package
Gem::PackageTask.new(win_spec) do |pkg|
Gem::PackageTask.new(mingw_spec) do |pkg|
pkg.package_dir = 'pkg'
pkg.need_tar = false
end
Expand Down
54 changes: 34 additions & 20 deletions ext/libxml/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,46 @@ def crash(str)
end
else
dir_config('xml2')
pkg_config('libxml-2.0')
end

found_header = find_header('libxml/xmlversion.h',
'/opt/include/libxml2',
'/opt/local/include/libxml2',
'/opt/homebrew/opt/libxml2/include/libxml2',
'/usr/local/include/libxml2',
'/usr/include/libxml2',
'/usr/local/include',
'/usr/local/opt/libxml2/include/libxml2')
include_dirs = []
lib_dirs = []

if (msystem_prefix = ENV['MSYSTEM_PREFIX']) && !msystem_prefix.empty?
include_dirs.concat([
"#{msystem_prefix}/include/libxml2",
"#{msystem_prefix}/include"
])
lib_dirs << "#{msystem_prefix}/lib"
end

include_dirs.concat([
'/opt/include/libxml2',
'/opt/local/include/libxml2',
'/opt/homebrew/opt/libxml2/include/libxml2',
'/usr/local/include/libxml2',
'/usr/include/libxml2',
'/usr/local/include',
'/usr/local/opt/libxml2/include/libxml2'
])

lib_dirs.concat([
'/opt/lib',
'/opt/local/lib',
'/opt/homebrew/opt/libxml2/lib',
'/usr/lib',
'/usr/local/lib',
'/usr/local/opt/libxml2/lib'
])

found_header = find_header('libxml/xmlversion.h', *include_dirs)

found_lib = find_library('xml2', 'xmlParseDoc',
'/opt/lib',
'/opt/local/lib',
'/opt/homebrew/opt/libxml2/lib',
'/usr/lib',
'/usr/local/lib',
'/usr/local/opt/libxml2/lib')
*lib_dirs)

found_lib ||= find_library('libxml2', 'xmlParseDoc',
'/opt/lib',
'/opt/local/lib',
'/opt/homebrew/opt/libxml2/lib',
'/usr/lib',
'/usr/local/lib',
'/usr/local/opt/libxml2/lib')
*lib_dirs)

if !found_header || !found_lib
crash(<<~EOL)
Expand Down
47 changes: 26 additions & 21 deletions ext/libxml/ruby_xml_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,29 @@

VALUE cXMLAttr;

void rxml_attr_mark(xmlAttrPtr xattr)
static void rxml_attr_mark(void *data)
{
xmlAttrPtr xattr = (xmlAttrPtr) data;
/* This can happen if Ruby does a GC run after creating the
new attribute but before initializing it. */
if (xattr != NULL)
rxml_node_mark((xmlNodePtr) xattr);
}

const rb_data_type_t rxml_attr_type = {
"LibXML::XML::Attr",
{rxml_attr_mark, NULL, 0},
&rxml_node_data_type, 0, RUBY_TYPED_FREE_IMMEDIATELY
};

VALUE rxml_attr_wrap(xmlAttrPtr xattr)
{
return Data_Wrap_Struct(cXMLAttr, rxml_attr_mark, NULL, xattr);
return TypedData_Wrap_Struct(cXMLAttr, &rxml_attr_type, xattr);
}

static VALUE rxml_attr_alloc(VALUE klass)
{
return Data_Wrap_Struct(klass, rxml_attr_mark, NULL, NULL);
return TypedData_Wrap_Struct(klass, &rxml_attr_type, NULL);
}

/*
Expand Down Expand Up @@ -78,7 +85,7 @@ static VALUE rxml_attr_initialize(int argc, VALUE *argv, VALUE self)
Check_Type(name, T_STRING);
Check_Type(value, T_STRING);

Data_Get_Struct(node, xmlNode, xnode);
TypedData_Get_Struct(node, xmlNode, &rxml_node_data_type, xnode);

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

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

DATA_PTR( self) = xattr;
RTYPEDDATA_DATA( self) = xattr;
return self;
}

Expand All @@ -110,7 +117,7 @@ static VALUE rxml_attr_initialize(int argc, VALUE *argv, VALUE self)
static VALUE rxml_attr_child_get(VALUE self)
{
xmlAttrPtr xattr;
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
if (xattr->children == NULL)
return Qnil;
else
Expand All @@ -129,7 +136,7 @@ static VALUE rxml_attr_child_get(VALUE self)
static VALUE rxml_attr_doc_get(VALUE self)
{
xmlAttrPtr xattr;
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
if (xattr->doc == NULL)
return Qnil;
else
Expand All @@ -145,7 +152,7 @@ static VALUE rxml_attr_doc_get(VALUE self)
static VALUE rxml_attr_last_get(VALUE self)
{
xmlAttrPtr xattr;
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
if (xattr->last == NULL)
return Qnil;
else
Expand All @@ -161,7 +168,7 @@ static VALUE rxml_attr_last_get(VALUE self)
static VALUE rxml_attr_name_get(VALUE self)
{
xmlAttrPtr xattr;
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);

if (xattr->name == NULL)
return Qnil;
Expand All @@ -178,7 +185,7 @@ static VALUE rxml_attr_name_get(VALUE self)
static VALUE rxml_attr_next_get(VALUE self)
{
xmlAttrPtr xattr;
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
if (xattr->next == NULL)
return Qnil;
else
Expand All @@ -194,7 +201,7 @@ static VALUE rxml_attr_next_get(VALUE self)
static VALUE rxml_attr_node_type(VALUE self)
{
xmlAttrPtr xattr;
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
return INT2NUM(xattr->type);
}

Expand All @@ -207,7 +214,7 @@ static VALUE rxml_attr_node_type(VALUE self)
static VALUE rxml_attr_ns_get(VALUE self)
{
xmlAttrPtr xattr;
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
if (xattr->ns == NULL)
return Qnil;
else
Expand All @@ -223,7 +230,7 @@ static VALUE rxml_attr_ns_get(VALUE self)
static VALUE rxml_attr_parent_get(VALUE self)
{
xmlAttrPtr xattr;
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
if (xattr->parent == NULL)
return Qnil;
else
Expand All @@ -239,7 +246,7 @@ static VALUE rxml_attr_parent_get(VALUE self)
static VALUE rxml_attr_prev_get(VALUE self)
{
xmlAttrPtr xattr;
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
if (xattr->prev == NULL)
return Qnil;
else
Expand All @@ -258,12 +265,10 @@ static VALUE rxml_attr_prev_get(VALUE self)
static VALUE rxml_attr_remove_ex(VALUE self)
{
xmlAttrPtr xattr;
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
xmlRemoveProp(xattr);

RDATA(self)->data = NULL;
RDATA(self)->dfree = NULL;
RDATA(self)->dmark = NULL;
RTYPEDDATA_DATA(self) = NULL;

return Qnil;
}
Expand All @@ -280,7 +285,7 @@ VALUE rxml_attr_value_get(VALUE self)
xmlChar *value;
VALUE result = Qnil;

Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);
value = xmlNodeGetContent((xmlNodePtr)xattr);

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

Check_Type(val, T_STRING);
Data_Get_Struct(self, xmlAttr, xattr);
TypedData_Get_Struct(self, xmlAttr, &rxml_attr_type, xattr);

if (xattr->ns)
xmlSetNsProp(xattr->parent, xattr->ns, xattr->name,
Expand Down
1 change: 1 addition & 0 deletions ext/libxml/ruby_xml_attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#define __RXML_ATTR__

extern VALUE cXMLAttr;
extern const rb_data_type_t rxml_attr_type;

void rxml_init_attr(void);
VALUE rxml_attr_wrap(xmlAttrPtr xattr);
Expand Down
Loading
Loading