nokogiri-fitzsimmons 1.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (237) hide show
  1. data/.autotest +26 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.ja.rdoc +666 -0
  4. data/CHANGELOG.rdoc +659 -0
  5. data/C_CODING_STYLE.rdoc +33 -0
  6. data/Manifest.txt +295 -0
  7. data/README.ja.rdoc +106 -0
  8. data/README.rdoc +178 -0
  9. data/ROADMAP.md +86 -0
  10. data/Rakefile +194 -0
  11. data/STANDARD_RESPONSES.md +47 -0
  12. data/Y_U_NO_GEMSPEC.md +155 -0
  13. data/bin/nokogiri +63 -0
  14. data/build_all +58 -0
  15. data/ext/nokogiri/depend +358 -0
  16. data/ext/nokogiri/extconf.rb +142 -0
  17. data/ext/nokogiri/html_document.c +170 -0
  18. data/ext/nokogiri/html_document.h +10 -0
  19. data/ext/nokogiri/html_element_description.c +276 -0
  20. data/ext/nokogiri/html_element_description.h +10 -0
  21. data/ext/nokogiri/html_entity_lookup.c +32 -0
  22. data/ext/nokogiri/html_entity_lookup.h +8 -0
  23. data/ext/nokogiri/html_sax_parser_context.c +116 -0
  24. data/ext/nokogiri/html_sax_parser_context.h +11 -0
  25. data/ext/nokogiri/html_sax_push_parser.c +87 -0
  26. data/ext/nokogiri/html_sax_push_parser.h +9 -0
  27. data/ext/nokogiri/nokogiri.c +133 -0
  28. data/ext/nokogiri/nokogiri.h +160 -0
  29. data/ext/nokogiri/xml_attr.c +94 -0
  30. data/ext/nokogiri/xml_attr.h +9 -0
  31. data/ext/nokogiri/xml_attribute_decl.c +70 -0
  32. data/ext/nokogiri/xml_attribute_decl.h +9 -0
  33. data/ext/nokogiri/xml_cdata.c +56 -0
  34. data/ext/nokogiri/xml_cdata.h +9 -0
  35. data/ext/nokogiri/xml_comment.c +54 -0
  36. data/ext/nokogiri/xml_comment.h +9 -0
  37. data/ext/nokogiri/xml_document.c +576 -0
  38. data/ext/nokogiri/xml_document.h +23 -0
  39. data/ext/nokogiri/xml_document_fragment.c +48 -0
  40. data/ext/nokogiri/xml_document_fragment.h +10 -0
  41. data/ext/nokogiri/xml_dtd.c +202 -0
  42. data/ext/nokogiri/xml_dtd.h +10 -0
  43. data/ext/nokogiri/xml_element_content.c +123 -0
  44. data/ext/nokogiri/xml_element_content.h +10 -0
  45. data/ext/nokogiri/xml_element_decl.c +69 -0
  46. data/ext/nokogiri/xml_element_decl.h +9 -0
  47. data/ext/nokogiri/xml_encoding_handler.c +79 -0
  48. data/ext/nokogiri/xml_encoding_handler.h +8 -0
  49. data/ext/nokogiri/xml_entity_decl.c +110 -0
  50. data/ext/nokogiri/xml_entity_decl.h +10 -0
  51. data/ext/nokogiri/xml_entity_reference.c +52 -0
  52. data/ext/nokogiri/xml_entity_reference.h +9 -0
  53. data/ext/nokogiri/xml_io.c +56 -0
  54. data/ext/nokogiri/xml_io.h +11 -0
  55. data/ext/nokogiri/xml_libxml2_hacks.c +112 -0
  56. data/ext/nokogiri/xml_libxml2_hacks.h +12 -0
  57. data/ext/nokogiri/xml_namespace.c +78 -0
  58. data/ext/nokogiri/xml_namespace.h +13 -0
  59. data/ext/nokogiri/xml_node.c +1480 -0
  60. data/ext/nokogiri/xml_node.h +13 -0
  61. data/ext/nokogiri/xml_node_set.c +467 -0
  62. data/ext/nokogiri/xml_node_set.h +14 -0
  63. data/ext/nokogiri/xml_processing_instruction.c +56 -0
  64. data/ext/nokogiri/xml_processing_instruction.h +9 -0
  65. data/ext/nokogiri/xml_reader.c +684 -0
  66. data/ext/nokogiri/xml_reader.h +10 -0
  67. data/ext/nokogiri/xml_relax_ng.c +161 -0
  68. data/ext/nokogiri/xml_relax_ng.h +9 -0
  69. data/ext/nokogiri/xml_sax_parser.c +293 -0
  70. data/ext/nokogiri/xml_sax_parser.h +39 -0
  71. data/ext/nokogiri/xml_sax_parser_context.c +222 -0
  72. data/ext/nokogiri/xml_sax_parser_context.h +10 -0
  73. data/ext/nokogiri/xml_sax_push_parser.c +115 -0
  74. data/ext/nokogiri/xml_sax_push_parser.h +9 -0
  75. data/ext/nokogiri/xml_schema.c +205 -0
  76. data/ext/nokogiri/xml_schema.h +9 -0
  77. data/ext/nokogiri/xml_syntax_error.c +58 -0
  78. data/ext/nokogiri/xml_syntax_error.h +13 -0
  79. data/ext/nokogiri/xml_text.c +52 -0
  80. data/ext/nokogiri/xml_text.h +9 -0
  81. data/ext/nokogiri/xml_xpath_context.c +319 -0
  82. data/ext/nokogiri/xml_xpath_context.h +10 -0
  83. data/ext/nokogiri/xslt_stylesheet.c +270 -0
  84. data/ext/nokogiri/xslt_stylesheet.h +14 -0
  85. data/lib/nokogiri.rb +127 -0
  86. data/lib/nokogiri/css.rb +27 -0
  87. data/lib/nokogiri/css/node.rb +102 -0
  88. data/lib/nokogiri/css/parser.rb +720 -0
  89. data/lib/nokogiri/css/parser.y +258 -0
  90. data/lib/nokogiri/css/parser_extras.rb +91 -0
  91. data/lib/nokogiri/css/syntax_error.rb +7 -0
  92. data/lib/nokogiri/css/tokenizer.rb +152 -0
  93. data/lib/nokogiri/css/tokenizer.rex +55 -0
  94. data/lib/nokogiri/css/xpath_visitor.rb +171 -0
  95. data/lib/nokogiri/decorators/slop.rb +35 -0
  96. data/lib/nokogiri/html.rb +37 -0
  97. data/lib/nokogiri/html/builder.rb +35 -0
  98. data/lib/nokogiri/html/document.rb +254 -0
  99. data/lib/nokogiri/html/document_fragment.rb +41 -0
  100. data/lib/nokogiri/html/element_description.rb +23 -0
  101. data/lib/nokogiri/html/element_description_defaults.rb +671 -0
  102. data/lib/nokogiri/html/entity_lookup.rb +13 -0
  103. data/lib/nokogiri/html/sax/parser.rb +52 -0
  104. data/lib/nokogiri/html/sax/parser_context.rb +16 -0
  105. data/lib/nokogiri/html/sax/push_parser.rb +16 -0
  106. data/lib/nokogiri/syntax_error.rb +4 -0
  107. data/lib/nokogiri/version.rb +88 -0
  108. data/lib/nokogiri/xml.rb +73 -0
  109. data/lib/nokogiri/xml/attr.rb +14 -0
  110. data/lib/nokogiri/xml/attribute_decl.rb +18 -0
  111. data/lib/nokogiri/xml/builder.rb +431 -0
  112. data/lib/nokogiri/xml/cdata.rb +11 -0
  113. data/lib/nokogiri/xml/character_data.rb +7 -0
  114. data/lib/nokogiri/xml/document.rb +267 -0
  115. data/lib/nokogiri/xml/document_fragment.rb +103 -0
  116. data/lib/nokogiri/xml/dtd.rb +22 -0
  117. data/lib/nokogiri/xml/element_content.rb +36 -0
  118. data/lib/nokogiri/xml/element_decl.rb +13 -0
  119. data/lib/nokogiri/xml/entity_decl.rb +19 -0
  120. data/lib/nokogiri/xml/namespace.rb +13 -0
  121. data/lib/nokogiri/xml/node.rb +946 -0
  122. data/lib/nokogiri/xml/node/save_options.rb +61 -0
  123. data/lib/nokogiri/xml/node_set.rb +357 -0
  124. data/lib/nokogiri/xml/notation.rb +6 -0
  125. data/lib/nokogiri/xml/parse_options.rb +98 -0
  126. data/lib/nokogiri/xml/pp.rb +2 -0
  127. data/lib/nokogiri/xml/pp/character_data.rb +18 -0
  128. data/lib/nokogiri/xml/pp/node.rb +56 -0
  129. data/lib/nokogiri/xml/processing_instruction.rb +8 -0
  130. data/lib/nokogiri/xml/reader.rb +112 -0
  131. data/lib/nokogiri/xml/relax_ng.rb +32 -0
  132. data/lib/nokogiri/xml/sax.rb +4 -0
  133. data/lib/nokogiri/xml/sax/document.rb +164 -0
  134. data/lib/nokogiri/xml/sax/parser.rb +115 -0
  135. data/lib/nokogiri/xml/sax/parser_context.rb +16 -0
  136. data/lib/nokogiri/xml/sax/push_parser.rb +60 -0
  137. data/lib/nokogiri/xml/schema.rb +63 -0
  138. data/lib/nokogiri/xml/syntax_error.rb +47 -0
  139. data/lib/nokogiri/xml/text.rb +9 -0
  140. data/lib/nokogiri/xml/xpath.rb +10 -0
  141. data/lib/nokogiri/xml/xpath/syntax_error.rb +11 -0
  142. data/lib/nokogiri/xml/xpath_context.rb +16 -0
  143. data/lib/nokogiri/xslt.rb +56 -0
  144. data/lib/nokogiri/xslt/stylesheet.rb +25 -0
  145. data/lib/xsd/xmlparser/nokogiri.rb +90 -0
  146. data/tasks/cross_compile.rb +153 -0
  147. data/tasks/nokogiri.org.rb +24 -0
  148. data/tasks/test.rb +95 -0
  149. data/test/css/test_nthiness.rb +159 -0
  150. data/test/css/test_parser.rb +341 -0
  151. data/test/css/test_tokenizer.rb +198 -0
  152. data/test/css/test_xpath_visitor.rb +91 -0
  153. data/test/decorators/test_slop.rb +16 -0
  154. data/test/files/2ch.html +108 -0
  155. data/test/files/address_book.rlx +12 -0
  156. data/test/files/address_book.xml +10 -0
  157. data/test/files/bar/bar.xsd +4 -0
  158. data/test/files/dont_hurt_em_why.xml +422 -0
  159. data/test/files/encoding.html +82 -0
  160. data/test/files/encoding.xhtml +84 -0
  161. data/test/files/exslt.xml +8 -0
  162. data/test/files/exslt.xslt +35 -0
  163. data/test/files/foo/foo.xsd +4 -0
  164. data/test/files/metacharset.html +10 -0
  165. data/test/files/noencoding.html +47 -0
  166. data/test/files/po.xml +32 -0
  167. data/test/files/po.xsd +66 -0
  168. data/test/files/shift_jis.html +10 -0
  169. data/test/files/shift_jis.xml +5 -0
  170. data/test/files/snuggles.xml +3 -0
  171. data/test/files/staff.dtd +10 -0
  172. data/test/files/staff.xml +59 -0
  173. data/test/files/staff.xslt +32 -0
  174. data/test/files/tlm.html +850 -0
  175. data/test/files/to_be_xincluded.xml +2 -0
  176. data/test/files/valid_bar.xml +2 -0
  177. data/test/files/xinclude.xml +4 -0
  178. data/test/helper.rb +147 -0
  179. data/test/html/sax/test_parser.rb +138 -0
  180. data/test/html/sax/test_parser_context.rb +46 -0
  181. data/test/html/test_builder.rb +164 -0
  182. data/test/html/test_document.rb +529 -0
  183. data/test/html/test_document_encoding.rb +138 -0
  184. data/test/html/test_document_fragment.rb +254 -0
  185. data/test/html/test_element_description.rb +100 -0
  186. data/test/html/test_named_characters.rb +14 -0
  187. data/test/html/test_node.rb +188 -0
  188. data/test/html/test_node_encoding.rb +27 -0
  189. data/test/test_convert_xpath.rb +135 -0
  190. data/test/test_css_cache.rb +45 -0
  191. data/test/test_encoding_handler.rb +46 -0
  192. data/test/test_memory_leak.rb +152 -0
  193. data/test/test_nokogiri.rb +132 -0
  194. data/test/test_reader.rb +488 -0
  195. data/test/test_soap4r_sax.rb +52 -0
  196. data/test/test_xslt_transforms.rb +254 -0
  197. data/test/xml/node/test_save_options.rb +28 -0
  198. data/test/xml/node/test_subclass.rb +44 -0
  199. data/test/xml/sax/test_parser.rb +338 -0
  200. data/test/xml/sax/test_parser_context.rb +106 -0
  201. data/test/xml/sax/test_push_parser.rb +157 -0
  202. data/test/xml/test_attr.rb +64 -0
  203. data/test/xml/test_attribute_decl.rb +86 -0
  204. data/test/xml/test_builder.rb +248 -0
  205. data/test/xml/test_c14n.rb +151 -0
  206. data/test/xml/test_cdata.rb +48 -0
  207. data/test/xml/test_comment.rb +29 -0
  208. data/test/xml/test_document.rb +742 -0
  209. data/test/xml/test_document_encoding.rb +28 -0
  210. data/test/xml/test_document_fragment.rb +216 -0
  211. data/test/xml/test_dtd.rb +103 -0
  212. data/test/xml/test_dtd_encoding.rb +33 -0
  213. data/test/xml/test_element_content.rb +56 -0
  214. data/test/xml/test_element_decl.rb +73 -0
  215. data/test/xml/test_entity_decl.rb +122 -0
  216. data/test/xml/test_entity_reference.rb +235 -0
  217. data/test/xml/test_namespace.rb +75 -0
  218. data/test/xml/test_node.rb +1029 -0
  219. data/test/xml/test_node_attributes.rb +53 -0
  220. data/test/xml/test_node_encoding.rb +107 -0
  221. data/test/xml/test_node_inheritance.rb +32 -0
  222. data/test/xml/test_node_reparenting.rb +374 -0
  223. data/test/xml/test_node_set.rb +755 -0
  224. data/test/xml/test_parse_options.rb +64 -0
  225. data/test/xml/test_processing_instruction.rb +30 -0
  226. data/test/xml/test_reader_encoding.rb +142 -0
  227. data/test/xml/test_relax_ng.rb +60 -0
  228. data/test/xml/test_schema.rb +94 -0
  229. data/test/xml/test_syntax_error.rb +12 -0
  230. data/test/xml/test_text.rb +45 -0
  231. data/test/xml/test_unparented_node.rb +413 -0
  232. data/test/xml/test_xinclude.rb +83 -0
  233. data/test/xml/test_xpath.rb +295 -0
  234. data/test/xslt/test_custom_functions.rb +129 -0
  235. data/test/xslt/test_exception_handling.rb +37 -0
  236. data/test_all +84 -0
  237. metadata +534 -0
@@ -0,0 +1,12 @@
1
+ #ifndef HAVE_XMLFIRSTELEMENTCHILD
2
+
3
+ #ifndef XML_LIBXML2_HACKS
4
+ #define XML_LIBXML2_HACKS
5
+
6
+ xmlNodePtr xmlFirstElementChild(xmlNodePtr parent);
7
+ xmlNodePtr xmlNextElementSibling(xmlNodePtr node);
8
+ xmlNodePtr xmlLastElementChild(xmlNodePtr parent);
9
+
10
+ #endif
11
+
12
+ #endif
@@ -0,0 +1,78 @@
1
+ #include <xml_namespace.h>
2
+
3
+ VALUE cNokogiriXmlNamespace ;
4
+
5
+ /*
6
+ * call-seq:
7
+ * prefix
8
+ *
9
+ * Get the prefix for this namespace. Returns +nil+ if there is no prefix.
10
+ */
11
+ static VALUE prefix(VALUE self)
12
+ {
13
+ xmlNsPtr ns;
14
+
15
+ Data_Get_Struct(self, xmlNs, ns);
16
+ if(!ns->prefix) return Qnil;
17
+
18
+ return NOKOGIRI_STR_NEW2(ns->prefix);
19
+ }
20
+
21
+ /*
22
+ * call-seq:
23
+ * href
24
+ *
25
+ * Get the href for this namespace
26
+ */
27
+ static VALUE href(VALUE self)
28
+ {
29
+ xmlNsPtr ns;
30
+
31
+ Data_Get_Struct(self, xmlNs, ns);
32
+ if(!ns->href) return Qnil;
33
+
34
+ return NOKOGIRI_STR_NEW2(ns->href);
35
+ }
36
+
37
+ VALUE Nokogiri_wrap_xml_namespace(xmlDocPtr doc, xmlNsPtr node)
38
+ {
39
+ VALUE ns, document, node_cache;
40
+
41
+ assert(doc->_private);
42
+
43
+ if(node->_private)
44
+ return (VALUE)node->_private;
45
+
46
+ ns = Data_Wrap_Struct(cNokogiriXmlNamespace, 0, 0, node);
47
+
48
+ document = DOC_RUBY_OBJECT(doc);
49
+
50
+ node_cache = rb_iv_get(document, "@node_cache");
51
+ rb_ary_push(node_cache, ns);
52
+
53
+ rb_iv_set(ns, "@document", DOC_RUBY_OBJECT(doc));
54
+
55
+ node->_private = (void *)ns;
56
+
57
+ return ns;
58
+ }
59
+
60
+ VALUE Nokogiri_wrap_xml_namespace2(VALUE document, xmlNsPtr node)
61
+ {
62
+ xmlDocPtr doc;
63
+ Data_Get_Struct(document, xmlDoc, doc) ;
64
+ return Nokogiri_wrap_xml_namespace(doc, node);
65
+ }
66
+
67
+
68
+ void init_xml_namespace()
69
+ {
70
+ VALUE nokogiri = rb_define_module("Nokogiri");
71
+ VALUE xml = rb_define_module_under(nokogiri, "XML");
72
+ VALUE klass = rb_define_class_under(xml, "Namespace", rb_cObject);
73
+
74
+ cNokogiriXmlNamespace = klass;
75
+
76
+ rb_define_method(klass, "prefix", prefix, 0);
77
+ rb_define_method(klass, "href", href, 0);
78
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef NOKOGIRI_XML_NAMESPACE
2
+ #define NOKOGIRI_XML_NAMESPACE
3
+
4
+ #include <nokogiri.h>
5
+
6
+ void init_xml_namespace();
7
+
8
+ extern VALUE cNokogiriXmlNamespace ;
9
+
10
+ VALUE Nokogiri_wrap_xml_namespace(xmlDocPtr doc, xmlNsPtr node) ;
11
+ VALUE Nokogiri_wrap_xml_namespace2(VALUE document, xmlNsPtr node) ;
12
+
13
+ #endif
@@ -0,0 +1,1480 @@
1
+ #include <xml_node.h>
2
+
3
+ static ID decorate, decorate_bang;
4
+
5
+ #ifdef DEBUG
6
+ static void debug_node_dealloc(xmlNodePtr x)
7
+ {
8
+ NOKOGIRI_DEBUG_START(x)
9
+ NOKOGIRI_DEBUG_END(x)
10
+ }
11
+ #else
12
+ # define debug_node_dealloc 0
13
+ #endif
14
+
15
+ static void mark(xmlNodePtr node)
16
+ {
17
+ rb_gc_mark(DOC_RUBY_OBJECT(node->doc));
18
+ }
19
+
20
+ /* :nodoc: */
21
+ typedef xmlNodePtr (*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
22
+
23
+ /* :nodoc: */
24
+ static void relink_namespace(xmlNodePtr reparented)
25
+ {
26
+ xmlNodePtr child;
27
+
28
+ /* Avoid segv when relinking against unlinked nodes. */
29
+ if(!reparented->parent) return;
30
+
31
+ /* Make sure that our reparented node has the correct namespaces */
32
+ if(!reparented->ns && reparented->doc != (xmlDocPtr)reparented->parent)
33
+ xmlSetNs(reparented, reparented->parent->ns);
34
+
35
+ /* Search our parents for an existing definition */
36
+ if(reparented->nsDef) {
37
+ xmlNsPtr curr = reparented->nsDef;
38
+ xmlNsPtr prev = NULL;
39
+
40
+ while(curr) {
41
+ xmlNsPtr ns = xmlSearchNsByHref(
42
+ reparented->doc,
43
+ reparented->parent,
44
+ curr->href
45
+ );
46
+ /* If we find the namespace is already declared, remove it from this
47
+ * definition list. */
48
+ if(ns && ns != curr) {
49
+ if (prev) {
50
+ prev->next = curr->next;
51
+ } else {
52
+ reparented->nsDef = curr->next;
53
+ }
54
+ nokogiri_root_nsdef(curr, reparented->doc);
55
+ } else {
56
+ prev = curr;
57
+ }
58
+ curr = curr->next;
59
+ }
60
+ }
61
+
62
+ /* Only walk all children if there actually is a namespace we need to */
63
+ /* reparent. */
64
+ if(NULL == reparented->ns) return;
65
+
66
+ /* When a node gets reparented, walk it's children to make sure that */
67
+ /* their namespaces are reparented as well. */
68
+ child = reparented->children;
69
+ while(NULL != child) {
70
+ relink_namespace(child);
71
+ child = child->next;
72
+ }
73
+ }
74
+
75
+ /* :nodoc: */
76
+ static xmlNodePtr xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
77
+ {
78
+ xmlNodePtr retval ;
79
+
80
+ retval = xmlReplaceNode(pivot, new_node) ;
81
+
82
+ if (retval == pivot) {
83
+ retval = new_node ; /* return semantics for reparent_node_with */
84
+ }
85
+
86
+ /* work around libxml2 issue: https://bugzilla.gnome.org/show_bug.cgi?id=615612 */
87
+ if (retval->type == XML_TEXT_NODE) {
88
+ if (retval->prev && retval->prev->type == XML_TEXT_NODE) {
89
+ retval = xmlTextMerge(retval->prev, retval);
90
+ }
91
+ if (retval->next && retval->next->type == XML_TEXT_NODE) {
92
+ retval = xmlTextMerge(retval, retval->next);
93
+ }
94
+ }
95
+
96
+ return retval ;
97
+ }
98
+
99
+ /* :nodoc: */
100
+ static VALUE reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
101
+ {
102
+ VALUE reparented_obj ;
103
+ xmlNodePtr reparentee, pivot, reparented, next_text, new_next_text ;
104
+
105
+ if(!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode))
106
+ rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
107
+ if(rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlDocument))
108
+ rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
109
+
110
+ Data_Get_Struct(reparentee_obj, xmlNode, reparentee);
111
+ Data_Get_Struct(pivot_obj, xmlNode, pivot);
112
+
113
+ if(XML_DOCUMENT_NODE == reparentee->type || XML_HTML_DOCUMENT_NODE == reparentee->type)
114
+ rb_raise(rb_eArgError, "cannot reparent a document node");
115
+
116
+ xmlUnlinkNode(reparentee);
117
+
118
+ if (reparentee->doc != pivot->doc || reparentee->type == XML_TEXT_NODE) {
119
+ /*
120
+ * if the reparentee is a text node, there's a very good chance it will be
121
+ * merged with an adjacent text node after being reparented, and in that case
122
+ * libxml will free the underlying C struct.
123
+ *
124
+ * since we clearly have a ruby object which references the underlying
125
+ * memory, we can't let the C struct get freed. let's pickle the original
126
+ * reparentee by rooting it; and then we'll reparent a duplicate of the
127
+ * node that we don't care about preserving.
128
+ *
129
+ * alternatively, if the reparentee is from a different document than the
130
+ * pivot node, libxml2 is going to get confused about which document's
131
+ * "dictionary" the node's strings belong to (this is an otherwise
132
+ * uninteresting libxml2 implementation detail). as a result, we cannot
133
+ * reparent the actual reparentee, so we reparent a duplicate.
134
+ */
135
+ nokogiri_root_node(reparentee);
136
+ if (!(reparentee = xmlDocCopyNode(reparentee, pivot->doc, 1))) {
137
+ rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
138
+ }
139
+ }
140
+
141
+ if (prf != xmlAddPrevSibling && prf != xmlAddNextSibling
142
+ && reparentee->type == XML_TEXT_NODE && pivot->next && pivot->next->type == XML_TEXT_NODE) {
143
+ /*
144
+ * libxml merges text nodes in a right-to-left fashion, meaning that if
145
+ * there are two text nodes who would be adjacent, the right (or following,
146
+ * or next) node will be merged into the left (or preceding, or previous)
147
+ * node.
148
+ *
149
+ * and by "merged" I mean the string contents will be concatenated onto the
150
+ * left node's contents, and then the node will be freed.
151
+ *
152
+ * which means that if we have a ruby object wrapped around the right node,
153
+ * its memory would be freed out from under it.
154
+ *
155
+ * so, we detect this edge case and unlink-and-root the text node before it gets
156
+ * merged. then we dup the node and insert that duplicate back into the
157
+ * document where the real node was.
158
+ *
159
+ * yes, this is totally lame.
160
+ */
161
+ next_text = pivot->next ;
162
+ new_next_text = xmlDocCopyNode(next_text, pivot->doc, 1) ;
163
+
164
+ xmlUnlinkNode(next_text);
165
+ nokogiri_root_node(next_text);
166
+
167
+ xmlAddNextSibling(pivot, new_next_text);
168
+ }
169
+
170
+ if(!(reparented = (*prf)(pivot, reparentee))) {
171
+ rb_raise(rb_eRuntimeError, "Could not reparent node");
172
+ }
173
+
174
+ /*
175
+ * make sure the ruby object is pointed at the just-reparented node, which
176
+ * might be a duplicate (see above) or might be the result of merging
177
+ * adjacent text nodes.
178
+ */
179
+ DATA_PTR(reparentee_obj) = reparented ;
180
+
181
+ relink_namespace(reparented);
182
+
183
+ reparented_obj = Nokogiri_wrap_xml_node(Qnil, reparented);
184
+
185
+ rb_funcall(reparented_obj, decorate_bang, 0);
186
+
187
+ return reparented_obj ;
188
+ }
189
+
190
+
191
+ /*
192
+ * call-seq:
193
+ * document
194
+ *
195
+ * Get the document for this Node
196
+ */
197
+ static VALUE document(VALUE self)
198
+ {
199
+ xmlNodePtr node;
200
+ Data_Get_Struct(self, xmlNode, node);
201
+ return DOC_RUBY_OBJECT(node->doc);
202
+ }
203
+
204
+ /*
205
+ * call-seq:
206
+ * pointer_id
207
+ *
208
+ * Get the internal pointer number
209
+ */
210
+ static VALUE pointer_id(VALUE self)
211
+ {
212
+ xmlNodePtr node;
213
+ Data_Get_Struct(self, xmlNode, node);
214
+
215
+ return INT2NUM((long)(node));
216
+ }
217
+
218
+ /*
219
+ * call-seq:
220
+ * encode_special_chars(string)
221
+ *
222
+ * Encode any special characters in +string+
223
+ */
224
+ static VALUE encode_special_chars(VALUE self, VALUE string)
225
+ {
226
+ xmlNodePtr node;
227
+ xmlChar *encoded;
228
+ VALUE encoded_str;
229
+
230
+ Data_Get_Struct(self, xmlNode, node);
231
+ encoded = xmlEncodeSpecialChars(
232
+ node->doc,
233
+ (const xmlChar *)StringValuePtr(string)
234
+ );
235
+
236
+ encoded_str = NOKOGIRI_STR_NEW2(encoded);
237
+ xmlFree(encoded);
238
+
239
+ return encoded_str;
240
+ }
241
+
242
+ /*
243
+ * call-seq:
244
+ * create_internal_subset(name, external_id, system_id)
245
+ *
246
+ * Create the internal subset of a document.
247
+ *
248
+ * doc.create_internal_subset("chapter", "-//OASIS//DTD DocBook XML//EN", "chapter.dtd")
249
+ * # => <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML//EN" "chapter.dtd">
250
+ *
251
+ * doc.create_internal_subset("chapter", nil, "chapter.dtd")
252
+ * # => <!DOCTYPE chapter SYSTEM "chapter.dtd">
253
+ */
254
+ static VALUE create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
255
+ {
256
+ xmlNodePtr node;
257
+ xmlDocPtr doc;
258
+ xmlDtdPtr dtd;
259
+
260
+ Data_Get_Struct(self, xmlNode, node);
261
+
262
+ doc = node->doc;
263
+
264
+ if(xmlGetIntSubset(doc))
265
+ rb_raise(rb_eRuntimeError, "Document already has an internal subset");
266
+
267
+ dtd = xmlCreateIntSubset(
268
+ doc,
269
+ NIL_P(name) ? NULL : (const xmlChar *)StringValuePtr(name),
270
+ NIL_P(external_id) ? NULL : (const xmlChar *)StringValuePtr(external_id),
271
+ NIL_P(system_id) ? NULL : (const xmlChar *)StringValuePtr(system_id)
272
+ );
273
+
274
+ if(!dtd) return Qnil;
275
+
276
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
277
+ }
278
+
279
+ /*
280
+ * call-seq:
281
+ * create_external_subset(name, external_id, system_id)
282
+ *
283
+ * Create an external subset
284
+ */
285
+ static VALUE create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
286
+ {
287
+ xmlNodePtr node;
288
+ xmlDocPtr doc;
289
+ xmlDtdPtr dtd;
290
+
291
+ Data_Get_Struct(self, xmlNode, node);
292
+
293
+ doc = node->doc;
294
+
295
+ if(doc->extSubset)
296
+ rb_raise(rb_eRuntimeError, "Document already has an external subset");
297
+
298
+ dtd = xmlNewDtd(
299
+ doc,
300
+ NIL_P(name) ? NULL : (const xmlChar *)StringValuePtr(name),
301
+ NIL_P(external_id) ? NULL : (const xmlChar *)StringValuePtr(external_id),
302
+ NIL_P(system_id) ? NULL : (const xmlChar *)StringValuePtr(system_id)
303
+ );
304
+
305
+ if(!dtd) return Qnil;
306
+
307
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
308
+ }
309
+
310
+ /*
311
+ * call-seq:
312
+ * external_subset
313
+ *
314
+ * Get the external subset
315
+ */
316
+ static VALUE external_subset(VALUE self)
317
+ {
318
+ xmlNodePtr node;
319
+ xmlDocPtr doc;
320
+ xmlDtdPtr dtd;
321
+
322
+ Data_Get_Struct(self, xmlNode, node);
323
+
324
+ if(!node->doc) return Qnil;
325
+
326
+ doc = node->doc;
327
+ dtd = doc->extSubset;
328
+
329
+ if(!dtd) return Qnil;
330
+
331
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
332
+ }
333
+
334
+ /*
335
+ * call-seq:
336
+ * internal_subset
337
+ *
338
+ * Get the internal subset
339
+ */
340
+ static VALUE internal_subset(VALUE self)
341
+ {
342
+ xmlNodePtr node;
343
+ xmlDocPtr doc;
344
+ xmlDtdPtr dtd;
345
+
346
+ Data_Get_Struct(self, xmlNode, node);
347
+
348
+ if(!node->doc) return Qnil;
349
+
350
+ doc = node->doc;
351
+ dtd = xmlGetIntSubset(doc);
352
+
353
+ if(!dtd) return Qnil;
354
+
355
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
356
+ }
357
+
358
+ /*
359
+ * call-seq:
360
+ * dup
361
+ *
362
+ * Copy this node. An optional depth may be passed in, but it defaults
363
+ * to a deep copy. 0 is a shallow copy, 1 is a deep copy.
364
+ */
365
+ static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
366
+ {
367
+ VALUE level;
368
+ xmlNodePtr node, dup;
369
+
370
+ if(rb_scan_args(argc, argv, "01", &level) == 0)
371
+ level = INT2NUM((long)1);
372
+
373
+ Data_Get_Struct(self, xmlNode, node);
374
+
375
+ dup = xmlDocCopyNode(node, node->doc, (int)NUM2INT(level));
376
+ if(dup == NULL) return Qnil;
377
+
378
+ nokogiri_root_node(dup);
379
+
380
+ return Nokogiri_wrap_xml_node(rb_obj_class(self), dup);
381
+ }
382
+
383
+ /*
384
+ * call-seq:
385
+ * unlink
386
+ *
387
+ * Unlink this node from its current context.
388
+ */
389
+ static VALUE unlink_node(VALUE self)
390
+ {
391
+ xmlNodePtr node;
392
+ Data_Get_Struct(self, xmlNode, node);
393
+ xmlUnlinkNode(node);
394
+ nokogiri_root_node(node);
395
+ return self;
396
+ }
397
+
398
+ /*
399
+ * call-seq:
400
+ * blank?
401
+ *
402
+ * Is this node blank?
403
+ */
404
+ static VALUE blank_eh(VALUE self)
405
+ {
406
+ xmlNodePtr node;
407
+ Data_Get_Struct(self, xmlNode, node);
408
+ return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
409
+ }
410
+
411
+ /*
412
+ * call-seq:
413
+ * next_sibling
414
+ *
415
+ * Returns the next sibling node
416
+ */
417
+ static VALUE next_sibling(VALUE self)
418
+ {
419
+ xmlNodePtr node, sibling;
420
+ Data_Get_Struct(self, xmlNode, node);
421
+
422
+ sibling = node->next;
423
+ if(!sibling) return Qnil;
424
+
425
+ return Nokogiri_wrap_xml_node(Qnil, sibling) ;
426
+ }
427
+
428
+ /*
429
+ * call-seq:
430
+ * previous_sibling
431
+ *
432
+ * Returns the previous sibling node
433
+ */
434
+ static VALUE previous_sibling(VALUE self)
435
+ {
436
+ xmlNodePtr node, sibling;
437
+ Data_Get_Struct(self, xmlNode, node);
438
+
439
+ sibling = node->prev;
440
+ if(!sibling) return Qnil;
441
+
442
+ return Nokogiri_wrap_xml_node(Qnil, sibling);
443
+ }
444
+
445
+ /*
446
+ * call-seq:
447
+ * next_element
448
+ *
449
+ * Returns the next Nokogiri::XML::Element type sibling node.
450
+ */
451
+ static VALUE next_element(VALUE self)
452
+ {
453
+ xmlNodePtr node, sibling;
454
+ Data_Get_Struct(self, xmlNode, node);
455
+
456
+ sibling = xmlNextElementSibling(node);
457
+ if(!sibling) return Qnil;
458
+
459
+ return Nokogiri_wrap_xml_node(Qnil, sibling);
460
+ }
461
+
462
+ /*
463
+ * call-seq:
464
+ * previous_element
465
+ *
466
+ * Returns the previous Nokogiri::XML::Element type sibling node.
467
+ */
468
+ static VALUE previous_element(VALUE self)
469
+ {
470
+ xmlNodePtr node, sibling;
471
+ Data_Get_Struct(self, xmlNode, node);
472
+
473
+ /*
474
+ * note that we don't use xmlPreviousElementSibling here because it's buggy pre-2.7.7.
475
+ */
476
+ sibling = node->prev;
477
+ if(!sibling) return Qnil;
478
+
479
+ while(sibling && sibling->type != XML_ELEMENT_NODE)
480
+ sibling = sibling->prev;
481
+
482
+ return sibling ? Nokogiri_wrap_xml_node(Qnil, sibling) : Qnil ;
483
+ }
484
+
485
+ /* :nodoc: */
486
+ static VALUE replace(VALUE self, VALUE new_node)
487
+ {
488
+ VALUE reparent = reparent_node_with(self, new_node, xmlReplaceNodeWrapper);
489
+
490
+ xmlNodePtr pivot;
491
+ Data_Get_Struct(self, xmlNode, pivot);
492
+ nokogiri_root_node(pivot);
493
+
494
+ return reparent;
495
+ }
496
+
497
+ /*
498
+ * call-seq:
499
+ * children
500
+ *
501
+ * Get the list of children for this node as a NodeSet
502
+ */
503
+ static VALUE children(VALUE self)
504
+ {
505
+ xmlNodePtr node;
506
+ xmlNodePtr child;
507
+ xmlNodeSetPtr set;
508
+ VALUE document;
509
+ VALUE node_set;
510
+
511
+ Data_Get_Struct(self, xmlNode, node);
512
+
513
+ child = node->children;
514
+ set = xmlXPathNodeSetCreate(child);
515
+
516
+ document = DOC_RUBY_OBJECT(node->doc);
517
+
518
+ if(!child) return Nokogiri_wrap_xml_node_set(set, document);
519
+
520
+ child = child->next;
521
+ while(NULL != child) {
522
+ xmlXPathNodeSetAddUnique(set, child);
523
+ child = child->next;
524
+ }
525
+
526
+ node_set = Nokogiri_wrap_xml_node_set(set, document);
527
+
528
+ return node_set;
529
+ }
530
+
531
+ /*
532
+ * call-seq:
533
+ * element_children
534
+ *
535
+ * Get the list of children for this node as a NodeSet. All nodes will be
536
+ * element nodes.
537
+ *
538
+ * Example:
539
+ *
540
+ * @doc.root.element_children.all? { |x| x.element? } # => true
541
+ */
542
+ static VALUE element_children(VALUE self)
543
+ {
544
+ xmlNodePtr node;
545
+ xmlNodePtr child;
546
+ xmlNodeSetPtr set;
547
+ VALUE document;
548
+ VALUE node_set;
549
+
550
+ Data_Get_Struct(self, xmlNode, node);
551
+
552
+ child = xmlFirstElementChild(node);
553
+ set = xmlXPathNodeSetCreate(child);
554
+
555
+ document = DOC_RUBY_OBJECT(node->doc);
556
+
557
+ if(!child) return Nokogiri_wrap_xml_node_set(set, document);
558
+
559
+ child = xmlNextElementSibling(child);
560
+ while(NULL != child) {
561
+ xmlXPathNodeSetAddUnique(set, child);
562
+ child = xmlNextElementSibling(child);
563
+ }
564
+
565
+ node_set = Nokogiri_wrap_xml_node_set(set, document);
566
+
567
+ return node_set;
568
+ }
569
+
570
+ /*
571
+ * call-seq:
572
+ * child
573
+ *
574
+ * Returns the child node
575
+ */
576
+ static VALUE child(VALUE self)
577
+ {
578
+ xmlNodePtr node, child;
579
+ Data_Get_Struct(self, xmlNode, node);
580
+
581
+ child = node->children;
582
+ if(!child) return Qnil;
583
+
584
+ return Nokogiri_wrap_xml_node(Qnil, child);
585
+ }
586
+
587
+ /*
588
+ * call-seq:
589
+ * first_element_child
590
+ *
591
+ * Returns the first child node of this node that is an element.
592
+ *
593
+ * Example:
594
+ *
595
+ * @doc.root.first_element_child.element? # => true
596
+ */
597
+ static VALUE first_element_child(VALUE self)
598
+ {
599
+ xmlNodePtr node, child;
600
+ Data_Get_Struct(self, xmlNode, node);
601
+
602
+ child = xmlFirstElementChild(node);
603
+ if(!child) return Qnil;
604
+
605
+ return Nokogiri_wrap_xml_node(Qnil, child);
606
+ }
607
+
608
+ /*
609
+ * call-seq:
610
+ * last_element_child
611
+ *
612
+ * Returns the last child node of this node that is an element.
613
+ *
614
+ * Example:
615
+ *
616
+ * @doc.root.last_element_child.element? # => true
617
+ */
618
+ static VALUE last_element_child(VALUE self)
619
+ {
620
+ xmlNodePtr node, child;
621
+ Data_Get_Struct(self, xmlNode, node);
622
+
623
+ child = xmlLastElementChild(node);
624
+ if(!child) return Qnil;
625
+
626
+ return Nokogiri_wrap_xml_node(Qnil, child);
627
+ }
628
+
629
+ /*
630
+ * call-seq:
631
+ * key?(attribute)
632
+ *
633
+ * Returns true if +attribute+ is set
634
+ */
635
+ static VALUE key_eh(VALUE self, VALUE attribute)
636
+ {
637
+ xmlNodePtr node;
638
+ Data_Get_Struct(self, xmlNode, node);
639
+ if(xmlHasProp(node, (xmlChar *)StringValuePtr(attribute)))
640
+ return Qtrue;
641
+ return Qfalse;
642
+ }
643
+
644
+ /*
645
+ * call-seq:
646
+ * namespaced_key?(attribute, namespace)
647
+ *
648
+ * Returns true if +attribute+ is set with +namespace+
649
+ */
650
+ static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
651
+ {
652
+ xmlNodePtr node;
653
+ Data_Get_Struct(self, xmlNode, node);
654
+ if(xmlHasNsProp(node, (xmlChar *)StringValuePtr(attribute),
655
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValuePtr(namespace)))
656
+ return Qtrue;
657
+ return Qfalse;
658
+ }
659
+
660
+ /*
661
+ * call-seq:
662
+ * []=(property, value)
663
+ *
664
+ * Set the +property+ to +value+
665
+ */
666
+ static VALUE set(VALUE self, VALUE property, VALUE value)
667
+ {
668
+ xmlNodePtr node, cur;
669
+ xmlAttrPtr prop;
670
+ Data_Get_Struct(self, xmlNode, node);
671
+
672
+ /* If a matching attribute node already exists, then xmlSetProp will destroy
673
+ * the existing node's children. However, if Nokogiri has a node object
674
+ * pointing to one of those children, we are left with a broken reference.
675
+ *
676
+ * We can avoid this by unlinking these nodes first.
677
+ */
678
+ if (node->type != XML_ELEMENT_NODE)
679
+ return(Qnil);
680
+ prop = xmlHasProp(node, (xmlChar *)StringValuePtr(property));
681
+ if (prop && prop->children) {
682
+ for (cur = prop->children; cur; cur = cur->next) {
683
+ if (cur->_private) {
684
+ nokogiri_root_node(cur);
685
+ xmlUnlinkNode(cur);
686
+ }
687
+ }
688
+ }
689
+
690
+ xmlSetProp(node, (xmlChar *)StringValuePtr(property),
691
+ (xmlChar *)StringValuePtr(value));
692
+
693
+ return value;
694
+ }
695
+
696
+ /*
697
+ * call-seq:
698
+ * get(attribute)
699
+ *
700
+ * Get the value for +attribute+
701
+ */
702
+ static VALUE get(VALUE self, VALUE attribute)
703
+ {
704
+ xmlNodePtr node;
705
+ xmlChar* propstr ;
706
+ VALUE rval ;
707
+ Data_Get_Struct(self, xmlNode, node);
708
+
709
+ if(NIL_P(attribute)) return Qnil;
710
+
711
+ propstr = xmlGetProp(node, (xmlChar *)StringValuePtr(attribute));
712
+
713
+ if(!propstr) return Qnil;
714
+
715
+ rval = NOKOGIRI_STR_NEW2(propstr);
716
+
717
+ xmlFree(propstr);
718
+ return rval ;
719
+ }
720
+
721
+ /*
722
+ * call-seq:
723
+ * set_namespace(namespace)
724
+ *
725
+ * Set the namespace to +namespace+
726
+ */
727
+ static VALUE set_namespace(VALUE self, VALUE namespace)
728
+ {
729
+ xmlNodePtr node;
730
+ xmlNsPtr ns = NULL;
731
+
732
+ Data_Get_Struct(self, xmlNode, node);
733
+
734
+ if(!NIL_P(namespace))
735
+ Data_Get_Struct(namespace, xmlNs, ns);
736
+
737
+ xmlSetNs(node, ns);
738
+
739
+ return self;
740
+ }
741
+
742
+ /*
743
+ * call-seq:
744
+ * attribute(name)
745
+ *
746
+ * Get the attribute node with +name+
747
+ */
748
+ static VALUE attr(VALUE self, VALUE name)
749
+ {
750
+ xmlNodePtr node;
751
+ xmlAttrPtr prop;
752
+ Data_Get_Struct(self, xmlNode, node);
753
+ prop = xmlHasProp(node, (xmlChar *)StringValuePtr(name));
754
+
755
+ if(! prop) return Qnil;
756
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
757
+ }
758
+
759
+ /*
760
+ * call-seq:
761
+ * attribute_with_ns(name, namespace)
762
+ *
763
+ * Get the attribute node with +name+ and +namespace+
764
+ */
765
+ static VALUE attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
766
+ {
767
+ xmlNodePtr node;
768
+ xmlAttrPtr prop;
769
+ Data_Get_Struct(self, xmlNode, node);
770
+ prop = xmlHasNsProp(node, (xmlChar *)StringValuePtr(name),
771
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValuePtr(namespace));
772
+
773
+ if(! prop) return Qnil;
774
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
775
+ }
776
+
777
+ /*
778
+ * call-seq:
779
+ * attribute_nodes()
780
+ *
781
+ * returns a list containing the Node attributes.
782
+ */
783
+ static VALUE attribute_nodes(VALUE self)
784
+ {
785
+ /* this code in the mode of xmlHasProp() */
786
+ xmlNodePtr node;
787
+ VALUE attr;
788
+
789
+ Data_Get_Struct(self, xmlNode, node);
790
+
791
+ attr = rb_ary_new();
792
+ Nokogiri_xml_node_properties(node, attr);
793
+
794
+ return attr ;
795
+ }
796
+
797
+
798
+ /*
799
+ * call-seq:
800
+ * namespace()
801
+ *
802
+ * returns the default namespace set on this node (as with an "xmlns="
803
+ * attribute), as a Namespace object.
804
+ */
805
+ static VALUE namespace(VALUE self)
806
+ {
807
+ xmlNodePtr node ;
808
+ Data_Get_Struct(self, xmlNode, node);
809
+
810
+ if (node->ns)
811
+ return Nokogiri_wrap_xml_namespace(node->doc, node->ns);
812
+
813
+ return Qnil ;
814
+ }
815
+
816
+ /*
817
+ * call-seq:
818
+ * namespace_definitions()
819
+ *
820
+ * returns namespaces defined on self element directly, as an array of Namespace objects. Includes both a default namespace (as in"xmlns="), and prefixed namespaces (as in "xmlns:prefix=").
821
+ */
822
+ static VALUE namespace_definitions(VALUE self)
823
+ {
824
+ /* this code in the mode of xmlHasProp() */
825
+ xmlNodePtr node ;
826
+ VALUE list;
827
+ xmlNsPtr ns;
828
+
829
+ Data_Get_Struct(self, xmlNode, node);
830
+
831
+ list = rb_ary_new();
832
+
833
+ ns = node->nsDef;
834
+
835
+ if(!ns) return list;
836
+
837
+ while(NULL != ns) {
838
+ rb_ary_push(list, Nokogiri_wrap_xml_namespace(node->doc, ns));
839
+ ns = ns->next;
840
+ }
841
+
842
+ return list;
843
+ }
844
+
845
+ /*
846
+ * call-seq:
847
+ * namespace_scopes()
848
+ *
849
+ * returns namespaces in scope for self -- those defined on self element
850
+ * directly or any ancestor node -- as an array of Namespace objects. Default
851
+ * namespaces ("xmlns=" style) for self are included in this array; Default
852
+ * namespaces for ancestors, however, are not. See also #namespaces
853
+ */
854
+ static VALUE namespace_scopes(VALUE self)
855
+ {
856
+ xmlNodePtr node ;
857
+ VALUE list;
858
+ xmlNsPtr *ns_list;
859
+ int j;
860
+
861
+ Data_Get_Struct(self, xmlNode, node);
862
+
863
+ list = rb_ary_new();
864
+ ns_list = xmlGetNsList(node->doc, node);
865
+
866
+ if(!ns_list) return list;
867
+
868
+ for (j = 0 ; ns_list[j] != NULL ; ++j) {
869
+ rb_ary_push(list, Nokogiri_wrap_xml_namespace(node->doc, ns_list[j]));
870
+ }
871
+
872
+ xmlFree(ns_list);
873
+ return list;
874
+ }
875
+
876
+ /*
877
+ * call-seq:
878
+ * node_type
879
+ *
880
+ * Get the type for this Node
881
+ */
882
+ static VALUE node_type(VALUE self)
883
+ {
884
+ xmlNodePtr node;
885
+ Data_Get_Struct(self, xmlNode, node);
886
+ return INT2NUM((long)node->type);
887
+ }
888
+
889
+ /*
890
+ * call-seq:
891
+ * content=
892
+ *
893
+ * Set the content for this Node
894
+ */
895
+ static VALUE set_content(VALUE self, VALUE content)
896
+ {
897
+ xmlNodePtr node, child, next ;
898
+ Data_Get_Struct(self, xmlNode, node);
899
+
900
+ child = node->children;
901
+ while (NULL != child) {
902
+ next = child->next ;
903
+ xmlUnlinkNode(child) ;
904
+ nokogiri_root_node(child);
905
+ child = next ;
906
+ }
907
+
908
+ xmlNodeSetContent(node, (xmlChar *)StringValuePtr(content));
909
+ return content;
910
+ }
911
+
912
+ /*
913
+ * call-seq:
914
+ * content
915
+ *
916
+ * Returns the content for this Node
917
+ */
918
+ static VALUE get_content(VALUE self)
919
+ {
920
+ xmlNodePtr node;
921
+ xmlChar * content;
922
+
923
+ Data_Get_Struct(self, xmlNode, node);
924
+
925
+ content = xmlNodeGetContent(node);
926
+ if(content) {
927
+ VALUE rval = NOKOGIRI_STR_NEW2(content);
928
+ xmlFree(content);
929
+ return rval;
930
+ }
931
+ return Qnil;
932
+ }
933
+
934
+ /* :nodoc: */
935
+ static VALUE add_child(VALUE self, VALUE new_child)
936
+ {
937
+ return reparent_node_with(self, new_child, xmlAddChild);
938
+ }
939
+
940
+ /*
941
+ * call-seq:
942
+ * parent
943
+ *
944
+ * Get the parent Node for this Node
945
+ */
946
+ static VALUE get_parent(VALUE self)
947
+ {
948
+ xmlNodePtr node, parent;
949
+ Data_Get_Struct(self, xmlNode, node);
950
+
951
+ parent = node->parent;
952
+ if(!parent) return Qnil;
953
+
954
+ return Nokogiri_wrap_xml_node(Qnil, parent) ;
955
+ }
956
+
957
+ /*
958
+ * call-seq:
959
+ * name=(new_name)
960
+ *
961
+ * Set the name for this Node
962
+ */
963
+ static VALUE set_name(VALUE self, VALUE new_name)
964
+ {
965
+ xmlNodePtr node;
966
+ Data_Get_Struct(self, xmlNode, node);
967
+ xmlNodeSetName(node, (xmlChar*)StringValuePtr(new_name));
968
+ return new_name;
969
+ }
970
+
971
+ /*
972
+ * call-seq:
973
+ * name
974
+ *
975
+ * Returns the name for this Node
976
+ */
977
+ static VALUE get_name(VALUE self)
978
+ {
979
+ xmlNodePtr node;
980
+ Data_Get_Struct(self, xmlNode, node);
981
+ if(node->name)
982
+ return NOKOGIRI_STR_NEW2(node->name);
983
+ return Qnil;
984
+ }
985
+
986
+ /*
987
+ * call-seq:
988
+ * path
989
+ *
990
+ * Returns the path associated with this Node
991
+ */
992
+ static VALUE path(VALUE self)
993
+ {
994
+ xmlNodePtr node;
995
+ xmlChar *path ;
996
+ VALUE rval;
997
+
998
+ Data_Get_Struct(self, xmlNode, node);
999
+
1000
+ path = xmlGetNodePath(node);
1001
+ rval = NOKOGIRI_STR_NEW2(path);
1002
+ xmlFree(path);
1003
+ return rval ;
1004
+ }
1005
+
1006
+ /* :nodoc: */
1007
+ static VALUE add_next_sibling(VALUE self, VALUE new_sibling)
1008
+ {
1009
+ return reparent_node_with(self, new_sibling, xmlAddNextSibling) ;
1010
+ }
1011
+
1012
+ /* :nodoc: */
1013
+ static VALUE add_previous_sibling(VALUE self, VALUE new_sibling)
1014
+ {
1015
+ return reparent_node_with(self, new_sibling, xmlAddPrevSibling) ;
1016
+ }
1017
+
1018
+ /*
1019
+ * call-seq:
1020
+ * native_write_to(io, encoding, options)
1021
+ *
1022
+ * Write this Node to +io+ with +encoding+ and +options+
1023
+ */
1024
+ static VALUE native_write_to(
1025
+ VALUE self,
1026
+ VALUE io,
1027
+ VALUE encoding,
1028
+ VALUE indent_string,
1029
+ VALUE options
1030
+ ) {
1031
+ xmlNodePtr node;
1032
+ const char * before_indent;
1033
+ xmlSaveCtxtPtr savectx;
1034
+
1035
+ Data_Get_Struct(self, xmlNode, node);
1036
+
1037
+ xmlIndentTreeOutput = 1;
1038
+
1039
+ before_indent = xmlTreeIndentString;
1040
+
1041
+ xmlTreeIndentString = StringValuePtr(indent_string);
1042
+
1043
+ savectx = xmlSaveToIO(
1044
+ (xmlOutputWriteCallback)io_write_callback,
1045
+ (xmlOutputCloseCallback)io_close_callback,
1046
+ (void *)io,
1047
+ RTEST(encoding) ? StringValuePtr(encoding) : NULL,
1048
+ (int)NUM2INT(options)
1049
+ );
1050
+
1051
+ xmlSaveTree(savectx, node);
1052
+ xmlSaveClose(savectx);
1053
+
1054
+ xmlTreeIndentString = before_indent;
1055
+ return io;
1056
+ }
1057
+
1058
+ /*
1059
+ * call-seq:
1060
+ * line
1061
+ *
1062
+ * Returns the line for this Node
1063
+ */
1064
+ static VALUE line(VALUE self)
1065
+ {
1066
+ xmlNodePtr node;
1067
+ Data_Get_Struct(self, xmlNode, node);
1068
+
1069
+ return INT2NUM(xmlGetLineNo(node));
1070
+ }
1071
+
1072
+ /*
1073
+ * call-seq:
1074
+ * add_namespace_definition(prefix, href)
1075
+ *
1076
+ * Adds a namespace definition with +prefix+ using +href+ value. The result is
1077
+ * as if parsed XML for this node had included an attribute
1078
+ * 'xmlns:prefix=value'. A default namespace for this node ("xmlns=") can be
1079
+ * added by passing 'nil' for prefix. Namespaces added this way will not
1080
+ * show up in #attributes, but they will be included as an xmlns attribute
1081
+ * when the node is serialized to XML.
1082
+ */
1083
+ static VALUE add_namespace_definition(VALUE self, VALUE prefix, VALUE href)
1084
+ {
1085
+ xmlNodePtr node, namespacee;
1086
+ xmlNsPtr ns;
1087
+
1088
+ Data_Get_Struct(self, xmlNode, node);
1089
+ namespacee = node ;
1090
+
1091
+ ns = xmlSearchNs(
1092
+ node->doc,
1093
+ node,
1094
+ (const xmlChar *)(NIL_P(prefix) ? NULL : StringValuePtr(prefix))
1095
+ );
1096
+
1097
+ if(!ns) {
1098
+ if (node->type != XML_ELEMENT_NODE) {
1099
+ namespacee = node->parent;
1100
+ }
1101
+ ns = xmlNewNs(
1102
+ namespacee,
1103
+ (const xmlChar *)StringValuePtr(href),
1104
+ (const xmlChar *)(NIL_P(prefix) ? NULL : StringValuePtr(prefix))
1105
+ );
1106
+ }
1107
+
1108
+ if (!ns) return Qnil ;
1109
+
1110
+ if(NIL_P(prefix) || node != namespacee) xmlSetNs(node, ns);
1111
+
1112
+ return Nokogiri_wrap_xml_namespace(node->doc, ns);
1113
+ }
1114
+
1115
+ /*
1116
+ * call-seq:
1117
+ * new(name, document)
1118
+ *
1119
+ * Create a new node with +name+ sharing GC lifecycle with +document+
1120
+ */
1121
+ static VALUE new(int argc, VALUE *argv, VALUE klass)
1122
+ {
1123
+ xmlDocPtr doc;
1124
+ xmlNodePtr node;
1125
+ VALUE name;
1126
+ VALUE document;
1127
+ VALUE rest;
1128
+ VALUE rb_node;
1129
+
1130
+ rb_scan_args(argc, argv, "2*", &name, &document, &rest);
1131
+
1132
+ Data_Get_Struct(document, xmlDoc, doc);
1133
+
1134
+ node = xmlNewNode(NULL, (xmlChar *)StringValuePtr(name));
1135
+ node->doc = doc->doc;
1136
+ nokogiri_root_node(node);
1137
+
1138
+ rb_node = Nokogiri_wrap_xml_node(
1139
+ klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
1140
+ node
1141
+ );
1142
+ rb_obj_call_init(rb_node, argc, argv);
1143
+
1144
+ if(rb_block_given_p()) rb_yield(rb_node);
1145
+
1146
+ return rb_node;
1147
+ }
1148
+
1149
+ /*
1150
+ * call-seq:
1151
+ * dump_html
1152
+ *
1153
+ * Returns the Node as html.
1154
+ */
1155
+ static VALUE dump_html(VALUE self)
1156
+ {
1157
+ xmlBufferPtr buf ;
1158
+ xmlNodePtr node ;
1159
+ VALUE html;
1160
+
1161
+ Data_Get_Struct(self, xmlNode, node);
1162
+
1163
+ buf = xmlBufferCreate() ;
1164
+ htmlNodeDump(buf, node->doc, node);
1165
+ html = NOKOGIRI_STR_NEW2(buf->content);
1166
+ xmlBufferFree(buf);
1167
+ return html ;
1168
+ }
1169
+
1170
+ /*
1171
+ * call-seq:
1172
+ * compare(other)
1173
+ *
1174
+ * Compare this Node to +other+ with respect to their Document
1175
+ */
1176
+ static VALUE compare(VALUE self, VALUE _other)
1177
+ {
1178
+ xmlNodePtr node, other;
1179
+ Data_Get_Struct(self, xmlNode, node);
1180
+ Data_Get_Struct(_other, xmlNode, other);
1181
+
1182
+ return INT2NUM((long)xmlXPathCmpNodes(other, node));
1183
+ }
1184
+
1185
+
1186
+ /*
1187
+ * call-seq:
1188
+ * process_xincludes(options)
1189
+ *
1190
+ * Loads and substitutes all xinclude elements below the node. The
1191
+ * parser context will be initialized with +options+.
1192
+ */
1193
+ static VALUE process_xincludes(VALUE self, VALUE options)
1194
+ {
1195
+ int rcode ;
1196
+ xmlNodePtr node;
1197
+ VALUE error_list = rb_ary_new();
1198
+
1199
+ Data_Get_Struct(self, xmlNode, node);
1200
+
1201
+ xmlSetStructuredErrorFunc((void *)error_list, Nokogiri_error_array_pusher);
1202
+ rcode = xmlXIncludeProcessTreeFlags(node, (int)NUM2INT(options));
1203
+ xmlSetStructuredErrorFunc(NULL, NULL);
1204
+
1205
+ if (rcode < 0) {
1206
+ xmlErrorPtr error;
1207
+
1208
+ error = xmlGetLastError();
1209
+ if(error)
1210
+ rb_exc_raise(Nokogiri_wrap_xml_syntax_error((VALUE)NULL, error));
1211
+ else
1212
+ rb_raise(rb_eRuntimeError, "Could not perform xinclude substitution");
1213
+ }
1214
+
1215
+ return self;
1216
+ }
1217
+
1218
+
1219
+ /* TODO: DOCUMENT ME */
1220
+ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
1221
+ {
1222
+ xmlNodePtr node, list = 0, child_iter, node_children, doc_children;
1223
+ xmlNodeSetPtr set;
1224
+ xmlParserErrors error;
1225
+ VALUE doc, err;
1226
+ int doc_is_empty;
1227
+
1228
+ Data_Get_Struct(self, xmlNode, node);
1229
+
1230
+ doc = DOC_RUBY_OBJECT(node->doc);
1231
+ err = rb_iv_get(doc, "@errors");
1232
+ doc_is_empty = (node->doc->children == NULL) ? 1 : 0;
1233
+ node_children = node->children;
1234
+ doc_children = node->doc->children;
1235
+
1236
+ xmlSetStructuredErrorFunc((void *)err, Nokogiri_error_array_pusher);
1237
+
1238
+ /* Twiddle global variable because of a bug in libxml2.
1239
+ * http://git.gnome.org/browse/libxml2/commit/?id=e20fb5a72c83cbfc8e4a8aa3943c6be8febadab7
1240
+ */
1241
+ #ifndef HTML_PARSE_NOIMPLIED
1242
+ htmlHandleOmittedElem(0);
1243
+ #endif
1244
+
1245
+ /* This function adds a fake node to the child of +node+. If the parser
1246
+ * does not exit cleanly with XML_ERR_OK, the list is freed. This can
1247
+ * leave the child pointers in a bad state if they were originally empty.
1248
+ *
1249
+ * http://git.gnome.org/browse/libxml2/tree/parser.c#n13177
1250
+ * */
1251
+ error = xmlParseInNodeContext(node, StringValuePtr(_str),
1252
+ (int)RSTRING_LEN(_str),
1253
+ (int)NUM2INT(_options), &list);
1254
+
1255
+ /* xmlParseInNodeContext should not mutate the original document or node,
1256
+ * so reassigning these pointers should be OK. The reason we're reassigning
1257
+ * is because if there were errors, it's possible for the child pointers
1258
+ * to be manipulated. */
1259
+ if (error != XML_ERR_OK) {
1260
+ node->doc->children = doc_children;
1261
+ node->children = node_children;
1262
+ }
1263
+
1264
+ /* make sure parent/child pointers are coherent so an unlink will work
1265
+ * properly (#331)
1266
+ */
1267
+ child_iter = node->doc->children ;
1268
+ while (child_iter) {
1269
+ if (child_iter->parent != (xmlNodePtr)node->doc)
1270
+ child_iter->parent = (xmlNodePtr)node->doc;
1271
+ child_iter = child_iter->next;
1272
+ }
1273
+
1274
+ #ifndef HTML_PARSE_NOIMPLIED
1275
+ htmlHandleOmittedElem(1);
1276
+ #endif
1277
+
1278
+ xmlSetStructuredErrorFunc(NULL, NULL);
1279
+
1280
+ /* Workaround for a libxml2 bug where a parsing error may leave a broken
1281
+ * node reference in node->doc->children.
1282
+ * This workaround is limited to when a parse error occurs, the document
1283
+ * went from having no children to having children, and the context node is
1284
+ * part of a document fragment.
1285
+ * https://bugzilla.gnome.org/show_bug.cgi?id=668155
1286
+ */
1287
+ if (error != XML_ERR_OK && doc_is_empty && node->doc->children != NULL) {
1288
+ child_iter = node;
1289
+ while (child_iter->parent)
1290
+ child_iter = child_iter->parent;
1291
+
1292
+ if (child_iter->type == XML_DOCUMENT_FRAG_NODE)
1293
+ node->doc->children = NULL;
1294
+ }
1295
+
1296
+ /* FIXME: This probably needs to handle more constants... */
1297
+ switch (error) {
1298
+ case XML_ERR_INTERNAL_ERROR:
1299
+ case XML_ERR_NO_MEMORY:
1300
+ rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error);
1301
+ break;
1302
+ default:
1303
+ break;
1304
+ }
1305
+
1306
+ set = xmlXPathNodeSetCreate(NULL);
1307
+
1308
+ while (list) {
1309
+ xmlXPathNodeSetAddUnique(set, list);
1310
+ list = list->next;
1311
+ }
1312
+
1313
+ return Nokogiri_wrap_xml_node_set(set, doc);
1314
+ }
1315
+
1316
+
1317
+ VALUE Nokogiri_wrap_xml_node(VALUE klass, xmlNodePtr node)
1318
+ {
1319
+ VALUE document = Qnil ;
1320
+ VALUE node_cache = Qnil ;
1321
+ VALUE rb_node = Qnil ;
1322
+ nokogiriTuplePtr node_has_a_document;
1323
+ xmlDocPtr doc;
1324
+ void (*mark_method)(xmlNodePtr) = NULL ;
1325
+
1326
+ assert(node);
1327
+
1328
+ if(node->type == XML_DOCUMENT_NODE || node->type == XML_HTML_DOCUMENT_NODE)
1329
+ return DOC_RUBY_OBJECT(node->doc);
1330
+
1331
+ /* It's OK if the node doesn't have a fully-realized document (as in XML::Reader). */
1332
+ /* see https://github.com/sparklemotion/nokogiri/issues/95 */
1333
+ /* and https://github.com/sparklemotion/nokogiri/issues/439 */
1334
+ doc = node->doc;
1335
+ if (doc->type == XML_DOCUMENT_FRAG_NODE) doc = doc->doc;
1336
+ node_has_a_document = DOC_RUBY_OBJECT_TEST(doc);
1337
+
1338
+ if(node->_private && node_has_a_document)
1339
+ return (VALUE)node->_private;
1340
+
1341
+ if(!RTEST(klass)) {
1342
+ switch(node->type)
1343
+ {
1344
+ case XML_ELEMENT_NODE:
1345
+ klass = cNokogiriXmlElement;
1346
+ break;
1347
+ case XML_TEXT_NODE:
1348
+ klass = cNokogiriXmlText;
1349
+ break;
1350
+ case XML_ATTRIBUTE_NODE:
1351
+ klass = cNokogiriXmlAttr;
1352
+ break;
1353
+ case XML_ENTITY_REF_NODE:
1354
+ klass = cNokogiriXmlEntityReference;
1355
+ break;
1356
+ case XML_COMMENT_NODE:
1357
+ klass = cNokogiriXmlComment;
1358
+ break;
1359
+ case XML_DOCUMENT_FRAG_NODE:
1360
+ klass = cNokogiriXmlDocumentFragment;
1361
+ break;
1362
+ case XML_PI_NODE:
1363
+ klass = cNokogiriXmlProcessingInstruction;
1364
+ break;
1365
+ case XML_ENTITY_DECL:
1366
+ klass = cNokogiriXmlEntityDecl;
1367
+ break;
1368
+ case XML_CDATA_SECTION_NODE:
1369
+ klass = cNokogiriXmlCData;
1370
+ break;
1371
+ case XML_DTD_NODE:
1372
+ klass = cNokogiriXmlDtd;
1373
+ break;
1374
+ case XML_ATTRIBUTE_DECL:
1375
+ klass = cNokogiriXmlAttributeDecl;
1376
+ break;
1377
+ case XML_ELEMENT_DECL:
1378
+ klass = cNokogiriXmlElementDecl;
1379
+ break;
1380
+ default:
1381
+ klass = cNokogiriXmlNode;
1382
+ }
1383
+ }
1384
+
1385
+ mark_method = node_has_a_document ? mark : NULL ;
1386
+
1387
+ rb_node = Data_Wrap_Struct(klass, mark_method, debug_node_dealloc, node) ;
1388
+ node->_private = (void *)rb_node;
1389
+
1390
+ if (node_has_a_document) {
1391
+ document = DOC_RUBY_OBJECT(doc);
1392
+ node_cache = DOC_NODE_CACHE(doc);
1393
+ rb_ary_push(node_cache, rb_node);
1394
+ rb_funcall(document, decorate, 1, rb_node);
1395
+ }
1396
+
1397
+ return rb_node ;
1398
+ }
1399
+
1400
+
1401
+ void Nokogiri_xml_node_properties(xmlNodePtr node, VALUE attr_list)
1402
+ {
1403
+ xmlAttrPtr prop;
1404
+ prop = node->properties ;
1405
+ while (prop != NULL) {
1406
+ rb_ary_push(attr_list, Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop));
1407
+ prop = prop->next ;
1408
+ }
1409
+ }
1410
+
1411
+ VALUE cNokogiriXmlNode ;
1412
+ VALUE cNokogiriXmlElement ;
1413
+
1414
+ void init_xml_node()
1415
+ {
1416
+ VALUE nokogiri = rb_define_module("Nokogiri");
1417
+ VALUE xml = rb_define_module_under(nokogiri, "XML");
1418
+ VALUE klass = rb_define_class_under(xml, "Node", rb_cObject);
1419
+
1420
+ cNokogiriXmlNode = klass;
1421
+
1422
+ cNokogiriXmlElement = rb_define_class_under(xml, "Element", klass);
1423
+
1424
+ rb_define_singleton_method(klass, "new", new, -1);
1425
+
1426
+ rb_define_method(klass, "add_namespace_definition", add_namespace_definition, 2);
1427
+ rb_define_method(klass, "node_name", get_name, 0);
1428
+ rb_define_method(klass, "document", document, 0);
1429
+ rb_define_method(klass, "node_name=", set_name, 1);
1430
+ rb_define_method(klass, "parent", get_parent, 0);
1431
+ rb_define_method(klass, "child", child, 0);
1432
+ rb_define_method(klass, "first_element_child", first_element_child, 0);
1433
+ rb_define_method(klass, "last_element_child", last_element_child, 0);
1434
+ rb_define_method(klass, "children", children, 0);
1435
+ rb_define_method(klass, "element_children", element_children, 0);
1436
+ rb_define_method(klass, "next_sibling", next_sibling, 0);
1437
+ rb_define_method(klass, "previous_sibling", previous_sibling, 0);
1438
+ rb_define_method(klass, "next_element", next_element, 0);
1439
+ rb_define_method(klass, "previous_element", previous_element, 0);
1440
+ rb_define_method(klass, "node_type", node_type, 0);
1441
+ rb_define_method(klass, "content", get_content, 0);
1442
+ rb_define_method(klass, "path", path, 0);
1443
+ rb_define_method(klass, "key?", key_eh, 1);
1444
+ rb_define_method(klass, "namespaced_key?", namespaced_key_eh, 2);
1445
+ rb_define_method(klass, "blank?", blank_eh, 0);
1446
+ rb_define_method(klass, "attribute_nodes", attribute_nodes, 0);
1447
+ rb_define_method(klass, "attribute", attr, 1);
1448
+ rb_define_method(klass, "attribute_with_ns", attribute_with_ns, 2);
1449
+ rb_define_method(klass, "namespace", namespace, 0);
1450
+ rb_define_method(klass, "namespace_definitions", namespace_definitions, 0);
1451
+ rb_define_method(klass, "namespace_scopes", namespace_scopes, 0);
1452
+ rb_define_method(klass, "encode_special_chars", encode_special_chars, 1);
1453
+ rb_define_method(klass, "dup", duplicate_node, -1);
1454
+ rb_define_method(klass, "unlink", unlink_node, 0);
1455
+ rb_define_method(klass, "internal_subset", internal_subset, 0);
1456
+ rb_define_method(klass, "external_subset", external_subset, 0);
1457
+ rb_define_method(klass, "create_internal_subset", create_internal_subset, 3);
1458
+ rb_define_method(klass, "create_external_subset", create_external_subset, 3);
1459
+ rb_define_method(klass, "pointer_id", pointer_id, 0);
1460
+ rb_define_method(klass, "line", line, 0);
1461
+
1462
+ rb_define_private_method(klass, "process_xincludes", process_xincludes, 1);
1463
+ rb_define_private_method(klass, "in_context", in_context, 2);
1464
+ rb_define_private_method(klass, "add_child_node", add_child, 1);
1465
+ rb_define_private_method(klass, "add_previous_sibling_node", add_previous_sibling, 1);
1466
+ rb_define_private_method(klass, "add_next_sibling_node", add_next_sibling, 1);
1467
+ rb_define_private_method(klass, "replace_node", replace, 1);
1468
+ rb_define_private_method(klass, "dump_html", dump_html, 0);
1469
+ rb_define_private_method(klass, "native_write_to", native_write_to, 4);
1470
+ rb_define_private_method(klass, "native_content=", set_content, 1);
1471
+ rb_define_private_method(klass, "get", get, 1);
1472
+ rb_define_private_method(klass, "set", set, 2);
1473
+ rb_define_private_method(klass, "set_namespace", set_namespace, 1);
1474
+ rb_define_private_method(klass, "compare", compare, 1);
1475
+
1476
+ decorate = rb_intern("decorate");
1477
+ decorate_bang = rb_intern("decorate!");
1478
+ }
1479
+
1480
+ /* vim: set noet sw=4 sws=4 */