Module: XML::Mapping::ClassMethods

Defined in:
lib/xml/mapping/base.rb

Overview

The instance methods of this module are automatically added as class methods to a class that includes XML::Mapping.

Instance Method Summary collapse

Instance Method Details

#add_accessor(name) ⇒ Object

Add getter and setter methods for a new attribute named name (must be a symbol or a string) to this class, taking care not to replace existing getters/setters. This is a convenience method intended to be called from Node class initializers.



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/xml/mapping/base.rb', line 308

def add_accessor(name)
  # existing methods search. Search for symbols and strings
  #  to be compatible with Ruby 1.8 and 1.9.
  methods = self.instance_methods
  if methods[0].kind_of? Symbol
    getter = :"#{name}"
    setter = :"#{name}="
  else
    getter = "#{name}"
    setter = "#{name}="
  end
  unless methods.include?(getter)
    self.module_eval <<-EOS
      attr_reader :#{name}
    EOS
  end
  unless methods.include?(setter)
    self.module_eval <<-EOS
      attr_writer :#{name}
    EOS
  end
end

#all_xml_mapping_nodes(options = {:mapping=>nil,:create=>true}) ⇒ Object

enumeration of all nodes in effect when marshalling/unmarshalling this class, that is, nodes defined for this class as well as for its superclasses. The nodes are returned in the order of their definition, starting with the topmost superclass that has nodes defined. keyword arguments are the same as for #xml_mapping_nodes.



394
395
396
397
398
399
400
401
402
# File 'lib/xml/mapping/base.rb', line 394

def all_xml_mapping_nodes(options={:mapping=>nil,:create=>true})
  # TODO: we could return a dynamic Enumerable here, or cache
  # the array...
  result = []
  if superclass and superclass.respond_to?(:all_xml_mapping_nodes)
    result += superclass.all_xml_mapping_nodes options
  end
  result += xml_mapping_nodes options
end

#default_mappingObject

return the current default mapping (:_default initially, or the value set with the latest call to use_mapping)



300
301
302
# File 'lib/xml/mapping/base.rb', line 300

def default_mapping
  @default_mapping
end

#default_root_element_nameObject

The default root element name for this class. Equals the class name, with all parent module names stripped, and with capital letters converted to lowercase and preceded by a dash; e.g. “Foo::Bar::MySampleClass” becomes “my-sample-class”.



435
436
437
# File 'lib/xml/mapping/base.rb', line 435

def default_root_element_name
  self.name.split('::')[-1].gsub(/^(.)/){$1.downcase}.gsub(/(.)([A-Z])/){$1+"-"+$2.downcase}
end

#initializing_xml_mappingObject

called on a class when it is being made a mapping class (i.e. immediately after XML::Mapping was included in it)



281
282
283
# File 'lib/xml/mapping/base.rb', line 281

def initializing_xml_mapping  #:nodoc:
  @default_mapping = :_default
end

#load_from_file(filename, options = {:mapping=>:_default}) ⇒ Object

Create a new instance of this class from the XML contained in the file named filename. Calls load_from_xml internally.



333
334
335
336
# File 'lib/xml/mapping/base.rb', line 333

def load_from_file(filename, options={:mapping=>:_default})
  xml = REXML::Document.new(File.new(filename))
  load_from_xml xml.root, :mapping=>options[:mapping]
end

#load_from_xml(xml, options = {:mapping=>:_default}) ⇒ Object

Create a new instance of this class from the XML contained in xml (a REXML::Element).

Allocates a new object, then calls fill_from_xml(xml) on it.

Raises:



343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/xml/mapping/base.rb', line 343

def load_from_xml(xml, options={:mapping=>:_default})
  raise(MappingError, "undefined mapping: #{options[:mapping].inspect}") \
    unless xml_mapping_nodes_hash.has_key?(options[:mapping])
  # create the new object. It is recommended that the class
  # have a no-argument initializer, so try new first. If that
  # doesn't work, try allocate, which bypasses the initializer.
  begin
    obj = self.new
    #TODO: this will normally invoke our base XML::Mapping#initialize, which calls
    #  obj.initialize_xml_mapping, which is called below again (with the correct :mapping parameter).
    #  obj.initialize_xml_mapping calls obj_initializing on all nodes.
    #  So obj_initializing may be called on the nodes twice for this initialization.
    #  Maybe document this for node writers?
  rescue ArgumentError # TODO: this may hide real errors.
                       #   how to statically check whether
                       #   self self.new accepts an empty
                       #   argument list?
    obj = self.allocate
  end
  obj.initialize_xml_mapping :mapping=>options[:mapping]
  obj.fill_from_xml xml, :mapping=>options[:mapping]
  obj
end

#mapping_output_formatter(formatter = nil) ⇒ Object

the formatter to be used for output formatting when writing xml to character streams (Files/IOs). Combined getter/setter. Defaults to simple (compact/no-whitespace) formatting, may be overridden on a per-call base via options



443
444
445
446
447
448
449
# File 'lib/xml/mapping/base.rb', line 443

def mapping_output_formatter(formatter=nil)
  # TODO make it per-mapping
  if formatter
    @mapping_output_formatter = formatter
  end
  @mapping_output_formatter ||= REXML::Formatters::Default.new
end

#root_element_name(name = nil, options = {:mapping=>@default_mapping}) ⇒ Object

The “root element name” of this class (combined getter/setter method).

The root element name is the name of the root element of the XML tree returned by <this class>.#save_to_xml (or, more specifically, <this class>.#pre_save). By default, this method returns the #default_root_element_name; you may call this method with an argument to set the root element name to something other than the default. The option argument :mapping specifies the mapping the root element is/will be defined in, it defaults to the current default mapping (:_default initially, or the value set with the latest call to use_mapping)



418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/xml/mapping/base.rb', line 418

def root_element_name(name=nil, options={:mapping=>@default_mapping})
  if Hash===name    # ugly...
    options=name; name=nil
  end
  @root_element_names ||= {}
  if name
    Classes_by_rootelt_names.remove_class root_element_name, options[:mapping], self
    @root_element_names[options[:mapping]] = name
    Classes_by_rootelt_names.create_classes_for(name, options[:mapping]) << self
  end
  @root_element_names[options[:mapping]] || default_root_element_name
end

#use_mapping(mapping) ⇒ Object

Make mapping the mapping to be used by default in future node declarations in this class. The default can be overwritten on a per-node basis by passing a :mapping option parameter to the node factory method

The initial default mapping in a mapping class is :_default



291
292
293
294
295
296
# File 'lib/xml/mapping/base.rb', line 291

def use_mapping mapping
  @default_mapping = mapping
  xml_mapping_nodes_hash[mapping] ||= []  # create empty mapping node list if
                                          # there wasn't one before so future calls
                                          # to load/save_xml etc. w/ this mapping don't raise
end

#xml_mapping_nodes(options = {:mapping=>nil,:create=>true}) ⇒ Object

array of all nodes defined in this class, in the order of their definition. Option :create specifies whether or not an empty array should be created and returned if there was none before (if not, an exception is raised). :mapping specifies the mapping the returned nodes must have been defined in; nil means return all nodes regardless of their mapping



374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/xml/mapping/base.rb', line 374

def xml_mapping_nodes(options={:mapping=>nil,:create=>true})
  unless options[:mapping]
    return xml_mapping_nodes_hash.values.inject([]){|a1,a2|a1+a2}
  end
  options[:create] = true if options[:create].nil?
  if options[:create]
    xml_mapping_nodes_hash[options[:mapping]] ||= []
  else
    xml_mapping_nodes_hash[options[:mapping]] ||
      raise(MappingError, "undefined mapping: #{options[:mapping].inspect}")
  end
end

#xml_mapping_nodes_hashObject

all nodes of this class, in the order of their definition, hashed by mapping (hash mapping => array of nodes)



275
276
277
# File 'lib/xml/mapping/base.rb', line 275

def xml_mapping_nodes_hash    #:nodoc:
  @xml_mapping_nodes ||= {}
end