teius 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/Makefile ADDED
@@ -0,0 +1,138 @@
1
+
2
+ SHELL = /bin/sh
3
+
4
+ #### Start of system configuration section. ####
5
+
6
+ srcdir = .
7
+ topdir = d:/msys/local/lib/ruby/1.8/i386-mingw32
8
+ hdrdir = $(topdir)
9
+ VPATH = $(srcdir);$(topdir);$(hdrdir)
10
+
11
+ DESTDIR = d:
12
+ prefix = $(DESTDIR)/msys/local
13
+ exec_prefix = $(DESTDIR)/msys/local
14
+ sitedir = $(prefix)/lib/ruby/site_ruby
15
+ rubylibdir = $(libdir)/ruby/$(ruby_version)
16
+ archdir = $(rubylibdir)/$(arch)
17
+ sbindir = $(exec_prefix)/sbin
18
+ datadir = $(prefix)/share
19
+ includedir = $(prefix)/include
20
+ infodir = $(prefix)/info
21
+ sysconfdir = $(prefix)/etc
22
+ mandir = $(prefix)/man
23
+ libdir = $(DESTDIR)/msys/local/lib
24
+ sharedstatedir = $(prefix)/com
25
+ oldincludedir = $(DESTDIR)/usr/include
26
+ sitearchdir = $(sitelibdir)/$(sitearch)
27
+ bindir = $(exec_prefix)/bin
28
+ localstatedir = $(prefix)/var
29
+ sitelibdir = $(sitedir)/$(ruby_version)
30
+ libexecdir = $(exec_prefix)/libexec
31
+
32
+ CC = gcc
33
+ LIBRUBY = lib$(LIBRUBY_SO).a
34
+ LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
35
+ LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
36
+ LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
37
+
38
+ CFLAGS = -g -O2
39
+ CPPFLAGS = -I. -I$(topdir) -I$(hdrdir) -I$(srcdir) -Id:/msys/local/include/libxml2
40
+ CXXFLAGS = $(CFLAGS)
41
+ DLDFLAGS = -Wl,--enable-auto-import,--export-all
42
+ LDSHARED = gcc -shared -s
43
+ AR = ar
44
+ EXEEXT = .exe
45
+
46
+ RUBY_INSTALL_NAME = ruby
47
+ RUBY_SO_NAME = msvcrt-ruby18
48
+ arch = i386-mingw32
49
+ sitearch = i386-msvcrt
50
+ ruby_version = 1.8
51
+ ruby = d:/msys/local/bin/ruby
52
+ RUBY = $(ruby)
53
+ RM = rm -f
54
+ MAKEDIRS = mkdir -p
55
+ INSTALL = /bin/install -c
56
+ INSTALL_PROG = $(INSTALL) -m 0755
57
+ INSTALL_DATA = $(INSTALL) -m 644
58
+ COPY = cp
59
+
60
+ #### End of system configuration section. ####
61
+
62
+ preload =
63
+
64
+ libpath = d:/msys/local/lib $(libdir)
65
+ LIBPATH = -L"d:/msys/local/lib" -L"$(libdir)"
66
+ DEFFILE =
67
+
68
+ CLEANFILES =
69
+ DISTCLEANFILES =
70
+
71
+ extout =
72
+ extout_prefix =
73
+ target_prefix =
74
+ LOCAL_LIBS =
75
+ LIBS = $(LIBRUBYARG_SHARED) -lxml2 -lwsock32
76
+ SRCS = teius.c
77
+ OBJS = teius.o
78
+ TARGET = teius
79
+ DLLIB = $(TARGET).so
80
+ STATIC_LIB =
81
+
82
+ RUBYCOMMONDIR = $(sitedir)$(target_prefix)
83
+ RUBYLIBDIR = $(sitelibdir)$(target_prefix)
84
+ RUBYARCHDIR = $(sitearchdir)$(target_prefix)
85
+
86
+ TARGET_SO = $(DLLIB)
87
+ CLEANLIBS = $(TARGET).so $(TARGET).il? $(TARGET).tds $(TARGET).map
88
+ CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
89
+
90
+ all: $(DLLIB)
91
+ static: $(STATIC_LIB)
92
+
93
+ clean:
94
+ @-$(RM) $(CLEANLIBS:/=\) $(CLEANOBJS:/=\) $(CLEANFILES:/=\)
95
+
96
+ distclean: clean
97
+ @-$(RM) Makefile extconf.h conftest.* mkmf.log
98
+ @-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES:/=\)
99
+
100
+ realclean: distclean
101
+ install: install-so install-rb
102
+
103
+ install-so: $(RUBYARCHDIR)
104
+ install-so: $(RUBYARCHDIR)/$(DLLIB)
105
+ $(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
106
+ $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
107
+ install-rb: pre-install-rb install-rb-default
108
+ install-rb-default: pre-install-rb-default
109
+ pre-install-rb: Makefile
110
+ pre-install-rb-default: Makefile
111
+ $(RUBYARCHDIR):
112
+ $(MAKEDIRS) $@
113
+
114
+ site-install: site-install-so site-install-rb
115
+ site-install-so: install-so
116
+ site-install-rb: install-rb
117
+
118
+ .SUFFIXES: .c .m .cc .cxx .cpp .o
119
+
120
+ .cc.o:
121
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
122
+
123
+ .cxx.o:
124
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
125
+
126
+ .cpp.o:
127
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
128
+
129
+ .c.o:
130
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
131
+
132
+ $(DLLIB): $(OBJS)
133
+ @-$(RM) $@
134
+ $(LDSHARED) $(DLDFLAGS) $(LIBPATH) -o $@ $(OBJS) $(LOCAL_LIBS) $(LIBS)
135
+
136
+
137
+
138
+ $(OBJS): ruby.h defines.h
data/ext/teius.c CHANGED
@@ -6,12 +6,14 @@
6
6
 
7
7
  static VALUE cParseError;
8
8
  static VALUE cXpathError;
9
- static VALUE cElementNotFound;
9
+ static VALUE cNodeNotFound;
10
+ static VALUE cNodeNotUnique;
10
11
  static VALUE cNode;
11
12
  static VALUE cDocument;
12
13
  static ID sRequired;
13
14
  static ID sFirst;
14
15
  static ID sAll;
16
+ static ID sUnique;
15
17
 
16
18
  static void doc_free(void *p) {
17
19
  xmlFreeDoc(p);
@@ -62,24 +64,24 @@ static VALUE node_find(int argc, VALUE *argv, VALUE self) {
62
64
  rb_scan_args(argc, argv, "21", &rType, &rXpath, &rOptions);
63
65
  int required = 0;
64
66
  if (argc == 3) {
65
- VALUE rRequired = rb_hash_aref(rOptions, sRequired);
66
- required = rRequired != Qnil;
67
+ VALUE rRequired = rb_hash_aref(rOptions, ID2SYM(sRequired));
68
+ required = rRequired != Qnil && rRequired != Qfalse;
67
69
  }
68
70
 
69
71
  xmlNodePtr node = NULL;
70
72
  Data_Get_Struct(self, xmlNode, node);
71
73
  xmlDocPtr doc = node->doc;
72
74
 
73
- xmlXPathContextPtr context;
74
- xmlXPathObjectPtr result;
75
+ xmlXPathContextPtr context;
76
+ xmlXPathObjectPtr result;
75
77
 
76
- context = xmlXPathNewContext(doc);
78
+ context = xmlXPathNewContext(doc);
77
79
  context->node = node;
78
80
 
79
81
  char *xpath = StringValuePtr(rXpath);
80
82
  result = xmlXPathEvalExpression(xpath, context);
81
83
  if (result == NULL) {
82
- xmlErrorPtr err = xmlGetLastError();
84
+ xmlErrorPtr err = xmlGetLastError();
83
85
  xmlXPathFreeContext(context);
84
86
  rb_raise(cXpathError, "Couldn't evaluate xpath [%s]: %s",
85
87
  xpath, err->message);
@@ -88,19 +90,24 @@ static VALUE node_find(int argc, VALUE *argv, VALUE self) {
88
90
  xmlNodeSetPtr node_set = result->nodesetval;
89
91
  int size = node_set != NULL ? node_set->nodeNr : 0;
90
92
 
93
+ ID type = SYM2ID(rType);
91
94
  if (size == 0 && required) {
92
95
  xmlXPathFreeObject(result);
93
96
  xmlXPathFreeContext(context);
94
- rb_raise(cElementNotFound, "No such element in %s: %s", node->name, xpath);
97
+ rb_raise(cNodeNotFound, "No such node in %s: %s", node->name, xpath);
98
+ } else if (size > 1 && type == sUnique) {
99
+ xmlXPathFreeObject(result);
100
+ xmlXPathFreeContext(context);
101
+ rb_raise(cNodeNotUnique, "node at path %s from %s is not unique",
102
+ xpath, node->name);
95
103
  }
96
104
 
97
105
  VALUE rResult;
98
- ID type = SYM2ID(rType);
99
- if (type == sFirst) { /* Just return first node */
106
+ if (type == sFirst || type == sUnique) { /* Just return first node */
100
107
  if (size == 0) {
101
108
  rResult = Qnil;
102
109
  } else {
103
- rResult = Data_Wrap_Struct(cNode, 0, 0, node_set->nodeTab[0]);
110
+ rResult = Data_Wrap_Struct(cNode, 0, 0, node_set->nodeTab[0]);
104
111
  }
105
112
  } else if (type == sAll) { /* Return ruby array of all nodes */
106
113
  int i;
@@ -108,15 +115,15 @@ static VALUE node_find(int argc, VALUE *argv, VALUE self) {
108
115
  for (i=0; i < size; i++) {
109
116
  xmlNodePtr cur_node = node_set->nodeTab[i];
110
117
 
111
- /* Create LibxmlElement and store it in arr */
118
+ /* Create Node and store it in arr */
112
119
  VALUE rNode = Data_Wrap_Struct(cNode, 0, 0, cur_node);
113
120
  rb_ary_store(arr, i, rNode);
114
121
  }
115
- rResult = arr;
122
+ rResult = arr;
116
123
  } else {
117
124
  xmlXPathFreeObject(result);
118
125
  xmlXPathFreeContext(context);
119
- rb_raise(rb_eArgError, "Unknown type: :%s (should be :first or :all)",
126
+ rb_raise(rb_eArgError, "Unknown type: :%s (should be :first, :unique or :all)",
120
127
  rb_id2name(type));
121
128
  }
122
129
 
@@ -132,18 +139,56 @@ static VALUE node_name(VALUE self) {
132
139
  return rb_str_new2(node->name);
133
140
  }
134
141
 
142
+ static VALUE node_xpath(VALUE self) {
143
+ xmlNodePtr node = NULL;
144
+ Data_Get_Struct(self, xmlNode, node);
145
+ return rb_str_new2(xmlGetNodePath(node));
146
+ }
147
+
148
+ static VALUE node_pointer(VALUE self) {
149
+ xmlNodePtr node = NULL;
150
+ Data_Get_Struct(self, xmlNode, node);
151
+ return INT2NUM((int)node);
152
+ }
153
+
135
154
  static VALUE parse_file(VALUE self, VALUE rFilename) {
136
- xmlDocPtr doc = xmlReadFile(StringValuePtr(rFilename), NULL, 0);
155
+ xmlDocPtr doc = xmlReadFile(StringValuePtr(rFilename), NULL, 0);
137
156
  if (doc == NULL) {
138
- xmlErrorPtr err = xmlGetLastError();
139
- rb_raise(cParseError, "could not parse file %s: %s",
140
- StringValuePtr(rFilename), err->message);
157
+ xmlErrorPtr err = xmlGetLastError();
158
+ rb_raise(cParseError, "could not parse file %s: %s",
159
+ StringValuePtr(rFilename), err->message);
141
160
  }
142
161
 
143
- /* Load new document */
144
- VALUE rDoc = Data_Wrap_Struct(cDocument, 0, doc_free, doc);
162
+ /* Load new document */
163
+ VALUE rDoc = Data_Wrap_Struct(cDocument, 0, doc_free, doc);
145
164
 
146
- return rDoc;
165
+ return rDoc;
166
+ }
167
+
168
+ static VALUE parse_string(VALUE self, VALUE rDocString) {
169
+ xmlDocPtr doc = xmlReadDoc(StringValuePtr(rDocString), NULL, NULL, 0);
170
+ if (doc == NULL) {
171
+ xmlErrorPtr err = xmlGetLastError();
172
+ rb_raise(cParseError, "could not parse string: %s", err->message);
173
+ }
174
+
175
+ /* Load new document */
176
+ VALUE rDoc = Data_Wrap_Struct(cDocument, 0, doc_free, doc);
177
+
178
+ return rDoc;
179
+ }
180
+
181
+ static VALUE document_to_s(VALUE self, VALUE rDocString) {
182
+ xmlDocPtr doc = NULL;
183
+ xmlChar *mem;
184
+ int size;
185
+
186
+ Data_Get_Struct(self, xmlDoc, doc);
187
+ xmlDocDumpMemory(doc, &mem, &size);
188
+ VALUE rStr = rb_str_new2(mem);
189
+ xmlFree(mem);
190
+
191
+ return rStr;
147
192
  }
148
193
 
149
194
  void Init_teius() {
@@ -153,25 +198,32 @@ void Init_teius() {
153
198
  sRequired = rb_intern("required");
154
199
  sFirst = rb_intern("first");
155
200
  sAll = rb_intern("all");
201
+ sUnique = rb_intern("unique");
156
202
 
157
203
  /* Modules */
158
204
  VALUE mTeius = rb_define_module("Teius");
159
205
 
160
206
  /* Exceptions */
161
- cParseError = rb_define_class_under(mTeius, "ParseError", rb_eStandardError);
162
- cXpathError = rb_define_class_under(mTeius, "XpathError", rb_eStandardError);
163
- cElementNotFound = rb_define_class_under(mTeius,
164
- "ElementNotFound", rb_eStandardError);
165
-
166
- /* LibxmlElement */
167
- cNode = rb_define_class_under(mTeius, "Node", rb_cObject);
168
- rb_define_method(cNode, "value", node_value, 0);
169
- rb_define_method(cNode, "document", node_document, 0);
170
- rb_define_method(cNode, "attributes", node_attributes, 0);
171
- rb_define_method(cNode, "find", node_find, -1);
172
- rb_define_method(cNode, "name", node_name, 0);
173
-
174
- /* LibxmlDocument */
207
+ cParseError = rb_define_class_under(mTeius, "ParseError", rb_eStandardError);
208
+ cXpathError = rb_define_class_under(mTeius, "XpathError", rb_eStandardError);
209
+ cNodeNotFound = rb_define_class_under(mTeius,
210
+ "NodeNotFound", rb_eStandardError);
211
+ cNodeNotUnique = rb_define_class_under(mTeius,
212
+ "NodeNotUnique", rb_eStandardError);
213
+
214
+ /* Node */
215
+ cNode = rb_define_class_under(mTeius, "Node", rb_cObject);
216
+ rb_define_method(cNode, "value", node_value, 0);
217
+ rb_define_method(cNode, "document", node_document, 0);
218
+ rb_define_method(cNode, "attributes", node_attributes, 0);
219
+ rb_define_method(cNode, "find", node_find, -1);
220
+ rb_define_method(cNode, "name", node_name, 0);
221
+ rb_define_method(cNode, "xpath", node_xpath, 0);
222
+ rb_define_method(cNode, "pointer", node_pointer, 0);
223
+
224
+ /* Document */
175
225
  cDocument = rb_define_class_under(mTeius, "Document", cNode);
176
- rb_define_singleton_method(cDocument, "parse_file", parse_file, 1);
226
+ rb_define_singleton_method(cDocument, "parse_file", parse_file, 1);
227
+ rb_define_singleton_method(cDocument, "parse_string", parse_string, 1);
228
+ rb_define_method(cNode, "to_s", document_to_s, 0);
177
229
  }
data/ext/teius.o ADDED
Binary file
data/ext/teius.so ADDED
Binary file
data/lib/teius.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'teius.so'
2
+
3
+ module Teius
4
+ class Node
5
+ def fetch(xpath)
6
+ node = find(:unique, xpath, :required => true)
7
+ return node ? node.value : nil
8
+ end
9
+
10
+ def ==(other)
11
+ self.pointer == other.pointer
12
+ end
13
+
14
+ def eql?(other)
15
+ self.pointer == other.pointer
16
+ end
17
+
18
+ def hash
19
+ self.pointer
20
+ end
21
+
22
+ def parent
23
+ self.find :first, '..'
24
+ end
25
+
26
+ def siblings
27
+ self.find :all, 'preceding-sibling::*|following-sibling::*'
28
+ end
29
+
30
+ def children
31
+ self.find :all, 'child::*'
32
+ end
33
+
34
+ end
35
+ end
data/lib/teius.so ADDED
Binary file
data/test/teius_test.rb CHANGED
@@ -1,6 +1,4 @@
1
- $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'lib')
2
- require 'rubygems'
3
- # need require_gem?
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
2
  require 'test/unit'
5
3
  require 'teius'
6
4
 
@@ -80,5 +78,61 @@ class TeiusTest < Test::Unit::TestCase
80
78
  assert_equal 'en-US', atts['language']
81
79
  assert_equal 8, atts.length
82
80
  end
81
+
82
+ def test_unique_find
83
+ el = @doc.find :unique, '/sports-content/sports-metadata/sports-title'
84
+ assert_equal 'Score Update: Chicago vs. Green Bay (Final)', el.value
85
+ assert_raise(NodeNotUnique) { @doc.find :unique, '//sports-content-code' }
86
+ assert_nil @doc.find(:unique, '/bogus')
87
+ assert_raise(NodeNotFound) { @doc.find :unique, '/bogus', { :required => true } }
88
+ end
89
+
90
+ def test_fetch
91
+ assert_equal 'Score Update: Chicago vs. Green Bay (Final)',
92
+ @doc.fetch('/sports-content/sports-metadata/sports-title')
93
+ end
83
94
 
95
+ def test_equality
96
+ n1 = @doc.find :first, '//team[1]'
97
+ assert_not_nil n1
98
+ n2 = @doc.find :first, '/sports-content/sports-event/team[1]'
99
+ assert_not_nil n2
100
+ assert_equal n1, n2
101
+ end
102
+
103
+ def test_hash
104
+ n1 = @doc.find :first, '//team[1]'
105
+ assert_not_nil n1
106
+ n2 = @doc.find :first, '/sports-content/sports-event/team[1]'
107
+ assert n1.eql?(n2)
108
+ hash = Hash.new
109
+ hash[n1] = 'test'
110
+ assert_equal 'test', hash[n2]
111
+ end
112
+
113
+ def test_parse_string
114
+ doc = Document.parse_string '<library><book /></library>'
115
+ book = doc.find :first, '//book'
116
+ assert_not_nil book
117
+ end
118
+
119
+ def test_xpath
120
+ n1 = @doc.find :first, '//team[1]'
121
+ n2 = @doc.find :first, '/sports-content/sports-event/team[1]'
122
+ assert_equal '/sports-content/sports-event/team[1]', n1.xpath
123
+ assert_equal n1, n2
124
+ end
125
+
126
+ def test_to_s
127
+ txt = @doc.to_s
128
+ assert_match /<\?xml version=/, txt
129
+ assert_match /Chicago 3 for 11 yards/, txt
130
+ end
131
+
132
+ def test_siblings
133
+ e = @doc.find :first, '//sports-content-code[5]'
134
+ sibs = e.siblings
135
+ assert_equal 9, sibs.size
136
+ end
137
+
84
138
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: teius
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.2
7
- date: 2006-03-06 00:00:00 +02:00
6
+ version: 0.1.0
7
+ date: 2006-05-05 00:00:00 +02:00
8
8
  summary: Light-weight Ruby API to LibXML.
9
9
  require_paths:
10
10
  - lib
@@ -29,7 +29,12 @@ authors:
29
29
  - Joshua Harvey
30
30
  files:
31
31
  - ext/extconf.rb
32
+ - ext/Makefile
32
33
  - ext/teius.c
34
+ - ext/teius.o
35
+ - ext/teius.so
36
+ - lib/teius.rb
37
+ - lib/teius.so
33
38
  - test/teius_test.rb
34
39
  - xml/xt.3608774-update-mid-event.xml
35
40
  - xml/xt.3608787-update-post-event.xml