nokogiri-happymapper 0.5.5 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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