nokogiri-happymapper 0.5.5 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/happymapper.rb CHANGED
@@ -7,7 +7,7 @@ class XmlContent; end
7
7
 
8
8
  module HappyMapper
9
9
 
10
- VERSION = "0.5.5"
10
+ VERSION = "0.5.6"
11
11
 
12
12
  DEFAULT_NS = "happymapper"
13
13
 
@@ -21,33 +21,33 @@ module HappyMapper
21
21
  end
22
22
 
23
23
  module ClassMethods
24
-
24
+
25
25
  #
26
26
  # The xml has the following attributes defined.
27
- #
27
+ #
28
28
  # @example
29
- #
29
+ #
30
30
  # "<country code='de'>Germany</country>"
31
- #
31
+ #
32
32
  # # definition of the 'code' attribute within the class
33
33
  # attribute :code, String
34
- #
34
+ #
35
35
  # @param [Symbol] name the name of the accessor that is created
36
36
  # @param [String,Class] type the class name of the name of the class whcih
37
37
  # the object will be converted upon parsing
38
38
  # @param [Hash] options additional parameters to send to the relationship
39
- #
39
+ #
40
40
  def attribute(name, type, options={})
41
41
  attribute = Attribute.new(name, type, options)
42
42
  @attributes[to_s] ||= []
43
43
  @attributes[to_s] << attribute
44
44
  attr_accessor attribute.method_name.intern
45
45
  end
46
-
46
+
47
47
  #
48
48
  # The elements defined through {#attribute}.
49
- #
50
- # @return [Array<Attribute>] a list of the attributes defined for this class;
49
+ #
50
+ # @return [Array<Attribute>] a list of the attributes defined for this class;
51
51
  # an empty array is returned when there have been no attributes defined.
52
52
  #
53
53
  def attributes
@@ -57,37 +57,37 @@ module HappyMapper
57
57
  #
58
58
  # Register a namespace that is used to persist the object namespace back to
59
59
  # XML.
60
- #
60
+ #
61
61
  # @example
62
- #
62
+ #
63
63
  # register_namespace 'prefix', 'http://www.unicornland.com/prefix'
64
- #
64
+ #
65
65
  # # the output will contain the namespace defined
66
- #
66
+ #
67
67
  # "<outputXML xmlns:prefix="http://www.unicornland.com/prefix">
68
68
  # ...
69
69
  # </outputXML>"
70
- #
70
+ #
71
71
  # @param [String] namespace the xml prefix
72
72
  # @param [String] ns url for the xml namespace
73
73
  #
74
74
  def register_namespace(namespace, ns)
75
75
  @registered_namespaces.merge!({namespace => ns})
76
76
  end
77
-
77
+
78
78
  #
79
79
  # An element defined in the XML that is parsed.
80
- #
80
+ #
81
81
  # @example
82
- #
82
+ #
83
83
  # "<address location='home'>
84
84
  # <city>Oldenburg</city>
85
85
  # </address>"
86
86
  #
87
87
  # # definition of the 'city' element within the class
88
- #
88
+ #
89
89
  # element :city, String
90
- #
90
+ #
91
91
  # @param [Symbol] name the name of the accessor that is created
92
92
  # @param [String,Class] type the class name of the name of the class whcih
93
93
  # the object will be converted upon parsing
@@ -102,7 +102,7 @@ module HappyMapper
102
102
 
103
103
  #
104
104
  # The elements defined through {#element}, {#has_one}, and {#has_many}.
105
- #
105
+ #
106
106
  # @return [Array<Element>] a list of the elements contained defined for this
107
107
  # class; an empty array is returned when there have been no elements
108
108
  # defined.
@@ -110,18 +110,18 @@ module HappyMapper
110
110
  def elements
111
111
  @elements[to_s] || []
112
112
  end
113
-
113
+
114
114
  #
115
115
  # The value stored in the text node of the current element.
116
116
  #
117
117
  # @example
118
- #
118
+ #
119
119
  # "<firstName>Michael Jackson</firstName>"
120
120
  #
121
121
  # # definition of the 'firstName' text node within the class
122
- #
122
+ #
123
123
  # content :first_name, String
124
- #
124
+ #
125
125
  # @param [Symbol] name the name of the accessor that is created
126
126
  # @param [String,Class] type the class name of the name of the class whcih
127
127
  # the object will be converted upon parsing. By Default String class will be taken.
@@ -145,21 +145,21 @@ module HappyMapper
145
145
  #
146
146
  # The object has one of these elements in the XML. If there are multiple,
147
147
  # the last one will be set to this value.
148
- #
148
+ #
149
149
  # @param [Symbol] name the name of the accessor that is created
150
150
  # @param [String,Class] type the class name of the name of the class whcih
151
151
  # the object will be converted upon parsing
152
152
  # @param [Hash] options additional parameters to send to the relationship
153
153
  #
154
154
  # @see #element
155
- #
155
+ #
156
156
  def has_one(name, type, options={})
157
157
  element name, type, {:single => true}.merge(options)
158
158
  end
159
-
159
+
160
160
  #
161
161
  # The object has many of these elements in the XML.
162
- #
162
+ #
163
163
  # @param [Symbol] name the name of accessor that is created
164
164
  # @param [String,Class] type the class name or the name of the class which
165
165
  # the object will be converted upon parsing.
@@ -170,7 +170,7 @@ module HappyMapper
170
170
  def has_many(name, type, options={})
171
171
  element name, type, {:single => false}.merge(options)
172
172
  end
173
-
173
+
174
174
  #
175
175
  # Specify a namespace if a node and all its children are all namespaced
176
176
  # elements. This is simpler than passing the :namespace option to each
@@ -193,13 +193,13 @@ module HappyMapper
193
193
 
194
194
  #
195
195
  # The name of the tag
196
- #
196
+ #
197
197
  # @return [String] the name of the tag as a string, downcased
198
198
  #
199
199
  def tag_name
200
200
  @tag_name ||= to_s.split('::')[-1].downcase
201
201
  end
202
-
202
+
203
203
  # There is an XML tag that needs to be known for parsing and should be generated
204
204
  # during a to_xml. But it doesn't need to be a class and the contained elements should
205
205
  # be made available on the parent class
@@ -207,7 +207,7 @@ module HappyMapper
207
207
  # @param [String] name the name of the element that is just a place holder
208
208
  # @param [Proc] blk the element definitions inside the place holder tag
209
209
  #
210
- def wrap(name, &blk)
210
+ def wrap(name, &blk)
211
211
  # Get an anonymous HappyMapper that has 'name' as its tag and defined
212
212
  # in '&blk'. Then save that to a class instance variable for later use
213
213
  wrapper = AnonymousWrapperClassFactory.get(name, &blk)
@@ -215,8 +215,8 @@ module HappyMapper
215
215
 
216
216
  # Create getter/setter for each element and attribute defined on the anonymous HappyMapper
217
217
  # onto this class. They get/set the value by passing thru to the anonymous class.
218
- passthrus = wrapper.attributes + wrapper.elements
219
- passthrus.each do |item|
218
+ passthrus = wrapper.attributes + wrapper.elements
219
+ passthrus.each do |item|
220
220
  class_eval %{
221
221
  def #{item.method_name}
222
222
  @#{name} ||= self.class.instance_variable_get('@wrapper_anonymous_classes')['#{wrapper.inspect}'].new
@@ -226,39 +226,59 @@ module HappyMapper
226
226
  @#{name} ||= self.class.instance_variable_get('@wrapper_anonymous_classes')['#{wrapper.inspect}'].new
227
227
  @#{name}.#{item.method_name} = value
228
228
  end
229
- }
230
- end
229
+ }
230
+ end
231
231
 
232
232
  has_one name, wrapper
233
233
  end
234
234
 
235
+ # The callback defined through {.with_nokogiri_config}.
236
+ #
237
+ # @return [Proc] the proc to pass to Nokogiri to setup parse options. nil if empty.
238
+ #
239
+ def nokogiri_config_callback
240
+ @nokogiri_config_callback
241
+ end
242
+
243
+ # Register a config callback according to the block Nokogori expects when calling Nokogiri::XML::Document.parse().
244
+ # See http://nokogiri.org/Nokogiri/XML/Document.html#method-c-parse
245
+ #
246
+ # @param [Proc] the proc to pass to Nokogiri to setup parse options
247
+ #
248
+ def with_nokogiri_config(&blk)
249
+ @nokogiri_config_callback = blk
250
+ end
251
+
235
252
  #
236
- # @param [Nokogiri::XML::Node,Nokogiri:XML::Document,String] xml the XML
253
+ # @param [Nokogiri::XML::Node,Nokogiri:XML::Document,String] xml the XML
237
254
  # contents to convert into Object.
238
255
  # @param [Hash] options additional information for parsing. :single => true
239
- # if requesting a single object, otherwise it defaults to retuning an
256
+ # if requesting a single object, otherwise it defaults to retuning an
240
257
  # array of multiple items. :xpath information where to start the parsing
241
258
  # :namespace is the namespace to use for additional information.
242
259
  #
243
260
  def parse(xml, options = {})
244
-
261
+
245
262
  # create a local copy of the objects namespace value for this parse execution
246
263
  namespace = @namespace
247
-
264
+
248
265
  # If the XML specified is an Node then we have what we need.
249
266
  if xml.is_a?(Nokogiri::XML::Node) && !xml.is_a?(Nokogiri::XML::Document)
250
267
  node = xml
251
268
  else
252
-
269
+
253
270
  # If xml is an XML document select the root node of the document
254
271
  if xml.is_a?(Nokogiri::XML::Document)
255
272
  node = xml.root
256
273
  else
257
-
274
+
258
275
  # Attempt to parse the xml value with Nokogiri XML as a document
259
276
  # and select the root element
260
-
261
- xml = Nokogiri::XML(xml, nil, nil, Nokogiri::XML::ParseOptions::STRICT)
277
+ xml = Nokogiri::XML(
278
+ xml, nil, nil,
279
+ Nokogiri::XML::ParseOptions::STRICT,
280
+ &nokogiri_config_callback
281
+ )
262
282
  node = xml.root
263
283
  end
264
284
 
@@ -272,13 +292,13 @@ module HappyMapper
272
292
  # if any namespaces have been provied then we should capture those and then
273
293
  # merge them with any namespaces found on the xml node and merge all that
274
294
  # with any namespaces that have been registered on the object
275
-
295
+
276
296
  namespaces = options[:namespaces] || {}
277
297
  namespaces = namespaces.merge(xml.collect_namespaces) if xml.respond_to?(:collect_namespaces)
278
298
  namespaces = namespaces.merge(@registered_namespaces)
279
-
299
+
280
300
  # if a namespace has been provided then set the current namespace to it
281
- # or set the default namespace to the one defined under 'xmlns'
301
+ # or set the default namespace to the one defined under 'xmlns'
282
302
  # or set the default namespace to the namespace that matches 'happymapper's
283
303
 
284
304
  if options[:namespace]
@@ -291,17 +311,17 @@ module HappyMapper
291
311
  elsif namespaces.has_key?(DEFAULT_NS)
292
312
  namespace ||= DEFAULT_NS
293
313
  end
294
-
314
+
295
315
  # from the options grab any nodes present and if none are present then
296
- # perform the following to find the nodes for the given class
297
-
316
+ # perform the following to find the nodes for the given class
317
+
298
318
  nodes = options.fetch(:nodes) do
299
-
319
+
300
320
  # when at the root use the xpath '/' otherwise use a more gready './/'
301
321
  # unless an xpath has been specified, which should overwrite default
302
322
  # and finally attach the current namespace if one has been defined
303
- #
304
-
323
+ #
324
+
305
325
  xpath = (root ? '/' : './/')
306
326
  xpath = options[:xpath].to_s.sub(/([^\/])$/, '\1/') if options[:xpath]
307
327
  xpath += "#{namespace}:" if namespace
@@ -334,21 +354,21 @@ module HappyMapper
334
354
  # a large result set of data.
335
355
 
336
356
  limit = options[:in_groups_of] || nodes.size
337
-
357
+
338
358
  # If the limit of 0 has been specified then the user obviously wants
339
359
  # none of the nodes that we are serving within this batch of nodes.
340
-
360
+
341
361
  return [] if limit == 0
342
362
 
343
363
  collection = []
344
-
364
+
345
365
  nodes.each_slice(limit) do |slice|
346
-
347
- part = slice.map do |n|
348
-
366
+
367
+ part = slice.map do |n|
368
+
349
369
  # If an existing HappyMapper object is provided, update it with the
350
370
  # values from the xml being parsed. Otherwise, create a new object
351
-
371
+
352
372
  obj = options[:update] ? options[:update] : new
353
373
 
354
374
  attributes.each do |attr|
@@ -362,16 +382,16 @@ module HappyMapper
362
382
  if @content
363
383
  obj.send("#{@content.method_name}=",@content.from_xml_node(n, namespace, namespaces))
364
384
  end
365
-
366
- # If the HappyMapper class has the method #xml_value=,
385
+
386
+ # If the HappyMapper class has the method #xml_value=,
367
387
  # attr_writer :xml_value, or attr_accessor :xml_value then we want to
368
388
  # assign the current xml that we just parsed to the xml_value
369
-
389
+
370
390
  if obj.respond_to?('xml_value=')
371
391
  n.namespaces.each {|name,path| n[name] = path }
372
392
  obj.xml_value = n.to_xml
373
393
  end
374
-
394
+
375
395
  # If the HappyMapper class has the method #xml_content=,
376
396
  # attr_write :xml_content, or attr_accessor :xml_content then we want to
377
397
  # assign the child xml that we just parsed to the xml_content
@@ -380,12 +400,12 @@ module HappyMapper
380
400
  n = n.children if n.respond_to?(:children)
381
401
  obj.xml_content = n.to_xml
382
402
  end
383
-
403
+
384
404
  # collect the object that we have created
385
-
405
+
386
406
  obj
387
407
  end
388
-
408
+
389
409
  # If a block has been provided and the user has requested that the objects
390
410
  # be handled in groups then we should yield the slice of the objects to them
391
411
  # otherwise continue to lump them together
@@ -395,7 +415,7 @@ module HappyMapper
395
415
  else
396
416
  collection += part
397
417
  end
398
-
418
+
399
419
  end
400
420
 
401
421
  # per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354
@@ -411,9 +431,9 @@ module HappyMapper
411
431
  collection
412
432
  end
413
433
  end
414
-
434
+
415
435
  end
416
-
436
+
417
437
  #
418
438
  # Create an xml representation of the specified class based on defined
419
439
  # HappyMapper elements and attributes. The method is defined in a way
@@ -424,7 +444,7 @@ module HappyMapper
424
444
  # is being used when called recursively.
425
445
  # @param [String] default_namespace the name of the namespace which is the
426
446
  # default for the xml being produced; this is specified by the element
427
- # declaration when calling #to_xml recursively.
447
+ # declaration when calling #to_xml recursively.
428
448
  # @param [String] tag_from_parent the xml tag to use on the element when being
429
449
  # called recursively. This lets the parent doc define its own structure.
430
450
  # Otherwise the element uses the tag it has defined for itself. Should only
@@ -435,35 +455,35 @@ module HappyMapper
435
455
  # and Nokogiri::XML::Builder object.
436
456
  #
437
457
  def to_xml(builder = nil,default_namespace = nil,tag_from_parent = nil)
438
-
458
+
439
459
  #
440
460
  # If to_xml has been called without a passed in builder instance that
441
461
  # means we are going to return xml output. When it has been called with
442
462
  # a builder instance that means we most likely being called recursively
443
- # and will return the end product as a builder instance.
463
+ # and will return the end product as a builder instance.
444
464
  #
445
465
  unless builder
446
466
  write_out_to_xml = true
447
467
  builder = Nokogiri::XML::Builder.new
448
468
  end
449
-
469
+
450
470
  #
451
471
  # Find the attributes for the class and collect them into an array
452
472
  # that will be placed into a Hash structure
453
473
  #
454
474
  attributes = self.class.attributes.collect do |attribute|
455
-
475
+
456
476
  #
457
477
  # If an attribute is marked as read_only then we want to ignore the attribute
458
478
  # when it comes to saving the xml document; so we wiill not go into any of
459
479
  # the below process
460
- #
480
+ #
461
481
  unless attribute.options[:read_only]
462
-
482
+
463
483
  value = send(attribute.method_name)
464
-
484
+
465
485
  #
466
- # If the attribute defines an on_save lambda/proc or value that maps to
486
+ # If the attribute defines an on_save lambda/proc or value that maps to
467
487
  # a method that the class has defined, then call it with the value as a
468
488
  # parameter.
469
489
  #
@@ -474,7 +494,7 @@ module HappyMapper
474
494
  value = send(on_save_action,value)
475
495
  end
476
496
  end
477
-
497
+
478
498
  #
479
499
  # Attributes that have a nil value should be ignored unless they explicitly
480
500
  # state that they should be expressed in the output.
@@ -485,27 +505,27 @@ module HappyMapper
485
505
  else
486
506
  []
487
507
  end
488
-
508
+
489
509
  else
490
510
  []
491
511
  end
492
-
512
+
493
513
  end.flatten
494
-
514
+
495
515
  attributes = Hash[ *attributes ]
496
-
516
+
497
517
  #
498
518
  # Create a tag in the builder that matches the class's tag name unless a tag was passed
499
519
  # in a recursive call from the parent doc. Then append
500
520
  # any attributes to the element that were defined above.
501
521
  #
502
522
  builder.send("#{tag_from_parent || self.class.tag_name}_",attributes) do |xml|
503
-
523
+
504
524
  #
505
525
  # Add all the registered namespaces to the root element.
506
526
  # When this is called recurisvely by composed classes the namespaces
507
527
  # are still added to the root element
508
- #
528
+ #
509
529
  # However, we do not want to add the namespace if the namespace is 'xmlns'
510
530
  # which means that it is the default namesapce of the code.
511
531
  #
@@ -515,7 +535,7 @@ module HappyMapper
515
535
  builder.doc.root.add_namespace(name,href)
516
536
  end
517
537
  end
518
-
538
+
519
539
  #
520
540
  # If the object we are persisting has a namespace declaration we will want
521
541
  # to use that namespace or we will use the default namespace.
@@ -528,17 +548,17 @@ module HappyMapper
528
548
  xml.parent.namespace = builder.doc.root.namespace_definitions.find { |x| x.prefix == default_namespace }
529
549
  end
530
550
 
531
-
551
+
532
552
  #
533
553
  # When a content has been defined we add the resulting value
534
554
  # the output xml
535
555
  #
536
556
  if content = self.class.instance_variable_get('@content')
537
-
557
+
538
558
  unless content.options[:read_only]
539
559
  text_accessor = content.tag || content.name
540
560
  value = send(text_accessor)
541
-
561
+
542
562
  if on_save_action = content.options[:on_save]
543
563
  if on_save_action.is_a?(Proc)
544
564
  value = on_save_action.call(value)
@@ -546,10 +566,10 @@ module HappyMapper
546
566
  value = send(on_save_action,value)
547
567
  end
548
568
  end
549
-
569
+
550
570
  builder.text(value)
551
571
  end
552
-
572
+
553
573
  end
554
574
 
555
575
  #
@@ -557,15 +577,15 @@ module HappyMapper
557
577
  # going to persist each one
558
578
  #
559
579
  self.class.elements.each do |element|
560
-
580
+
561
581
  #
562
- # If an element is marked as read only do not consider at all when
582
+ # If an element is marked as read only do not consider at all when
563
583
  # saving to XML.
564
- #
584
+ #
565
585
  unless element.options[:read_only]
566
-
586
+
567
587
  tag = element.tag || element.name
568
-
588
+
569
589
  #
570
590
  # The value to store is the result of the method call to the element,
571
591
  # by default this is simply utilizing the attr_accessor defined. However,
@@ -575,7 +595,7 @@ module HappyMapper
575
595
 
576
596
  #
577
597
  # If the element defines an on_save lambda/proc then we will call that
578
- # operation on the specified value. This allows for operations to be
598
+ # operation on the specified value. This allows for operations to be
579
599
  # performed to convert the value to a specific value to be saved to the xml.
580
600
  #
581
601
  if on_save_action = element.options[:on_save]
@@ -583,7 +603,7 @@ module HappyMapper
583
603
  value = on_save_action.call(value)
584
604
  elsif respond_to?(on_save_action)
585
605
  value = send(on_save_action,value)
586
- end
606
+ end
587
607
  end
588
608
 
589
609
  #
@@ -593,7 +613,7 @@ module HappyMapper
593
613
  if value.nil? && element.options[:single] && element.options[:state_when_nil]
594
614
  xml.send("#{tag}_","")
595
615
  end
596
-
616
+
597
617
  #
598
618
  # To allow for us to treat both groups of items and singular items
599
619
  # equally we wrap the value and treat it as an array.
@@ -605,7 +625,7 @@ module HappyMapper
605
625
  else
606
626
  values = [value]
607
627
  end
608
-
628
+
609
629
  values.each do |item|
610
630
 
611
631
  if item.is_a?(HappyMapper)
@@ -618,9 +638,9 @@ module HappyMapper
618
638
  item.to_xml(xml,element.options[:namespace],element.options[:tag] || nil)
619
639
 
620
640
  elsif item
621
-
622
- item_namespace = element.options[:namespace] || self.class.namespace || default_namespace
623
-
641
+
642
+ item_namespace = element.options[:namespace] || self.class.namespace || default_namespace
643
+
624
644
  #
625
645
  # When a value exists we should append the value for the tag
626
646
  #
@@ -641,7 +661,7 @@ module HappyMapper
641
661
  end
642
662
 
643
663
  end
644
-
664
+
645
665
  end
646
666
  end
647
667
 
@@ -650,24 +670,24 @@ module HappyMapper
650
670
  # Write out to XML, this value was set above, based on whether or not an XML
651
671
  # builder object was passed to it as a parameter. When there was no parameter
652
672
  # we assume we are at the root level of the #to_xml call and want the actual
653
- # xml generated from the object. If an XML builder instance was specified
654
- # then we assume that has been called recursively to generate a larger
673
+ # xml generated from the object. If an XML builder instance was specified
674
+ # then we assume that has been called recursively to generate a larger
655
675
  # XML document.
656
676
  write_out_to_xml ? builder.to_xml : builder
657
-
677
+
658
678
  end
659
-
679
+
660
680
  # Parse the xml and update this instance. This does not update instances
661
681
  # of HappyMappers that are children of this object. New instances will be
662
- # created for any HappyMapper children of this object.
663
- #
682
+ # created for any HappyMapper children of this object.
683
+ #
664
684
  # Params and return are the same as the class parse() method above.
665
685
  def parse(xml, options = {})
666
686
  self.class.parse(xml, options.merge!(:update => self))
667
- end
668
-
687
+ end
688
+
669
689
  private
670
-
690
+
671
691
  # Factory for creating anonmyous HappyMappers
672
692
  class AnonymousWrapperClassFactory
673
693
  def self.get(name, &blk)
@@ -675,10 +695,10 @@ module HappyMapper
675
695
  include HappyMapper
676
696
  tag name
677
697
  instance_eval &blk
678
- end
698
+ end
679
699
  end
680
700
  end
681
-
701
+
682
702
  end
683
703
 
684
704
  require File.dirname(__FILE__) + '/happymapper/item'
@@ -0,0 +1,3 @@
1
+ <root>
2
+ <item>&#26;some item</item>
3
+ </root>
@@ -120,7 +120,7 @@ class Product
120
120
  end
121
121
 
122
122
  class Rate
123
- include HappyMapper
123
+ include HappyMapper
124
124
  end
125
125
 
126
126
  module FamilySearch
@@ -313,7 +313,7 @@ end
313
313
 
314
314
 
315
315
  class State
316
- include HappyMapper
316
+ include HappyMapper
317
317
  end
318
318
 
319
319
  class Address
@@ -453,9 +453,9 @@ end
453
453
 
454
454
  class PublishOptions
455
455
  include HappyMapper
456
-
456
+
457
457
  tag 'publishOptions'
458
-
458
+
459
459
  element :author, String, :tag => 'author'
460
460
 
461
461
  element :draft, Boolean, :tag => 'draft'
@@ -465,41 +465,41 @@ class PublishOptions
465
465
  element :published_time, String, :tag => 'publishDisplayTime'
466
466
  element :created_day, String, :tag => 'publishDisplayDay'
467
467
  element :created_time, String, :tag => 'publishDisplayTime'
468
-
468
+
469
469
  end
470
470
 
471
471
  class Article
472
472
  include HappyMapper
473
-
473
+
474
474
  tag 'Article'
475
475
  namespace 'article'
476
-
476
+
477
477
  attr_writer :xml_value
478
-
478
+
479
479
  element :title, String
480
480
  element :text, String
481
481
  has_many :photos, 'Photo', :tag => 'Photo', :namespace => 'photo', :xpath => '/article:Article'
482
482
  has_many :galleries, 'Gallery', :tag => 'Gallery', :namespace => 'gallery'
483
-
483
+
484
484
  element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'article'
485
-
485
+
486
486
  end
487
487
 
488
488
  class PartiallyBadArticle
489
489
  include HappyMapper
490
-
490
+
491
491
  attr_writer :xml_value
492
-
492
+
493
493
  tag 'Article'
494
494
  namespace 'article'
495
-
495
+
496
496
  element :title, String
497
497
  element :text, String
498
498
  has_many :photos, 'Photo', :tag => 'Photo', :namespace => 'photo', :xpath => '/article:Article'
499
499
  has_many :videos, 'Video', :tag => 'Video', :namespace => 'video'
500
-
500
+
501
501
  element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'article'
502
-
502
+
503
503
  end
504
504
 
505
505
  class Photo
@@ -507,45 +507,45 @@ class Photo
507
507
 
508
508
  tag 'Photo'
509
509
  namespace 'photo'
510
-
510
+
511
511
  attr_writer :xml_value
512
-
512
+
513
513
  element :title, String
514
514
  element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'photo'
515
-
515
+
516
516
  end
517
517
 
518
518
  class Gallery
519
519
  include HappyMapper
520
-
520
+
521
521
  tag 'Gallery'
522
522
  namespace 'gallery'
523
523
 
524
524
  attr_writer :xml_value
525
525
 
526
526
  element :title, String
527
-
527
+
528
528
  end
529
529
 
530
530
  class Video
531
531
  include HappyMapper
532
-
532
+
533
533
  tag 'Video'
534
534
  namespace 'video'
535
535
 
536
536
  attr_writer :xml_value
537
-
537
+
538
538
  element :title, String
539
539
  element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'video'
540
-
540
+
541
541
  end
542
542
 
543
543
  class OptionalAttribute
544
544
  include HappyMapper
545
545
  tag 'address'
546
-
546
+
547
547
  attribute :street, String
548
- end
548
+ end
549
549
 
550
550
  class DefaultNamespaceCombi
551
551
  include HappyMapper
@@ -673,23 +673,23 @@ describe HappyMapper do
673
673
  end
674
674
  end
675
675
 
676
- describe "#content" do
677
- it "should take String as default argument for type" do
676
+ describe "#content" do
677
+ it "should take String as default argument for type" do
678
678
  State.content :name
679
679
  address = Address.parse(fixture_file('address.xml'))
680
680
  address.state.name.should == "Lower Saxony"
681
681
  address.state.name.class == String
682
682
  end
683
-
684
- it "should work when specific type is provided" do
683
+
684
+ it "should work when specific type is provided" do
685
685
  Rate.content :value, Float
686
686
  Product.has_one :rate, Rate
687
- product = Product.parse(fixture_file('product_default_namespace.xml'), :single => true)
687
+ product = Product.parse(fixture_file('product_default_namespace.xml'), :single => true)
688
688
  product.rate.value.should == 120.25
689
689
  product.rate.class == Float
690
- end
690
+ end
691
691
  end
692
-
692
+
693
693
  it "should parse xml attributes into ruby objects" do
694
694
  posts = Post.parse(fixture_file('posts.xml'))
695
695
  posts.size.should == 20
@@ -946,26 +946,26 @@ describe HappyMapper do
946
946
  l = Location.parse(fixture_file('lastfm.xml'))
947
947
  l.first.latitude.should == "51.53469"
948
948
  end
949
-
949
+
950
950
  describe "Parse optional attributes" do
951
-
951
+
952
952
  it "should parse an empty String as empty" do
953
953
  a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
954
954
  a[0].street.should == ""
955
955
  end
956
-
956
+
957
957
  it "should parse a String with value" do
958
958
  a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
959
959
  a[1].street.should == "Milchstrasse"
960
960
  end
961
-
961
+
962
962
  it "should parse a String with value" do
963
963
  a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
964
964
  a[2].street.should be_nil
965
965
  end
966
-
966
+
967
967
  end
968
-
968
+
969
969
  describe "Default namespace combi" do
970
970
  before(:each) do
971
971
  file_contents = fixture_file('default_namespace_combi.xml')
@@ -1005,8 +1005,8 @@ describe HappyMapper do
1005
1005
  items = AmbigousItems::Item.parse(fixture_file('ambigous_items.xml'), :xpath => '/ambigous/my-items')
1006
1006
  items.map(&:name).should == %w(first second third).map{|s| "My #{s} item" }
1007
1007
  end
1008
-
1009
-
1008
+
1009
+
1010
1010
  context Article do
1011
1011
  it "should parse the publish options for Article and Photo" do
1012
1012
  @article.title.should_not be_nil
@@ -1014,7 +1014,7 @@ describe HappyMapper do
1014
1014
  @article.photos.should_not be_nil
1015
1015
  @article.photos.first.title.should_not be_nil
1016
1016
  end
1017
-
1017
+
1018
1018
  it "should parse the publish options for Article" do
1019
1019
  @article.publish_options.should_not be_nil
1020
1020
  end
@@ -1026,13 +1026,13 @@ describe HappyMapper do
1026
1026
  it "should only find only items at the parent level" do
1027
1027
  @article.photos.length.should == 1
1028
1028
  end
1029
-
1029
+
1030
1030
  before(:all) do
1031
1031
  @article = Article.parse(fixture_file('subclass_namespace.xml'))
1032
1032
  end
1033
-
1033
+
1034
1034
  end
1035
-
1035
+
1036
1036
  context "Namespace is missing because an optional element that uses it is not present" do
1037
1037
  it "should parse successfully" do
1038
1038
  @article = PartiallyBadArticle.parse(fixture_file('subclass_namespace.xml'))
@@ -1043,8 +1043,8 @@ describe HappyMapper do
1043
1043
  @article.photos.first.title.should_not be_nil
1044
1044
  end
1045
1045
  end
1046
-
1047
-
1046
+
1047
+
1048
1048
  describe "with limit option" do
1049
1049
  it "should return results with limited size: 6" do
1050
1050
  sizes = []
@@ -1062,5 +1062,44 @@ describe HappyMapper do
1062
1062
  sizes.should == [10, 10]
1063
1063
  end
1064
1064
  end
1065
-
1065
+
1066
+ context "when letting user set Nokogiri::XML::ParseOptions" do
1067
+ let(:default) {
1068
+ Class.new do
1069
+ include HappyMapper
1070
+ element :item, String
1071
+ end
1072
+ }
1073
+ let(:custom) {
1074
+ Class.new do
1075
+ include HappyMapper
1076
+ element :item, String
1077
+ with_nokogiri_config do |config|
1078
+ config.default_xml
1079
+ end
1080
+ end
1081
+ }
1082
+
1083
+ it 'initializes @nokogiri_config_callback to nil' do
1084
+ default.nokogiri_config_callback.should be_nil
1085
+ end
1086
+
1087
+ it 'defaults to Nokogiri::XML::ParseOptions::STRICT' do
1088
+ expect { default.parse(fixture_file('set_config_options.xml')) }.to raise_error(Nokogiri::XML::SyntaxError)
1089
+ end
1090
+
1091
+ it 'accepts .on_config callback' do
1092
+ custom.nokogiri_config_callback.should_not be_nil
1093
+ end
1094
+
1095
+ it 'parses according to @nokogiri_config_callback' do
1096
+ expect { custom.parse(fixture_file('set_config_options.xml')) }.to_not raise_error(Nokogiri::XML::SyntaxError)
1097
+ end
1098
+
1099
+ it 'can clear @nokogiri_config_callback' do
1100
+ custom.with_nokogiri_config {}
1101
+ expect { custom.parse(fixture_file('set_config_options.xml')) }.to raise_error(Nokogiri::XML::SyntaxError)
1102
+ end
1103
+ end
1104
+
1066
1105
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nokogiri-happymapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5
4
+ version: 0.5.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2011-08-22 00:00:00.000000000 Z
17
+ date: 2012-10-29 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: nokogiri
@@ -23,7 +23,7 @@ dependencies:
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: '1.4'
26
+ version: '1.5'
27
27
  type: :runtime
28
28
  prerelease: false
29
29
  version_requirements: !ruby/object:Gem::Requirement
@@ -31,7 +31,7 @@ dependencies:
31
31
  requirements:
32
32
  - - ~>
33
33
  - !ruby/object:Gem::Version
34
- version: '1.4'
34
+ version: '1.5'
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: rspec
37
37
  requirement: !ruby/object:Gem::Requirement
@@ -50,7 +50,7 @@ dependencies:
50
50
  version: '2.8'
51
51
  description: Object to XML Mapping Library, using Nokogiri (fork from John Nunemaker's
52
52
  Happymapper)
53
- email: franklin.webber@gmail.com
53
+ email:
54
54
  executables: []
55
55
  extensions: []
56
56
  extra_rdoc_files:
@@ -88,6 +88,7 @@ files:
88
88
  - spec/fixtures/product_single_namespace.xml
89
89
  - spec/fixtures/quarters.xml
90
90
  - spec/fixtures/radar.xml
91
+ - spec/fixtures/set_config_options.xml
91
92
  - spec/fixtures/statuses.xml
92
93
  - spec/fixtures/subclass_namespace.xml
93
94
  - spec/fixtures/wrapper.xml
@@ -106,9 +107,8 @@ files:
106
107
  - spec/xpath_spec.rb
107
108
  homepage: http://github.com/dam5s/happymapper
108
109
  licenses: []
109
- post_install_message: ! "\n Thank you for installing nokogiri-happymapper 0.5.5 /
110
- 2012-09-30.\n \n Changes:\n \n * Fix for Boolean attributes to ensure that
111
- they parse correctly (zrob)\n \n\n\n"
110
+ post_install_message: ! "\n Thank you for installing nokogiri-happymapper 0.5.6 /
111
+ .\n\n Changes:\n \n\n"
112
112
  rdoc_options: []
113
113
  require_paths:
114
114
  - lib
@@ -153,6 +153,7 @@ test_files:
153
153
  - spec/fixtures/product_single_namespace.xml
154
154
  - spec/fixtures/quarters.xml
155
155
  - spec/fixtures/radar.xml
156
+ - spec/fixtures/set_config_options.xml
156
157
  - spec/fixtures/statuses.xml
157
158
  - spec/fixtures/subclass_namespace.xml
158
159
  - spec/fixtures/wrapper.xml