libxml-ruby 2.0.9 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY CHANGED
@@ -1,5 +1,30 @@
1
1
  = Release History
2
2
 
3
+ == 2.1.0 / 2011-07-31 Charlie Savage
4
+
5
+ * Ruby 1.9.3 compatability (Charlie Savage).
6
+
7
+ * Added XPath expression <-> Ruby value conversion methods (Jens Wille).
8
+
9
+ * Extracted rxml_xpath_to_value from rxml_xpath_context_find (Jens Wille).
10
+
11
+ * Adapted rxml_xpath_from_value from Gregoire Lejeune's ruby-xslt
12
+ library, see https://github.com/glejeune/ruby-xslt (Jens Wille).
13
+
14
+ * Allow calling #find on nodes returned from Reader (Charlie Savage).
15
+
16
+ * Change document handling in XPath::Context to address segmentation fault on
17
+ Ruby Enterprise Edition (Charlie Savage).
18
+
19
+ * Update gemspec file to work directly with bundler thereby allowing git
20
+ repository to be used as gem (Charlie Savage).
21
+
22
+ * Support gem buld (Charlie Savage).
23
+
24
+ * Simplify memory management of attributes namespaces to fix
25
+ segmentation faults that occurred when using Ruby 1.9.3 (Charlie Savage).
26
+
27
+
3
28
  == 2.0.8 / 2011-06-23 Charlie Savage
4
29
 
5
30
  * Add in 2 new HTML Parser constants - NODEFDTD and NOIMPLIED.
data/Rakefile CHANGED
@@ -4,7 +4,6 @@ require "rubygems"
4
4
  require "rake/extensiontask"
5
5
  require "rake/testtask"
6
6
  require "rubygems/package_task"
7
- ##require 'hanna/rdoctask'
8
7
  require "rdoc/task"
9
8
  require "grancher/task"
10
9
  require "yaml"
@@ -40,6 +39,7 @@ if RUBY_PLATFORM.match(/win32|mingw32/)
40
39
  win_spec = spec.clone
41
40
  win_spec.platform = Gem::Platform::CURRENT
42
41
  win_spec.files += binaries.to_a
42
+ win_spec.instance_variable_set(:@cache_file, nil)
43
43
 
44
44
  # Unset extensions
45
45
  win_spec.extensions = nil
@@ -16,37 +16,11 @@
16
16
  #include <libxml/xmlreader.h>
17
17
  #include <libxml/c14n.h>
18
18
 
19
- /* Needed for Ruby 1.8.5 */
20
- #ifndef RARRAY_LEN
21
- #define RARRAY_LEN(s) (RARRAY(s)->len)
22
- #endif
23
-
24
- /* Needed for Ruby 1.8.5 */
25
- #ifndef RARRAY_PTR
26
- #define RARRAY_PTR(s) (RARRAY(s)->ptr)
27
- #endif
28
-
29
- /* Needed for Ruby 1.8.5 */
30
- #ifndef RSTRING_LEN
31
- #define RSTRING_LEN(s) (RSTRING(s)->len)
32
- #endif
33
-
34
- /* Needed for Ruby 1.8.5 */
35
- #ifndef RSTRING_PTR
36
- #define RSTRING_PTR(s) (RSTRING(s)->ptr)
37
- #endif
38
-
39
19
  /* Needed prior to Ruby 1.9.1 */
40
20
  #ifndef RHASH_TBL
41
21
  #define RHASH_TBL(s) (RHASH(s)->tbl)
42
22
  #endif
43
23
 
44
- // Not in Ruby 1.9
45
- #ifndef GetWriteFile
46
- #define GetWriteFile(fp) rb_io_stdio_file(fp)
47
- #define OpenFile rb_io_t
48
- #endif
49
-
50
24
  // Encoding support added in Ruby 1.9.*
51
25
  #ifdef HAVE_RUBY_ENCODING_H
52
26
  #include <ruby/encoding.h>
@@ -16,57 +16,38 @@
16
16
  * attribute.remove!
17
17
  */
18
18
 
19
+ /* Attributes are owned and freed by their nodes. Thus, its easier for the
20
+ ruby bindings to not manage attribute memory management. This does mean
21
+ that accessing a particular attribute multiple times will return multiple
22
+ different ruby objects. Since we are not using free or xnode->_private
23
+ this works out fine. Previous versions of the bindings had a one to
24
+ one mapping between ruby object and xml attribute, but that could
25
+ result in segfaults because the ruby object could be gc'ed. In theory
26
+ the mark method on the parent node could prevent that, but if an
27
+ attribute is returned using an xpath statement then the node would
28
+ never by surfaced to ruby and the mark method never called. */
29
+
19
30
  #include "ruby_libxml.h"
20
31
  #include "ruby_xml_attr.h"
21
32
 
22
33
  VALUE cXMLAttr;
23
34
 
24
- void rxml_attr_free(xmlAttrPtr xattr)
25
- {
26
- if (!xattr)
27
- return;
28
-
29
- xattr->_private = NULL;
30
-
31
- if (xattr->parent == NULL && xattr->doc == NULL)
32
- {
33
- xmlFreeProp(xattr);
34
- }
35
- }
36
-
37
35
  void rxml_attr_mark(xmlAttrPtr xattr)
38
36
  {
39
37
  /* This can happen if Ruby does a GC run after creating the
40
38
  new attribute but before initializing it. */
41
- if (xattr == NULL)
42
- return;
43
-
44
- if (xattr->_private == NULL)
45
- {
46
- rb_warning("XmlAttr is not bound! (%s:%d)", __FILE__, __LINE__);
47
- return;
48
- }
49
-
50
- rxml_node_mark((xmlNodePtr) xattr);
39
+ if (xattr != NULL)
40
+ rxml_node_mark((xmlNodePtr) xattr);
51
41
  }
52
42
 
53
43
  VALUE rxml_attr_wrap(xmlAttrPtr xattr)
54
44
  {
55
- VALUE result;
56
-
57
- /* Check if the node is already wrapped. */
58
- if (xattr->_private != NULL)
59
- return (VALUE) xattr->_private;
60
-
61
- result = Data_Wrap_Struct(cXMLAttr, rxml_attr_mark, rxml_attr_free, xattr);
62
- xattr->_private = (void*) result;
63
-
64
- return result;
45
+ return Data_Wrap_Struct(cXMLAttr, rxml_attr_mark, NULL, xattr);
65
46
  }
66
47
 
67
48
  static VALUE rxml_attr_alloc(VALUE klass)
68
49
  {
69
- return Data_Wrap_Struct(klass, rxml_attr_mark, rxml_attr_free, NULL);
50
+ return Data_Wrap_Struct(klass, rxml_attr_mark, NULL, NULL);
70
51
  }
71
52
 
72
53
  /*
@@ -116,7 +97,6 @@ static VALUE rxml_attr_initialize(int argc, VALUE *argv, VALUE self)
116
97
  if (!xattr)
117
98
  rb_raise(rb_eRuntimeError, "Could not create attribute.");
118
99
 
119
- xattr->_private = (void *) self;
120
100
  DATA_PTR( self) = xattr;
121
101
  return self;
122
102
  }
@@ -231,7 +211,7 @@ static VALUE rxml_attr_ns_get(VALUE self)
231
211
  if (xattr->ns == NULL)
232
212
  return Qnil;
233
213
  else
234
- return rxml_namespace_wrap(xattr->ns, NULL);
214
+ return rxml_namespace_wrap(xattr->ns);
235
215
  }
236
216
 
237
217
  /*
@@ -268,21 +248,24 @@ static VALUE rxml_attr_prev_get(VALUE self)
268
248
 
269
249
  /*
270
250
  * call-seq:
271
- * node.remove! -> nil
251
+ * attr.remove! -> nil
272
252
  *
273
- * Removes this attribute from it's parent.
253
+ * Removes this attribute from it's parent. Note
254
+ * the attribute and its content is freed and can
255
+ * no longer be used. If you try to use it you
256
+ * will get a segmentation fault.
274
257
  */
275
258
  static VALUE rxml_attr_remove_ex(VALUE self)
276
259
  {
277
260
  xmlAttrPtr xattr;
278
261
  Data_Get_Struct(self, xmlAttr, xattr);
262
+ xmlRemoveProp(xattr);
279
263
 
280
- if (xattr->_private == NULL)
281
- xmlRemoveProp(xattr);
282
- else
283
- xmlUnlinkNode((xmlNodePtr) xattr);
264
+ RDATA(self)->data = NULL;
265
+ RDATA(self)->dfree = NULL;
266
+ RDATA(self)->dmark = NULL;
284
267
 
285
- return Qnil;;
268
+ return Qnil;
286
269
  }
287
270
 
288
271
  /*
@@ -15,28 +15,12 @@ VALUE cXMLAttrDecl;
15
15
 
16
16
  void rxml_attr_decl_mark(xmlAttributePtr xattr)
17
17
  {
18
- if (xattr->_private == NULL)
19
- {
20
- rb_warning("AttrDecl is not bound! (%s:%d)", __FILE__, __LINE__);
21
- return;
22
- }
23
-
24
18
  rxml_node_mark((xmlNodePtr) xattr);
25
19
  }
26
20
 
27
21
  VALUE rxml_attr_decl_wrap(xmlAttributePtr xattr)
28
22
  {
29
- VALUE result;
30
-
31
- // This node is already wrapped
32
- if (xattr->_private != NULL)
33
- return (VALUE) xattr->_private;
34
-
35
- result = Data_Wrap_Struct(cXMLAttrDecl, rxml_attr_decl_mark, NULL, xattr);
36
-
37
- xattr->_private = (void*) result;
38
-
39
- return result;
23
+ return Data_Wrap_Struct(cXMLAttrDecl, rxml_attr_decl_mark, NULL, xattr);
40
24
  }
41
25
 
42
26
  /*
@@ -21,32 +21,17 @@ VALUE cXMLNamespace;
21
21
  * assert_nil(node.namespaces.namespace)
22
22
  */
23
23
 
24
- static void rxml_namespace_free(xmlNsPtr xns)
25
- {
26
- xns->_private = NULL;
27
- }
24
+ /* Namespaces are owned and freed by their nodes. Thus, its easier for the
25
+ ruby bindings to not manage attribute memory management. */
28
26
 
29
27
  static VALUE rxml_namespace_alloc(VALUE klass)
30
28
  {
31
- return Data_Wrap_Struct(klass, NULL, rxml_namespace_free, NULL);
29
+ return Data_Wrap_Struct(klass, NULL, NULL, NULL);
32
30
  }
33
31
 
34
- VALUE rxml_namespace_wrap(xmlNsPtr xns, RUBY_DATA_FUNC freeFunc)
32
+ VALUE rxml_namespace_wrap(xmlNsPtr xns)
35
33
  {
36
- if (xns->_private)
37
- {
38
- return (VALUE)xns->_private;
39
- }
40
- else
41
- {
42
- VALUE ns;
43
- if (freeFunc == NULL)
44
- freeFunc = (RUBY_DATA_FUNC)rxml_namespace_free;
45
-
46
- ns = Data_Wrap_Struct(cXMLNamespace, NULL, freeFunc, xns);
47
- xns->_private = (void*)ns;
48
- return ns;
49
- }
34
+ return Data_Wrap_Struct(cXMLNamespace, NULL, NULL, xns);
50
35
  }
51
36
 
52
37
  static VALUE rxml_namespace_string(xmlNsPtr xns, const char* buffer)
@@ -84,7 +69,6 @@ static VALUE rxml_namespace_initialize(VALUE self, VALUE node, VALUE prefix,
84
69
  if (!xns)
85
70
  rxml_raise(&xmlLastError);
86
71
 
87
- xns->_private = (void*)self;
88
72
  DATA_PTR(self) = xns;
89
73
  return self;
90
74
  }
@@ -163,7 +147,7 @@ static VALUE rxml_namespace_next(VALUE self)
163
147
  if (xns == NULL || xns->next == NULL)
164
148
  return (Qnil);
165
149
  else
166
- return (rxml_namespace_wrap(xns->next, NULL));
150
+ return rxml_namespace_wrap(xns->next);
167
151
  }
168
152
 
169
153
  void rxml_init_namespace(void)
@@ -6,5 +6,5 @@
6
6
  extern VALUE cXMLNamespace;
7
7
 
8
8
  void rxml_init_namespace(void);
9
- VALUE rxml_namespace_wrap(xmlNsPtr xns, RUBY_DATA_FUNC freeFunc);
9
+ VALUE rxml_namespace_wrap(xmlNsPtr xns);
10
10
  #endif
@@ -90,7 +90,7 @@ static VALUE rxml_namespaces_definitions(VALUE self)
90
90
 
91
91
  while (xns)
92
92
  {
93
- VALUE anamespace = rxml_namespace_wrap(xns, NULL);
93
+ VALUE anamespace = rxml_namespace_wrap(xns);
94
94
  rb_ary_push(arr, anamespace);
95
95
  xns = xns->next;
96
96
  }
@@ -126,7 +126,7 @@ static VALUE rxml_namespaces_each(VALUE self)
126
126
 
127
127
  for (xns = nsList; *xns != NULL; xns++)
128
128
  {
129
- VALUE ns = rxml_namespace_wrap(*xns, NULL);
129
+ VALUE ns = rxml_namespace_wrap(*xns);
130
130
  rb_yield(ns);
131
131
  }
132
132
  xmlFree(nsList);
@@ -161,7 +161,7 @@ static VALUE rxml_namespaces_find_by_href(VALUE self, VALUE href)
161
161
 
162
162
  xns = xmlSearchNsByHref(xnode->doc, xnode, (xmlChar*) StringValuePtr(href));
163
163
  if (xns)
164
- return rxml_namespace_wrap(xns, NULL);
164
+ return rxml_namespace_wrap(xns);
165
165
  else
166
166
  return Qnil;
167
167
  }
@@ -200,7 +200,7 @@ static VALUE rxml_namespaces_find_by_prefix(VALUE self, VALUE prefix)
200
200
 
201
201
  xns = xmlSearchNs(xnode->doc, xnode, xprefix);
202
202
  if (xns)
203
- return rxml_namespace_wrap(xns, NULL);
203
+ return rxml_namespace_wrap(xns);
204
204
  else
205
205
  return Qnil;
206
206
  }
@@ -224,7 +224,7 @@ static VALUE rxml_namespaces_namespace_get(VALUE self)
224
224
  Data_Get_Struct(self, xmlNode, xnode);
225
225
 
226
226
  if (xnode->ns)
227
- return rxml_namespace_wrap(xnode->ns, NULL);
227
+ return rxml_namespace_wrap(xnode->ns);
228
228
  else
229
229
  return Qnil;
230
230
  }
@@ -508,8 +508,7 @@ static VALUE rxml_node_doc(VALUE self)
508
508
  else if (xdoc->_private)
509
509
  return (VALUE) xdoc->_private;
510
510
  else
511
- /* This can happen by calling Reader#expand.doc */
512
- rb_raise(eXMLError, "Document is not accessible to Ruby (hint - did you call Reader#expand?)");
511
+ return (Qnil);
513
512
  }
514
513
 
515
514
  /*
@@ -350,7 +350,7 @@ static VALUE rxml_parser_context_encoding_set(VALUE self, VALUE encoding)
350
350
  xmlCharEncodingHandlerPtr hdlr = xmlFindCharEncodingHandler(xencoding);
351
351
 
352
352
  if (!hdlr)
353
- rb_raise(rb_eRuntimeError, "Unknown encoding: %s", encoding);
353
+ rb_raise(rb_eArgError, "Unknown encoding: %i", NUM2INT(encoding));
354
354
 
355
355
  Data_Get_Struct(self, xmlParserCtxt, ctxt);
356
356
  result = xmlSwitchToEncoding(ctxt, hdlr);
@@ -42,6 +42,11 @@
42
42
  *
43
43
  * For a more in depth tutorial, albeit in C, see http://xmlsoft.org/xmlreader.html.*/
44
44
 
45
+
46
+ /* NOTE - We need to wrap the readers document to support Reader.read.node.find('/').
47
+ To do this we need to use xmlTextReaderCurrentDoc which means we have to free the
48
+ document ourselves. Annoying... */
49
+
45
50
  VALUE cXMLReader;
46
51
 
47
52
  static ID BASE_URI_SYMBOL;
@@ -54,11 +59,20 @@ static void rxml_reader_free(xmlTextReaderPtr xreader)
54
59
  xmlFreeTextReader(xreader);
55
60
  }
56
61
 
62
+ static void rxml_reader_mark(xmlTextReaderPtr xreader)
63
+ {
64
+ xmlDocPtr xdoc = xmlTextReaderCurrentDoc(xreader);
65
+
66
+ if (xdoc && xdoc->_private)
67
+ rb_gc_mark((VALUE) xdoc->_private);
68
+ }
69
+
57
70
  static VALUE rxml_reader_wrap(xmlTextReaderPtr xreader)
58
71
  {
59
72
  return Data_Wrap_Struct(cXMLReader, NULL, rxml_reader_free, xreader);
60
73
  }
61
74
 
75
+
62
76
  static xmlTextReaderPtr rxml_text_reader_get(VALUE obj)
63
77
  {
64
78
  xmlTextReaderPtr xreader;
@@ -414,7 +428,7 @@ static VALUE rxml_reader_normalization(VALUE self)
414
428
 
415
429
  /*
416
430
  * call-seq:
417
- * reader.read -> code
431
+ * reader.read -> nil|true|false
418
432
  *
419
433
  * Causes the reader to move to the next node in the stream, exposing its properties.
420
434
  *
@@ -873,7 +887,15 @@ static VALUE rxml_reader_lookup_namespace(VALUE self, VALUE prefix)
873
887
  static VALUE rxml_reader_expand(VALUE self)
874
888
  {
875
889
  xmlTextReaderPtr xreader = rxml_text_reader_get(self);
876
- xmlNodePtr xnode = xmlTextReaderExpand(xreader);
890
+ xmlNodePtr xnode = NULL;
891
+
892
+ /* At this point we need to wrap the reader's document as explained above. */
893
+ rxml_document_wrap(xmlTextReaderCurrentDoc(xreader));
894
+
895
+ /* And now hook in a mark function */
896
+ RDATA(self)->dmark = (RUBY_DATA_FUNC)rxml_reader_mark;
897
+
898
+ xnode = xmlTextReaderExpand(xreader);
877
899
 
878
900
  if (!xnode)
879
901
  {
@@ -1,9 +1,9 @@
1
1
  /* Don't nuke this block! It is used for automatically updating the
2
2
  * versions below. VERSION = string formatting, VERNUM = numbered
3
3
  * version for inline testing: increment both or none at all.*/
4
- #define RUBY_LIBXML_VERSION "2.0.9"
5
- #define RUBY_LIBXML_VERNUM 209
4
+ #define RUBY_LIBXML_VERSION "2.1.0"
5
+ #define RUBY_LIBXML_VERNUM 210
6
6
  #define RUBY_LIBXML_VER_MAJ 2
7
- #define RUBY_LIBXML_VER_MIN 0
8
- #define RUBY_LIBXML_VER_MIC 9
7
+ #define RUBY_LIBXML_VER_MIN 1
8
+ #define RUBY_LIBXML_VER_MIC 0
9
9
  #define RUBY_LIBXML_VER_PATCH 0
@@ -78,6 +78,88 @@
78
78
 
79
79
  VALUE mXPath;
80
80
 
81
+ VALUE
82
+ rxml_xpath_to_value(xmlXPathContextPtr xctxt, xmlXPathObjectPtr xobject) {
83
+ VALUE result;
84
+ int type;
85
+
86
+ if (xobject == NULL) {
87
+ /* xmlLastError is different than xctxt->lastError. Use
88
+ xmlLastError since it has the message set while xctxt->lastError
89
+ does not. */
90
+ xmlErrorPtr xerror = xmlGetLastError();
91
+ rxml_raise(xerror);
92
+ }
93
+
94
+ switch (type = xobject->type) {
95
+ case XPATH_NODESET:
96
+ result = rxml_xpath_object_wrap(xctxt->doc, xobject);
97
+ break;
98
+ case XPATH_BOOLEAN:
99
+ result = (xobject->boolval != 0) ? Qtrue : Qfalse;
100
+ xmlXPathFreeObject(xobject);
101
+ break;
102
+ case XPATH_NUMBER:
103
+ result = rb_float_new(xobject->floatval);
104
+ xmlXPathFreeObject(xobject);
105
+ break;
106
+ case XPATH_STRING:
107
+ result = rxml_str_new2((const char*)xobject->stringval, xctxt->doc->encoding);
108
+ xmlXPathFreeObject(xobject);
109
+ break;
110
+ default:
111
+ xmlXPathFreeObject(xobject);
112
+ rb_raise(rb_eTypeError,
113
+ "can't convert XPath object of type %d to Ruby value", type
114
+ );
115
+ }
116
+
117
+ return result;
118
+ }
119
+
120
+ xmlXPathObjectPtr
121
+ rxml_xpath_from_value(VALUE value) {
122
+ xmlXPathObjectPtr result = NULL;
123
+
124
+ switch (TYPE(value)) {
125
+ case T_TRUE:
126
+ case T_FALSE:
127
+ result = xmlXPathNewBoolean(RTEST(value));
128
+ break;
129
+ case T_FIXNUM:
130
+ case T_FLOAT:
131
+ result = xmlXPathNewFloat(NUM2DBL(value));
132
+ break;
133
+ case T_STRING:
134
+ result = xmlXPathWrapString(xmlStrdup((const xmlChar *)StringValuePtr(value)));
135
+ break;
136
+ case T_NIL:
137
+ result = xmlXPathNewNodeSet(NULL);
138
+ break;
139
+ case T_ARRAY: {
140
+ int i, j;
141
+ result = xmlXPathNewNodeSet(NULL);
142
+
143
+ for (i = RARRAY_LEN(value); i > 0; i--) {
144
+ xmlXPathObjectPtr obj = rxml_xpath_from_value(rb_ary_shift(value));
145
+
146
+ if ((obj->nodesetval != NULL) && (obj->nodesetval->nodeNr != 0)) {
147
+ for (j = 0; j < obj->nodesetval->nodeNr; j++) {
148
+ xmlXPathNodeSetAdd(result->nodesetval, obj->nodesetval->nodeTab[j]);
149
+ }
150
+ }
151
+ }
152
+ break;
153
+ }
154
+ default:
155
+ rb_raise(rb_eTypeError,
156
+ "can't convert object of type %s to XPath object", rb_obj_classname(value)
157
+ );
158
+ }
159
+
160
+ return result;
161
+ }
162
+
81
163
  void rxml_init_xpath(void)
82
164
  {
83
165
  mXPath = rb_define_module_under(mXML, "XPath");
@@ -5,6 +5,9 @@
5
5
 
6
6
  extern VALUE mXPath;
7
7
 
8
+ extern VALUE rxml_xpath_to_value(xmlXPathContextPtr, xmlXPathObjectPtr);
9
+ extern xmlXPathObjectPtr rxml_xpath_from_value(VALUE);
10
+
8
11
  void rxml_init_xpath(void);
9
12
 
10
13
  #endif
@@ -26,16 +26,20 @@
26
26
 
27
27
  VALUE cXMLXPathContext;
28
28
 
29
- static ID DOC_ATTRIBUTE;
30
-
31
29
  static void rxml_xpath_context_free(xmlXPathContextPtr ctxt)
32
30
  {
33
31
  xmlXPathFreeContext(ctxt);
34
32
  }
35
33
 
34
+ static void rxml_xpath_context_mark(xmlXPathContextPtr ctxt)
35
+ {
36
+ if (ctxt->doc->_private)
37
+ rb_gc_mark((VALUE) ctxt->doc->_private);
38
+ }
39
+
36
40
  static VALUE rxml_xpath_context_alloc(VALUE klass)
37
41
  {
38
- return Data_Wrap_Struct(cXMLXPathContext, NULL, rxml_xpath_context_free, NULL);
42
+ return Data_Wrap_Struct(cXMLXPathContext, rxml_xpath_context_mark, rxml_xpath_context_free, NULL);
39
43
  }
40
44
 
41
45
  /* call-seq:
@@ -72,12 +76,25 @@ static VALUE rxml_xpath_context_initialize(VALUE self, VALUE node)
72
76
  Data_Get_Struct(document, xmlDoc, xdoc);
73
77
  DATA_PTR(self) = xmlXPathNewContext(xdoc);
74
78
 
75
- /* Save the doc as an attribute, this will expose it to Ruby's GC. */
76
- rb_ivar_set(self, DOC_ATTRIBUTE, document);
77
-
78
79
  return self;
79
80
  }
80
81
 
82
+ /*
83
+ * call-seq:
84
+ * context.doc -> document
85
+ *
86
+ * Obtain the XML::Document this node belongs to.
87
+ */
88
+ static VALUE rxml_xpath_context_doc(VALUE self)
89
+ {
90
+ xmlDocPtr xdoc = NULL;
91
+ xmlXPathContextPtr ctxt;
92
+ Data_Get_Struct(self, xmlXPathContext, ctxt);
93
+
94
+ xdoc = ctxt->doc;
95
+ return rxml_document_wrap(xdoc);
96
+ }
97
+
81
98
  /*
82
99
  * call-seq:
83
100
  * context.register_namespace(prefix, uri) -> (true|false)
@@ -264,7 +281,6 @@ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr)
264
281
  xmlXPathContextPtr xctxt;
265
282
  xmlXPathObjectPtr xobject;
266
283
  xmlXPathCompExprPtr xcompexpr;
267
- VALUE result;
268
284
 
269
285
  Data_Get_Struct(self, xmlXPathContext, xctxt);
270
286
 
@@ -284,37 +300,7 @@ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr)
284
300
  "Argument should be an intance of a String or XPath::Expression");
285
301
  }
286
302
 
287
- if (xobject == NULL)
288
- {
289
- /* xmlLastError is different than xctxt->lastError. Use
290
- xmlLastError since it has the message set while xctxt->lastError
291
- does not. */
292
- xmlErrorPtr xerror = xmlGetLastError();
293
- rxml_raise(xerror);
294
- }
295
-
296
- switch (xobject->type)
297
- {
298
- case XPATH_NODESET:
299
- result = rxml_xpath_object_wrap(xctxt->doc, xobject);
300
- break;
301
- case XPATH_BOOLEAN:
302
- result = (xobject->boolval != 0) ? Qtrue : Qfalse;
303
- xmlXPathFreeObject(xobject);
304
- break;
305
- case XPATH_NUMBER:
306
- result = rb_float_new(xobject->floatval);
307
- xmlXPathFreeObject(xobject);
308
- break;
309
- case XPATH_STRING:
310
- result = rxml_str_new2((const char*)xobject->stringval, xctxt->doc->encoding);
311
- xmlXPathFreeObject(xobject);
312
- break;
313
- default:
314
- result = Qnil;
315
- xmlXPathFreeObject(xobject);
316
- }
317
- return result;
303
+ return rxml_xpath_to_value(xctxt, xobject);
318
304
  }
319
305
 
320
306
  #if LIBXML_VERSION >= 20626
@@ -370,11 +356,9 @@ rxml_xpath_context_disable_cache(VALUE self)
370
356
 
371
357
  void rxml_init_xpath_context(void)
372
358
  {
373
- DOC_ATTRIBUTE = rb_intern("@doc");
374
-
375
359
  cXMLXPathContext = rb_define_class_under(mXPath, "Context", rb_cObject);
376
360
  rb_define_alloc_func(cXMLXPathContext, rxml_xpath_context_alloc);
377
- rb_define_attr(cXMLXPathContext, "doc", 1, 0);
361
+ rb_define_method(cXMLXPathContext, "doc", rxml_xpath_context_doc, 0);
378
362
  rb_define_method(cXMLXPathContext, "initialize", rxml_xpath_context_initialize, 1);
379
363
  rb_define_method(cXMLXPathContext, "register_namespaces", rxml_xpath_context_register_namespaces, 1);
380
364
  rb_define_method(cXMLXPathContext, "register_namespaces_from_node", rxml_xpath_context_register_namespaces_from_node, 1);
@@ -45,7 +45,6 @@ static void rxml_xpath_object_free(rxml_xpath_object *rxpop)
45
45
  /* Custom free function for copied namespace nodes */
46
46
  static void rxml_namespace_xpath_free(xmlNsPtr xns)
47
47
  {
48
- xns->_private = NULL;
49
48
  xmlFreeNs(xns);
50
49
  }
51
50
 
@@ -82,7 +81,8 @@ VALUE rxml_xpath_object_wrap(xmlDocPtr xdoc, xmlXPathObjectPtr xpop)
82
81
 
83
82
  /* Specify a custom free function here since by default
84
83
  namespace nodes will not be freed */
85
- ns = rxml_namespace_wrap((xmlNsPtr)xnode, (RUBY_DATA_FUNC)rxml_namespace_xpath_free);
84
+ ns = rxml_namespace_wrap((xmlNsPtr)xnode);
85
+ RDATA(ns)->dfree = (RUBY_DATA_FUNC)rxml_namespace_xpath_free;
86
86
  rb_ary_push(rxpop->nsnodes, ns);
87
87
  }
88
88
  }
@@ -93,7 +93,6 @@ VALUE rxml_xpath_object_wrap(xmlDocPtr xdoc, xmlXPathObjectPtr xpop)
93
93
 
94
94
  static VALUE rxml_xpath_object_tabref(xmlXPathObjectPtr xpop, int apos)
95
95
  {
96
-
97
96
  if (apos < 0)
98
97
  apos = xpop->nodesetval->nodeNr + apos;
99
98
 
@@ -106,7 +105,7 @@ static VALUE rxml_xpath_object_tabref(xmlXPathObjectPtr xpop, int apos)
106
105
  return rxml_attr_wrap((xmlAttrPtr) xpop->nodesetval->nodeTab[apos]);
107
106
  break;
108
107
  case XML_NAMESPACE_DECL:
109
- return rxml_namespace_wrap((xmlNsPtr)xpop->nodesetval->nodeTab[apos], NULL);
108
+ return rxml_namespace_wrap((xmlNsPtr)xpop->nodesetval->nodeTab[apos]);
110
109
  break;
111
110
  default:
112
111
  return rxml_node_wrap(xpop->nodesetval->nodeTab[apos]);
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ require 'rake'
2
3
 
3
4
  # Determine the current version of the software
4
5
  version = File.read('ext/libxml/ruby_xml_version.h').match(/\s*RUBY_LIBXML_VERSION\s*['"](\d.+)['"]/)[1]
@@ -27,6 +27,7 @@ class AttrNodeTest < Test::Unit::TestCase
27
27
 
28
28
  def teardown
29
29
  @doc = nil
30
+ GC.start
30
31
  end
31
32
 
32
33
  def city_member
@@ -37,117 +38,118 @@ class AttrNodeTest < Test::Unit::TestCase
37
38
  assert_not_nil(@doc)
38
39
  assert_equal(XML::Encoding::NONE, @doc.encoding)
39
40
  end
40
-
41
+
41
42
  def test_types
42
43
  attribute = city_member.attributes.get_attribute('name')
43
44
  assert_instance_of(XML::Attr, attribute)
44
45
  assert_equal('attribute', attribute.node_type_name)
45
46
  end
46
-
47
+
47
48
  def test_name
48
49
  attribute = city_member.attributes.get_attribute('name')
49
50
  assert_equal('name', attribute.name)
50
51
  assert_equal(Encoding::ASCII_8BIT, attribute.name.encoding) if defined?(Encoding)
51
-
52
+
52
53
  attribute = city_member.attributes.get_attribute('href')
53
54
  assert_equal('href', attribute.name)
54
55
  assert_equal('xlink', attribute.ns.prefix)
55
56
  assert_equal('http://www.w3.org/1999/xlink', attribute.ns.href)
56
-
57
+
57
58
  attribute = city_member.attributes.get_attribute_ns('http://www.w3.org/1999/xlink', 'href')
58
59
  assert_equal('href', attribute.name)
59
60
  assert_equal('xlink', attribute.ns.prefix)
60
61
  assert_equal('http://www.w3.org/1999/xlink', attribute.ns.href)
61
62
  end
62
-
63
+
63
64
  def test_value
64
65
  attribute = city_member.attributes.get_attribute('name')
65
66
  assert_equal('Cambridge', attribute.value)
66
67
  assert_equal(Encoding::ASCII_8BIT, attribute.value.encoding) if defined?(Encoding)
67
-
68
+
68
69
  attribute = city_member.attributes.get_attribute('href')
69
70
  assert_equal('http://www.foo.net/cgi-bin/wfs?FeatureID=C10239', attribute.value)
70
71
  end
71
-
72
+
72
73
  def test_set_value
73
74
  attribute = city_member.attributes.get_attribute('name')
74
75
  attribute.value = 'London'
75
76
  assert_equal('London', attribute.value)
76
77
  assert_equal(Encoding::ASCII_8BIT, attribute.value.encoding) if defined?(Encoding)
77
-
78
+
78
79
  attribute = city_member.attributes.get_attribute('href')
79
80
  attribute.value = 'http://i.have.changed'
80
81
  assert_equal('http://i.have.changed', attribute.value)
81
82
  assert_equal(Encoding::ASCII_8BIT, attribute.value.encoding) if defined?(Encoding)
82
83
  end
83
-
84
+
84
85
  def test_set_nil
85
86
  attribute = city_member.attributes.get_attribute('name')
86
87
  assert_raise(TypeError) do
87
88
  attribute.value = nil
88
89
  end
89
90
  end
90
-
91
+
91
92
  def test_create
92
93
  attributes = city_member.attributes
93
94
  assert_equal(5, attributes.length)
94
-
95
+
95
96
  attr = XML::Attr.new(city_member, 'size', '50,000')
96
97
  assert_instance_of(XML::Attr, attr)
97
-
98
+
98
99
  attributes = city_member.attributes
99
100
  assert_equal(6, attributes.length)
100
-
101
+
101
102
  assert_equal(attributes['size'], '50,000')
102
103
  end
103
-
104
+
104
105
  def test_create_on_node
105
106
  attributes = city_member.attributes
106
107
  assert_equal(5, attributes.length)
107
-
108
+
108
109
  attributes['country'] = 'England'
109
-
110
+
110
111
  attributes = city_member.attributes
111
112
  assert_equal(6, attributes.length)
112
-
113
+
113
114
  assert_equal(attributes['country'], 'England')
114
115
  end
115
-
116
+
116
117
  def test_create_ns
117
118
  assert_equal(5, city_member.attributes.length)
118
-
119
+
119
120
  ns = XML::Namespace.new(city_member, 'my_namepace', 'http://www.mynamespace.com')
120
121
  attr = XML::Attr.new(city_member, 'rating', 'rocks', ns)
121
122
  assert_instance_of(XML::Attr, attr)
122
123
  assert_equal('rating', attr.name)
123
124
  assert_equal('rocks', attr.value)
124
-
125
+
125
126
  attributes = city_member.attributes
126
127
  assert_equal(6, attributes.length)
127
-
128
+
128
129
  assert_equal('rocks', city_member['rating'])
129
130
  end
130
131
 
131
132
  def test_remove
132
133
  attributes = city_member.attributes
133
134
  assert_equal(5, attributes.length)
134
-
135
+
135
136
  attribute = attributes.get_attribute('name')
136
137
  assert_not_nil(attribute.parent)
137
138
  assert(attribute.parent?)
138
-
139
+
139
140
  attribute.remove!
140
141
  assert_equal(4, attributes.length)
141
- assert_nil(attribute.parent)
142
- assert(!attribute.parent?)
142
+
143
+ attribute = attributes.get_attribute('name')
144
+ assert_nil(attribute)
143
145
  end
144
-
146
+
145
147
  def test_first
146
148
  attribute = city_member.attributes.first
147
149
  assert_instance_of(XML::Attr, attribute)
148
150
  assert_equal('name', attribute.name)
149
151
  assert_equal('Cambridge', attribute.value)
150
-
152
+
151
153
  attribute = attribute.next
152
154
  assert_instance_of(XML::Attr, attribute)
153
155
  assert_equal('type', attribute.name)
@@ -157,7 +159,7 @@ class AttrNodeTest < Test::Unit::TestCase
157
159
  assert_instance_of(XML::Attr, attribute)
158
160
  assert_equal('title', attribute.name)
159
161
  assert_equal('Trinity Lane', attribute.value)
160
-
162
+
161
163
  attribute = attribute.next
162
164
  assert_instance_of(XML::Attr, attribute)
163
165
  assert_equal('href', attribute.name)
@@ -167,7 +169,7 @@ class AttrNodeTest < Test::Unit::TestCase
167
169
  assert_instance_of(XML::Attr, attribute)
168
170
  assert_equal('remoteSchema', attribute.name)
169
171
  assert_equal("city.xsd#xpointer(//complexType[@name='RoadType'])", attribute.value)
170
-
172
+
171
173
  attribute = attribute.next
172
174
  assert_nil(attribute)
173
175
  end
@@ -6,7 +6,7 @@ require 'test/unit'
6
6
  class AttributesTest < Test::Unit::TestCase
7
7
  def setup
8
8
  xp = XML::Parser.string(<<-EOS)
9
- <CityModel
9
+ <CityModel name="value"
10
10
  xmlns="http://www.opengis.net/examples"
11
11
  xmlns:city="http://www.opengis.net/examples"
12
12
  xmlns:gml="http://www.opengis.net/gml"
@@ -90,6 +90,14 @@ class AttributesTest < Test::Unit::TestCase
90
90
  assert_equal('http://www.foo.net/cgi-bin/wfs?FeatureID=C10239', attributes[:href])
91
91
  end
92
92
 
93
+ def test_get_values_gc
94
+ # There used to be a bug caused by accessing an
95
+ # attribute over and over and over again.
96
+ 20000.times do
97
+ @doc.root.attributes["key"]
98
+ end
99
+ end
100
+
93
101
  def test_set_values
94
102
  city_member[:name] = 'London'
95
103
  assert_equal('London', city_member[:name])
@@ -34,6 +34,22 @@ class TestParserContext < Test::Unit::TestCase
34
34
  assert_equal(XML::Encoding::ISO_8859_1, context.encoding)
35
35
  end
36
36
 
37
+ def test_invalid_encoding
38
+ # UTF8
39
+ xml = <<-EOS
40
+ <bands>
41
+ <metal>m\303\266tley_cr\303\274e</metal>
42
+ </bands>
43
+ EOS
44
+
45
+ context = XML::Parser::Context.string(xml)
46
+
47
+ error = assert_raise(ArgumentError) do
48
+ context.encoding = -999
49
+ end
50
+ assert_equal("Unknown encoding: -999", error.to_s)
51
+ end
52
+
37
53
  def test_base_uri
38
54
  # UTF8
39
55
  xml = <<-EOS
@@ -51,7 +67,7 @@ class TestParserContext < Test::Unit::TestCase
51
67
 
52
68
  def test_string_empty
53
69
  error = assert_raise(TypeError) do
54
- parser = XML::Parser::Context.string(nil)
70
+ XML::Parser::Context.string(nil)
55
71
  end
56
72
  assert_equal("wrong argument type nil (expected String)", error.to_s)
57
73
 
@@ -171,12 +171,33 @@ class TestReader < Test::Unit::TestCase
171
171
  node = reader.expand
172
172
  assert_equal('feed', node.name)
173
173
  assert_equal(::Encoding::UTF_8, node.name.encoding) if defined?(::Encoding)
174
+ end
175
+
176
+ def test_expand_doc
177
+ reader = XML::Reader.file(XML_FILE)
178
+ reader.read.to_s
179
+ reader.read
180
+
181
+ # Read a node
182
+ node = reader.expand
174
183
 
175
184
  # Try to access the document
176
- error = assert_raise(XML::Error) do
177
- assert_not_nil(node.doc)
178
- end
179
- assert_equal(" Document is not accessible to Ruby (hint - did you call Reader#expand?).", error.to_s)
185
+ assert_not_nil(node.doc)
186
+ end
187
+
188
+ def test_expand_find
189
+ reader = XML::Reader.file(XML_FILE)
190
+ reader.read.to_s
191
+ reader.read
192
+
193
+ # Read first node which
194
+ node = reader.expand
195
+ assert_equal('feed', node.name)
196
+
197
+ # Search for entries
198
+ entries = node.find('atom:entry', 'atom:http://www.w3.org/2005/Atom')
199
+
200
+ assert_equal(1, entries.length)
180
201
  end
181
202
 
182
203
  def test_mode
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libxml-ruby
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
+ - 1
8
9
  - 0
9
- - 9
10
- version: 2.0.9
10
+ version: 2.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ross Bamform
@@ -20,7 +20,7 @@ autorequire:
20
20
  bindir: bin
21
21
  cert_chain: []
22
22
 
23
- date: 2011-06-25 00:00:00 Z
23
+ date: 2011-07-31 00:00:00 Z
24
24
  dependencies: []
25
25
 
26
26
  description: " The Libxml-Ruby project provides Ruby language bindings for the GNOME\n Libxml2 XML toolkit. It is free software, released under the MIT License.\n Libxml-ruby's primary advantage over REXML is performance - if speed\n is your need, these are good libraries to consider, as demonstrated\n by the informal benchmark below.\n"
@@ -222,7 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
222
  requirements: []
223
223
 
224
224
  rubyforge_project:
225
- rubygems_version: 1.7.2
225
+ rubygems_version: 1.8.6
226
226
  signing_key:
227
227
  specification_version: 3
228
228
  summary: Ruby Bindings for LibXML2