ox 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ox might be problematic. Click here for more details.

@@ -18,7 +18,8 @@ changes with releases making Marshal dumped Object incompatible between some
18
18
  versions. The use of a binary format make debugging message streams or file
19
19
  contents next to impossible unless the same version of Ruby and only Ruby is
20
20
  used for inspecting the serialize Object. Ox on the other hand uses human
21
- readable XML.
21
+ readable XML. Ox also includes options that allow strict, tolerant, or a mode
22
+ that automatically defines missing classes.
22
23
 
23
24
  It is possible to write an XML serialization gem with Nokogiri but writing
24
25
  such a package in Ruby results in a module significantly slower than
@@ -51,8 +51,9 @@ static VALUE parse_double_time(const char *text, VALUE clas);
51
51
  static VALUE parse_regexp(const char *text);
52
52
 
53
53
  static VALUE get_var_sym_from_attrs(Attr a);
54
- static VALUE get_obj_from_attrs(Attr a, int best_effort);
55
- static VALUE get_class_from_attrs(Attr a, int best_effort);
54
+ static VALUE get_obj_from_attrs(Attr a, PInfo pi);
55
+ static VALUE get_class_from_attrs(Attr a, PInfo pi);
56
+ static VALUE classname2class(const char *name, PInfo pi);
56
57
  static unsigned long get_id_from_attrs(PInfo pi, Attr a);
57
58
  static CircArray circ_array_new(void);
58
59
  static void circ_array_free(CircArray ca);
@@ -93,48 +94,37 @@ name2var(const char *name) {
93
94
  }
94
95
 
95
96
  inline static VALUE
96
- classname2class(const char *name, int best_effort) {
97
- VALUE *slot;
97
+ resolve_classname(VALUE mod, const char *class_name, Effort effort) {
98
98
  VALUE clas;
99
-
100
- if (Qundef == (clas = ox_cache_get(class_cache, name, &slot))) {
101
- char class_name[1024];
102
- char *s;
103
- const char *n = name;
104
- ID ci;
99
+ ID ci = rb_intern(class_name);
105
100
 
106
- clas = rb_cObject;
107
- for (s = class_name; '\0' != *n; n++) {
108
- if (':' == *n) {
109
- *s = '\0';
110
- n++;
111
- ci = rb_intern(class_name);
112
- if (!best_effort || rb_const_defined(clas, ci)) {
113
- clas = rb_const_get(clas, ci);
114
- } else {
115
- return Qundef;
116
- }
117
- s = class_name;
118
- } else {
119
- *s++ = *n;
120
- }
101
+ switch (effort) {
102
+ case TolerantEffort:
103
+ if (rb_const_defined(mod, ci)) {
104
+ clas = rb_const_get(mod, ci);
105
+ } else {
106
+ clas = Qundef;
121
107
  }
122
- *s = '\0';
123
- ci = rb_intern(class_name);
124
- if (!best_effort || rb_const_defined(clas, ci)) {
125
- clas = rb_const_get(clas, ci);
108
+ break;
109
+ case AutoEffort:
110
+ if (rb_const_defined(mod, ci)) {
111
+ clas = rb_const_get(mod, ci);
126
112
  } else {
127
- return Qundef;
113
+ clas = rb_define_class_under(mod, class_name, ox_bag_clas);
128
114
  }
129
- //clas = rb_const_get(clas, rb_intern(class_name));
130
- *slot = clas;
115
+ break;
116
+ case StrictEffort:
117
+ default:
118
+ // raise an error if name is not defined
119
+ clas = rb_const_get(mod, ci);
120
+ break;
131
121
  }
132
122
  return clas;
133
123
  }
134
124
 
135
125
  inline static VALUE
136
- classname2obj(const char *name, int best_effort) {
137
- VALUE clas = classname2class(name, best_effort);
126
+ classname2obj(const char *name, PInfo pi) {
127
+ VALUE clas = classname2class(name, pi);
138
128
 
139
129
  if (Qundef == clas) {
140
130
  return Qnil;
@@ -178,6 +168,37 @@ parse_time(const char *text, VALUE clas) {
178
168
  return t;
179
169
  }
180
170
 
171
+ static VALUE
172
+ classname2class(const char *name, PInfo pi) {
173
+ VALUE *slot;
174
+ VALUE clas;
175
+
176
+ if (Qundef == (clas = ox_cache_get(class_cache, name, &slot))) {
177
+ char class_name[1024];
178
+ char *s;
179
+ const char *n = name;
180
+
181
+ clas = rb_cObject;
182
+ for (s = class_name; '\0' != *n; n++) {
183
+ if (':' == *n) {
184
+ *s = '\0';
185
+ n++;
186
+ if (Qundef == (clas = resolve_classname(clas, class_name, pi->effort))) {
187
+ return Qundef;
188
+ }
189
+ s = class_name;
190
+ } else {
191
+ *s++ = *n;
192
+ }
193
+ }
194
+ *s = '\0';
195
+ if (Qundef != (clas = resolve_classname(clas, class_name, pi->effort))) {
196
+ *slot = clas;
197
+ }
198
+ }
199
+ return clas;
200
+ }
201
+
181
202
  static VALUE
182
203
  get_var_sym_from_attrs(Attr a) {
183
204
  for (; 0 != a->name; a++) {
@@ -189,10 +210,10 @@ get_var_sym_from_attrs(Attr a) {
189
210
  }
190
211
 
191
212
  static VALUE
192
- get_obj_from_attrs(Attr a, int best_effort) {
213
+ get_obj_from_attrs(Attr a, PInfo pi) {
193
214
  for (; 0 != a->name; a++) {
194
215
  if ('c' == *a->name && '\0' == *(a->name + 1)) {
195
- return classname2obj(a->value, best_effort);
216
+ return classname2obj(a->value, pi);
196
217
  }
197
218
  }
198
219
  return Qundef;
@@ -209,10 +230,10 @@ get_struct_from_attrs(Attr a) {
209
230
  }
210
231
 
211
232
  static VALUE
212
- get_class_from_attrs(Attr a, int best_effort) {
233
+ get_class_from_attrs(Attr a, PInfo pi) {
213
234
  for (; 0 != a->name; a++) {
214
235
  if ('c' == *a->name && '\0' == *(a->name + 1)) {
215
- return classname2class(a->value, best_effort);
236
+ return classname2class(a->value, pi);
216
237
  }
217
238
  }
218
239
  return Qundef;
@@ -537,7 +558,7 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
537
558
  break;
538
559
  case RawCode:
539
560
  if (hasChildren) {
540
- h->obj = parse(pi->s, ox_gen_callbacks, &pi->s, pi->trace, pi->best_effort);
561
+ h->obj = parse(pi->s, ox_gen_callbacks, &pi->s, pi->trace, pi->effort);
541
562
  if (0 != pi->circ_array) {
542
563
  circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
543
564
  }
@@ -546,7 +567,7 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
546
567
  }
547
568
  break;
548
569
  case ObjectCode:
549
- h->obj = get_obj_from_attrs(attrs, pi->best_effort);
570
+ h->obj = get_obj_from_attrs(attrs, pi);
550
571
  if (0 != pi->circ_array && Qnil != h->obj) {
551
572
  circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
552
573
  }
@@ -558,7 +579,7 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
558
579
  }
559
580
  break;
560
581
  case ClassCode:
561
- h->obj = get_class_from_attrs(attrs, pi->best_effort);
582
+ h->obj = get_class_from_attrs(attrs, pi);
562
583
  break;
563
584
  case RefCode:
564
585
  h->obj = Qundef;
@@ -71,7 +71,10 @@ VALUE optimized_sym;
71
71
  VALUE object_sym;
72
72
  VALUE generic_sym;
73
73
  VALUE limited_sym;
74
- VALUE best_effort_sym;
74
+ VALUE strict_sym;
75
+ VALUE tolerant_sym;
76
+ VALUE effort_sym;
77
+ VALUE auto_define_sym;
75
78
  VALUE trace_sym;
76
79
  VALUE empty_string;
77
80
  VALUE zero_fixnum;
@@ -81,7 +84,7 @@ VALUE ox_comment_clas;
81
84
  VALUE ox_doctype_clas;
82
85
  VALUE ox_document_clas;
83
86
  VALUE ox_element_clas;
84
- VALUE ox_text_clas;
87
+ VALUE ox_bag_clas;
85
88
  VALUE struct_class;
86
89
  VALUE time_class;
87
90
 
@@ -112,7 +115,7 @@ to_obj(VALUE self, VALUE ruby_xml) {
112
115
  Check_Type(ruby_xml, T_STRING);
113
116
  // the xml string gets modified so make a copy of it
114
117
  xml = strdup(StringValuePtr(ruby_xml));
115
- obj = parse(xml, ox_obj_callbacks, 0, 0, 0);
118
+ obj = parse(xml, ox_obj_callbacks, 0, 0, StrictEffort);
116
119
  free(xml);
117
120
  return obj;
118
121
  }
@@ -131,7 +134,7 @@ to_gen(VALUE self, VALUE ruby_xml) {
131
134
  Check_Type(ruby_xml, T_STRING);
132
135
  // the xml string gets modified so make a copy of it
133
136
  xml = strdup(StringValuePtr(ruby_xml));
134
- obj = parse(xml, ox_gen_callbacks, 0, 0, 0);
137
+ obj = parse(xml, ox_gen_callbacks, 0, 0, StrictEffort);
135
138
  free(xml);
136
139
  return obj;
137
140
  }
@@ -147,8 +150,8 @@ static VALUE
147
150
  load(char *xml, int argc, VALUE *argv, VALUE self) {
148
151
  VALUE obj;
149
152
  int mode = AutoMode;
153
+ int effort = StrictEffort;
150
154
  int trace = 0;
151
- int best_effort = 0;
152
155
 
153
156
  if (1 == argc && rb_cHash == rb_obj_class(*argv)) {
154
157
  VALUE h = *argv;
@@ -169,27 +172,35 @@ load(char *xml, int argc, VALUE *argv, VALUE self) {
169
172
  rb_raise(rb_eArgError, ":mode must be :generic, :object, or :limited.\n");
170
173
  }
171
174
  }
175
+ if (Qnil != (v = rb_hash_lookup(h, effort_sym))) {
176
+ if (auto_define_sym == v) {
177
+ effort = AutoEffort;
178
+ } else if (tolerant_sym == v) {
179
+ effort = TolerantEffort;
180
+ } else if (strict_sym == v) {
181
+ effort = StrictEffort;
182
+ } else {
183
+ rb_raise(rb_eArgError, ":effort must be :strict, :tolerant, or :auto_define.\n");
184
+ }
185
+ }
172
186
  if (Qnil != (v = rb_hash_lookup(h, trace_sym))) {
173
187
  Check_Type(v, T_FIXNUM);
174
188
  trace = FIX2INT(v);
175
189
  }
176
- if (Qnil != (v = rb_hash_lookup(h, best_effort_sym))) {
177
- best_effort = (Qfalse != v);
178
- }
179
190
  }
180
191
  switch (mode) {
181
192
  case ObjMode:
182
- obj = parse(xml, ox_obj_callbacks, 0, trace, best_effort);
193
+ obj = parse(xml, ox_obj_callbacks, 0, trace, effort);
183
194
  break;
184
195
  case GenMode:
185
- obj = parse(xml, ox_gen_callbacks, 0, trace, 0);
196
+ obj = parse(xml, ox_gen_callbacks, 0, trace, StrictEffort);
186
197
  break;
187
198
  case LimMode:
188
- obj = parse(xml, ox_limited_callbacks, 0, trace, best_effort);
199
+ obj = parse(xml, ox_limited_callbacks, 0, trace, effort);
189
200
  break;
190
201
  case AutoMode:
191
202
  default:
192
- obj = parse(xml, ox_gen_callbacks, 0, trace, 0);
203
+ obj = parse(xml, ox_gen_callbacks, 0, trace, StrictEffort);
193
204
  break;
194
205
  }
195
206
  free(xml);
@@ -204,12 +215,15 @@ load(char *xml, int argc, VALUE *argv, VALUE self) {
204
215
  * malformed or the classes specified are not valid.
205
216
  * [xml] XML String
206
217
  * [options] load options
207
- * [:mode] format expected
208
- * [:object] object format
209
- * [:generic] read as a generic XML file
210
- * [:limited] read as a generic XML file but with callbacks on text and elements events only
211
- * [:trace] trace level as a Fixnum, default: 0 (silent)
212
- * [:best_effort] use best effort to create Objects using nil if undefined Class, default: 0
218
+ * [:mode] format expected
219
+ * [:object] object format
220
+ * [:generic] read as a generic XML file
221
+ * [:limited] read as a generic XML file but with callbacks on text and elements events only
222
+ * [:effort] effort to use when an undefined class is encountered, default: :strict
223
+ * [:strict] raise an NameError for missing classes and modules
224
+ * [:tolerant] return nil for missing classes and modules
225
+ * [:auto_define] auto define missing classes and modules
226
+ * [:trace] trace level as a Fixnum, default: 0 (silent)
213
227
  */
214
228
  static VALUE
215
229
  load_str(int argc, VALUE *argv, VALUE self) {
@@ -229,12 +243,15 @@ load_str(int argc, VALUE *argv, VALUE self) {
229
243
  * malformed or the classes specified are not valid.
230
244
  * [file_path] file path to read the XML document from
231
245
  * [options] load options
232
- * [:mode] format expected
233
- * [:object] object format
234
- * [:generic] read as a generic XML file
235
- * [:limited] read as a generic XML file but with callbacks on text and elements events only
236
- * [:trace] trace level as a Fixnum, default: 0 (silent)
237
- * [:best_effort] use best effort to create Objects using nil if undefined Class, default: 0
246
+ * [:mode] format expected
247
+ * [:object] object format
248
+ * [:generic] read as a generic XML file
249
+ * [:limited] read as a generic XML file but with callbacks on text and elements events only
250
+ * [:effort] effort to use when an undefined class is encountered, default: :strict
251
+ * [:strict] raise an NameError for missing classes and modules
252
+ * [:tolerant] return nil for missing classes and modules
253
+ * [:auto_define] auto define missing classes and modules
254
+ * [:trace] trace level as a Fixnum, default: 0 (silent)
238
255
  */
239
256
  static VALUE
240
257
  load_file(int argc, VALUE *argv, VALUE self) {
@@ -419,7 +436,10 @@ void Init_ox() {
419
436
  generic_sym = ID2SYM(rb_intern("generic"));
420
437
  limited_sym = ID2SYM(rb_intern("limited"));
421
438
  trace_sym = ID2SYM(rb_intern("trace"));
422
- best_effort_sym = ID2SYM(rb_intern("best_effort"));
439
+ effort_sym = ID2SYM(rb_intern("effort"));
440
+ strict_sym = ID2SYM(rb_intern("strict"));
441
+ tolerant_sym = ID2SYM(rb_intern("tolerant"));
442
+ auto_define_sym = ID2SYM(rb_intern("auto_define"));
423
443
  empty_string = rb_str_new2("");
424
444
  zero_fixnum = INT2NUM(0);
425
445
 
@@ -429,6 +449,7 @@ void Init_ox() {
429
449
  ox_comment_clas = rb_const_get(Ox, rb_intern("Comment"));
430
450
  ox_doctype_clas = rb_const_get(Ox, rb_intern("DocType"));
431
451
  ox_cdata_clas = rb_const_get(Ox, rb_intern("CData"));
452
+ ox_bag_clas = rb_const_get(Ox, rb_intern("Bag"));
432
453
 
433
454
  ox_cache_new(&symbol_cache);
434
455
  ox_cache_new(&class_cache);
@@ -65,6 +65,12 @@ typedef enum {
65
65
  UseRaw = 11,
66
66
  } Use;
67
67
 
68
+ typedef enum {
69
+ StrictEffort = 0,
70
+ TolerantEffort = 1,
71
+ AutoEffort = 2,
72
+ } Effort;
73
+
68
74
  typedef enum {
69
75
  NoCode = 0,
70
76
  ArrayCode = 'a',
@@ -133,10 +139,10 @@ struct _PInfo {
133
139
  rb_encoding *encoding;
134
140
  unsigned long id; /* set for text types when cirs_array is set */
135
141
  int trace;
136
- int best_effort;
142
+ Effort effort;
137
143
  };
138
144
 
139
- extern VALUE parse(char *xml, ParseCallbacks pcb, char **endp, int trace, int best_effort);
145
+ extern VALUE parse(char *xml, ParseCallbacks pcb, char **endp, int trace, Effort effort);
140
146
  extern void _raise_error(const char *msg, const char *xml, const char *current, const char* file, int line);
141
147
 
142
148
  extern char* write_obj_to_str(VALUE obj, int indent, int xsd_date, int circular);
@@ -172,7 +178,7 @@ extern VALUE zero_fixnum;
172
178
 
173
179
  extern VALUE ox_document_clas;
174
180
  extern VALUE ox_element_clas;
175
- extern VALUE ox_text_clas;
181
+ extern VALUE ox_bag_clas;
176
182
  extern VALUE ox_comment_clas;
177
183
  extern VALUE ox_doctype_clas;
178
184
  extern VALUE ox_cdata_clas;
@@ -79,7 +79,7 @@ next_non_white(PInfo pi) {
79
79
  }
80
80
 
81
81
  VALUE
82
- parse(char *xml, ParseCallbacks pcb, char **endp, int trace, int best_effort) {
82
+ parse(char *xml, ParseCallbacks pcb, char **endp, int trace, Effort effort) {
83
83
  struct _PInfo pi;
84
84
  int body_read = 0;
85
85
 
@@ -98,7 +98,7 @@ parse(char *xml, ParseCallbacks pcb, char **endp, int trace, int best_effort) {
98
98
  pi.circ_array = 0;
99
99
  pi.encoding = 0;
100
100
  pi.trace = trace;
101
- pi.best_effort = best_effort;
101
+ pi.effort = effort;
102
102
  while (1) {
103
103
  next_non_white(&pi); // skip white space
104
104
  if ('\0' == *pi.s) {
data/lib/ox.rb CHANGED
@@ -93,5 +93,6 @@ require 'ox/cdata'
93
93
  require 'ox/doctype'
94
94
  require 'ox/element'
95
95
  require 'ox/document'
96
+ require 'ox/bag'
96
97
 
97
98
  require 'ox/ox' # C extension
@@ -0,0 +1,88 @@
1
+
2
+ module Ox
3
+
4
+ # A generic class that is used only for storing attributes. It is the base
5
+ # Class for auto-generated classes in the storage system. Instance variables
6
+ # are added using the instance_variable_set() method. All instance variables
7
+ # can be accessed using the variable name (without the @ prefix). No setters
8
+ # are provided as the Class is intended for reading only.
9
+ class Bag
10
+
11
+ # The initializer can take multiple arguments in the form of key values
12
+ # where the key is the variable name and the value is the variable
13
+ # value. This is intended for testing purposes only.
14
+ # Example: Ox::Bag.new(:@x => 42, :@y => 57)
15
+ def initialize(args={ })
16
+ args.each do |k,v|
17
+ self.instance_variable_set(k, v)
18
+ m = k.to_s[1..-1].to_sym
19
+ unless respond_to?(m)
20
+ self.class.define_get(m, k)
21
+ end
22
+ end
23
+ end
24
+
25
+ # Replaces the Object.respond_to?() method to return true for any method
26
+ # than matches instance variables.
27
+ # [m] method symbol
28
+ def respond_to?(m)
29
+ at_m = ('@' + m.to_s).to_sym
30
+ instance_variables.include?(at_m)
31
+ end
32
+
33
+ # Handles requests for variable values. Others cause an Exception to be
34
+ # raised.
35
+ # [m] method symbol
36
+ def method_missing(m, *args, &block)
37
+ raise ArgumentError.new("wrong number of arguments(#{args.size} for 0)") unless args.nil? or args.empty?
38
+ at_m = ('@' + m.to_s).to_sym
39
+ raise NoMethodError("undefined method", m) unless instance_variable_defined?(at_m)
40
+ instance_variable_get(at_m)
41
+ end
42
+
43
+ # Replace eql?() with something more reasonable for this Class.
44
+ # [other] Object to compare this one to
45
+ def eql?(other)
46
+ return false if (other.nil? or self.class != other.class)
47
+ ova = other.instance_variables
48
+ iv = instance_variables
49
+ return false if ova.size != iv.size
50
+ iv.each do |vid|
51
+ return false if instance_variable_get(vid) != other.instance_variable_get(vid)
52
+ end
53
+ true
54
+ end
55
+ alias == eql?
56
+
57
+ end # Bag
58
+
59
+ # Define a new class based on the Ox::Bag class. This is used internally in
60
+ # the Ox module and is available to service wrappers that receive XML
61
+ # requests that include Objects of Classes not defined in the storage
62
+ # process.
63
+ # [classname] Class name or symbol that includes Module names
64
+ def self.define_class(classname)
65
+ classname = classname.to_s unless classname.is_a?(String)
66
+ tokens = classname.split('::').map { |n| n.to_sym }
67
+ raise "Invalid classname '#{classname}" if tokens.empty?
68
+ m = Object
69
+ tokens[0..-2].each do |sym|
70
+ if m.const_defined?(sym)
71
+ m = m.const_get(sym)
72
+ else
73
+ c = Module.new
74
+ m.const_set(sym, c)
75
+ m = c
76
+ end
77
+ end
78
+ sym = tokens[-1]
79
+ if m.const_defined?(sym)
80
+ c = m.const_get(sym)
81
+ else
82
+ c = Class.new(Ox::Bag)
83
+ m.const_set(sym, c)
84
+ end
85
+ c
86
+ end
87
+
88
+ end # Ox
@@ -112,15 +112,26 @@ class Func < ::Test::Unit::TestCase
112
112
 
113
113
  def test_bad_object
114
114
  xml = %{<?xml version="1.0"?>
115
- <o c="Bad">
115
+ <o c="Bad::Boy">
116
116
  <i a="@x">3</i>
117
117
  </o>
118
+ }
119
+ xml2 = %{<?xml version="1.0"?>
120
+ <o c="Bad">
121
+ <i a="@x">7</i>
122
+ </o>
118
123
  }
119
124
  assert_raise(NameError) {
120
125
  Ox.load(xml, :mode => :object, :trace => 0)
121
126
  }
122
- loaded = Ox.load(xml, :mode => :object, :trace => 0, :best_effort => true)
127
+ loaded = Ox.load(xml, :mode => :object, :trace => 0, :effort => :tolerant)
123
128
  assert_equal(loaded, nil)
129
+ loaded = Ox.load(xml, :mode => :object, :trace => 0, :effort => :auto_define)
130
+ assert_equal(loaded.class.to_s, 'Bad::Boy')
131
+ assert_equal(loaded.class.superclass.to_s, 'Ox::Bag')
132
+ loaded = Ox.load(xml2, :mode => :object, :trace => 0, :effort => :auto_define)
133
+ assert_equal(loaded.class.to_s, 'Bad')
134
+ assert_equal(loaded.class.superclass.to_s, 'Ox::Bag')
124
135
  end
125
136
 
126
137
  def test_class
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ox
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.0.3
5
+ version: 1.1.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Peter Ohler
@@ -10,7 +10,8 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-07-04 00:00:00 Z
13
+ date: 2011-07-06 00:00:00 +09:00
14
+ default_executable:
14
15
  dependencies: []
15
16
 
16
17
  description: A fast XML parser and object serializer that uses only standard C lib.
@@ -22,6 +23,7 @@ extensions:
22
23
  extra_rdoc_files:
23
24
  - README.rdoc
24
25
  files:
26
+ - lib/ox/bag.rb
25
27
  - lib/ox/cdata.rb
26
28
  - lib/ox/comment.rb
27
29
  - lib/ox/doctype.rb
@@ -73,6 +75,7 @@ files:
73
75
  - test/Sample.graffle
74
76
  - LICENSE
75
77
  - README.rdoc
78
+ has_rdoc: true
76
79
  homepage: http://www.ohler.com/ox
77
80
  licenses: []
78
81
 
@@ -98,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
101
  requirements: []
99
102
 
100
103
  rubyforge_project: ox
101
- rubygems_version: 1.8.5
104
+ rubygems_version: 1.6.2
102
105
  signing_key:
103
106
  specification_version: 3
104
107
  summary: A fast XML parser and object serializer.