pax_global_header00006660000000000000000000000064120435673170014522gustar00rootroot0000000000000052 comment=c689e0476248c2df3f8952a44f68f55f99f6d9b6 ruby-roxml-3.3.1/000077500000000000000000000000001204356731700136465ustar00rootroot00000000000000ruby-roxml-3.3.1/.gitmodules000066400000000000000000000002001204356731700160130ustar00rootroot00000000000000[submodule "vendor/override_rake_task"] path = vendor/override_rake_task url = git://github.com/Empact/override_rake_task.git ruby-roxml-3.3.1/.rspec000066400000000000000000000000101204356731700147520ustar00rootroot00000000000000--colourruby-roxml-3.3.1/Gemfile000066400000000000000000000003641204356731700151440ustar00rootroot00000000000000source "http://rubygems.org" gem 'activesupport', '>= 2.3.0' gem 'nokogiri', '>= 1.3.3' group :development, :test do gem 'rake' gem 'jeweler' gem "rspec", '>= 2.0.0' gem "sqlite3-ruby", '>= 1.2.4' gem "activerecord", '>= 2.2.2' end ruby-roxml-3.3.1/Gemfile.lock000066400000000000000000000020041204356731700160640ustar00rootroot00000000000000GEM remote: http://rubygems.org/ specs: activemodel (3.1.3) activesupport (= 3.1.3) builder (~> 3.0.0) i18n (~> 0.6) activerecord (3.1.3) activemodel (= 3.1.3) activesupport (= 3.1.3) arel (~> 2.2.1) tzinfo (~> 0.3.29) activesupport (3.1.3) multi_json (~> 1.0) arel (2.2.1) builder (3.0.0) diff-lcs (1.1.3) git (1.2.5) i18n (0.6.0) jeweler (1.6.4) bundler (~> 1.0) git (>= 1.2.5) rake multi_json (1.0.4) nokogiri (1.5.0) rake (0.9.2.2) rspec (2.8.0) rspec-core (~> 2.8.0) rspec-expectations (~> 2.8.0) rspec-mocks (~> 2.8.0) rspec-core (2.8.0) rspec-expectations (2.8.0) diff-lcs (~> 1.1.2) rspec-mocks (2.8.0) sqlite3 (1.3.5) sqlite3-ruby (1.3.3) sqlite3 (>= 1.3.3) tzinfo (0.3.31) PLATFORMS ruby DEPENDENCIES activerecord (>= 2.2.2) activesupport (>= 2.3.0) jeweler nokogiri (>= 1.3.3) rake rspec (>= 2.0.0) sqlite3-ruby (>= 1.2.4) ruby-roxml-3.3.1/History.txt000066400000000000000000000327621204356731700160620ustar00rootroot00000000000000== 3.3.0 (February 9, 2012) * major enhancement * Don't extend/modify the XML parser == 3.1.6 (September 9, 2010) * bug fix * load active_support in a way that is compatible with 2.x and 3.x (fixes gh issue #27) * change the way we monkey patch Nokogiri to leave the original behaviour of the search() method unchanged (fixes gh issue #16) == 3.1.5 (December 18, 2009) * bug fix * don't use tasks/ because those rake files are picked up by those vendoring roxml == 3.1.4 (December 18, 2009) * bug fix * require the necessary version of active support (#tap wasn't introduced until 2.3) == 3.1.3 (October 30, 2009) * minor enhancements * Add support for local-name() reference reading via :namespace => '*' (ala http://techrageo.us/2008/11/01/wildcard-namespaces-in-xpath/) * bug fixes * attributes collected :as => [] were previously output improperly, as a single attribute on a single node * don't output crazy, context-less namespaces and local-name xpaths when trying to output namespaced attributes == 3.1.2 (October 18, 2009) * minor enhancements * Retain whitespace in element contents, but still default on blank (rather than entirely empty) elements * bug fixes * Include namespaces in xml output * Fix that auto-wrapped collections weren't output with their wrappers (which requires introducing the roxml_references accessor on the instance) == 3.1.1 (October 17, 2009) * bug fix * Fix bad load paths == 3.1 (October 16, 2009) * major enhancements * Add support for registering XML namespace prefixes via the xml_namespaces method * bug fix * References to arrays of attributes were only returning the first. No more. == 3.0 (October 14, 2009) * major enhancements * Add Nokogiri support * Remove previously deprecated functionality * Remove REXML support * Error on any unrecognized options * Normalize hash declaration syntax: * for :key => '@string', string is taken to be the :from argument * for :key => {:from => '@string', :as => Type}, the arguments are just the same as a regular declaration * minor enhancements * Include 't' and 'f' in the list of possible boolean values, since rails uses them * Remove :attrs hash syntax. Not particularly helpful & somewhat obfuscatory. Use :key, :value instead. * Default attrs ending in '_at' to DateTime. This can be overriden via :as * Default attrs ending in '_on' to Date. This can be overriden via :as * Don't require rubygems within the library * Don't mess with the load path == 2.5.4 (October 4, 2009) * bug fix * Rely on REXML's #add_child and LibXML's <<, rather than #child_add which had been removed from REXML and deprecated from LibXML == 2.5.3 (March 22, 2009) * minor enhancement * Work around apparently unintentional breaking change in libxml-ruby 1.1.3 == 2.5.2 (March 12, 2009) * minor enhancements * Remove dependency on an Object#try which conflicted with ActiveSupport 2.3's version * Document the :to_xml option for attr references * Require active_support directly, as it's less brittle and plays nicer with other libraries == 2.5.1 (March 2, 2009) * minor enhancements * Add Document#save to REXML support, complete with XMLDecl output * bug fixes * rexml support has been fixed * the first example in the readme was broken and has been fixed == 2.5.0 (February 24, 2009) * major enhancements * support for mapping ActiveRecord classes. See examples/rails.rb. * .from_xml will now use the setter for the declared variable, if one is available, rather than directly setting the instance variable * All declaration type arguments are now supported via the :as parameter, e.g. :as => [MyType]. Other uses are deprecated. * All xml source path arguments are now supported via the :from and :in parameters, e.g. :from => :attr or :from => '@MyAttr'. Other uses are deprecated. * All other options are presented separately, e.g. :cdata => true rather than :as => :cdata. Other uses are deprecated. * minor enhancements * .xml_attr declaration declares neither a reader nor a writer. With it you're left to your own devices. * You can use literal [] for the [:text] object type declaration, though they should be used in the :as parameter: :as => [] * You can use [] with your :as declarations. e.g. :as => [Float] is equivalent to the old :as => [Float, :array] * Show the actual call point of a deprecation, rather than some internal path * Add support for BigDecimal and Fixnum as block shorthands [James Healy] * Update libxml support to 0.9.6, and add it as a dependency, to ensure correct versioning, and as it's an order of magnitude faster than rexml * breaking changes * :else option only applies to instances created via .from_xml * On .from_xml, #initialize is now called with the *initialization_args before extracting attributes from the xml. * #xml_initialize has been replaced with the #after_parse callback, which takes no arguments. * .xml_accessor will overwrite the setter for this variable if it has already been defined. Use .xml_reader or .xml_attr, or define your writer later, if this is not the behavior you want. * deprecations * Use :cdata => true rather than :as => :cdata * Use literal [] around your regular object type, rather than :as => :array * Use :from => :content rather than the :content object declaration type * Specifying an unknown symbol or Class for :as will raise in 3.0 * Specifying :as with anything other than a type argument e.g. :bool, Float, [Date], will not be supported in 3.0 * Use :from => :attr or :from => '@attribute_name' rather than the :attr object declaration type * Passing any type declaration outside the :as parameter is deprecated * In 3.0, attributes ending in _on and _at will default to :as => Date and DateTime, respectively, rather than :text * Deprecated hash :attrs declaration syntax in favor of {:key => '@attr1', :value => '@attr2'} * Deprecated hash {Type => 'name'} declaration syntax in favor of {:as => Type, :from => 'name} * Deprecated String#to_utf and #to_latin. * bug fixes * xml_accessor now properly handles punctuation, such that the writer appears without '?' for boolean attributes * text node contents are no longer truncated when '&' are present in the contents * When using :as => Integer or Float, don't raise on missing element [James Healy] == 2.4.3 (February 1, 2009) * 1 bug fix * Fix roxml to work in ruby 1.8.6, which has been broken since the removal of extensions in version 2.4.1. Thanks Pat! [Pat Nakajima] == 2.4.2 (January 31, 2009) * 1 major enhancement * xml_namespace for declaring Class-level, inheritable default namespaces. * 4 minor enhancements * add :as => Time, DateTime, and Date support * support Pathname, IO and URI objects as #from_xml arguments * :as => :bool now supports all capitalizations of 'true', 'false', 'yes', 'no', as well as '1' and '0' * For basic types (:as => Integer, Float, Date, &c.), interpret empty strings just as missing elements (by returning nil), rather than raising. Raise behavior can be accessed by supplying your own block or using the :required option. * 3 bug fixes * Arrays of attrs or elements :as => :bool weren't previously supported. An oversight. * Don't apply xml_convention if name is explicitly set * Protect xpath operators : and / from modification via String#camelcase & such == 2.4.1 (January 28, 2009) * 3 minor enhancements * remove dependency on 'extensions' gem, as we weren't using it much and it was causing problems for some * deprecate the 'xml' declaration in favor of the more explicit 'xml_reference' declaration. Reorder params to make for cleaner 3.0 transition. * deprecate '#tag_name' in favor of 'self.class.tag_name', as it's a class-specific value == 2.4.0 (January 15, 2009) * 1 major enhancement * Add xml_convention to enable easy defaulting to common naming formats, such as camel-case and underscored [Ben Woosley] * 6 minor enhancements * Add :frozen option for freezing values on parse [Ben Woosley] * Attempt to minimize node creation by better matching wrappers [Ben Woosley] * Preserve hash values where a single key maps to multiple values, return them as an array rather any single one of them at random (as in group_by rather than index_by) [Ben Woosley] * Deprecate #xml_name? as it's only used for triggering the xml_name warning [Ben Woosley] * REXML parser ignores whitespace, which doesn't matter to us anyway [Ben Woosley] * xml_name is inherited by default [Ben Woosley] * 2 bug fixes * Don't detect objects which define their own empty? as being absent for the purposes of :default and :required [Ben Woosley] * Sub-objects pick up their parent's attributes, even if they're added after the child's use [Ben Woosley] == 2.3.2 (December 11, 2008) * Fix that both false and nil values were excluded from to_xml output, when only nil values should be [Ben Woosley] == 2.3.1 (December 9, 2008) * Add missing dependencies to extensions/enumerable and Symbol.to_proc, which are as-yet inexplicably pre-included on my system... [Ben Woosley, Per Melin] == 2.3 (December 7, 2008) * Fix a bug in the application of blocks to array types [Ben Woosley] * Objects now inherit xml attributes from their parents, as they should [Ben Woosley, Per Melin] * Add #xml_initialize, which is called at the end of #from_xml, after the xml attributes are set. Deprecate the half-baked xml_construct in it's favor. [Ben Woosley] * Fix a bug in the handling of empty Hash types [Ben Woosley] * Implement automatic bool-ification when the accessor name ends with ?. [Ben Woosley] * Add missing dependency ActiveSupport [Ben Woosley] * Remove support for installing as a rails plugin [Ben Woosley] * Fix a bug where xml_construct was using the refs' names rather than their accessor names for comparison [Ben Woosley] * Significantly reduce our footprint by selectively including smaller parts of ActiveSupport and Extensions. This avoids problems such as the conflict between ActiveSupport's #to_json and the JSON gem's #to_json. Thanks to Per Melin for reporting this problem. [Ben Woosley] * Rationalize sub-element xml naming by enforcing the following precedence for the containing xml of an object: :from of parent, xml_name of child, parent's accessor name. The previous fallback did not include xml_name. This new behavior is more consistent, explicit, predictable, and DRY, but it is a breaking change, so a warning is printed to alert others of this behavior change. ROXML::SILENCE_XML_NAME_WARNING may be used to deactivate this warning. [Ben Woosley, James W. Thompson, Delynn Berry] == 2.2 (November 2, 2008) * fix gem dependencies [James Healy] * Add block shorthands for Float and Integer, which precede the block argume if present [Ben Woosley] * Add :required option to throw on absence [Ben Woosley] * Deprecate the non-specific #parse in favor of #from_xml [Ben Woosley] * Fix a bug whereby the default value was carrying over information from one object to another [James Healy, Ben Woosley] * Fix support for :in on :attr elements [Ben Woosley] * Deprecate Array#to_h in favor of Array#to_hash [Ben Woosley] * Deprecate Object#to_latin and Object#to_utf in favor of the same methods on String [Ben Woosley] == 2.1 (October 3, 2008) * rake test now uses the default parser selection [Ben Woosley] * Added rcov code coverage for tests [Anders Engström] * Accommodate that libxml requires you to name the default namespace when available [Ben Woosley] * Enable optional selection of a parser through the early definition of ROXML::XML_PARSER [Ben Woosley] * Enable fallback to the REXML parser if LibXML is unavailable [Ben Woosley] == 2.0 (September 20, 2008) * :text_content becomes simply :content, and is joined by :name [Ben Woosley] * Allow hash mapping from node names and contents: [Ben Woosley] xml_reader :name, {:key => :name, :value => :content}, :in => 'container' * Allow supplying a default via the :else option [Ben Woosley] * Allow hash mapping of text and attr elements: [Ben Woosley] xml_reader :name, {:key => {:text => 'key_name'}, :value => {:attr => 'attr_name'}}, :in => 'container' * Allow 'xml_reader :name, [Type]' as an alternative to 'xml_reader :name, Type, :as => :array' [Ben Woosley] * Allow attaching a block for manipulating a value on fetch: [Ben Woosley] xml_accessor :count, :attr => 'my_int' do |val| Integer(val) end * Collapse xml_attr, xml_text and xml_object into a single api: xml, patterned after the standard attr, and offer xml_reader and xml_accessor as well. Remove the :readonly arg in the process [Ben Woosley] * Attach string extensions (#to_latin, #to_utf) to Object rather than String, so we don't have to call #to_s first every time [Ben Woosley] * Allow a ROXML object to call its constructor on initialization with the xml_construct function [Ben Woosley] * Use symbols (e.g. :text_content) rather than TAG_CONSTANTS (e.g. TEXT_CONTENT) for readability [Ben Woosley] * Use named arguments (e.g. :as, :in) rather than positional for clarity, position-independence, and invisible exclusion [Ben Woosley] * Split out rails_plugin_package_task_gem [Ben Woosley] * Increase testing significantly, particularly on new functionality & to_xml [Ben Woosley] == 1.2 (October 10, 2007) * Fix a bug such that the TEXT_CONTENT tag is no longer also READ_ONLY [Russ Olsen] == 1.1 (September 24, 2006) * Initial design & development [Zak Mandhro & Anders Engstrom] ruby-roxml-3.3.1/LICENSE000066400000000000000000000021051204356731700146510ustar00rootroot00000000000000Copyright (c) 2004-2009 Ben Woosley, Zak Mandhro and Anders Engstrom Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ruby-roxml-3.3.1/README.rdoc000066400000000000000000000130111204356731700154500ustar00rootroot00000000000000ROXML Ruby Object to XML mapping library. For more information visit: http://rdoc.info/projects/Empact/roxml http://empact.github.com/roxml/ http://rubyforge.org/projects/roxml/ Please submit bugs here: http://github.com/Empact/roxml/issues =Quick Start Guide This is a short usage example. See ROXML::ClassMethods::Declarations and packaged test cases for more information. ==Basic Mapping Consider an XML document representing a Library containing a number of Books. You can map this structure to Ruby classes that provide addition useful behavior. With ROXML, you can annotate the Ruby classes as follows: class Book include ROXML xml_accessor :isbn, :from => "@ISBN" # attribute with name 'ISBN' xml_accessor :title xml_accessor :description, :cdata => true # text node with cdata protection xml_accessor :author end class Library include ROXML xml_accessor :name, :from => "NAME", :cdata => true xml_accessor :books, :as => [Book] # by default roxml searches for books for in child nodes, then, if none are present, in ./books/book children end To create a library and put a number of books in it we could run the following code: book = Book.new book.isbn = "0201710897" book.title = "The PickAxe" book.description = "Best Ruby book out there!" book.author = "David Thomas, Andrew Hunt, Dave Thomas" lib = Library.new lib.name = "Favorite Books" lib.books = [book] To save this information to an XML file: doc = Nokogiri::XML::Document.new doc.root = lib.to_xml open("library.xml", 'w') do |file| file << doc.serialize end or doc = LibXML::XML::Document.new doc.root = lib.to_xml doc.save("library.xml") To later populate the library object from the XML file: lib = Library.from_xml(File.read("library.xml")) Similarly, to do a one-to-one mapping between XML objects, such as book and publisher, you would add a reference to another ROXML class. For example: Programming Ruby - 2nd Edition Second edition of the great book. Pragmatic Bookshelf can be mapped using the following code: class Publisher include ROXML xml_accessor :name # other important functionality end class BookWithPublisher include ROXML xml_name 'book' xml_reader :publisher, :as => Publisher # or, alternatively, if no class is needed to hang functionality on: # xml_reader :publisher, :from => 'name', :in => 'publisher' end Note: In the above example, _xml_name_ annotation tells ROXML to set the element name to "book" for mapping to XML. The default is XML element name is the class name in lowercase; "bookwithpublisher" in this case. === Namespace Support Namespaced nodes are supported via the xml_namespace and xml_namespaces declarations and the :from and :namespace attr options. See spec/xml/namespace_spec.rb for usage. Note that ROXML does not currently support outputting namespaced nodes. This is planned for a future version. == Manipulation Extending the above examples, say you want to parse a book's page count and have it available as an Integer. In such a case, you can extend any object with a block to manipulate it's value at parse time. For example: class Dog include ROXML xml_reader(:age, :from => '@human_years', :as => Integer) {|years| years * 7 } end The result of the block above is stored, rather than the actual value parsed from the document. == Construction Object life-cycle is as follows: .from_xml is called with a first argument representing the xml in file, string, or path form, and with optional initialization_args following. Firt .new and thus #initialize, is called with those same initialization_args, or no args if none are present. Then the object is populated with the attribute values from xml. Then the #after_parse callback is called, with no arguments. In #after_parse you can ensure that your object initialization is complete, including initialization which requires more than one variable in concert. E.g.: class Measurement include ROXML xml_reader :units, :from => :attr xml_reader :value, :from => :content def initialize(value = 0, units = 'meters') to_metric end private def after_parse # xml attributes of self are already valid to_metric end def to_metric # translate units & value into metric, for example end end One important use of this approach is to make ROXML object which may or may not include an xml backing, which may be used via _new_ construction as well as _from_xml_ construction. == Selecting a parser By default, ROXML will use Nokogiri if it is available, followed by LibXML. If you'd like to explicitly require one or the other, you may do the following: module ROXML XML_PARSER = 'nokogiri' # or 'libxml' end require 'roxml' For more information on available annotations, see ROXML::ClassMethods::Declarations == Note on Patches/Pull Requests * Fork the project. * Make your feature addition or bug fix. * Add specs for it. This is important so I don't break it in a future version unintentionally. * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) * Send me a pull request. Bonus points for topic branches. == Copyright Copyright (c) 2004-2009 Ben Woosley, Zak Mandhro and Anders Engstrom. See LICENSE for details. ruby-roxml-3.3.1/Rakefile000066400000000000000000000054001204356731700153120ustar00rootroot00000000000000require 'rake' ENV['RUBY_FLAGS'] = '-W1' # Generate all the Rake tasks # Run 'rake -T' to see list of generated tasks (from gem root directory) require 'jeweler' Jeweler::Tasks.new do |gem| gem.name = 'roxml' gem.rubyforge_project = "roxml" gem.summary = "Ruby Object to XML mapping library" gem.description = < [:test, :spec] task :all => [:libxml, :nokogiri] task :libxml => ['test:libxml', 'spec:libxml'] task :nokogiri => ['test:nokogiri', 'spec:nokogiri'] require 'rdoc/task' RDoc::Task.new do |rdoc| version = File.exist?('VERSION') ? File.read('VERSION') : "" rdoc.rdoc_dir = 'rdoc' rdoc.title = "roxml #{version}" rdoc.rdoc_files.include('README*') rdoc.rdoc_files.include('lib/**/*.rb') end require 'rspec/core/rake_task' desc "Run specs" RSpec::Core::RakeTask.new(:spec) do |spec| spec.ruby_opts = '-Ilib -Ispec -Iexamples' # spec.spec_files = FileList['spec/**/*_spec.rb'] end namespace :spec do [:libxml, :nokogiri].each do |parser| desc "Spec ROXML under the #{parser} parser" RSpec::Core::RakeTask.new(parser) do |spec| spec.ruby_opts = '-Ilib -Ispec -Iexamples' # spec.spec_files = ["spec/support/#{parser}.rb"] + FileList['spec/**/*_spec.rb'] end end end desc "Run specs with rcov" RSpec::Core::RakeTask.new(:rcov) do |spec| spec.rcov = true spec.ruby_opts = '-Ilib -Ispec -Iexamples' # spec.spec_files = FileList['spec/**/*_spec.rb'] end require 'rake/testtask' desc "Test ROXML using the default parser selection behavior" task :test do require 'rake/runtest' $LOAD_PATH << '.' Rake.run_tests 'test/unit/*_test.rb' end namespace :test do desc "Test ROXML under the Nokogiri parser" task :nokogiri do $LOAD_PATH << '.' require 'spec/support/nokogiri' Rake::Task["test"].invoke end desc "Test ROXML under the LibXML parser" task :libxml do $LOAD_PATH << '.' require 'spec/support/libxml' Rake::Task["test"].invoke end desc "Runs tests under RCOV" task :rcov do system "rcov -T --no-html -x '^/' #{FileList['test/unit/*_test.rb']}" end end ruby-roxml-3.3.1/TODO000066400000000000000000000020631204356731700143370ustar00rootroot00000000000000Planned: v 3.2 * Support outputting namespaced attrs * Consider class_inheritable_attribute rather than superclass.try stuff. * Do some benchmarking * Back with http://xml-object.rubyforge.org/doc/ to minimize need for specifications? * Commandeer #parse to use opposite #from_xml, but in an unrooted, collection-friendly fashion, ala HappyMapper's parse v 3.x * :self => true for sending method_missing to this attribute? * :attributes extensions ala HappyMapper? * Add xml_attrs helper to share :in declarations between several attributes. E.g.: xml_reader :count, :in => 'Attributes', :as => Integer xml_reader :something_else, :in => 'Attributes', :as => Date becomes: xml_attrs :in => 'Attributes' do |xml| xml.reader :count, :as => Integer xml.reader :something_else, :as => Date end * Ensure (perhaps optionally) that references are unambiguous. That is error/warn a singular specification has multiple possible node references * Use lazy evaluation to minimize parsing time for large files ruby-roxml-3.3.1/VERSION000066400000000000000000000000051204356731700147110ustar00rootroot000000000000003.3.1ruby-roxml-3.3.1/examples/000077500000000000000000000000001204356731700154645ustar00rootroot00000000000000ruby-roxml-3.3.1/examples/amazon.rb000077500000000000000000000020251204356731700173000ustar00rootroot00000000000000#!/usr/bin/env ruby require_relative './../spec/spec_helper' # The document `pita.xml` contains both a default namespace and the 'georss' # namespace (for the 'point' xml_reader). module PITA class Base include ROXML xml_convention :camelcase end class Item < Base xml_reader :asin, :from => 'ASIN' xml_reader :detail_page_url, :from => 'DetailPageURL' xml_reader :manufacturer, :in => 'ItemAttributes' # this is the only xml_reader that exists in a different namespace, so it # must be explicitly specified xml_reader :point, :namespace => 'georss' end class ItemSearchResponse < Base xml_reader :total_results, :as => Integer, :in => 'Items' xml_reader :total_pages, :as => Integer, :in => 'Items' xml_reader :items, :as => [Item] end end unless defined?(RSpec) response = PITA::ItemSearchResponse.from_xml(xml_for('amazon')) p response.total_results p response.total_pages response.items.each do |i| puts i.asin, i.detail_page_url, i.manufacturer, i.point, '' end endruby-roxml-3.3.1/examples/current_weather.rb000077500000000000000000000015011204356731700212120ustar00rootroot00000000000000#!/usr/bin/env ruby require_relative './../spec/spec_helper' class Base include ROXML xml_convention :dasherize xml_namespace 'aws' end class WeatherObservation < Base xml_name 'ob' xml_reader :temperature, :as => Float, :from => 'aws:temp' xml_reader :feels_like, :as => Integer xml_reader :current_condition #, :attributes => {:icon => String} # pending end class Weather < Base xml_reader :observation, :as => WeatherObservation, :required => true end unless defined?(RSpec) current_weather = Weather.from_xml(xml_for('current_weather')).observation puts "temperature: #{current_weather.temperature}" puts "feels_like: #{current_weather.feels_like}" puts "current_condition: #{current_weather.current_condition}" # puts "current_condition.icon: #{current_weather.current_condition.icon}" # pending endruby-roxml-3.3.1/examples/dashed_elements.rb000077500000000000000000000006501204356731700211410ustar00rootroot00000000000000#!/usr/bin/env ruby require_relative './../spec/spec_helper' module GitHub class Commit include ROXML xml_convention :dasherize xml_reader :url xml_reader :tree xml_reader :message xml_reader :id xml_reader :committed_date, :as => Date end end unless defined?(RSpec) commit = GitHub::Commit.from_xml(xml_for('dashed_elements')) puts commit.committed_date, commit.url, commit.id, '' endruby-roxml-3.3.1/examples/library.rb000066400000000000000000000016751204356731700174660ustar00rootroot00000000000000class Publisher include ROXML xml_accessor :name def initialize(name = nil) @name = name end def ==(other) name == other.name end # other important functionality end class Novel include ROXML xml_accessor :isbn, :from => "@ISBN" # attribute with name 'ISBN' xml_accessor :title xml_accessor :description, :cdata => true # text node with cdata protection xml_accessor :author xml_accessor :publisher, :as => Publisher # singular object reference for illustrative purposes. def ==(other) self.class.roxml_attrs.map(&:accessor).all? {|attr| send(attr) == other.send(attr) } end end class Library include ROXML xml_accessor :name, :from => "NAME", :cdata => true xml_accessor :novels, :as => [Novel] # by default roxml searches for books for in children, then, if none are present, in ./novels/novel children def ==(other) name == other.name && novels == other.novels end end ruby-roxml-3.3.1/examples/library_with_fines.rb000066400000000000000000000003641204356731700216770ustar00rootroot00000000000000class LibraryWithFines include ROXML xml_name 'library' xml_accessor :name xml_accessor :fines, :as => { :key => 'name', :value => 'desc' }, :from => 'fine', :in => 'policy/fines' endruby-roxml-3.3.1/examples/person.rb000077500000000000000000000012461204356731700173250ustar00rootroot00000000000000#!/usr/bin/env ruby require_relative './../spec/spec_helper' class Person include ROXML xml_accessor :name, :from => 'name' xml_accessor :lat, :from => 'latitude', :in => 'location/coordinates' xml_accessor :long, :from => 'longitude', :in => 'location/coordinates' xml_accessor :street, :from => 'street', :in => 'location/address' xml_accessor :city, :from => 'city', :in => 'location/address' xml_accessor :zip, :from => 'zip', :in => 'location/address' end unless defined?(RSpec) p = Person.new p.name = 'John Doe' p.lat = '40.715224' p.long = '-74.005966' p.street = 'Evergreen Terrace' p.city = 'Springfield' p.zip = '2342' puts p.to_xml.to_s endruby-roxml-3.3.1/examples/posts.rb000077500000000000000000000011371204356731700171660ustar00rootroot00000000000000#!/usr/bin/env ruby require_relative './../spec/spec_helper' class Post include ROXML xml_reader :href, :from => :attr xml_reader :hash, :from => :attr xml_reader :description, :from => :attr xml_reader :tag, :from => :attr xml_reader :created_at, :from => '@time' xml_reader :others, :from => :attr, :as => Integer xml_reader :extended, :from => :attr end class Posts include ROXML xml_reader :posts, :as => [Post] end unless defined?(RSpec) posts = Posts.from_xml(xml_for('posts')) posts.posts.each do |post| puts post.description, post.href, post.extended, '' end endruby-roxml-3.3.1/examples/rails.rb000066400000000000000000000030271204356731700171250ustar00rootroot00000000000000#!/usr/bin/env ruby require_relative './../spec/spec_helper' require 'sqlite3' require 'active_record' ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => ':memory:' ) class Waypoint < ActiveRecord::Base include ROXML belongs_to :route xml_attr :isLeg xml_attr :lonlatx xml_attr :lonlaty xml_attr :gridReference xml_attr :ascent xml_attr :descent xml_attr :distance xml_attr :bearing xml_attr :timemins end class Route < ActiveRecord::Base include ROXML has_many :waypoints xml_attr :title xml_attr :totalDist xml_attr :totalMins xml_attr :totalHg xml_attr :lonlatx xml_attr :lonlaty xml_attr :grcenter xml_attr :waypoints, :as => [Waypoint], :in => "waypoints" end # do a quick pseudo migration. This should only get executed on the first run if !Waypoint.table_exists? ActiveRecord::Base.connection.create_table(:waypoints) do |t| t.column :route_id, :integer t.column :isLeg, :string t.column :lonlatx, :string t.column :lonlaty, :string t.column :gridReference, :string t.column :ascent, :string t.column :descent, :string t.column :distance, :string t.column :bearing, :string t.column :timeMins, :string end end if !Route.table_exists? ActiveRecord::Base.connection.create_table(:routes) do |t| t.column :title, :string t.column :totalDist, :string t.column :totalMins, :string t.column :totalHg, :string t.column :lonlatx, :string t.column :lonlaty, :string t.column :grcenter, :string end endruby-roxml-3.3.1/examples/twitter.rb000077500000000000000000000014401204356731700175150ustar00rootroot00000000000000#!/usr/bin/env ruby require_relative './../spec/spec_helper' require 'time' class User include ROXML xml_reader :id, :as => Integer xml_reader :name xml_reader :screen_name xml_reader :location xml_reader :description xml_reader :profile_image_url xml_reader :url xml_reader :protected? xml_reader :followers_count, :as => Integer end class Status include ROXML xml_reader :id, :as => Integer xml_reader :text xml_reader :created_at # This defaults to :as => DateTime, due to the '_at' xml_reader :source xml_reader :truncated? xml_reader :in_reply_to_status_id, :as => Integer xml_reader :in_reply_to_user_id, :as => Integer xml_reader :favorited? xml_reader :user, :as => User end class Statuses include ROXML xml_reader :statuses, :as => [Status] endruby-roxml-3.3.1/examples/xml/000077500000000000000000000000001204356731700162645ustar00rootroot00000000000000ruby-roxml-3.3.1/examples/xml/active_record.xml000066400000000000000000000042231204356731700216200ustar00rootroot00000000000000 11185.321521477119 640 235.75000000000003 357865 271635 SH 71635 57865 false 357290 271650 SH 71650 57290 81 220 0 0 false 357260 274600 SH 74600 57260 275 48 2950.152538429157 91 false 359160 273330 SH 73330 59160 73 170 2285.3664913969487 326 false 359170 270050 SH 70050 59170 182 172 3280.015243867016 270 false 357470 269740 SH 69740 57470 29 107 1728.0335644888382 190 false 356840 270440 SH 70440 56840 640 717 941.7536832951597 132 ruby-roxml-3.3.1/examples/xml/amazon.xml000066400000000000000000000136301204356731700202760ustar00rootroot00000000000000
16WRJBVEM155Q026KCV1 0.064924955368042
True Books Ruby on Rails 22 3 0321480791 38.5351715088 -121.7948684692 http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh Michael Hartl Aurelius Prochazka Addison-Wesley Professional Book RailsSpace: Building a Social Networking Website with Ruby on Rails (Addison-Wesley Professional Ruby Series) 047022388X http://www.amazon.com/gp/redirect.html%3FASIN=047022388X%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/047022388X%253FSubscriptionId=dontbeaswoosh Noel Rappin Wrox Book Professional Ruby on Rails 1590598814 http://www.amazon.com/gp/redirect.html%3FASIN=1590598814%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/1590598814%253FSubscriptionId=dontbeaswoosh Ola Bini Apress Book Practical JRuby on Rails Web 2.0 Projects: Bringing Ruby on Rails to Java 0596101325 http://www.amazon.com/gp/redirect.html%3FASIN=0596101325%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0596101325%253FSubscriptionId=dontbeaswoosh Bruce Tate Curt Hibbs O'Reilly Media, Inc. Book Ruby on Rails: Up and Running 0470081201 http://www.amazon.com/gp/redirect.html%3FASIN=0470081201%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0470081201%253FSubscriptionId=dontbeaswoosh Barry Burd For Dummies Book Ruby on Rails For Dummies (For Dummies (Computer/Tech)) 0975841955 http://www.amazon.com/gp/redirect.html%3FASIN=0975841955%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0975841955%253FSubscriptionId=dontbeaswoosh Patrick Lenz SitePoint Book Build Your Own Ruby on Rails Web Applications 0470069155 http://www.amazon.com/gp/redirect.html%3FASIN=0470069155%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0470069155%253FSubscriptionId=dontbeaswoosh Steve, Ph.D. Holzner Wrox Book Beginning Ruby on Rails (Wrox Beginning Guides) 1590597362 http://www.amazon.com/gp/redirect.html%3FASIN=1590597362%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/1590597362%253FSubscriptionId=dontbeaswoosh Christian Hellsten Jarkko Laine Apress Book Beginning Ruby on Rails E-Commerce: From Novice to Professional (Rails) 1590597524 http://www.amazon.com/gp/redirect.html%3FASIN=1590597524%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/1590597524%253FSubscriptionId=dontbeaswoosh Justin Williams friends of ED Book Rails Solutions: Ruby on Rails Made Easy (Solutions) 0321517067 http://www.amazon.com/gp/redirect.html%3FASIN=0321517067%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321517067%253FSubscriptionId=dontbeaswoosh Aurelius Prochazka Addison-Wesley Professional Book RailsSpace Ruby on Rails Tutorial (Video Training) (LiveLessons)
ruby-roxml-3.3.1/examples/xml/current_weather.xml000066400000000000000000000103271204356731700222120ustar00rootroot00000000000000 http://weather.weatherbug.com/IN/Carmel-weather.html?ZCode=Z5546&Units=0&stat=MOCAR mocar MOCAR Mohawk Trail ES Carmel, IN USA 39.9711111111111 -86.0938888888889 http://www1.ccs.k12.in.us/mte/home 74 +0.0 Sunny 35 817 51 W 25 53 100.0 42.5 -5.0 75 +0.0 28 -1.5 -10 29.71 30.18 29.71 -0.04 6.64 0.00 0.00 0.00 53.83 51.8 52 29 +2.5 44.24 4 7 SSW SW ruby-roxml-3.3.1/examples/xml/dashed_elements.xml000066400000000000000000000026671204356731700221450ustar00rootroot00000000000000 commands.rb helpers.rb commands/commands.rb commands/helpers.rb move commands.rb and helpers.rb into commands/ dir @@ -56,7 +56,7 @@ module GitHub end def load(file) - file[0] == ?/ ? super : super(BasePath + "/#{file}") + file[0] == ?/ ? super : super(BasePath + "/commands/#{file}") end def debug(*messages) lib/github.rb d462d2a2e60438ded3dd9e8e6593ca4146c5a0ba http://github.com/defunkt/github-gem/commit/c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b Chris Wanstrath chris@ozmm.org c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b 2008-03-02T16:45:41-08:00 2008-03-02T16:45:41-08:00 28a1a1ca3e663d35ba8bf07d3f1781af71359b76 Chris Wanstrath chris@ozmm.org ruby-roxml-3.3.1/examples/xml/library_with_fines.xml000066400000000000000000000006731204356731700226770ustar00rootroot00000000000000 Ruby library late-book The book was returned late. damaged-book The book was returned damaged. talking The librarian won't go out with you. Stop asking. ruby-roxml-3.3.1/examples/xml/person.xml000066400000000000000000000004621204356731700203160ustar00rootroot00000000000000 John Doe 40.715224 -74.005966
Evergreen Terrace Springfield 2342
ruby-roxml-3.3.1/examples/xml/posts.xml000066400000000000000000000163361204356731700201670ustar00rootroot00000000000000 ruby-roxml-3.3.1/examples/xml/twitter.xml000066400000000000000000000445241204356731700205210ustar00rootroot00000000000000 Sat Aug 09 05:38:12 +0000 2008 882281424 I so just thought the guy lighting the Olympic torch was falling when he began to run on the wall. Wow that would have been catastrophic. web false 1234 12345 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Sat Aug 09 02:04:56 +0000 2008 882145663 @ijonas - wow that stuff sounds sweet web false 882005142 1000471 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Sat Aug 09 01:36:41 +0000 2008 882126691 Steph is driving Sally for the first time. I'm proud of her. <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Fri Aug 08 22:21:21 +0000 2008 881987762 @ijonas - what are you making with couchdb, ruby and httparty? web false 881947237 1000471 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Fri Aug 08 14:20:14 +0000 2008 881535796 @oaknd1 - delete it off phone and iTunes. <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 881526234 3038211 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Fri Aug 08 14:07:29 +0000 2008 881522394 Listening to U2 "beautiful day" in honor of it being such a beautiful day. <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Fri Aug 08 14:06:44 +0000 2008 881521592 @lizsmc1 - hi! (just passed her on the road) <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 881519558 11485452 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Fri Aug 08 13:59:35 +0000 2008 881514030 Beautiful day for a motorcycle ride. <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Fri Aug 08 13:45:21 +0000 2008 881499439 @lizamc1 - no way! Politos will be missed. I remember eating a whole garlic pizza there with Joe. <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Fri Aug 08 13:41:50 +0000 2008 881496024 Riding my motorcyle to campus. Using the library basement for a meeting. <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Thu Aug 07 22:52:20 +0000 2008 880896190 Scraping super glue off my finger with a knife. web false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Thu Aug 07 22:14:35 +0000 2008 880866160 So cold...Starbucks north side, you win the day, but I shall bring a sweatshirt to our next battle! <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Thu Aug 07 17:25:40 +0000 2008 880610064 Headed home for a bit to get my headphones and then to the north side to meet @orderedlist. <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 485 Thu Aug 07 17:15:59 +0000 2008 880600278 Panera wifi, why do you hate me? <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 485 Thu Aug 07 15:46:25 +0000 2008 880509577 At panera. Turned my alarm off this morning and woke up late. Oh well. <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 485 Thu Aug 07 15:01:35 +0000 2008 880463746 @kloh I remember days like that. Exhausting. Also, NullRiver said to sync again, uninstall app from phone and then resync app. Evidently ... web true 880432701 10193732 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 485 Thu Aug 07 02:52:38 +0000 2008 879986739 @kloh - I haven't updated my OS so I'm wondering how apple could have made the app stop working. I did contact NullRiver support just no ... web true 879980813 10193732 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Thu Aug 07 02:38:58 +0000 2008 879976045 @jerry - i went with the pdf download. web false 879878196 613 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Thu Aug 07 02:31:26 +0000 2008 879969851 @kloh - it worked at home for multiple tests and just stopped when I acyltually needed it. <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 879968483 10193732 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 Thu Aug 07 01:18:28 +0000 2008 879913748 Netshare will no longer start up for me. Of course it borks the first time I actually want to use it. <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a> false 4243 John Nunemaker jnunemaker Mishawaka, IN, US Loves his wife, ruby, notre dame football and iu basketball http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg http://addictedtonew.com false 486 ruby-roxml-3.3.1/lib/000077500000000000000000000000001204356731700144145ustar00rootroot00000000000000ruby-roxml-3.3.1/lib/roxml.rb000066400000000000000000000500201204356731700160770ustar00rootroot00000000000000require 'uri' require 'active_support' if Gem.loaded_specs['activesupport'] && Gem.loaded_specs['activesupport'].version >= Gem::Version.new('3') require 'active_support/inflector' require 'active_support/core_ext/object/duplicable' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/array/extract_options' require 'active_support/core_ext/hash' require 'active_support/core_ext/string/starts_ends_with' end require 'roxml/definition' require 'roxml/xml' module ROXML # :nodoc: VERSION = File.read(File.expand_path("../../VERSION", __FILE__)) def self.included(base) # :nodoc: base.class_eval do extend ClassMethods::Accessors, ClassMethods::Declarations, ClassMethods::Operations include InstanceMethods attr_accessor :roxml_references end end module InstanceMethods # :nodoc: # Returns an XML object representing this object def to_xml(params = {}) params.reverse_merge!(:name => self.class.tag_name, :namespace => self.class.roxml_namespace) params[:namespace] = nil if ['*', 'xmlns'].include?(params[:namespace]) XML.new_node([params[:namespace], params[:name]].compact.join(':')).tap do |root| refs = (self.roxml_references.present? \ ? self.roxml_references \ : self.class.roxml_attrs.map {|attr| attr.to_ref(self) }) refs.each do |ref| value = ref.to_xml(self) unless value.nil? ref.update_xml(root, value) end end end end end # This class defines the annotation methods that are mixed into your # Ruby classes for XML mapping information and behavior. # # See xml_name, xml_initialize, xml, xml_reader and xml_accessor for # available annotations. # module ClassMethods # :nodoc: module Declarations # Sets the name of the XML element that represents this class. Use this # to override the default lowercase class name. # # Example: # class BookWithPublisher # xml_name :book # end # # Without the xml_name annotation, the XML mapped tag would have been "bookwithpublisher". # def xml_name(name) @roxml_tag_name = name end # Sets the namemespace for attributes and elements of this class. You can override # this value on individual elements via the :from option # # Example: # class Book # xml_namespace :aws # # xml_reader :default_namespace # xml_reader :different_namespace, :from => 'different:namespace' # xml_reader :no_namespace, :from => 'no_namespace', :namespace => false # end # # # value # value # value # # def xml_namespace(namespace) @roxml_namespace = namespace.to_s end # Sets up a mapping of namespace prefixes to hrefs, to be used by this class. # These namespace prefixes are independent of what appears in the xml, only # the namespace hrefs themselves need to match # # Example: # class Tires # include ROXML # # xml_namespaces \ # :bobsbike => 'http://bobsbikes.example.com', # :alicesauto => 'http://alicesautosupply.example.com/' # # xml_reader :bike_tires, :as => [], :from => '@name', :in => 'bobsbike:tire' # xml_reader :car_tires, :as => [], :from => '@name', :in => 'alicesauto:tire' # end # # >> xml = %{ # # # # # # # } # >> Tires.from_xml(xml).bike_tires # => ['skinny street'] # def xml_namespaces(namespaces) @roxml_namespaces = namespaces.inject({}) do |all, (prefix, href)| all[prefix.to_s] = href.to_s all end end def roxml_namespaces # :nodoc: @roxml_namespaces || {} end # Most xml documents have a consistent naming convention, for example, the node and # and attribute names might appear in CamelCase. xml_convention enables you to adapt # the roxml default names for this object to suit this convention. For example, # if I had a document like so: # # # # # # # Then I could access it's contents by defining the following class: # # class XmlDoc # include ROXML # xml_convention :camelcase # xml_reader :my_precious_data # xml_reader :in_attrs, :in => 'MoreToSee' # end # # You may supply a block or any #to_proc-able object as the argument, # and it will be called against the default node and attribute names before searching # the document. Here are some example declaration: # # xml_convention :upcase # xml_convention &:camelcase # xml_convention {|val| val.gsub('_', '').downcase } # # See ActiveSupport::CoreExtensions::String::Inflections for more prepackaged formats # # Note that the xml_convention is also applied to the default root-level tag_name, # but in this case an underscored version of the name is applied, for convenience. def xml_convention(to_proc_able = nil, &block) raise ArgumentError, "conventions are already set" if @roxml_naming_convention @roxml_naming_convention = if to_proc_able raise ArgumentError, "only one conventions can be set" if block_given? to_proc_able.to_proc elsif block_given? block end end def roxml_naming_convention # :nodoc: @roxml_naming_convention || begin superclass.roxml_naming_convention if superclass.respond_to?(:roxml_naming_convention) end end # Declares a reference to a certain xml element, whether an attribute, a node, # or a typed collection of nodes. This method does not add a corresponding accessor # to the object. For that behavior see the similar methods: .xml_reader and .xml_accessor. # # == Sym Option # [sym] Symbol representing the name of the accessor. # # === Default naming # This name will be the default node or attribute name searched for, # if no other is declared. For example, # # xml_reader :bob # xml_accessor :pony, :from => :attr # # are equivalent to: # # xml_reader :bob, :from => 'bob' # xml_accessor :pony, :from => '@pony' # # === Boolean attributes # If the name ends in a ?, ROXML will attempt to coerce the value to true or false, # with True, TRUE, true and 1 mapping to true and False, FALSE, false and 0 mapping # to false, as shown below: # # xml_reader :desirable? # xml_reader :bizzare?, :from => '@BIZZARE' # # x = #from_xml(%{ # # False # # }) # x.desirable? # => false # x.bizzare? # => true # # If an unexpected value is encountered, the attribute will be set to nil, # unless you provide a block, in which case the block will recived # the actual unexpected value. # # #from_xml(%{ # # Dunno # # }).desirable? # => nil # # xml_reader :strange? do |val| # val.upcase # end # # #from_xml(%{ # # Dunno # # }).strange? # => DUNNO # # == Blocks # You may also pass a block which manipulates the associated parsed value. # # class Muffins # include ROXML # # xml_reader(:count, :from => 'bakers_dozens') {|val| val.to_i * 13 } # end # # For hash types, the block recieves the key and value as arguments, and they should # be returned as an array of [key, value] # # For array types, the entire array is passed in, and must be returned in the same fashion. # # == Options # === :as # ==== Basic Types # Allows you to specify one of several basic types to return the value as. For example # # xml_reader :count, :as => Integer # # is equivalent to: # # xml_reader(:count) {|val| Integer(val) unless val.empty? } # # Such block shorthands for Integer, Float, Fixnum, BigDecimal, Date, Time, and DateTime # are currently available, but only for non-Hash declarations. # # To reference many elements, put the desired type in a literal array. e.g.: # # xml_reader :counts, :as => [Integer] # # Even an array of text nodes can be specified with :as => [] # # xml_reader :quotes, :as => [] # # === Other ROXML Class # Declares an accessor that represents another ROXML class as child XML element # (one-to-one or composition) or array of child elements (one-to-many or # aggregation) of this type. Default is one-to-one. For one-to-many, simply pass the class # as the only element in an array. # # Composition example: # # # Pragmatic Bookshelf # # # # Can be mapped using the following code: # class Book # xml_reader :publisher, :as => Publisher # end # # Aggregation example: # # # # # # # # Can be mapped using the following code: # class Library # xml_reader :books, :as => [Book], :in => "books" # end # # If you don't have the tag to wrap around the list of tags: # # Ruby books # # # # # You can skip the wrapper argument: # xml_reader :books, :as => [Book] # # ==== Hash # Somewhere between the simplicity of a :text/:attr mapping, and the complexity of # a full Object/Type mapping, lies the Hash mapping. It serves in the case where you have # a collection of key-value pairs represented in your xml. You create a hash declaration by # passing a hash mapping as the type argument. A few examples: # # ===== Hash of element contents # For xml such as this: # # # # # # # # # # # # # You can individually declare your key and value names: # xml_reader :definitions, :as => {:key => 'word', # :value => 'meaning'} # # ===== Hash of :content &c. # For xml such as this: # # # adjective: (of a geological formation) sloping downward from the center in all directions. # To use evasions or ambiguities; equivocate. # # # You can individually declare the key and value, but with the attr, you need to provide both the type # and name of that type (i.e. {:attr => :word}), because omitting the type will result in ROXML # defaulting to :text # xml_reader :definitions, :as => {:key => {:attr => 'word'}, # :value => :content} # # ===== Hash of :name &c. # For xml such as this: # # # adjective: (of a geological formation) sloping downward from the center in all directions. # To use evasions or ambiguities; equivocate. # # # You can pick up the node names (e.g. quaquaversally) using the :name keyword: # xml_reader :definitions, :as => {:key => :name, # :value => :content} # # === :from # The name by which the xml value will be found, either an attribute or tag name in XML. # Default is sym, or the singular form of sym, in the case of arrays and hashes. # # This value may also include XPath notation. # # ==== :from => :content # When :from is set to :content, this refers to the content of the current node, # rather than a sub-node. It is equivalent to :from => '.' # # Example: # class Contributor # xml_reader :name, :from => :content # xml_reader :role, :from => :attr # end # # To map: # James Wick # # ==== :from => :attr # When :from is set to :attr, this refers to the content of an attribute, # rather than a sub-node. It is equivalent to :from => '@attribute_name' # # Example: # class Book # xml_reader :isbn, :from => "@ISBN" # xml_accessor :title, :from => :attr # :from defaults to '@title' # end # # To map: # # # ==== :from => :text # The default source, if none is specified, this means the accessor # represents a text node from XML. This is documented for completeness # only. You should just leave this option off when you want the default behavior, # as in the examples below. # # :text is equivalent to :from => accessor_name, and you should specify the # actual node name (and, optionally, a namespace) if it differs, as in the case of :author below. # # Example: # class Book # xml_reader :author, :from => 'Author' # xml_accessor :description, :cdata => true # xml_reader :title # end # # To map: # # Programming Ruby: the pragmatic programmers' guide # # David Thomas # # # Likewise, a number of :text node values can be collected in an array like so: # # Example: # class Library # xml_reader :books, :as => [] # end # # To map: # # To kill a mockingbird # House of Leaves # Gödel, Escher, Bach # # # === Other Options # [:in] An optional name of a wrapping tag for this XML accessor. # This can include other xpath values, which will be joined with :from with a '/' # [:else] Default value for attribute, if missing from the xml on .from_xml # [:required] If true, throws RequiredElementMissing when the element isn't present # [:frozen] If true, all results are frozen (using #freeze) at parse-time. # [:cdata] true for values which should be input from or output as cdata elements # [:to_xml] this proc is applied to the attributes value outputting the instance via #to_xml # [:namespace] (false) disables or (string) overrides the default namespace declared with xml_namespace # def xml_attr(*syms, &block) opts = syms.extract_options! syms.map do |sym| Definition.new(sym, opts, &block).tap do |attr| if roxml_attrs.map(&:accessor).include? attr.accessor raise "Accessor #{attr.accessor} is already defined as XML accessor in class #{self.name}" end @roxml_attrs << attr end end end # Declares a read-only xml reference. See xml_attr for details. # # Note that while xml_reader does not create a setter for this attribute, # its value can be modified indirectly via methods. For more complete # protection, consider the :frozen option. def xml_reader(*syms, &block) xml_attr(*syms, &block).each do |attr| add_reader(attr) end end # Declares a writable xml reference. See xml_attr for details. # # Note that while xml_accessor does create a setter for this attribute, # you can use the :frozen option to prevent its value from being # modified indirectly via methods. def xml_accessor(*syms, &block) xml_attr(*syms, &block).each do |attr| add_reader(attr) attr_writer(attr.attr_name) end end private def add_reader(attr) define_method(attr.accessor) do instance_variable_get(attr.instance_variable_name) end end end module Accessors # Returns the tag name (also known as xml_name) of the class. # If no tag name is set with xml_name method, returns default class name # in lowercase. # # If xml_convention is set, it is called with an *underscored* version of # the class name. This is because active support's inflector generally expects # an underscored version, and several operations (e.g. camelcase(:lower), dasherize) # do not work without one. def tag_name return roxml_tag_name if roxml_tag_name if tag_name = name.split('::').last roxml_naming_convention ? roxml_naming_convention.call(tag_name.underscore) : tag_name.downcase end end def roxml_tag_name # :nodoc: @roxml_tag_name || begin superclass.roxml_tag_name if superclass.respond_to?(:roxml_tag_name) end end def roxml_namespace # :nodoc: @roxml_namespace || begin superclass.roxml_namespace if superclass.respond_to?(:roxml_namespace) end end # Returns array of internal reference objects, such as attributes # and composed XML objects def roxml_attrs @roxml_attrs ||= [] (@roxml_attrs + (superclass.respond_to?(:roxml_attrs) ? superclass.roxml_attrs : [])).freeze end end module Operations # # Creates a new Ruby object from XML using mapping information # annotated in the class. # # The input data is either an XML::Node, String, Pathname, or File representing # the XML document. # # Example # book = Book.from_xml(File.read("book.xml")) # or # book = Book.from_xml("Beyond Java") # # _initialization_args_ passed into from_xml will be passed into # the object's .new, prior to populating the xml_attrs. # # After the instatiation and xml population # # See also: xml_initialize # def from_xml(data, *initialization_args) xml = XML::Node.from(data) new(*initialization_args).tap do |inst| inst.roxml_references = roxml_attrs.map {|attr| attr.to_ref(inst) } inst.roxml_references.each do |ref| value = ref.value_in(xml) inst.respond_to?(ref.opts.setter) \ ? inst.send(ref.opts.setter, value) \ : inst.instance_variable_set(ref.opts.instance_variable_name, value) end inst.send(:after_parse) if inst.respond_to?(:after_parse, true) end rescue ArgumentError => e raise e, e.message + " for class #{self}" end end end end ruby-roxml-3.3.1/lib/roxml/000077500000000000000000000000001204356731700155555ustar00rootroot00000000000000ruby-roxml-3.3.1/lib/roxml/definition.rb000066400000000000000000000145151204356731700202400ustar00rootroot00000000000000require 'roxml/hash_definition' class Module def bool_attr_reader(*attrs) attrs.each do |attr| define_method :"#{attr}?" do instance_variable_get(:"@#{attr}") || false end end end end module ROXML class ContradictoryNamespaces < StandardError end class Definition # :nodoc: attr_reader :name, :sought_type, :wrapper, :hash, :blocks, :accessor, :to_xml, :attr_name, :namespace bool_attr_reader :name_explicit, :array, :cdata, :required, :frozen def initialize(sym, opts = {}, &block) opts.assert_valid_keys(:from, :in, :as, :namespace, :else, :required, :frozen, :cdata, :to_xml) @default = opts.delete(:else) @to_xml = opts.delete(:to_xml) @name_explicit = opts.has_key?(:from) && opts[:from].is_a?(String) @cdata = opts.delete(:cdata) @required = opts.delete(:required) @frozen = opts.delete(:frozen) @wrapper = opts.delete(:in) @namespace = opts.delete(:namespace) @accessor = sym.to_s opts[:as] ||= if @accessor.ends_with?('?') :bool elsif @accessor.ends_with?('_on') Date elsif @accessor.ends_with?('_at') DateTime end @array = opts[:as].is_a?(Array) @blocks = collect_blocks(block, opts[:as]) @sought_type = extract_type(opts[:as]) if @sought_type.respond_to?(:roxml_tag_name) opts[:from] ||= @sought_type.roxml_tag_name end if opts[:from] == :content opts[:from] = '.' elsif opts[:from] == :name opts[:from] = '*' elsif opts[:from] == :attr @sought_type = :attr opts[:from] = nil elsif opts[:from] == :namespace opts[:from] = '*' @sought_type = :namespace elsif opts[:from].to_s.starts_with?('@') @sought_type = :attr opts[:from].sub!('@', '') end @name = @attr_name = accessor.to_s.chomp('?') @name = @name.singularize if hash? || array? @name = (opts[:from] || @name).to_s if hash? && (hash.key.name? || hash.value.name?) @name = '*' end raise ContradictoryNamespaces if @name.include?(':') && (@namespace.present? || @namespace == false) raise ArgumentError, "Can't specify both :else default and :required" if required? && @default end def instance_variable_name :"@#{attr_name}" end def setter :"#{attr_name}=" end def hash if hash? @sought_type.wrapper ||= name @sought_type end end def hash? @sought_type.is_a?(HashDefinition) end def name? @name == '*' end def content? @name == '.' end def default if @default.nil? @default = [] if array? @default = {} if hash? end @default.duplicable? ? @default.dup : @default end def to_ref(inst) case sought_type when :attr then XMLAttributeRef when :text then XMLTextRef when :namespace then XMLNameSpaceRef when HashDefinition then XMLHashRef when Symbol then raise ArgumentError, "Invalid type argument #{sought_type}" else XMLObjectRef end.new(self, inst) end private def self.all(items, &block) array = items.is_a?(Array) results = (array ? items : [items]).map do |item| yield item end array ? results : results.first end def self.fetch_bool(value, default) value = value.to_s.downcase if %w{true yes 1 t}.include? value true elsif %w{false no 0 f}.include? value false else default end end CORE_BLOCK_SHORTHANDS = { # Core Shorthands Integer => lambda do |val| all(val) do |v| Integer(v) unless v.blank? end end, Float => lambda do |val| all(val) do |v| Float(v) unless v.blank? end end, Fixnum => lambda do |val| all(val) do |v| v.to_i unless v.blank? end end, Time => lambda do |val| all(val) {|v| Time.parse(v) unless v.blank? } end, :bool => nil, :bool_standalone => lambda do |val| all(val) do |v| fetch_bool(v, nil) end end, :bool_combined => lambda do |val| all(val) do |v| fetch_bool(v, v) end end } def self.block_shorthands # dynamically load these shorthands at class definition time, but # only if they're already availbable CORE_BLOCK_SHORTHANDS.tap do |blocks| blocks.reverse_merge!(BigDecimal => lambda do |val| all(val) do |v| BigDecimal.new(v) unless v.blank? end end) if defined?(BigDecimal) blocks.reverse_merge!(DateTime => lambda do |val| if defined?(DateTime) all(val) {|v| DateTime.parse(v) unless v.blank? } end end) if defined?(DateTime) blocks.reverse_merge!(Date => lambda do |val| if defined?(Date) all(val) {|v| Date.parse(v) unless v.blank? } end end) if defined?(Date) end end def collect_blocks(block, as) if as.is_a?(Array) if as.size > 1 raise ArgumentError, "multiple :as types (#{as.map(&:inspect).join(', ')}) is not supported. Use a block if you want more complicated behavior." end as = as.first end if as == :bool # if a second block is present, and we can't coerce the xml value # to bool, we need to be able to pass it to the user-provided block as = (block ? :bool_combined : :bool_standalone) end as = self.class.block_shorthands.fetch(as) do unless (as == :text) || as.respond_to?(:from_xml) || (as.respond_to?(:first) && as.first.respond_to?(:from_xml)) || (as.is_a?(Hash) && !(as.keys & [:key, :value]).empty?) raise ArgumentError, "Invalid :as argument #{as}" unless as.nil? end nil end [as, block].compact end def extract_type(as) if as.is_a?(Hash) return HashDefinition.new(as) elsif as.respond_to?(:from_xml) return as elsif as.is_a?(Array) && as.first.respond_to?(:from_xml) @array = true return as.first else :text end end end end ruby-roxml-3.3.1/lib/roxml/hash_definition.rb000066400000000000000000000011411204356731700212320ustar00rootroot00000000000000module ROXML class HashDefinition # :nodoc: attr_reader :key, :value attr_accessor :wrapper def initialize(opts) opts.assert_valid_keys(:key, :value) @key = Definition.new(nil, to_definition_options(opts, :key)) @value = Definition.new(nil, to_definition_options(opts, :value)) end private def to_definition_options(opts, what) case opts[what] when Hash opts[what] when String, Symbol {:from => opts[what]} else raise ArgumentError, "unrecognized hash parameter: #{what} => #{opts[what]}" end end end endruby-roxml-3.3.1/lib/roxml/xml.rb000066400000000000000000000016501204356731700167040ustar00rootroot00000000000000module ROXML PARSERS = %w[nokogiri libxml].freeze unless const_defined? 'XML_PARSER' parsers = PARSERS.dup begin require parsers.first XML_PARSER = parsers.first # :nodoc: rescue LoadError parsers.shift retry unless parsers.empty? raise "Could not load a parser. Tried #{PARSERS.to_sentence}" end end require File.join('roxml/xml/parsers', XML_PARSER) module XML class Node def self.from(data) case data when XML::Node data when XML::Document data.root when File, IO XML.parse_io(data).root else if (defined?(URI) && data.is_a?(URI::Generic)) || (defined?(Pathname) && data.is_a?(Pathname)) XML.parse_file(data.to_s).root else XML.parse_string(data).root end end end end end end require 'roxml/xml/references' ruby-roxml-3.3.1/lib/roxml/xml/000077500000000000000000000000001204356731700163555ustar00rootroot00000000000000ruby-roxml-3.3.1/lib/roxml/xml/parsers/000077500000000000000000000000001204356731700200345ustar00rootroot00000000000000ruby-roxml-3.3.1/lib/roxml/xml/parsers/libxml.rb000066400000000000000000000030641204356731700216530ustar00rootroot00000000000000require 'libxml' module ROXML module XML # :nodoc:all class << self def set_attribute(node, name, value) node.attributes[name] = value end def set_content(node, content) node.content = content.gsub('&', '&') end def new_node(name) LibXML::XML::Node.new(name) end def add_node(parent, name) add_child(parent, new_node(name)) end def add_cdata(parent, content) add_child(parent, LibXML::XML::Node.new_cdata(content)) end def add_child(parent, child) parent << child child end def parse_string(str_data) LibXML::XML::Parser.string(str_data).parse end def parse_file(path) LibXML::XML::Parser.file(path).parse end def parse_io(stream) LibXML::XML::Parser.io(stream).parse end def save_doc(doc, path) doc.save(path) end def default_namespace(doc) doc = doc.doc if doc.respond_to?(:doc) default = doc.root.namespaces.default default.prefix || 'xmlns' if default end def search(xml, xpath, roxml_namespaces = {}) if xml.namespaces.default roxml_namespaces = {:xmlns => namespaces.default.href}.merge(roxml_namespaces) end if roxml_namespaces.present? xml.find(xpath, roxml_namespaces.map {|prefix, href| [prefix, href].join(':') }) else xml.find(xpath) end end end Document = LibXML::XML::Document Node = LibXML::XML::Node end end ruby-roxml-3.3.1/lib/roxml/xml/parsers/nokogiri.rb000066400000000000000000000030701204356731700222020ustar00rootroot00000000000000require 'nokogiri' module ROXML module XML # :nodoc:all class << self def set_attribute(node, name, value) node[name] = value end def set_content(node, content) node.content = content end def new_node(name) Nokogiri::XML::Node.new(name, Document.new) end def add_node(parent, name) add_child(parent, Nokogiri::XML::Node.new(name, parent.document)) end def add_cdata(parent, content) parent.add_child(Nokogiri::XML::CDATA.new(parent.document, content)) end def add_child(parent, child) parent.add_child(child) end def parse_string(string) Nokogiri::XML(string) end def parse_file(path) path = path.sub('file:', '') if path.starts_with?('file:') parse_io(open(path)) end def parse_io(stream) Nokogiri::XML(stream) end def save_doc(doc, path) open(path, 'w') do |file| file << doc.serialize end end def default_namespace(doc) doc = doc.document if doc.respond_to?(:document) 'xmlns' if doc.root.namespaces['xmlns'] end def search(xml, xpath, roxml_namespaces = {}) case xml when Nokogiri::XML::Document xml.search(xpath, roxml_namespaces) else xpath = "./#{xpath}" (roxml_namespaces.present? ? xml.search(xpath, roxml_namespaces) : xml.search(xpath)) end end end Document = Nokogiri::XML::Document Node = Nokogiri::XML::Node end end ruby-roxml-3.3.1/lib/roxml/xml/references.rb000066400000000000000000000165041204356731700210310ustar00rootroot00000000000000module ROXML class RequiredElementMissing < Exception # :nodoc: end # # Internal base class that represents an XML - Class binding. # class XMLRef # :nodoc: attr_reader :opts delegate :required?, :array?, :accessor, :default, :wrapper, :to => :opts def initialize(opts, instance) @opts = opts @instance = instance end def blocks opts.blocks || [] end def to_xml(instance) val = instance.__send__(accessor) opts.to_xml.respond_to?(:call) ? opts.to_xml.call(val) : val end def name opts.name_explicit? ? opts.name : conventionize(opts.name) end def xpath_name namespacify(name) end def value_in(xml) value = fetch_value(XML::Node.from(xml)) value = default if value.nil? value = apply_blocks(value) value = freeze(value) if value && opts.frozen? value end private def conventionize(what) convention ||= @instance.class.respond_to?(:roxml_naming_convention) && @instance.class.roxml_naming_convention if !what.blank? && convention.respond_to?(:call) URI.unescape(convention.call(URI.escape(what, /\/|::/))) else what end end def namespacify(what) if what.to_s.present? && !what.to_s.include?(':') && opts.namespace != false [opts.namespace, @instance.class.roxml_namespace, @default_namespace].each do |namespace| return opts.namespace == '*' ? (what == '*' ? "*" : "*[local-name()='#{what}']") : "#{namespace}:#{what}" if namespace end end what end def apply_blocks(val) blocks.inject(val) {|val, block| block.call(val) } rescue Exception => ex raise ex, "#{accessor}: #{ex.message}" end def freeze(val) val.each(&:freeze) if val.is_a?(Enumerable) val.freeze end def xpath opts.wrapper ? "#{namespacify(opts.wrapper)}/#{xpath_name}" : xpath_name.to_s end def auto_wrapper namespacify(conventionize(opts.name.pluralize)) end def auto_xpath "#{auto_wrapper}/#{xpath_name}" if array? end def several? array? end def wrap(xml, opts = {:always_create => false}) wrap_with = @auto_vals ? auto_wrapper : wrapper return xml if !wrap_with || xml.name == wrap_with wraps = wrap_with.to_s.split('/') wraps.inject(xml) do |node,wrap| if !opts[:always_create] && (child = node.children.find {|c| c.name == wrap }) child else XML.add_node(node, wrap) end end end def nodes_in(xml) @default_namespace = XML.default_namespace(xml) vals = XML.search(xml, xpath, @instance.class.roxml_namespaces) if several? && vals.empty? && !wrapper && auto_xpath vals = XML.search(xml, auto_xpath, @instance.class.roxml_namespaces) @auto_vals = !vals.empty? end if vals.empty? raise RequiredElementMissing, "#{name} from #{xml} for #{accessor}" if required? default elsif several? vals.map do |val| yield val end else yield(vals.first) end end end # Interal class representing an XML attribute binding # # In context: # # XMLTextRef # class XMLAttributeRef < XMLRef # :nodoc: # Updates the attribute in the given XML block to # the value provided. def update_xml(xml, values) if array? values.each do |value| wrap(xml, :always_create => true).tap do |node| XML.set_attribute(node, name, value.to_s) end end else wrap(xml).tap do |xml| XML.set_attribute(xml, name, values.to_s) end end end private def fetch_value(xml) nodes_in(xml) do |node| node.value end end def xpath_name "@#{name}" end end # Interal class representing XML content text binding # # In context: # # XMLTextRef # class XMLTextRef < XMLRef # :nodoc: delegate :cdata?, :content?, :name?, :to => :opts # Updates the text in the given _xml_ block to # the _value_ provided. def update_xml(xml, value) wrap(xml).tap do |xml| if content? add(xml, value) elsif name? xml.name = value elsif array? value.each do |v| add(XML.add_node(xml, name), v) end else add(XML.add_node(xml, name), value) end end end private def fetch_value(xml) if content? || name? value = if content? xml.content.to_s elsif name? xml.name end if value.blank? raise RequiredElementMissing, "#{name} from #{xml} for #{accessor}" if required? default else value end else nodes_in(xml) do |node| node.content end end end def add(dest, value) if cdata? XML.add_cdata(dest, value.to_s) else XML.set_content(dest, value.to_s) end end end class XMLNameSpaceRef < XMLRef # :nodoc: private def fetch_value(xml) xml.namespace.prefix end end class XMLHashRef < XMLTextRef # :nodoc: delegate :hash, :to => :opts def initialize(opts, inst) super(opts, inst) @key = opts.hash.key.to_ref(inst) @value = opts.hash.value.to_ref(inst) end def several? true end # Updates the composed XML object in the given XML block to # the value provided. def update_xml(xml, value) wrap(xml).tap do |xml| value.each_pair do |k, v| node = XML.add_node(xml, hash.wrapper) @key.update_xml(node, k) @value.update_xml(node, v) end end end private def fetch_value(xml) nodes_in(xml) do |node| [@key.value_in(node), @value.value_in(node)] end end def apply_blocks(vals) unless blocks.empty? vals.collect! do |kvp| super(kvp) end end to_hash(vals) if vals end def freeze(vals) vals.each_pair{|k, v| k.freeze; v.freeze } vals.freeze end def to_hash(array) hash = array.inject({}) do |result, (k, v)| result[k] ||= [] result[k] << v result end hash.each_pair do |k, v| hash[k] = v.first if v.size == 1 end end end class XMLObjectRef < XMLTextRef # :nodoc: delegate :sought_type, :to => :opts # Updates the composed XML object in the given XML block to # the value provided. def update_xml(xml, value) wrap(xml).tap do |xml| params = {:name => name, :namespace => opts.namespace} if array? value.each do |v| XML.add_child(xml, v.to_xml(params)) end elsif value.is_a?(ROXML) XML.add_child(xml, value.to_xml(params)) else XML.add_node(xml, name).tap do |node| XML.set_content(node, value.to_xml) end end end end private def fetch_value(xml) nodes_in(xml) do |node| if sought_type.respond_to? :from_xml sought_type.from_xml(node) else sought_type.new(node) end end end end end ruby-roxml-3.3.1/metadata.yml000066400000000000000000000151561204356731700161610ustar00rootroot00000000000000--- !ruby/object:Gem::Specification name: roxml version: !ruby/object:Gem::Version version: 3.3.1 prerelease: platform: ruby authors: - Ben Woosley - Zak Mandhro - Anders Engstrom - Russ Olsen autorequire: bindir: bin cert_chain: [] date: 2012-02-10 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: activesupport requirement: &70250009547600 !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 2.3.0 type: :runtime prerelease: false version_requirements: *70250009547600 - !ruby/object:Gem::Dependency name: nokogiri requirement: &70250009546900 !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.3.3 type: :runtime prerelease: false version_requirements: *70250009546900 - !ruby/object:Gem::Dependency name: rake requirement: &70250009546320 !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: *70250009546320 - !ruby/object:Gem::Dependency name: jeweler requirement: &70250009545720 !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: *70250009545720 - !ruby/object:Gem::Dependency name: rspec requirement: &70250009544920 !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 2.0.0 type: :development prerelease: false version_requirements: *70250009544920 - !ruby/object:Gem::Dependency name: sqlite3-ruby requirement: &70250009544260 !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.2.4 type: :development prerelease: false version_requirements: *70250009544260 - !ruby/object:Gem::Dependency name: activerecord requirement: &70250009543720 !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 2.2.2 type: :development prerelease: false version_requirements: *70250009543720 description: ! 'ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes. As a result, ROXML simplifies the development of RESTful applications, Web Services, and XML-RPC. ' email: ben.woosley@gmail.com executables: [] extensions: [] extra_rdoc_files: - History.txt - README.rdoc files: - .gitmodules - .rspec - Gemfile - Gemfile.lock - History.txt - LICENSE - README.rdoc - Rakefile - TODO - VERSION - examples/amazon.rb - examples/current_weather.rb - examples/dashed_elements.rb - examples/library.rb - examples/library_with_fines.rb - examples/person.rb - examples/posts.rb - examples/rails.rb - examples/twitter.rb - examples/xml/active_record.xml - examples/xml/amazon.xml - examples/xml/current_weather.xml - examples/xml/dashed_elements.xml - examples/xml/library_with_fines.xml - examples/xml/person.xml - examples/xml/posts.xml - examples/xml/twitter.xml - lib/roxml.rb - lib/roxml/definition.rb - lib/roxml/hash_definition.rb - lib/roxml/xml.rb - lib/roxml/xml/parsers/libxml.rb - lib/roxml/xml/parsers/nokogiri.rb - lib/roxml/xml/references.rb - roxml.gemspec - spec/definition_spec.rb - spec/examples/active_record_spec.rb - spec/examples/amazon_spec.rb - spec/examples/current_weather_spec.rb - spec/examples/dashed_elements_spec.rb - spec/examples/library_spec.rb - spec/examples/library_with_fines_spec.rb - spec/examples/person_spec.rb - spec/examples/post_spec.rb - spec/examples/twitter_spec.rb - spec/reference_spec.rb - spec/regression_spec.rb - spec/roxml_spec.rb - spec/shared_specs.rb - spec/spec_helper.rb - spec/support/libxml.rb - spec/support/nokogiri.rb - spec/xml/array_spec.rb - spec/xml/attributes_spec.rb - spec/xml/encoding_spec.rb - spec/xml/namespace_spec.rb - spec/xml/namespaces_spec.rb - spec/xml/object_spec.rb - spec/xml/parser_spec.rb - spec/xml/text_spec.rb - test/fixtures/book_malformed.xml - test/fixtures/book_pair.xml - test/fixtures/book_text_with_attribute.xml - test/fixtures/book_valid.xml - test/fixtures/book_with_authors.xml - test/fixtures/book_with_contributions.xml - test/fixtures/book_with_contributors.xml - test/fixtures/book_with_contributors_attrs.xml - test/fixtures/book_with_default_namespace.xml - test/fixtures/book_with_depth.xml - test/fixtures/book_with_octal_pages.xml - test/fixtures/book_with_publisher.xml - test/fixtures/book_with_wrapped_attr.xml - test/fixtures/dictionary_of_attr_name_clashes.xml - test/fixtures/dictionary_of_attrs.xml - test/fixtures/dictionary_of_guarded_names.xml - test/fixtures/dictionary_of_mixeds.xml - test/fixtures/dictionary_of_name_clashes.xml - test/fixtures/dictionary_of_names.xml - test/fixtures/dictionary_of_texts.xml - test/fixtures/library.xml - test/fixtures/library_uppercase.xml - test/fixtures/muffins.xml - test/fixtures/nameless_ageless_youth.xml - test/fixtures/node_with_attr_name_conflicts.xml - test/fixtures/node_with_name_conflicts.xml - test/fixtures/numerology.xml - test/fixtures/person.xml - test/fixtures/person_with_guarded_mothers.xml - test/fixtures/person_with_mothers.xml - test/mocks/dictionaries.rb - test/mocks/mocks.rb - test/support/fixtures.rb - test/test_helper.rb - test/unit/definition_test.rb - test/unit/deprecations_test.rb - test/unit/to_xml_test.rb - test/unit/xml_attribute_test.rb - test/unit/xml_block_test.rb - test/unit/xml_bool_test.rb - test/unit/xml_convention_test.rb - test/unit/xml_hash_test.rb - test/unit/xml_initialize_test.rb - test/unit/xml_name_test.rb - test/unit/xml_namespace_test.rb - test/unit/xml_object_test.rb - test/unit/xml_required_test.rb - test/unit/xml_text_test.rb - website/index.html homepage: http://roxml.rubyforge.org licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: roxml rubygems_version: 1.8.10 signing_key: specification_version: 3 summary: Ruby Object to XML mapping library test_files: [] ruby-roxml-3.3.1/roxml.gemspec000066400000000000000000000142371204356731700163630ustar00rootroot00000000000000# Generated by jeweler # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- Gem::Specification.new do |s| s.name = "roxml" s.version = "3.3.1" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Ben Woosley", "Zak Mandhro", "Anders Engstrom", "Russ Olsen"] s.date = "2012-02-10" s.description = "ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML.\nUsing simple annotations, it enables Ruby classes to be mapped to XML. ROXML takes care\nof the marshalling and unmarshalling of mapped attributes so that developers can focus on\nbuilding first-class Ruby classes. As a result, ROXML simplifies the development of\nRESTful applications, Web Services, and XML-RPC.\n" s.email = "ben.woosley@gmail.com" s.extra_rdoc_files = [ "History.txt", "README.rdoc" ] s.files = [ ".gitmodules", ".rspec", "Gemfile", "Gemfile.lock", "History.txt", "LICENSE", "README.rdoc", "Rakefile", "TODO", "VERSION", "examples/amazon.rb", "examples/current_weather.rb", "examples/dashed_elements.rb", "examples/library.rb", "examples/library_with_fines.rb", "examples/person.rb", "examples/posts.rb", "examples/rails.rb", "examples/twitter.rb", "examples/xml/active_record.xml", "examples/xml/amazon.xml", "examples/xml/current_weather.xml", "examples/xml/dashed_elements.xml", "examples/xml/library_with_fines.xml", "examples/xml/person.xml", "examples/xml/posts.xml", "examples/xml/twitter.xml", "lib/roxml.rb", "lib/roxml/definition.rb", "lib/roxml/hash_definition.rb", "lib/roxml/xml.rb", "lib/roxml/xml/parsers/libxml.rb", "lib/roxml/xml/parsers/nokogiri.rb", "lib/roxml/xml/references.rb", "roxml.gemspec", "spec/definition_spec.rb", "spec/examples/active_record_spec.rb", "spec/examples/amazon_spec.rb", "spec/examples/current_weather_spec.rb", "spec/examples/dashed_elements_spec.rb", "spec/examples/library_spec.rb", "spec/examples/library_with_fines_spec.rb", "spec/examples/person_spec.rb", "spec/examples/post_spec.rb", "spec/examples/twitter_spec.rb", "spec/reference_spec.rb", "spec/regression_spec.rb", "spec/roxml_spec.rb", "spec/shared_specs.rb", "spec/spec_helper.rb", "spec/support/libxml.rb", "spec/support/nokogiri.rb", "spec/xml/array_spec.rb", "spec/xml/attributes_spec.rb", "spec/xml/encoding_spec.rb", "spec/xml/namespace_spec.rb", "spec/xml/namespaces_spec.rb", "spec/xml/object_spec.rb", "spec/xml/parser_spec.rb", "spec/xml/text_spec.rb", "test/fixtures/book_malformed.xml", "test/fixtures/book_pair.xml", "test/fixtures/book_text_with_attribute.xml", "test/fixtures/book_valid.xml", "test/fixtures/book_with_authors.xml", "test/fixtures/book_with_contributions.xml", "test/fixtures/book_with_contributors.xml", "test/fixtures/book_with_contributors_attrs.xml", "test/fixtures/book_with_default_namespace.xml", "test/fixtures/book_with_depth.xml", "test/fixtures/book_with_octal_pages.xml", "test/fixtures/book_with_publisher.xml", "test/fixtures/book_with_wrapped_attr.xml", "test/fixtures/dictionary_of_attr_name_clashes.xml", "test/fixtures/dictionary_of_attrs.xml", "test/fixtures/dictionary_of_guarded_names.xml", "test/fixtures/dictionary_of_mixeds.xml", "test/fixtures/dictionary_of_name_clashes.xml", "test/fixtures/dictionary_of_names.xml", "test/fixtures/dictionary_of_texts.xml", "test/fixtures/library.xml", "test/fixtures/library_uppercase.xml", "test/fixtures/muffins.xml", "test/fixtures/nameless_ageless_youth.xml", "test/fixtures/node_with_attr_name_conflicts.xml", "test/fixtures/node_with_name_conflicts.xml", "test/fixtures/numerology.xml", "test/fixtures/person.xml", "test/fixtures/person_with_guarded_mothers.xml", "test/fixtures/person_with_mothers.xml", "test/mocks/dictionaries.rb", "test/mocks/mocks.rb", "test/support/fixtures.rb", "test/test_helper.rb", "test/unit/definition_test.rb", "test/unit/deprecations_test.rb", "test/unit/to_xml_test.rb", "test/unit/xml_attribute_test.rb", "test/unit/xml_block_test.rb", "test/unit/xml_bool_test.rb", "test/unit/xml_convention_test.rb", "test/unit/xml_hash_test.rb", "test/unit/xml_initialize_test.rb", "test/unit/xml_name_test.rb", "test/unit/xml_namespace_test.rb", "test/unit/xml_object_test.rb", "test/unit/xml_required_test.rb", "test/unit/xml_text_test.rb", "website/index.html" ] s.homepage = "http://roxml.rubyforge.org" s.require_paths = ["lib"] s.rubyforge_project = "roxml" s.rubygems_version = "1.8.10" s.summary = "Ruby Object to XML mapping library" if s.respond_to? :specification_version then s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q, [">= 2.3.0"]) s.add_runtime_dependency(%q, [">= 1.3.3"]) s.add_development_dependency(%q, [">= 0"]) s.add_development_dependency(%q, [">= 0"]) s.add_development_dependency(%q, [">= 2.0.0"]) s.add_development_dependency(%q, [">= 1.2.4"]) s.add_development_dependency(%q, [">= 2.2.2"]) else s.add_dependency(%q, [">= 2.3.0"]) s.add_dependency(%q, [">= 1.3.3"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 2.0.0"]) s.add_dependency(%q, [">= 1.2.4"]) s.add_dependency(%q, [">= 2.2.2"]) end else s.add_dependency(%q, [">= 2.3.0"]) s.add_dependency(%q, [">= 1.3.3"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 2.0.0"]) s.add_dependency(%q, [">= 1.2.4"]) s.add_dependency(%q, [">= 2.2.2"]) end end ruby-roxml-3.3.1/spec/000077500000000000000000000000001204356731700146005ustar00rootroot00000000000000ruby-roxml-3.3.1/spec/definition_spec.rb000066400000000000000000000405471204356731700203010ustar00rootroot00000000000000# encoding: utf-8 require_relative './spec_helper' describe ROXML::Definition do describe "#name_explicit?" do it "should indicate whether from option is present" do ROXML::Definition.new(:element, :from => 'somewhere').name_explicit?.should be_true ROXML::Definition.new(:element).name_explicit?.should be_false end it "should not consider name proxies as explicit" do ROXML::Definition.new(:element, :from => :attr).name_explicit?.should be_false ROXML::Definition.new(:element, :from => :content).name_explicit?.should be_false end end shared_examples_for "DateTime reference" do it "should return nil on empty string" do @subject.blocks.first.call(" ").should be_nil end it "should return a time version of the string" do @subject.blocks.first.call("12:05pm, September 3rd, 1970").to_s == "1970-09-03T12:05:00+00:00" end context "when passed an array of values" do it "should timify all of them" do @subject.blocks.first.call(["12:05pm, September 3rd, 1970", "3:00pm, May 22, 1700"]).map(&:to_s).should == ["1970-09-03T12:05:00+00:00", "1700-05-22T15:00:00+00:00"] end end end shared_examples_for "Date reference" do it "should return nil on empty string" do @subject.blocks.first.call(" ").should be_nil end it "should return a time version of the string" do @subject.blocks.first.call("September 3rd, 1970").to_s == "1970-09-03" end context "when passed an array of values" do it "should timify all of them" do @subject.blocks.first.call(["September 3rd, 1970", "1776-07-04"]).map(&:to_s).should == ["1970-09-03", "1776-07-04"] end end end it "should unescape xml entities" do ROXML::Definition.new(:questions, :as => []).to_ref(RoxmlObject.new).value_in(%{ "Wickard & Filburn" > < McCulloch & Maryland? }).should == ["\"Wickard & Filburn\" >", " < McCulloch & Maryland?"] end it "should unescape utf characters in xml" do ROXML::Definition.new(:questions, :as => []).to_ref(RoxmlObject.new).value_in(%{ ROXML\342\204\242 }).should == ["ROXML™"] end describe "attr name" do context "when ending with '_at'" do context "and without an :as argument" do before(:all) do @subject = ROXML::Definition.new(:time_at) end it_should_behave_like "DateTime reference" end end context "when ending with '_on'" do context "and without an :as argument" do before(:all) do @subject = ROXML::Definition.new(:created_on) end it_should_behave_like "Date reference" end end end describe ":as" do describe "=> []" do it "should means array of texts" do opts = ROXML::Definition.new(:authors, :as => []) opts.array?.should be_true opts.sought_type.should == :text end end describe "=> RoxmlClass" do class RoxmlClass include ROXML end it "should store type" do opts = ROXML::Definition.new(:name, :as => RoxmlClass) opts.sought_type.should == RoxmlClass end end describe "=> NonRoxmlClassWithFromXmlDefined" do class OctalInteger def self.from_xml(val) new(Integer(val.content)) end end it "should accept type" do opts = ROXML::Definition.new(:name, :as => OctalInteger) opts.sought_type.should == OctalInteger end end describe "=> NonRoxmlClass" do it "should fail with a warning" do proc { ROXML::Definition.new(:authors, :as => Module) }.should raise_error(ArgumentError) end end describe "=> [NonRoxmlClass]" do it "should raise" do proc { ROXML::Definition.new(:authors, :as => [Module]) }.should raise_error(ArgumentError) end end describe "=> {}" do shared_examples_for "hash options declaration" do it "should represent a hash" do @opts.hash?.should be_true end it "should have hash definition" do {@opts.hash.key.sought_type => @opts.hash.key.name}.should == @hash_args[:key] {@opts.hash.value.sought_type => @opts.hash.value.name}.should == @hash_args[:value] end it "should not represent an array" do @opts.array?.should be_false end end describe "hash with attr key and text val" do before do @opts = ROXML::Definition.new(:attributes, :as => {:key => '@name', :value => 'value'}) @hash_args = {:key => {:attr => 'name'}, :value => {:text => 'value'}} end it_should_behave_like "hash options declaration" end describe "hash with String class for type" do before do @opts = ROXML::Definition.new(:attributes, :as => {:key => 'name', :value => 'value'}) @hash_args = {:key => {:text => 'name'}, :value => {:text => 'value'}} end it_should_behave_like "hash options declaration" end describe "hash with attr key and content val" do before do @opts = ROXML::Definition.new(:attributes, :as => {:key => '@name', :value => :content}) @hash_args = {:key => {:attr => 'name'}, :value => {:text => '.'}} end it_should_behave_like "hash options declaration" end describe "hash with names as keys and content vals" do before do @opts = ROXML::Definition.new(:attributes, :as => {:key => :name, :value => :content}) @hash_args = {:key => {:text => '*'}, :value => {:text => '.'}} end it_should_behave_like "hash options declaration" end end describe "for block shorthand" do describe "in literal array" do before do @opts = ROXML::Definition.new(:intarray, :as => [Integer]) end it "should be detected as array reference" do @opts.array?.should be_true end it "should be normal otherwise" do @opts.sought_type.should == :text @opts.blocks.size.should == 1 end end it "should have no blocks without a shorthand" do ROXML::Definition.new(:count).blocks.should be_empty end it "should raise on unknown :as" do proc { ROXML::Definition.new(:count, :as => :bogus) }.should raise_error(ArgumentError) proc { ROXML::Definition.new(:count, :as => :foat) }.should raise_error(ArgumentError) end shared_examples_for "block shorthand type declaration" do it "should translate nil to nil" do @definition.blocks.first.call(nil).should be_nil end it "should translate empty strings to nil" do @definition.blocks.first.call("").should be_nil @definition.blocks.first.call(" ").should be_nil end end describe "Integer" do before do @definition = ROXML::Definition.new(:intvalue, :as => Integer) end it_should_behave_like "block shorthand type declaration" it "should translate text to integers" do @definition.blocks.first['3'].should == 3 @definition.blocks.first['792'].should == 792 end it "should raise on non-integer values" do proc { @definition.blocks.first['08'] }.should raise_error(ArgumentError) proc { @definition.blocks.first['793.12'] }.should raise_error(ArgumentError) proc { @definition.blocks.first['junk 11'] }.should raise_error(ArgumentError) proc { @definition.blocks.first['11sttf'] }.should raise_error(ArgumentError) end context "when passed an array" do it "should translate the array elements to integer" do @definition.blocks.first.call(["792", "12", "328"]).should == [792, 12, 328] end end end describe "Float" do before do @definition = ROXML::Definition.new(:floatvalue, :as => Float) end it_should_behave_like "block shorthand type declaration" it "should translate text to float" do @definition.blocks.first['3'].should == 3.0 @definition.blocks.first['12.7'].should == 12.7 end it "should raise on non-float values" do proc { @definition.blocks.first['junk 11.3'] }.should raise_error(ArgumentError) proc { @definition.blocks.first['11.1sttf'] }.should raise_error(ArgumentError) end context "when passed an array" do it "should translate the array elements to integer" do @definition.blocks.first.call(["792.13", "240", "3.14"]).should == [792.13, 240.0, 3.14] end end end describe "BigDecimal" do before do @definition = ROXML::Definition.new(:decimalvalue, :as => BigDecimal) end it_should_behave_like "block shorthand type declaration" it "should translate text to decimal numbers" do @definition.blocks.first['3'].should == BigDecimal.new("3.0") @definition.blocks.first['0.3'].should == BigDecimal.new("0.3") end it "should extract what it can, and fall back to 0" do @definition.blocks.first['junk 11'].should eql(BigDecimal.new("0")) @definition.blocks.first['11sttf'].should eql(BigDecimal.new("11.0")) end context "when passed an array" do it "should translate the array elements to integer" do @definition.blocks.first.call(["12.1", "328.2"]).should == [BigDecimal.new("12.1"), BigDecimal.new("328.2")] end end end describe "Fixnum" do before do @definition = ROXML::Definition.new(:fixnumvalue, :as => Fixnum) end it_should_behave_like "block shorthand type declaration" it "should translate text to integers" do @definition.blocks.first['3'].should == 3 @definition.blocks.first['792'].should == 792 @definition.blocks.first['08'].should == 8 @definition.blocks.first['279.23'].should == 279 end it "should extract whatever is possible and fall back to 0" do @definition.blocks.first['junk 11'].should eql(0) @definition.blocks.first['.?sttf'].should eql(0) @definition.blocks.first['11sttf'].should eql(11) end context "when passed an array" do it "should translate the array elements to integer" do @definition.blocks.first.call(["792", "12", "328"]).should == [792, 12, 328] end end end describe ":bool" do it "should boolify individual values" do ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("1").should be_true ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("True").should be_true ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("Yes").should be_true end context "when an array is passed in" do it "should boolify arrays of values" do ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("0").should be_false ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("false").should be_false ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("nO").should be_false end end context "when no value is detected" do it "should return nil" do ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("junk").should be_nil end context "when a literal block is available" do it "should pass the value itself to the block" end end end describe "Time" do it "should return nil on empty string" do ROXML::Definition.new(:floatvalue, :as => Time).blocks.first.call(" ").should be_nil end it "should return a time version of the string" do ROXML::Definition.new(:datevalue, :as => Time).blocks.first.call("12:31am").min.should == 31 end context "when passed an array of values" do it "should timify all of them" do ROXML::Definition.new(:datevalue, :as => Time).blocks.first.call(["12:31am", "3:00pm", "11:59pm"]).map(&:min).should == [31, 0, 59] end end end describe "Date" do before do @subject = ROXML::Definition.new(:datevalue, :as => Date) end it_should_behave_like "Date reference" end describe "DateTime" do before do @subject = ROXML::Definition.new(:datevalue, :as => DateTime) end it_should_behave_like "DateTime reference" end it "should prohibit multiple shorthands" do proc { ROXML::Definition.new(:count, :as => [Float, Integer]) }.should raise_error(ArgumentError) end it "should stack block shorthands with explicit blocks" do ROXML::Definition.new(:count, :as => Integer) {|val| val.to_i }.blocks.size.should == 2 ROXML::Definition.new(:count, :as => Float) {|val| val.object_id }.blocks.size.should == 2 end end end describe ":from" do shared_examples_for "attribute reference" do it "should be interpreted as :attr" do @opts.sought_type.should == :attr end it "should strip '@' from name" do @opts.name.should == 'attr_name' end it "should unescape xml entities" do @opts.to_ref(RoxmlObject.new).value_in(%{ }).should == "\"Wickard & Filburn\" > / < McCulloch & Marryland?" end end context ":attr" do before do @opts = ROXML::Definition.new(:attr_name, :from => :attr) end it_should_behave_like "attribute reference" end context "@attribute_name" do before do @opts = ROXML::Definition.new(:attr_name, :from => '@attr_name') end it_should_behave_like "attribute reference" end describe ":content" do it "should be recognized" do ROXML::Definition.new(:author).content?.should be_false ROXML::Definition.new(:author, :from => :content).content?.should == true end it "should be equivalent to :from => '.'" do ROXML::Definition.new(:author, :from => '.').content?.should == true end end end describe ":in" do context "as xpath" do it "should pass through as wrapper" do ROXML::Definition.new(:manufacturer, :in => './').wrapper.should == './' end end context "as xpath" do it "should pass through as wrapper" do ROXML::Definition.new(:manufacturer, :in => 'wrapper').wrapper.should == 'wrapper' end end end describe "options" do shared_examples_for "boolean option" do it "should be recognized" do ROXML::Definition.new(:author, :from => :content, @option => true).respond_to?(:"#{@option}?") ROXML::Definition.new(:author, :from => :content, @option => true).send(:"#{@option}?").should be_true ROXML::Definition.new(:author, :from => :content, @option => false).send(:"#{@option}?").should be_false end it "should default to false" do ROXML::Definition.new(:author, :from => :content).send(:"#{@option}?").should be_false end end describe ":required" do before do @option = :required end it_should_behave_like "boolean option" it "should not be allowed together with :else" do proc { ROXML::Definition.new(:author, :from => :content, :required => true, :else => 'Johnny') }.should raise_error(ArgumentError) proc { ROXML::Definition.new(:author, :from => :content, :required => false, :else => 'Johnny') }.should_not raise_error end end describe ":frozen" do before do @option = :frozen end it_should_behave_like "boolean option" end describe ":cdata" do before do @option = :cdata end it_should_behave_like "boolean option" end end end ruby-roxml-3.3.1/spec/examples/000077500000000000000000000000001204356731700164165ustar00rootroot00000000000000ruby-roxml-3.3.1/spec/examples/active_record_spec.rb000066400000000000000000000020021204356731700225600ustar00rootroot00000000000000require 'fileutils' require 'spec_helper' require_relative '../../examples/rails' describe ROXML, "under ActiveRecord" do before do @route = Route.from_xml(xml_for('active_record')) end it "should be parsed" do @route.should_not == nil @route.should be_an_instance_of(Route) end describe "xml attributes" do it "should extract xml attributes" do @route.totalHg.should == "640" @route.lonlatx.should == "357865" @route.lonlaty.should == "271635" @route.grcenter.should == "SH 71635 57865" @route.totalMins.should == "235.75000000000003" @route.totalDist.should == "11185.321521477119" end end describe "xml sub-objects" do it "should extract xml sub-objects" do @route.should have(6).waypoints @route.waypoints.each {|waypoint| waypoint.should be_an_instance_of(Waypoint)} end it "should be usable as a ActiveRecord object" do Waypoint.count.should == 0 @route.save! Waypoint.count.should == 6 end end endruby-roxml-3.3.1/spec/examples/amazon_spec.rb000066400000000000000000000030141204356731700212400ustar00rootroot00000000000000require 'spec_helper' require_relative './../../examples/amazon' describe PITA::ItemSearchResponse do before do @response = PITA::ItemSearchResponse.from_xml(xml_for('amazon')) end describe "#total_results" do it "should be parsed as a number" do @response.total_results.should > 0 end end describe "#total_pages" do it "should be parsed as a number" do @response.total_pages.should > 0 end end describe "#items" do it "should return a collection of items" do @response.items.should be_an_instance_of(Array) @response.items.size.should > 0 @response.items.each {|item| item.should be_an_instance_of(PITA::Item) } end it "should have the some number less than or equal to #total_results" do @response.items.size.should > 0 @response.items.size.should <= @response.total_results end end end describe PITA::Item do before do @items = PITA::ItemSearchResponse.from_xml(xml_for('amazon')).items end it "should extract asin" do @items.each {|item| item.asin.should be_an_instance_of(String) } @items.each {|item| item.asin.should_not be_empty } end it "should extract detail_page_url" do @items.each {|item| item.detail_page_url.should be_an_instance_of(String) } @items.each {|item| item.detail_page_url.should_not be_empty } end it "should extract manufacturer" do @items.each {|item| item.manufacturer.should be_an_instance_of(String) } @items.each {|item| item.manufacturer.should_not be_empty } end endruby-roxml-3.3.1/spec/examples/current_weather_spec.rb000066400000000000000000000016571204356731700231670ustar00rootroot00000000000000require 'spec_helper' require_relative './../../examples/current_weather' describe Weather do before do @weather = Weather.from_xml(xml_for('current_weather')) end it "should extract observations" do @weather.observation.should be_an_instance_of(WeatherObservation) end end describe WeatherObservation do before do @observation = Weather.from_xml(xml_for('current_weather')).observation end it "should extract temperature" do @observation.temperature.should > 0 end it "should extract feels_like" do @observation.feels_like.should > 0 end describe "#current_condition" do it "should extract current_condition" do @observation.current_condition.should_not be_empty end it "should extract icon attribute" do pending "need to think options through for HappyMapper-style :attributes extensions" @observation.current_condition.icon.should_not be_empty end end endruby-roxml-3.3.1/spec/examples/dashed_elements_spec.rb000066400000000000000000000006641204356731700231070ustar00rootroot00000000000000require 'spec_helper' require_relative './../../examples/dashed_elements' describe GitHub::Commit do before do @commit = GitHub::Commit.from_xml(xml_for('dashed_elements')) end it "should extract committed date" do @commit.committed_date.should be_an_instance_of(Date) end it "should extract url" do @commit.url.should_not be_empty end it "should extract id" do @commit.id.should_not be_empty end endruby-roxml-3.3.1/spec/examples/library_spec.rb000066400000000000000000000035121204356731700214220ustar00rootroot00000000000000require 'spec_helper' require_relative './../../examples/library' describe Library do before :all do book = Novel.new book.isbn = "0201710897" book.title = "The PickAxe" book.description = "Best Ruby book out there!" book.author = "David Thomas, Andrew Hunt, Dave Thomas" book.publisher = Publisher.new('Addison Wesley Longman, Inc.') @lib = Library.new @lib.name = "Favorite Books" @lib.novels = [book] end describe "#to_xml" do it "should contain the expected information" do @lib.to_xml.to_s.should == ROXML::XML.parse_string(%{The PickAxeDavid Thomas, Andrew Hunt, Dave ThomasAddison Wesley Longman, Inc.}).root.to_s end context "when written to a file" do before :all do @path = "spec/examples/library.xml" @doc = ROXML::XML::Document.new @doc.root = @lib.to_xml ROXML::XML.save_doc(@doc, @path) end after :all do FileUtils.rm @path end it "should be contain the expected xml" do ROXML::XML.parse_string(File.read(@path)).to_s.should == ROXML::XML.parse_string(%{The PickAxeDavid Thomas, Andrew Hunt, Dave ThomasAddison Wesley Longman, Inc.}).to_s end it "should be re-parsable via .from_xml" do File.open("spec/examples/library.xml") do |file| Library.from_xml(file).should == @lib end end end end end ruby-roxml-3.3.1/spec/examples/library_with_fines_spec.rb000066400000000000000000000020351204356731700236400ustar00rootroot00000000000000require_relative './../spec_helper' require_relative './../../examples/library_with_fines' describe LibraryWithFines do let(:xml) { File.read(xml_for('library_with_fines')) } let(:library) { LibraryWithFines.from_xml(xml) } it "should read nested elements" do library.fines.should be_a(Hash) library.fines.size == 3 library.fines.should have_key('talking') library.fines['talking'].should match(/Stop asking/) end class String def remove_whitespace self.gsub(/\s{2,}/, '').gsub("\n", '') end end it "should write deeply nested elements" do xml_out = library.to_xml.to_s xml_out.remove_whitespace.should == xml.remove_whitespace end it "should write two children of library: name and policy" do library.to_xml.children.map{|e| e.name }.should == ['name', 'policy'] end it "should be re-parsable via .from_xml" do lib_reparsed = LibraryWithFines.from_xml(library.to_xml.to_s) lib_reparsed.name.should == library.name lib_reparsed.fines.should == library.fines end end ruby-roxml-3.3.1/spec/examples/person_spec.rb000066400000000000000000000017041204356731700212650ustar00rootroot00000000000000require 'spec_helper' require_relative './../../examples/person' describe Person do before do @person = Person.new @person.name = 'John Doe' @person.lat = '40.715224' @person.long = '-74.005966' @person.street = 'Evergreen Terrace' @person.city = 'Springfield' @person.zip = '2342' end it 'should only contain one location element' do ROXML::XML.search(@person.to_xml, 'location').count.should == 1 end describe '#to_xml' do before do @xml_generated = @person.to_xml.to_s.gsub("\n",'').squeeze(' ') end it 'should generate the expected xml' do xml_file = File.read(xml_for('person')).gsub("\n",'').squeeze(' ') xml_file.should == @xml_generated end it 'should generate identical xml after a full roundtrip' do p = Person.from_xml(@xml_generated) xml_roundtrip = p.to_xml.to_s.gsub("\n",'').squeeze(' ') xml_roundtrip.should == @xml_generated end end endruby-roxml-3.3.1/spec/examples/post_spec.rb000066400000000000000000000010721204356731700207420ustar00rootroot00000000000000require 'spec_helper' require_relative './../../examples/posts' describe Post do before do @posts = Posts.from_xml(xml_for('posts')).posts end it "should extract description" do @posts.each {|post| post.description.should_not be_empty } end it "should extract href" do @posts.each {|post| post.href.should_not be_empty } end it "should extract extended" do @posts.each {|post| post.extended.should_not be_empty } end it "should extract time" do @posts.each {|post| post.created_at.should be_an_instance_of(DateTime) } end endruby-roxml-3.3.1/spec/examples/twitter_spec.rb000066400000000000000000000013561204356731700214640ustar00rootroot00000000000000require 'spec_helper' require_relative './../../examples/twitter' describe Statuses do describe Status do before do @statuses = Statuses.from_xml(xml_for('twitter')).statuses end it "should extract text" do @statuses.each {|status| status.text.should_not be_empty } end it "should extract source" do @statuses.each {|status| status.source.should_not be_empty } end describe User do before do @users = @statuses.map(&:user) end it "should extract name" do @users.each {|user| user.name.should == "John Nunemaker" } end it "should extract screen_name" do @users.each {|user| user.screen_name.should == "jnunemaker" } end end end endruby-roxml-3.3.1/spec/reference_spec.rb000066400000000000000000000013511204356731700200750ustar00rootroot00000000000000# encoding: utf-8 require_relative './spec_helper' describe ROXML::XMLRef do class Org include ROXML xml_accessor :fines, :in => 'policy/fines', :from => 'fine', :as => { :key => 'name', :value => 'desc' } end let(:org) do org = Org.new org.fines = { 'name' => 'a fine', 'desc' => 'a desc' } org end let(:reference) do Org.roxml_attrs.first.to_ref(org) end it "should properly reconstruct wrappers with multiple elements" do reference.should be_a(ROXML::XMLHashRef) xml = ROXML::XML.new_node('org').tap do |root| reference.update_xml(root, org.fines) end xml_path( xml ).should == %w{org policy fines fine name} end end ruby-roxml-3.3.1/spec/regression_spec.rb000066400000000000000000000005611204356731700203210ustar00rootroot00000000000000require 'spec_helper' describe ROXML do describe 'frozen nils' do subject { nil } context 'before unmarshalling an XML document' do it { should_not be_frozen } end context 'after unmarshalling an XML document' do before do lib = Library.from_xml(fixture(:library)) end it { should_not be_frozen } end end end ruby-roxml-3.3.1/spec/roxml_spec.rb000066400000000000000000000236461204356731700173130ustar00rootroot00000000000000require_relative './spec_helper' describe ROXML do describe "::VERSION" do it "should be equal to the VERSION file contents" do ROXML::VERSION.should == File.read('VERSION') end end describe "#from_xml" do shared_examples_for "from_xml call" do it "should fetch values" do book = BookWithContributors.from_xml(@path) book.title.should == "Programming Ruby - 2nd Edition" book.contributors.map(&:name).should == ["David Thomas","Andrew Hunt","Chad Fowler"] end end context "called with PathName" do before do @path = Pathname.new(fixture_path(:book_with_contributors)) end it_should_behave_like "from_xml call" end context "called with File" do before do @path = File.new(fixture_path(:book_with_contributors)) end it_should_behave_like "from_xml call" end context "called with URI" do before do require 'uri' @path = URI.parse("file://#{File.expand_path(File.expand_path(fixture_path(:book_with_contributors)))}") end it_should_behave_like "from_xml call" end end end describe ROXML, "#xml" do class DescriptionReadonly include ROXML xml_reader :writable, :from => :content xml_reader :readonly, :from => :content, :frozen => true end class Contributor include ROXML xml_reader :role, :from => :attr xml_reader :name end class BookWithContributions include ROXML xml_name :book xml_reader :isbn, :from => :attr xml_reader :title xml_reader :description, :as => DescriptionReadonly xml_reader :contributions, :as => [Contributor], :from => 'contributor', :in => "contributions" end class BookWithContributionsReadonly include ROXML xml_name :book xml_reader :isbn, :from => :attr, :frozen => true xml_reader :title, :frozen => true xml_reader :description, :as => DescriptionReadonly, :frozen => true xml_reader :contributions, :as => [Contributor], :from => 'contributor', :in => "contributions", :frozen => true end before do @writable = BookWithContributions.from_xml(fixture(:book_with_contributions)) @readonly = BookWithContributionsReadonly.from_xml(fixture(:book_with_contributions)) end it "should raise on duplicate accessor name" do proc do Class.new do include ROXML xml_reader :id xml_accessor :id end end.should raise_error(RuntimeError) end class OctalInteger def self.from_xml(val) new(Integer(val.content)) end def initialize(value) @val = value end def ==(other) @val == other end def to_xml sprintf("%#o", @val) end end describe "overriding output" do class BookWithOctalPages include ROXML xml_accessor :pages_with_as, :as => Integer, :to_xml => proc {|val| sprintf("%#o", val) }, :required => true xml_accessor :pages_with_type, :as => OctalInteger, :required => true end # to_xml_test :book_with_octal_pages describe "with :to_xml option" do it "should output with to_xml filtering" end describe "with #to_xml on the object" do it "should output with to_xml filtering" end end describe "overriding input" do before do @book_with_octal_pages_xml = %{ 0357 } @expected_pages = 239 end describe "with :as block shorthand" do class BookWithOctalPagesBlockShorthand include ROXML xml_accessor :pages, :as => Integer, :required => true end it "should apply filtering on input" do book = BookWithOctalPagesBlockShorthand.from_xml(@book_with_octal_pages_xml) book.pages.should == @expected_pages end end describe "with #from_xml defined on the object" do class BookWithOctalPagesType include ROXML xml_accessor :pages, :as => OctalInteger, :required => true end it "should apply filtering on input" do book = BookWithOctalPagesType.from_xml(@book_with_octal_pages_xml) book.pages.should == @expected_pages end end end describe "attribute reference" do before do @frozen = @readonly.isbn @unfrozen = @writable.isbn end it_should_behave_like "freezable xml reference" end describe "text reference" do before do @frozen = @readonly.title @unfrozen = @writable.title end it_should_behave_like "freezable xml reference" end describe "object reference" do before do @frozen = @readonly.description @unfrozen = @writable.description end it_should_behave_like "freezable xml reference" describe "indirect reference via an object" do it "does not inherit the frozen status from its parent" do @frozen.writable.frozen?.should be_false @frozen.readonly.frozen?.should be_true @unfrozen.writable.frozen?.should be_false @unfrozen.readonly.frozen?.should be_true end end end describe "array reference" do before do @frozen = @readonly.contributions @unfrozen = @writable.contributions end it_should_behave_like "freezable xml reference" it "should apply :frozen to the constituent elements" do @frozen.all?(&:frozen?).should be_true @unfrozen.any?(&:frozen?).should be_false end context "no elements are present in root, no :in is specified" do class BookWithContributors include ROXML xml_name :book xml_reader :isbn, :from => :attr xml_reader :title xml_reader :description xml_reader :contributors, :as => [Contributor] end it "should look for elements :in the plural of name" do book = BookWithContributors.from_xml(%{ David Thomas Andrew Hunt Chad Fowler }) book.contributors.map(&:name).sort.should == ["David Thomas","Andrew Hunt","Chad Fowler"].sort end end end describe "hash reference" do class DictionaryOfGuardedNames include ROXML xml_name :dictionary xml_reader :definitions, :as => {:key => :name, :value => :content}, :in => :definitions end class DictionaryOfGuardedNamesReadonly include ROXML xml_name :dictionary xml_reader :definitions, :as => {:key => :name, :value => :content}, :in => :definitions, :frozen => true end before do @frozen = DictionaryOfGuardedNamesReadonly.from_xml(fixture(:dictionary_of_guarded_names)).definitions @unfrozen = DictionaryOfGuardedNames.from_xml(fixture(:dictionary_of_guarded_names)).definitions end it_should_behave_like "freezable xml reference" it "should have frozen keys, as with all hashes" do @frozen.keys.all?(&:frozen?).should be_true @unfrozen.keys.all?(&:frozen?).should be_true end it "should apply :frozen to the constituent values" do @frozen.values.all?(&:frozen?).should be_true @unfrozen.values.any?(&:frozen?).should be_false end end end describe ROXML, "inheritance" do class Book include ROXML xml_accessor :isbn, :from => '@ISBN' xml_reader :title xml_reader :description, :cdata => true xml_reader :author xml_accessor :pages, :from => 'pagecount', :as => Integer end class Measurement include ROXML xml_reader :units, :from => :attr xml_reader :value, :from => :content, :as => Float def initialize(value = 0, units = 'pixels') @value = Float(value) @units = units.to_s normalize_hundredths end def to_s "#{value} #{units}" end def ==(other) other.units == @units && other.value == @value end private def after_parse normalize_hundredths end def normalize_hundredths if @units.starts_with? 'hundredths-' @value /= 100 @units = @units.split('hundredths-')[1] end end end class InheritedBookWithDepth < Book xml_reader :depth, :as => Measurement end before do @book_xml = %{ The PickAxe David Thomas, Andrew Hunt, Dave Thomas 1130 Pragmattic Programmers } @parent = Book.from_xml(@book_xml) @child = InheritedBookWithDepth.from_xml(@book_xml) end describe "parent" do it "should include its attributes" do @child.isbn.should == "0201710897" @child.title.should == "The PickAxe" @child.description.should == "Probably the best Ruby book out there" @child.author.should == 'David Thomas, Andrew Hunt, Dave Thomas' @child.pages.should == nil end it "should not include its child's attributes" do @parent.should_not respond_to(:depth) end end describe "child" do it "should include its parent's attributes" do @child.isbn.should == @parent.isbn @child.title.should == @parent.title @child.description.should == @parent.description @child.author.should == @parent.author @child.pages.should == @parent.pages end it "should include its attributes" do @child.depth.to_s.should == '11.3 meters' end it "should include parent's attributes added after declaration" do Book.class_eval do xml_reader :publisher, :required => true end book = InheritedBookWithDepth.from_xml(@book_xml) book.publisher.should == "Pragmattic Programmers" end end end ruby-roxml-3.3.1/spec/shared_specs.rb000066400000000000000000000005451204356731700175740ustar00rootroot00000000000000if defined?(shared_examples_for) shared_examples_for "freezable xml reference" do describe "with :frozen option" do it "should be frozen" do @frozen.frozen?.should be_true end end describe "without :frozen option" do it "should not be frozen" do @unfrozen.frozen?.should be_false end end end end ruby-roxml-3.3.1/spec/spec_helper.rb000066400000000000000000000011421204356731700174140ustar00rootroot00000000000000require 'ostruct' require 'rubygems' require 'pathname' require 'ostruct' require_relative './../test/support/fixtures' require_relative './../lib/roxml' require_relative './shared_specs' def xml_for(name) Pathname.new(File.dirname(__FILE__)).expand_path.dirname.join("examples/xml/#{name}.xml") end class RoxmlObject include ROXML end # returns an array representing the path through first child of each element in the doc def xml_path(xml, path = []) path << xml.name if xml.is_a?(Nokogiri::XML::Element) unless xml.children.empty? xml_path(xml.children.first, path) end return path end ruby-roxml-3.3.1/spec/support/000077500000000000000000000000001204356731700163145ustar00rootroot00000000000000ruby-roxml-3.3.1/spec/support/libxml.rb000066400000000000000000000000511204356731700201240ustar00rootroot00000000000000module ROXML XML_PARSER = 'libxml' end ruby-roxml-3.3.1/spec/support/nokogiri.rb000066400000000000000000000000531204356731700204600ustar00rootroot00000000000000module ROXML XML_PARSER = 'nokogiri' end ruby-roxml-3.3.1/spec/xml/000077500000000000000000000000001204356731700154005ustar00rootroot00000000000000ruby-roxml-3.3.1/spec/xml/array_spec.rb000066400000000000000000000014021204356731700200520ustar00rootroot00000000000000require 'spec_helper' module ArraySpec class Book include ROXML xml_reader :id, :as => Integer xml_reader :title end class Store include ROXML xml_reader :books, :from => 'books', :as => [Book] end class MyXml include ROXML xml_reader :store, :as => Store end end describe ":as => []" do context "with plural from" do it "should accept the plural name as the name for each item" do ArraySpec::MyXml.from_xml(%( 1first book 2second book 3third book )).store.books.size.should == 3 end end end ruby-roxml-3.3.1/spec/xml/attributes_spec.rb000066400000000000000000000040071204356731700211260ustar00rootroot00000000000000require 'spec_helper' describe ROXML::XMLAttributeRef do before do @xml = ROXML::XML.parse_string %( ) end context "plain vanilla" do before do @ref = ROXML::XMLAttributeRef.new(OpenStruct.new(:name => 'name', :wrapper => 'node', :array? => false), RoxmlObject.new) end it "should return one instance" do @ref.value_in(@xml).should == "first" end it "should output one instance" end context "with :as => []" do before do @ref = ROXML::XMLAttributeRef.new(OpenStruct.new(:name => 'name', :wrapper => 'node', :array? => true), RoxmlObject.new) end it "should collect all instances" do @ref.value_in(@xml).should == ["first", "second", "third"] end it "should output all instances" do xml = ROXML::XML.new_node('myxml') @ref.update_xml(xml, ["first", "second", "third"]) xml.to_s.squeeze(' ').should == @xml.root.to_s.squeeze(' ') end end context "when the namespaces are different" do before do @xml = ROXML::XML.parse_string %( ) end context "with :namespace => '*'" do before do @ref = ROXML::XMLAttributeRef.new(OpenStruct.new(:name => 'name', :wrapper => 'node', :array? => true, :namespace => '*'), RoxmlObject.new) end it "should collect all instances" do pending "Test bug?" @ref.value_in(@xml).should == ["first", "second", "third"] end it "should output all instances with namespaces" do pending "Full namespace write support" xml = ROXML::XML.new_node('result') @ref.update_xml(xml, ["first", "second", "third"]) xml.should == @xml.root end end end endruby-roxml-3.3.1/spec/xml/encoding_spec.rb000066400000000000000000000033171204356731700205310ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe ROXML, "encoding" do class TestResult include ROXML xml_accessor :message end context "when provided non-latin characters" do it "should output those characters as input via methods" do res = TestResult.new res.message = "sadfk одловыа jjklsd " #random russian and english charecters doc = ROXML::XML::Document.new doc.root = res.to_xml if defined?(Nokogiri) doc.at('message').inner_text else doc.find_first('message').inner_xml end.should == "sadfk одловыа jjklsd " end it "should output those characters as input via xml" do res = TestResult.from_xml("sadfk одловыа jjklsd ") doc = ROXML::XML::Document.new doc.root = res.to_xml if defined?(Nokogiri) doc.at('message').inner_text else doc.find_first('message').inner_xml end.should == "sadfk одловыа jjklsd " end it "should allow override via the document" do res = TestResult.from_xml("sadfk одловыа jjklsd ") if defined?(Nokogiri) xml = res.to_xml doc = xml.document doc.root = xml doc.encoding = 'ISO-8859-1' doc.to_s.should include('ISO-8859-1') doc.at('message').inner_text else doc = LibXML::XML::Document.new doc.encoding = LibXML::XML::Encoding::ASCII doc.root = res.to_xml pending "Libxml bug" doc.to_s.should include('ISO-8859-1') doc.find_first('message').inner_xml end.should == "sadfk одловыа jjklsd " end end end ruby-roxml-3.3.1/spec/xml/namespace_spec.rb000066400000000000000000000276151204356731700207060ustar00rootroot00000000000000require_relative './../spec_helper.rb' describe ROXML, "with namespaces" do describe "for writing" do before do @xml = < allowInOut true OhNo! Another! gronk EOS end class NetworkConfig include ROXML xml_namespace :gronk xml_name 'NetworkConfig' xml_reader :name, :from => '@name' xml_reader :errors, :as => [] xml_accessor :fence_mode, :from => 'vmw:FenceMode' xml_accessor :dhcp?, :from => 'vmw:Dhcp' end class VApp include ROXML xml_namespace :gronk xml_name "VApp" xml_reader :name, :from => '@name' xml_reader :status, :from => '@status' xml_reader :href, :from => '@href' xml_reader :type, :from => '@type' xml_accessor :foo, :from => 'foo', :namespace => false xml_accessor :bar, :from => 'bar', :namespace => false xml_accessor :network_configs, :as => [NetworkConfig], :namespace => :gronk end describe "#to_xml" do it "should reproduce the input xml" do output = ROXML::XML::Document.new output.root = VApp.from_xml(@xml).to_xml pending "Full namespace write support" output.should == ROXML::XML.parse_string(@xml) end end end shared_examples_for "roxml namespacey declaration" do context "with a namespacey :from" do context "and an explicit :namespace" do it "should raise" do proc do Class.new do include ROXML xml_reader :default_namespace_with_namespacey_from_and_explicit_namespace, :from => 'namespacey:with_namespacey_from', :namespace => 'explicit' end end.should raise_error(ROXML::ContradictoryNamespaces) end end context "and :namespace => false" do it "should raise" do proc do Class.new do include ROXML xml_reader :default_namespace_with_namespacey_from_and_namespace_false, :from => 'namespacey:with_namespacey_from', :namespace => false end end.should raise_error(ROXML::ContradictoryNamespaces) end end end end shared_examples_for "roxml namespacey declaration with default" do it_should_behave_like "roxml namespacey declaration" it "should use the default namespace" do @instance.default_namespace.should == 'default namespace node' end context "and :namespace => false" do it "should find the namespace-less node" do @instance.default_namespace_with_namespace_false.should == 'namespaceless node' end end context "with an explicit :namespace" do it "should use the explicit namespace" do @instance.default_and_explicit_namespace == 'explicit namespace node' end end context "with a namespace-less :from" do it "should use the default namespace" do @instance.default_namespace_with_namespaceless_from.should == 'default namespace node' end context "and :namespace => false" do it "should find the namespace-less node" do @instance.default_namespace_with_namespaceless_from_and_namespace_false.should == 'namespaceless node' end end context "and an explicit :namespace" do it "should use the explicit namespace" do @instance.default_namespace_with_namespaceless_from_and_explicit_namespace.should == 'explicit namespace node' end end end context "with a namespacey :from" do it "should use the :from namespace" do @instance.default_namespace_with_namespacey_from.should == 'namespacey node' end end end context "with a default namespace declared" do class DefaultNamespaceyObject include ROXML xml_namespace :default_declared xml_reader :default_namespace xml_reader :default_namespace_with_namespace_false, :namespace => false xml_reader :default_and_explicit_namespace, :namespace => 'explicit' xml_reader :default_namespace_with_namespaceless_from, :from => 'with_namespaceless_from' xml_reader :default_namespace_with_namespaceless_from_and_explicit_namespace, :from => 'with_namespaceless_from', :namespace => 'explicit' xml_reader :default_namespace_with_namespaceless_from_and_namespace_false, :from => 'with_namespaceless_from', :namespace => false xml_reader :default_namespace_with_namespacey_from, :from => 'namespacey:with_namespacey_from' # These are handled in the "roxml namespacey declaration" shared spec # xml_reader :default_namespace_with_namespacey_from_and_namespace_false, :from => 'namespacey:with_namespaceless_from', :namespace => false # xml_reader :default_namespace_with_namespacey_from_and_explicit_namespace, :from => 'namespacey:with_namespaceless_from', :namespace => 'explicit' end before do @instance = DefaultNamespaceyObject.from_xml(%{ default namespace node namespacey node explicit namespace node namespaceless node default namespace node explicit namespace node namespaceless node }) end it_should_behave_like "roxml namespacey declaration with default" end context "with a default namespace on the root node" do class XmlDefaultNamespaceyObject include ROXML xml_reader :default_namespace xml_reader :default_namespace_with_namespace_false, :namespace => false xml_reader :default_and_explicit_namespace, :namespace => 'explicit' xml_reader :default_namespace_with_namespaceless_from, :from => 'with_namespaceless_from' xml_reader :default_namespace_with_namespaceless_from_and_explicit_namespace, :from => 'with_namespaceless_from', :namespace => 'explicit' xml_reader :default_namespace_with_namespaceless_from_and_namespace_false, :from => 'with_namespaceless_from', :namespace => false xml_reader :default_namespace_with_namespacey_from, :from => 'namespacey:with_namespacey_from' # These are handled in the "roxml namespacey declaration" shared spec # xml_reader :default_namespace_with_namespacey_from_and_namespace_false, :from => 'namespacey:with_namespaceless_from', :namespace => false # xml_reader :default_namespace_with_namespacey_from_and_explicit_namespace, :from => 'namespacey:with_namespaceless_from', :namespace => 'explicit' end before do @instance = XmlDefaultNamespaceyObject.from_xml(%{ default namespace node namespacey node explicit namespace node namespaceless node default namespace node explicit namespace node namespaceless node }) end it_should_behave_like "roxml namespacey declaration with default" end context "without a default namespace" do class NamespaceyObject include ROXML xml_reader :no_default_namespace xml_reader :no_default_namespace_with_namespace_false, :namespace => false xml_reader :no_default_but_an_explicit_namespace, :namespace => 'explicit' xml_reader :no_default_namespace_with_namespaceless_from, :from => 'with_namespaceless_from' xml_reader :no_default_namespace_with_namespaceless_from_and_explicit_namespace, :from => 'with_namespaceless_from', :namespace => 'explicit' xml_reader :no_default_namespace_with_namespaceless_from_and_namespace_false, :from => 'with_namespaceless_from', :namespace => false xml_reader :no_default_namespace_with_namespacey_from, :from => 'namespacey:with_namespacey_from' # These are handled in the "roxml namespacey declaration" shared spec # xml_reader :no_default_namespace_with_namespacey_from_and_explicit_namespace, :from => 'namespacey:with_namespacey_from', :namespace => 'explicit' # xml_reader :no_default_namespace_with_namespacey_from_and_namespace_false, :from => 'namespacey:with_namespacey_from', :namespace => false end before do @instance = NamespaceyObject.from_xml(%{ namespacey node explicit namespace node namespaceless node explicit namespace node namespaceless node namespaceless node }) end it_should_behave_like "roxml namespacey declaration" it "should find the namespace-less node" do @instance.no_default_namespace.should == 'namespaceless node' end context "with :namespace => false" do it "should find the namespace-less node" do @instance.no_default_namespace_with_namespace_false.should == 'namespaceless node' end end context "with an explicit :namespace" do it "should use the explicit namespace" do @instance.no_default_but_an_explicit_namespace.should == 'explicit namespace node' end end context "with a namespace-less :from" do it "should find the namespace-less node" do @instance.no_default_namespace_with_namespaceless_from.should == 'namespaceless node' end context "and an explicit :namespace" do it "should use the explicit namespace" do @instance.no_default_namespace_with_namespaceless_from_and_explicit_namespace.should == 'explicit namespace node' end end context "with :namespace => false" do it "should find the namespace-less node" do @instance.no_default_namespace_with_namespaceless_from_and_namespace_false.should == 'namespaceless node' end end end context "with a namespacey :from" do it "should use the :from namespace" do @instance.no_default_namespace_with_namespacey_from.should == 'namespacey node' end end end end ruby-roxml-3.3.1/spec/xml/namespaces_spec.rb000066400000000000000000000040421204356731700210560ustar00rootroot00000000000000require_relative './../spec_helper.rb' describe ROXML, "#xml_namespaces" do describe "for reading" do class Tires include ROXML xml_namespaces \ :bobsbike => 'http://bobsbikes.example.com', :alicesauto => 'http://alicesautosupply.example.com/' xml_reader :bike_tires, :as => [], :from => '@name', :in => 'bobsbike:tire' xml_reader :car_tires, :as => [], :from => '@name', :in => 'alicesauto:tire' xml_reader :tires, :as => [], :from => '@name', :in => 'tire', :namespace => '*' end before do @xml = %{ } end it "should remap default namespaces" do Tires.from_xml(@xml).car_tires.should =~ ['super slick racing tire', 'all weather tire'] end it "should remap prefix namespaces" do Tires.from_xml(@xml).bike_tires.should == ['skinny street'] end context "with namespace-indifferent option" do it "should return all tires" do Tires.from_xml(@xml).tires.should =~ ['super slick racing tire', 'all weather tire', 'skinny street'] end end end context "when an included namespace is not defined in the xml" do context "where the missing namespace is the default" do it "should raise" context "but the namespace is declared in the body" do it "should succeed" end end context "where the missing namespace is included in a namespacey from" do it "should raise" context "but the namespace is declared in the body" do it "should succeed" end end context "where the missing namespace is included in an explicit :namespace" do it "should raise" context "but the namespace is declared in the body" do it "should succeed" end end end endruby-roxml-3.3.1/spec/xml/object_spec.rb000066400000000000000000000045311204356731700202100ustar00rootroot00000000000000require 'spec_helper' describe ROXML::XMLObjectRef do class SubObject include ROXML xml_reader :value, :from => :attr def initialize(value = nil) @value = value end end before do @xml = ROXML::XML.parse_string %( ) end context "plain vanilla" do before do @ref = ROXML::XMLObjectRef.new(OpenStruct.new(:name => 'name', :wrapper => 'node', :array? => false, :sought_type => SubObject), RoxmlObject.new) end it "should return one instance" do @ref.value_in(@xml).value.should == "first" end it "should output one instance" end context "with :as => []" do before do @ref = ROXML::XMLObjectRef.new(OpenStruct.new(:name => 'name', :wrapper => 'node', :array? => true, :sought_type => SubObject), RoxmlObject.new) end it "should collect all instances" do @ref.value_in(@xml).map(&:value).should == ["first", "second", "third"] end it "should output all instances" do xml = ROXML::XML.new_node('myxml') @ref.update_xml(xml, ["first", "second", "third"].map {|value| SubObject.new(value) }) xml.to_s.squeeze(' ').should == @xml.root.to_s.squeeze(' ') end end context "when the namespaces are different" do before do @xml = ROXML::XML.parse_string %( first second third ) end context "with :namespace => '*'" do before do @ref = ROXML::XMLObjectRef.new(OpenStruct.new(:name => 'name', :wrapper => 'node', :array? => true, :namespace => '*', :sought_type => SubObject), RoxmlObject.new) end it "should collect all instances" do pending "Test bug?" @ref.value_in(@xml).map(&:value).should == ["first", "second", "third"] end it "should output all instances with namespaces" do pending "Full namespace write support" xml = ROXML::XML.new_node('myxml') @ref.update_xml(xml, ["first", "second", "third"].map {|value| SubObject.new(value) }) xml.should == @xml.root end end end endruby-roxml-3.3.1/spec/xml/parser_spec.rb000066400000000000000000000010421204356731700202300ustar00rootroot00000000000000require_relative './../spec_helper.rb' describe ROXML::XML do it "should escape invalid characters on output to text node" do node = ROXML::XML.new_node("entities") ROXML::XML.set_content(node, " < > ' \" & ") node.to_s.should == " < > ' \" & " end it "should esape invalid characters for attribute name" do node = ROXML::XML.new_node("attr_holder") ROXML::XML.set_attribute(node, "entities", "\"'<>&") node.to_s.should == %{} end end ruby-roxml-3.3.1/spec/xml/text_spec.rb000066400000000000000000000037401204356731700177270ustar00rootroot00000000000000require 'spec_helper' describe ROXML::XMLTextRef do before do @xml = ROXML::XML.parse_string %( first second third ) end context "plain vanilla" do before do @ref = ROXML::XMLTextRef.new(OpenStruct.new(:name => 'name', :wrapper => 'node', :array? => false), RoxmlObject.new) end it "should return one instance" do @ref.value_in(@xml).should == "first" end it "should output one instance" end context "with :as => []" do before do @ref = ROXML::XMLTextRef.new(OpenStruct.new(:name => 'name', :wrapper => 'node', :array? => true), RoxmlObject.new) end it "should collect all instances" do @ref.value_in(@xml).should == ["first", "second", "third"] end it "should output all instances" do xml = ROXML::XML.new_node('myxml') @ref.update_xml(xml, ["first", "second", "third"]) xml.to_s.squeeze(' ').should == @xml.root.to_s.squeeze(' ') end end context "when the namespaces are different" do before do @xml = ROXML::XML.parse_string %( first second third ) end context "with :namespace => '*'" do before do @ref = ROXML::XMLTextRef.new(OpenStruct.new(:name => 'name', :wrapper => 'node', :array? => true, :namespace => '*'), RoxmlObject.new) end it "should collect all instances" do @ref.value_in(@xml).should == ["first", "second", "third"] end it "should output all instances with namespaces" do pending "Full namespace write support" xml = ROXML::XML.new_node('myxml') @ref.update_xml(xml, ["first", "second", "third"]) xml.should == @xml.root end end end endruby-roxml-3.3.1/test/000077500000000000000000000000001204356731700146255ustar00rootroot00000000000000ruby-roxml-3.3.1/test/fixtures/000077500000000000000000000000001204356731700164765ustar00rootroot00000000000000ruby-roxml-3.3.1/test/fixtures/book_malformed.xml000066400000000000000000000003051204356731700221760ustar00rootroot00000000000000 The PickAxe<title> <description><![CDATA[Probably the best Ruby book out there]]></description> <author>David Thomas, Andrew Hunt, Dave Thomas</author> </book>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ruby-roxml-3.3.1/test/fixtures/book_pair.xml��������������������������������������������������������0000664�0000000�0000000�00000000465�12043567317�0021172�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<book isbn="0974514055"> <title>Programming Ruby - 2nd Edition Second edition of the great book out there Agile Web Development with Rails Jolt winning original Ruby on Rails book ruby-roxml-3.3.1/test/fixtures/book_text_with_attribute.xml000066400000000000000000000002731204356731700243360ustar00rootroot00000000000000 The PickAxe David Thomas ruby-roxml-3.3.1/test/fixtures/book_valid.xml000066400000000000000000000003471204356731700213350ustar00rootroot00000000000000 The PickAxe David Thomas, Andrew Hunt & Dave Thomas 357ruby-roxml-3.3.1/test/fixtures/book_with_authors.xml000066400000000000000000000003521204356731700227520ustar00rootroot00000000000000 The PickAxe David Thomas Andrew Hunt Dave Thomas ruby-roxml-3.3.1/test/fixtures/book_with_contributions.xml000066400000000000000000000006431204356731700241720ustar00rootroot00000000000000 Programming Ruby - 2nd Edition Second edition of the great book out there David Thomas Andrew Hunt Chad Fowler ruby-roxml-3.3.1/test/fixtures/book_with_contributors.xml000066400000000000000000000005761204356731700240320ustar00rootroot00000000000000 Programming Ruby - 2nd Edition Second edition of the great book out there David Thomas Andrew Hunt Chad Fowler ruby-roxml-3.3.1/test/fixtures/book_with_contributors_attrs.xml000066400000000000000000000005131204356731700252360ustar00rootroot00000000000000 Programming Ruby - 2nd Edition Second edition of the great book out there ruby-roxml-3.3.1/test/fixtures/book_with_default_namespace.xml000066400000000000000000000007071204356731700247310ustar00rootroot00000000000000 Programming Ruby - 2nd Edition Second edition of the great book out there David Thomas Andrew Hunt Chad Fowler ruby-roxml-3.3.1/test/fixtures/book_with_depth.xml000066400000000000000000000003661204356731700223760ustar00rootroot00000000000000 The PickAxe David Thomas, Andrew Hunt, Dave Thomas 1130 ruby-roxml-3.3.1/test/fixtures/book_with_octal_pages.xml000066400000000000000000000002141204356731700235430ustar00rootroot00000000000000 0357 0357 ruby-roxml-3.3.1/test/fixtures/book_with_publisher.xml000066400000000000000000000003311204356731700232570ustar00rootroot00000000000000 Programming Ruby - 2nd Edition Second edition of the great book out there Pragmatic Bookshelf ruby-roxml-3.3.1/test/fixtures/book_with_wrapped_attr.xml000066400000000000000000000000521204356731700237560ustar00rootroot00000000000000 ruby-roxml-3.3.1/test/fixtures/dictionary_of_attr_name_clashes.xml000066400000000000000000000004671204356731700256140ustar00rootroot00000000000000 adjective: (of a geological formation) sloping downward from the center in all directions. To use evasions or ambiguities; equivocate. ruby-roxml-3.3.1/test/fixtures/dictionary_of_attrs.xml000066400000000000000000000004301204356731700232630ustar00rootroot00000000000000 ruby-roxml-3.3.1/test/fixtures/dictionary_of_guarded_names.xml000066400000000000000000000004101204356731700247220ustar00rootroot00000000000000 adjective: (of a geological formation) sloping downward from the center in all directions. To use evasions or ambiguities; equivocate. ruby-roxml-3.3.1/test/fixtures/dictionary_of_mixeds.xml000066400000000000000000000004011204356731700234150ustar00rootroot00000000000000 adjective: (of a geological formation) sloping downward from the center in all directions. To use evasions or ambiguities; equivocate. ruby-roxml-3.3.1/test/fixtures/dictionary_of_name_clashes.xml000066400000000000000000000005131204356731700245520ustar00rootroot00000000000000 quaquaversally adjective: (of a geological formation) sloping downward from the center in all directions. tergiversate To use evasions or ambiguities; equivocate. ruby-roxml-3.3.1/test/fixtures/dictionary_of_names.xml000066400000000000000000000003431204356731700232340ustar00rootroot00000000000000 adjective: (of a geological formation) sloping downward from the center in all directions. To use evasions or ambiguities; equivocate. ruby-roxml-3.3.1/test/fixtures/dictionary_of_texts.xml000066400000000000000000000005131204356731700232770ustar00rootroot00000000000000 quaquaversally adjective: (of a geological formation) sloping downward from the center in all directions. tergiversate To use evasions or ambiguities; equivocate. ruby-roxml-3.3.1/test/fixtures/library.xml000066400000000000000000000016411204356731700206660ustar00rootroot00000000000000 Ruby library Programming Ruby - 2nd Edition Second edition of the great book out there David Thomas Andrew Hunt Chad Fowler Agile Web Development with Rails Jolt winning original Ruby on Rails book David Thomas David Heinemeier Hansson ruby-roxml-3.3.1/test/fixtures/library_uppercase.xml000066400000000000000000000016411204356731700227350ustar00rootroot00000000000000 Ruby library Programming Ruby - 2nd Edition Second edition of the great book out there David Thomas Andrew Hunt Chad Fowler Agile Web Development with Rails Jolt winning original Ruby on Rails book David Thomas David Heinemeier Hansson ruby-roxml-3.3.1/test/fixtures/muffins.xml000066400000000000000000000000671204356731700206720ustar00rootroot00000000000000 3 ruby-roxml-3.3.1/test/fixtures/nameless_ageless_youth.xml000066400000000000000000000000221204356731700237540ustar00rootroot00000000000000 ruby-roxml-3.3.1/test/fixtures/node_with_attr_name_conflicts.xml000066400000000000000000000000671204356731700253010ustar00rootroot00000000000000ruby-roxml-3.3.1/test/fixtures/node_with_name_conflicts.xml000066400000000000000000000001201204356731700242350ustar00rootroot00000000000000 Just junk... really Cartwheel ruby-roxml-3.3.1/test/fixtures/numerology.xml000066400000000000000000000002031204356731700214130ustar00rootroot00000000000000 ruby-roxml-3.3.1/test/fixtures/person.xml000066400000000000000000000000361204356731700205250ustar00rootroot00000000000000Ben Franklin ruby-roxml-3.3.1/test/fixtures/person_with_guarded_mothers.xml000066400000000000000000000004361204356731700250200ustar00rootroot00000000000000 Ben "Benji" Franklin Abiah 'Abby' Folger Madeup Mother < the third > ruby-roxml-3.3.1/test/fixtures/person_with_mothers.xml000066400000000000000000000002411204356731700233170ustar00rootroot00000000000000 Ben Franklin Abiah Folger Madeup Mother ruby-roxml-3.3.1/test/mocks/000077500000000000000000000000001204356731700157415ustar00rootroot00000000000000ruby-roxml-3.3.1/test/mocks/dictionaries.rb000066400000000000000000000024561204356731700207520ustar00rootroot00000000000000require_relative "./../../lib/roxml" class DictionaryOfAttrs include ROXML xml_name :dictionary xml_reader :definitions, :as => {:key => '@dt', :value => '@dd'}, :in => :definitions end class DictionaryOfTexts include ROXML xml_name :dictionary xml_reader :definitions, :as => {:key => :word, :value => :meaning} end class DictionaryOfMixeds include ROXML xml_name :dictionary xml_reader :definitions, :as => {:key => '@word', :value => :content} end class DictionaryOfNames include ROXML xml_name :dictionary xml_reader :definitions, :as => {:key => :name, :value => :content} end class DictionaryOfGuardedNames include ROXML xml_name :dictionary xml_reader :definitions, :as => {:key => :name, :value => :content}, :in => :definitions end class DictionaryOfNameClashes include ROXML xml_name :dictionary xml_reader :definitions, :as => {:key => 'name', :value => 'content'}, :from => :definition end class DictionaryOfAttrNameClashes include ROXML xml_name :dictionary xml_reader :definitions, :as => {:key => '@name', :value => 'content'}, :from => :definition endruby-roxml-3.3.1/test/mocks/mocks.rb000066400000000000000000000125231204356731700174050ustar00rootroot00000000000000require_relative "./../../lib/roxml" class Muffins include ROXML xml_reader(:count, :from => 'bakers_dozens') {|val| val.to_i * 13 } end class MuffinsWithStackedBlocks include ROXML xml_reader(:count, :from => 'bakers_dozens', :as => Integer) {|val| val * 13 } end class Numerology include ROXML xml_reader :predictions, :as => {:key => '@number', :value => '@meaning'} do |k, v| [Integer(k), v] end end class Contributor include ROXML xml_reader :role, :from => :attr xml_reader :name end class WriteableContributor include ROXML xml_accessor :role, :from => :attr xml_accessor :name end class Book include ROXML xml_accessor :isbn, :from => '@ISBN' xml_reader :title xml_reader :description, :cdata => true xml_reader :author xml_accessor :pages, :from => 'pagecount', :as => Integer end class BookWithRequired include ROXML xml_accessor :isbn, :from => '@ISBN', :required => true xml_reader :title, :required => true xml_reader :contributors, :as => [Contributor], :in => 'contributor_array', :required => true xml_reader :contributor_hash, :as => {:key => '@role', :value => '@name'}, :from => 'contributor', :in => 'contributor_hash', :required => true end class BookWithAttrFrom include ROXML xml_accessor :isbn, :from => '@ISBN' end class BookWithWrappedAttr include ROXML xml_name :book xml_accessor :isbn, :from => '@ISBN', :in => 'ids' end class Measurement include ROXML xml_reader :units, :from => :attr xml_reader :value, :from => :content, :as => Float def initialize(value = 0, units = 'pixels') @value = Float(value) @units = units.to_s normalize_hundredths end def to_s "#{value} #{units}" end def ==(other) other.units == @units && other.value == @value end private def after_parse normalize_hundredths end def normalize_hundredths if @units.starts_with? 'hundredths-' @value /= 100 @units = @units.split('hundredths-')[1] end end end class BookWithDepth include ROXML xml_reader :isbn, :from => '@ISBN' xml_reader :title xml_reader :description, :cdata => true xml_reader :author xml_reader :depth, :as => Measurement end class Author include ROXML xml_reader :role, :from => :attr xml_reader :text, :from => :content end class BookWithAuthors include ROXML xml_name :book xml_reader :isbn, :from => '@ISBN' xml_reader :title xml_reader :description, :cdata => true xml_reader :authors, :as => [] end class BookWithAuthorTextAttribute include ROXML xml_name :book xml_reader :isbn, :from => '@ISBN' xml_reader :title xml_reader :description, :cdata => true xml_reader :author, :as => Author end class BookWithContributions include ROXML xml_name :book xml_reader :isbn, :from => :attr xml_reader :title xml_reader :description xml_reader :contributions, :as => [Contributor], :from => 'contributor', :in => "contributions" end class BookWithContributors include ROXML xml_name :book xml_reader :isbn, :from => :attr xml_reader :title xml_reader :description xml_reader :contributors, :as => [Contributor] end class WriteableBookWithContributors include ROXML xml_name :book xml_accessor :isbn, :from => :attr xml_accessor :title xml_accessor :description xml_accessor :contributors, :as => [Contributor] end class NamelessBook include ROXML xml_reader :isbn, :from => :attr xml_reader :title xml_reader :description xml_reader :contributors, :as => [Contributor] end class Publisher include ROXML xml_reader :name end class BookWithPublisher include ROXML xml_reader :book xml_reader :isbn, :from => :attr xml_reader :title xml_reader :description xml_reader :publisher, :as => Publisher end class BookPair include ROXML xml_reader :isbn, :from => :attr xml_reader :title xml_reader :description xml_reader :author xml_reader :book, :as => Book end class Library include ROXML xml_reader :name xml_reader :books, :as => [BookWithContributions] end class UppercaseLibrary include ROXML xml_name :library xml_reader :name, :from => 'NAME' xml_reader :books, :as => [BookWithContributions], :from => 'BOOK' end class LibraryWithBooksOfUnderivableName include ROXML xml_accessor :name xml_reader :novels, :as => [NamelessBook] end class NodeWithNameConflicts include ROXML xml_name :node xml_reader :content xml_reader :name end class NodeWithAttrNameConflicts include ROXML xml_name :node xml_reader :content, :from => '@content' xml_reader :name, :from => '@name' end class Person include ROXML xml_accessor :age, :from => :attr, :else => 21 xml_accessor :name, :from => :content, :else => 'Unknown' def self.blank new.tap do |instance| instance.age = 21 instance.name = 'Unknown' end end end class PersonWithMother include ROXML xml_name :person xml_reader :name xml_reader :mother, :as => PersonWithMother, :from => 'mother' end class PersonWithGuardedMother include ROXML xml_name :person xml_reader :name xml_reader :mother, :as => PersonWithGuardedMother, :from => :person, :in => :mother end class PersonWithMotherOrMissing include ROXML xml_reader :age, :from => :attr, :else => 21 xml_reader :name, :else => 'Anonymous' xml_reader :mother,:as => PersonWithMotherOrMissing, :else => Person.blank endruby-roxml-3.3.1/test/support/000077500000000000000000000000001204356731700163415ustar00rootroot00000000000000ruby-roxml-3.3.1/test/support/fixtures.rb000066400000000000000000000002741204356731700205420ustar00rootroot00000000000000def fixture(name) File.read(fixture_path(name)) end def xml_fixture(name) ROXML::XML.parse_file(fixture_path(name)).root end def fixture_path(name) "test/fixtures/#{name}.xml" end ruby-roxml-3.3.1/test/test_helper.rb000066400000000000000000000016401204356731700174710ustar00rootroot00000000000000require 'rubygems' require 'active_support/test_case' require_relative './mocks/mocks' require_relative './mocks/dictionaries' require_relative './support/fixtures' def to_xml_test(*names) names = names.first if names.size == 1 && names.first.is_a?(Hash) names.each do |name, xml_name| xml_name ||= name define_method "test_#{name}" do klass = name.is_a?(Symbol) ? name.to_s.camelize.constantize : name xml = xml_name.is_a?(Symbol) ? xml_fixture(xml_name) : xml_name dict = klass.from_xml(xml) xml = remove_children(xml) assert_equal xml.to_s, dict.to_xml.to_s end end end def remove_children(xml) xml = ROXML::XML.parse_string(xml).root if xml.is_a?(String) return unless xml.respond_to? :children xml.children.each do |child| if child.to_s.blank? defined?(Nokogiri) ? child.remove : child.remove! else remove_children(child) end end xml endruby-roxml-3.3.1/test/unit/000077500000000000000000000000001204356731700156045ustar00rootroot00000000000000ruby-roxml-3.3.1/test/unit/definition_test.rb000066400000000000000000000216701204356731700213260ustar00rootroot00000000000000require_relative './../test_helper' class TestDefinition < ActiveSupport::TestCase def assert_hash(opts, kvp) assert opts.hash? assert !opts.array? assert_equal kvp, {opts.hash.key.sought_type => opts.hash.key.name, opts.hash.value.sought_type => opts.hash.value.name} end def test_empty_array_means_as_array_for_text opts = ROXML::Definition.new(:authors, :as => []) assert opts.array? assert_equal :text, opts.sought_type end def test_attr_in_array_means_as_array_for_attr opts = ROXML::Definition.new(:authors, :as => [], :from => :attr) assert opts.array? assert_equal :attr, opts.sought_type end def test_block_shorthand_in_array_means_array opts = ROXML::Definition.new(:intarray, :as => [Integer]) assert opts.array? assert_equal :text, opts.sought_type assert_equal 1, opts.blocks.size end def test_required assert !ROXML::Definition.new(:author).required? assert ROXML::Definition.new(:author, :required => true).required? assert !ROXML::Definition.new(:author, :required => false).required? end def test_required_conflicts_with_else assert_raise ArgumentError do ROXML::Definition.new(:author, :required => true, :else => 'Johnny') end assert_nothing_raised do ROXML::Definition.new(:author, :required => false, :else => 'Johnny') end end def test_hash_of_attrs opts = ROXML::Definition.new(:attributes, :as => {:key => '@name', :value => '@value'}) assert_hash(opts, :attr => 'name', :attr => 'value') end def test_hash_with_attr_key_and_text_val opts = ROXML::Definition.new(:attributes, :as => {:key => '@name', :value => :value}) assert_hash(opts, :attr => 'name', :text => 'value') end def test_hash_with_string_class_for_type opts = ROXML::Definition.new(:attributes, :as => {:key => 'name', :value => 'value'}) assert_hash(opts, :text => 'name', :text => 'value') end def test_hash_with_attr_key_and_content_val opts = ROXML::Definition.new(:attributes, :as => {:key => '@name', :value => :content}) assert_hash(opts, :attr => 'name', :text => '.') end def test_hash_with_options opts = ROXML::Definition.new(:definitions, :as => {:key => '@dt', :value => '@dd'}, :in => :definitions, :from => 'definition') assert_hash(opts, :attr => 'dt', :attr => 'dd') assert_equal 'definition', opts.hash.wrapper end def test_no_block_shorthand_means_no_block assert ROXML::Definition.new(:count).blocks.empty? end def test_block_integer_shorthand assert_equal 3, ROXML::Definition.new(:count, :as => Integer).blocks.first['3'] end def test_block_float_shorthand assert_equal 3.1, ROXML::Definition.new(:count, :as => Float).blocks.first['3.1'] end def test_from_attr_is_supported opts = ROXML::Definition.new(:count, :from => :attr) assert_equal "count", opts.name assert_equal :attr, opts.sought_type end def test_from_at_name_is_supported opts = ROXML::Definition.new(:count, :from => "@COUNT") assert_equal "COUNT", opts.name assert_equal :attr, opts.sought_type end def test_multiple_shorthands_raises assert_raise ArgumentError do assert_deprecated do ROXML::Definition.new(:count, :as => [Float, Integer]) end end end def test_stacked_blocks assert_equal 2, ROXML::Definition.new(:count, :as => Integer) {|val| val.to_i }.blocks.size assert_equal 2, ROXML::Definition.new(:count, :as => Float) {|val| val.object_id }.blocks.size end def test_block_shorthand_supports_bool assert_equal true, ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("1") assert_equal [true, false, nil], ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call(["TrUe", "0", "328"]) end def test_block_shorthand_supports_integer assert_equal nil, ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call(" ") assert_equal 792, ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call("792") assert_raise ArgumentError do ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call("792.13") end assert_equal [792, 12, 328], ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call(["792", "12", "328"]) end def test_block_shorthand_supports_float assert_equal nil, ROXML::Definition.new(:floatvalue, :as => Float).blocks.first.call(" ") assert_equal 792.13, ROXML::Definition.new(:floatvalue, :as => Float).blocks.first.call("792.13") assert_equal 240.0, ROXML::Definition.new(:floatvalue, :as => Float).blocks.first.call("240") assert_equal [792.13, 240.0, 3.14], ROXML::Definition.new(:floatvalue, :as => Float).blocks.first.call(["792.13", "240", "3.14"]) end def test_block_shorthand_supports_time assert_equal nil, ROXML::Definition.new(:floatvalue, :as => Time).blocks.first.call(" ") assert_equal 31, ROXML::Definition.new(:datevalue, :as => Time).blocks.first.call("12:31am").min assert_equal [31, 0, 59], ROXML::Definition.new(:datevalue, :as => Time).blocks.first.call(["12:31am", "3:00pm", "11:59pm"]).map(&:min) end def test_block_shorthand_supports_date assert_equal nil, ROXML::Definition.new(:floatvalue, :as => Date).blocks.first.call(" ") assert_equal "1970-09-03", ROXML::Definition.new(:datevalue, :as => Date).blocks.first.call("September 3rd, 1970").to_s assert_equal ["1970-09-03", "1776-07-04"], ROXML::Definition.new(:datevalue, :as => Date).blocks.first.call(["September 3rd, 1970", "1776-07-04"]).map(&:to_s) end def test_block_shorthand_supports_datetime assert_equal nil, ROXML::Definition.new(:floatvalue, :as => DateTime).blocks.first.call(" ") assert_equal "1970-09-03T12:05:00+00:00", ROXML::Definition.new(:datevalue, :as => DateTime).blocks.first.call("12:05pm, September 3rd, 1970").to_s assert_equal ["1970-09-03T12:05:00+00:00", "1700-05-22T15:00:00+00:00"], ROXML::Definition.new(:datevalue, :as => DateTime).blocks.first.call(["12:05pm, September 3rd, 1970", "3:00pm, May 22, 1700"]).map(&:to_s) end def test_name_explicit_indicates_whether_from_option_is_present assert_equal true, ROXML::Definition.new(:element, :from => 'somewhere').name_explicit? assert_equal false, ROXML::Definition.new(:element).name_explicit? end def test_xpath_in_is_formed_properly opts = ROXML::Definition.new(:manufacturer, :in => './') assert_equal "manufacturer", opts.name assert_equal "./", opts.wrapper end def test_cdata_is_specifiable assert ROXML::Definition.new(:manufacturer, :cdata => true).cdata? end def test_as_supports_generic_roxml_types assert_equal RoxmlObject, ROXML::Definition.new(:type, :as => RoxmlObject).sought_type end def test_as_supports_generic_roxml_types_in_arrays assert_equal RoxmlObject, ROXML::Definition.new(:types, :as => [RoxmlObject]).sought_type end def test_default_works opts = ROXML::Definition.new(:missing, :else => true) assert_equal true, opts.to_ref(RoxmlObject.new).value_in(ROXML::XML.parse_string('')) end def test_default_works_for_arrays opts = ROXML::Definition.new(:missing, :as => []) assert_equal [], opts.to_ref(RoxmlObject.new).value_in(ROXML::XML.parse_string('')) end def test_default_works_for_recursive_objects opts = ROXML::Definition.new(:missing, :as => RecursiveObject, :else => false) assert_equal false, opts.to_ref(RoxmlObject.new).value_in(ROXML::XML.parse_string('')) end def test_content_is_accepted_as_from assert ROXML::Definition.new(:author, :from => :content).content? assert ROXML::Definition.new(:author, :from => '.').content? end def test_content_is_a_recognized_type opts = ROXML::Definition.new(:author, :from => :content) assert opts.content? assert_equal '.', opts.name assert_equal :text, opts.sought_type end def test_content_symbol_as_target_is_translated_to_string opts = ROXML::Definition.new(:content, :from => :attr) assert_equal 'content', opts.name assert_equal :attr, opts.sought_type end def test_attr_is_accepted_as_from assert_equal :attr, ROXML::Definition.new(:author, :from => :attr).sought_type assert_equal :attr, ROXML::Definition.new(:author, :from => '@author').sought_type end def test_attr_is_a_recognized_type opts = ROXML::Definition.new(:author, :from => :attr) assert_equal 'author', opts.name assert_equal :attr, opts.sought_type end end class RecursiveObject include ROXML xml_reader :next, :as => RecursiveObject, :else => true end class RoxmlObject include ROXML end class HashDefinitionTest < ActiveSupport::TestCase def test_content_detected_as_from opts = ROXML::Definition.new(:hash, :as => {:key => :content, :value => :name}) assert_equal '.', opts.hash.key.name assert_equal :text, opts.hash.key.sought_type end endruby-roxml-3.3.1/test/unit/deprecations_test.rb000066400000000000000000000011561204356731700216530ustar00rootroot00000000000000require_relative './../test_helper' class TestDeprecation < ActiveSupport::TestCase def test_as_array_not_deprecated assert_not_deprecated do opts = ROXML::Definition.new(:name, :as => []) assert_equal :text, opts.sought_type assert opts.array? end end def test_as_hash_not_deprecated assert_not_deprecated do opts = ROXML::Definition.new(:name, :as => {:key => '@dt', :value => '@dd'}) assert opts.hash? end end def test_as_object_with_from_xml_not_deprecated assert_not_deprecated do ROXML::Definition.new(:name, :as => OctalInteger) end end endruby-roxml-3.3.1/test/unit/to_xml_test.rb000066400000000000000000000044131204356731700204740ustar00rootroot00000000000000require_relative './../test_helper' class TestHashToXml < ActiveSupport::TestCase to_xml_test :dictionary_of_attrs, :dictionary_of_mixeds, :dictionary_of_texts, :dictionary_of_names, :dictionary_of_guarded_names, :dictionary_of_name_clashes, :dictionary_of_attr_name_clashes end class TestOtherToXml < ActiveSupport::TestCase to_xml_test :book => :book_valid, :book_with_author_text_attribute => :book_text_with_attribute, :uppercase_library => :library_uppercase to_xml_test :book_with_authors, :book_with_contributors, :book_with_contributions, :library, :node_with_name_conflicts, :node_with_attr_name_conflicts to_xml_test :person_with_mother => :person_with_mothers, :person_with_guarded_mother => :person_with_guarded_mothers to_xml_test :book_with_wrapped_attr end class TestToXmlWithDefaults < ActiveSupport::TestCase def test_content_and_attr_defaults_are_represented_in_output dict = Person.from_xml(fixture(:nameless_ageless_youth)) xml = 'Unknown' assert_equal ROXML::XML.parse_string(xml).root.to_s, dict.to_xml.to_s end end class TestToXmlWithBlocks < ActiveSupport::TestCase def test_pagecount_serialized_properly_after_modification b = Book.from_xml(fixture(:book_valid)) xml = xml_fixture(:book_valid) assert_equal '357', ROXML::XML.search(xml, 'pagecount').first.content assert_equal 357, b.pages b.pages = 500 doc = ROXML::XML::Document.new() doc.root = b.to_xml assert_equal '500', ROXML::XML.search(doc, 'pagecount').first.content end end class OctalInteger def self.from_xml(val) new(Integer(val.content)) end def initialize(value) @val = value end def ==(other) @val == other end def to_xml sprintf("%#o", @val) end end class BookWithOctalPages include ROXML xml_accessor :pages_with_to_xml_proc, :as => Integer, :to_xml => proc {|val| sprintf("%#o", val) }, :required => true xml_accessor :pages_with_type, :as => OctalInteger, :required => true end class TestToXmlWithOverriddenOutput < ActiveSupport::TestCase to_xml_test :book_with_octal_pages end ruby-roxml-3.3.1/test/unit/xml_attribute_test.rb000066400000000000000000000022511204356731700220530ustar00rootroot00000000000000require_relative './../test_helper' class TestXMLAttribute < ActiveSupport::TestCase def test_attr_from # :attr => * book = Book.from_xml(fixture(:book_text_with_attribute)) assert_equal '0201710897', book.isbn # :attr, :from => * book = BookWithAttrFrom.from_xml(fixture(:book_text_with_attribute)) assert_equal '0201710897', book.isbn end def test_mutable_attr book = Book.from_xml(fixture(:book_text_with_attribute)) assert book.respond_to?(:'isbn=') end def test_default_initialization person = PersonWithMotherOrMissing.from_xml(fixture(:nameless_ageless_youth)) assert_equal 21, person.age end def test_recursive_with_default_initialization p = PersonWithMotherOrMissing.from_xml(fixture(:person_with_mothers)) assert_equal 21, p.mother.mother.mother.age end def test_no_name_clashes n = NodeWithAttrNameConflicts.from_xml(fixture(:node_with_attr_name_conflicts)) assert_equal "Just junk... really", n.content assert_equal "Cartwheel", n.name end def test_wrapped_attr_accessible b = BookWithWrappedAttr.from_xml(fixture(:book_with_wrapped_attr)) assert_equal "0974514055", b.isbn end endruby-roxml-3.3.1/test/unit/xml_block_test.rb000066400000000000000000000036041204356731700211450ustar00rootroot00000000000000require_relative './../test_helper' class ArrayWithBlockShorthand include ROXML xml_reader :array, :as => [Integer], :from => 'number' end class ArrayWithBlock include ROXML xml_reader :array, :as => [], :from => 'number' do |arr| arr.map(&:to_i).reverse end end class TestXMLBlocks < ActiveSupport::TestCase def test_block_is_applied muffins = Muffins.from_xml(fixture(:muffins)) assert muffins.count > 0 assert_equal 0, muffins.count % 13 end def test_block_is_applied_to_hash numerology = Numerology.from_xml(fixture(:numerology)) assert !numerology.predictions.keys.empty? assert numerology.predictions.keys.all? {|k| k.is_a? Integer } assert numerology.predictions.values.all? {|k| k.is_a? String } end def test_stacked_blocks_are_applied muffins = MuffinsWithStackedBlocks.from_xml(fixture(:muffins)) assert muffins.count > 0 assert_equal 0, muffins.count % 13 end def test_block_shorthand_applied_properly_to_array obj = ArrayWithBlockShorthand.from_xml(%{ 1 2 3 }) assert_equal [1, 2, 3], obj.array end def test_block_applied_properly_to_array obj = ArrayWithBlock.from_xml(%{ 1 2 3 }) assert_equal [3, 2, 1], obj.array end def test_block_shorthand_applied_properly_to_empty_array obj = ArrayWithBlockShorthand.from_xml(%{ }) assert_equal [], obj.array end def test_block_applied_properly_to_empty_array obj = ArrayWithBlock.from_xml(%{ }) assert_equal [], obj.array end endruby-roxml-3.3.1/test/unit/xml_bool_test.rb000066400000000000000000000064221204356731700210070ustar00rootroot00000000000000require_relative './../test_helper' PROC_TRUE = proc {|val| val ? 'TRUE' : 'FALSE'} PROC_True = proc {|val| val ? 'True' : 'False'} PROC_true = proc {|val| val.to_s} PROC_1 = proc {|val| val ? 1 : 0} class XmlBool include ROXML xml_name 'xml_bool' xml_reader :true_from_TRUE?, :to_xml => PROC_TRUE xml_reader :false_from_FALSE?, :from => 'text_for_FALSE', :to_xml => PROC_TRUE xml_reader :true_from_one?, :from => '@attr_for_one', :to_xml => PROC_1 xml_reader :false_from_zero?, :from => 'text_for_zero', :in => 'container', :to_xml => PROC_1 xml_reader :true_from_True?, :from => '@attr_for_True', :in => 'container', :to_xml => PROC_True xml_reader :false_from_False?, :from => 'false_from_cdata_False', :cdata => true, :to_xml => PROC_True xml_reader :true_from_true?, :to_xml => PROC_true xml_reader :false_from_false?, :to_xml => PROC_true xml_reader :missing? end class XmlBoolRequired include ROXML xml_reader :required?, :required => true end class XmlBoolUnexpected include ROXML xml_reader :unexpected? end class XmlBoolUnexpectedWithBlock include ROXML xml_reader :unexpected? do |val| val end end BOOL_XML = %{ TRUE FALSE 0 true false } PRESENT = %{ true } ABSENT = %{ } UNEXPECTED_VALUE_XML = %{ Unexpected Value } class TestXMLBool < ActiveSupport::TestCase def test_bool_results_for_various_inputs x = XmlBool.from_xml(BOOL_XML) assert_equal true, x.true_from_TRUE? assert_equal false, x.false_from_FALSE? assert_equal true, x.true_from_one? assert_equal false, x.false_from_zero? assert_equal true, x.true_from_True? assert_equal false, x.false_from_False? assert_equal true, x.true_from_true? assert_equal false, x.false_from_false? end def test_missing_results_in_nil x = XmlBool.from_xml(BOOL_XML) assert_equal nil, x.missing? end def test_unexpected_value_results_in_nil x = XmlBoolUnexpected.from_xml(UNEXPECTED_VALUE_XML) assert_equal nil, x.unexpected? end def test_block_recieves_unexpected_value_rather_than_nil x = XmlBoolUnexpectedWithBlock.from_xml(UNEXPECTED_VALUE_XML) assert_equal "Unexpected Value", x.unexpected? end def test_required_raises_on_missing assert_nothing_raised do XmlBoolRequired.from_xml(PRESENT) end assert_raise ROXML::RequiredElementMissing do XmlBoolRequired.from_xml(ABSENT) end end def test_writable_references_properly_handle_punctuation klass = Class.new do include ROXML xml_accessor :punctuation? end instance = klass.from_xml("True") assert_equal true, instance.punctuation? instance.punctuation = false assert_equal false, instance.punctuation? end to_xml_test XmlBool => BOOL_XML endruby-roxml-3.3.1/test/unit/xml_convention_test.rb000066400000000000000000000074731204356731700222450ustar00rootroot00000000000000require_relative './../test_helper' XML_CAMELLOWER = %{ 12 GED House of Leaves } XML_CAMELCASE = %{ 12 GED House of Leaves } XML_UNDERSCORE = %{ 12 GED House of Leaves } XML_DASHES = %{ 12 GED House of Leaves } XML_UPCASE = %{ 12 GED House of Leaves } class BookCase include ROXML xml_reader :book_count, :as => Integer, :required => true xml_reader :big_books, :as => [], :required => true end class BookCaseCamelCase < BookCase xml_convention :camelcase end class BookCaseUnderScore < BookCase xml_convention :underscore end class BookCaseDashes < BookCase xml_convention &:dasherize end class BookCaseCamelLower < BookCase xml_convention {|val| val.camelcase(:lower) } end class BookCaseUpCase < BookCase xml_convention {|val| val.gsub('_', '').upcase } end class InheritedBookCaseCamelCase < BookCaseCamelCase end class InheritedBookCaseUpCase < BookCaseUpCase end # Same as BookCase. Needed to keep BookCase clean for other tests class ParentBookCaseDefault include ROXML xml_reader :book_count, :as => Integer, :required => true xml_reader :big_books, :as => [], :required => true end class InheritedBookCaseDefault < ParentBookCaseDefault end class TestXMLConvention < ActiveSupport::TestCase # TODO: Test convention applies to xml_name as well... def test_default_convention_is_underscore bc = BookCase.from_xml(XML_UNDERSCORE) assert_has_book_case_info(bc) end [BookCaseUpCase, BookCaseCamelLower, BookCaseDashes, BookCaseUnderScore, BookCaseCamelCase].each do |klass| define_method(:"test_xml_convention_#{klass.to_s.underscore}") do data = :"XML_#{klass.to_s.sub('BookCase', '').upcase}" assert_equal Proc, klass.roxml_naming_convention.class bc = klass.from_xml(Object.const_get(data)) assert_has_book_case_info(bc) end end def test_child_should_inherit_convention_if_it_doesnt_declare_one [InheritedBookCaseUpCase, InheritedBookCaseCamelCase].each do |klass| data = :"XML_#{klass.to_s.sub('InheritedBookCase', '').upcase}" assert_equal Proc, klass.roxml_naming_convention.class bc = klass.from_xml(Object.const_get(data)) assert_has_book_case_info(bc) end end def test_child_should_inherit_convention_even_if_it_is_added_after_child_declaration bc = InheritedBookCaseDefault.from_xml(XML_UNDERSCORE) assert_has_book_case_info(bc) ParentBookCaseDefault.class_eval do xml_convention :dasherize end bc = InheritedBookCaseDefault.from_xml(XML_DASHES) assert_has_book_case_info(bc) assert_raise ROXML::RequiredElementMissing do InheritedBookCaseDefault.from_xml(XML_UNDERSCORE) end end def test_tag_name_should_get_convention_treatment_as_well assert_equal "book-case-dashes", BookCaseDashes.tag_name assert_equal "INHERITEDBOOKCASEUPCASE", InheritedBookCaseUpCase.tag_name assert_equal "InheritedBookCaseCamelCase", InheritedBookCaseCamelCase.tag_name end def assert_has_book_case_info(bc) assert_equal 12, bc.book_count assert_equal ['GED', 'House of Leaves'], bc.big_books end endruby-roxml-3.3.1/test/unit/xml_hash_test.rb000066400000000000000000000070641204356731700210020ustar00rootroot00000000000000require_relative './../test_helper' class BookWithContributorHash include ROXML xml_reader :contributors, :as => {:key => '@role', :value => 'name'} end class TestXMLHash < ActiveSupport::TestCase def setup @contents = {'quaquaversally' => 'adjective: (of a geological formation) sloping downward from the center in all directions.', 'tergiversate' => 'To use evasions or ambiguities; equivocate.'} end def test_hash_preserves_data b = BookWithContributorHash.from_xml(%{ David Thomas Andrew Hunt Chad Fowler }) assert_equal({'author' => 'David Thomas', 'supporting author' => ['Andrew Hunt', 'Chad Fowler']}, b.contributors) end def test_hash_with_object_key_fails assert_raise ArgumentError do Class.new do include ROXML xml_reader :object_key_to_text, :as => {:key => BookWithContributorHash, :value => 'text_node'} end end end def test_hash_with_object_value_fails assert_raise ArgumentError do Class.new do include ROXML xml_reader :key_to_object_value, :as => {:key => '@text_node', :value => BookWithContributorHash} end end end def test_attrs_hash dict = DictionaryOfAttrs.from_xml(fixture(:dictionary_of_attrs)) assert_equal Hash, dict.definitions.class assert_equal @contents, dict.definitions end def test_text_hash dict = DictionaryOfTexts.from_xml(fixture(:dictionary_of_texts)) assert_equal Hash, dict.definitions.class assert_equal @contents, dict.definitions end def test_mixed_content_hash dict = DictionaryOfMixeds.from_xml(fixture(:dictionary_of_mixeds)) assert_equal Hash, dict.definitions.class assert_equal @contents, dict.definitions end def test_name_hash dict = DictionaryOfNames.from_xml(fixture(:dictionary_of_names)) assert_equal Hash, dict.definitions.class assert_equal @contents, dict.definitions end def test_guarded_name_hash dict = DictionaryOfGuardedNames.from_xml(fixture(:dictionary_of_guarded_names)) assert_equal Hash, dict.definitions.class assert_equal @contents, dict.definitions end def test_text_name_clashes dict = DictionaryOfNameClashes.from_xml(fixture(:dictionary_of_name_clashes)) assert_equal Hash, dict.definitions.class assert_equal @contents, dict.definitions end def test_attr_name_clashes dict = DictionaryOfAttrNameClashes.from_xml(fixture(:dictionary_of_attr_name_clashes)) assert_equal Hash, dict.definitions.class assert_equal @contents, dict.definitions end def test_it_should_gracefully_handle_empty_hash dict = Class.new do include ROXML xml_reader :missing_hash, :as => {:key => :name, :value => :content}, :in => 'EmptyDictionary' end assert_equal({}, dict.from_xml(%{ }).missing_hash) end def test_as_hash_of_as_type_not_deprecated assert_not_deprecated do opts = ROXML::Definition.new(:name, :as => {:key => :name, :value => {:from => 'value', :as => OctalInteger}}) assert opts.hash? assert_equal OctalInteger, opts.hash.value.sought_type assert_equal 'value', opts.hash.value.name end end endruby-roxml-3.3.1/test/unit/xml_initialize_test.rb000066400000000000000000000026631204356731700222200ustar00rootroot00000000000000require_relative './../test_helper' class InheritedBookWithDepth < Book xml_reader :depth, :as => Measurement end class BookWithXmlInitialize < BookWithDepth attr_reader :created_at, :creator def initialize(created_at, creator = "Unknown") @created_at = created_at @creator = creator end end class TestXMLInitialize < ActiveSupport::TestCase def test_initialize_is_run m = Measurement.from_xml('1130') assert_equal 11.3, m.value assert_equal 'meters', m.units end def test_initialize_is_run_for_nested_type b = BookWithDepth.from_xml(fixture(:book_with_depth)) assert_equal Measurement.new(11.3, 'meters'), b.depth end def test_initialize_is_run_for_nested_type_with_inheritance b = InheritedBookWithDepth.from_xml(fixture(:book_with_depth)) assert_equal Measurement.new(11.3, 'meters'), b.depth end def test_initialize_fails_on_missing_required_arg assert_raise ArgumentError do BookWithXmlInitialize.from_xml(fixture(:book_with_depth)) end end def test_initialize_with_extra_args now = Time.now b = BookWithXmlInitialize.from_xml(fixture(:book_with_depth), now) assert_equal now, b.created_at assert_equal "Unknown", b.creator b = BookWithXmlInitialize.from_xml(fixture(:book_with_depth), Time.now, "Joe Librarian") assert now < b.created_at assert_equal "Joe Librarian", b.creator end endruby-roxml-3.3.1/test/unit/xml_name_test.rb000066400000000000000000000075351204356731700210020ustar00rootroot00000000000000require_relative './../test_helper' # Parent | Child # :from | no :from | # -------------------|-------------- # :from | xml_name | xml_name-d # value | value | # -------------------|-------------- # :from | parent's | # value | accessor | un-xml_name-d # | name | class Child include ROXML end class NamedChild include ROXML xml_name :xml_name_of_child end class ParentOfNamedChild include ROXML xml_name :parent xml_accessor :child_accessor_name, :as => NamedChild end class ParentOfNamedChildWithFrom include ROXML xml_name :parent xml_accessor :child_accessor_name, :as => NamedChild, :from => 'child_from_name' end class ParentOfUnnamedChild include ROXML xml_name :parent xml_accessor :child_accessor_name, :as => Child end class ParentOfUnnamedChildWithFrom include ROXML xml_name :parent xml_accessor :child_accessor_name,:as => Child, :from => 'child_from_name' end class TestXMLName < ActiveSupport::TestCase def test_from_always_dominates_attribute_name_xml_name_or_not parent = ParentOfNamedChildWithFrom.new parent.child_accessor_name = Child.new assert_equal "", parent.to_xml.to_s.gsub(/[\n ]/, '') parent = ParentOfUnnamedChildWithFrom.new parent.child_accessor_name = Child.new assert_equal "", parent.to_xml.to_s.gsub(/[\n ]/, '') end def test_attribute_name_comes_from_the_xml_name_value_if_present parent = ParentOfNamedChild.new parent.child_accessor_name = Child.new assert_equal "", parent.to_xml.to_s.gsub(/[\n ]/, '') end def test_attribute_name_comes_from_parent_accessor_by_default parent = ParentOfUnnamedChild.new parent.child_accessor_name = Child.new assert_equal "", parent.to_xml.to_s.gsub(/[\n ]/, '') end def test_it_should_be_inherited class_with_inherited_name = Class.new(ParentOfNamedChild) assert_equal :parent, class_with_inherited_name.tag_name end def test_it_should_be_inherited_over_multiple_levels class_with_inherited_name = Class.new(Class.new(ParentOfNamedChild)) assert_equal :parent, class_with_inherited_name.tag_name end def test_named_books_picked_up named = Library.from_xml(fixture(:library)) assert named.books assert_equal :book, named.books.first.class.tag_name end def test_nameless_books_missing nameless = LibraryWithBooksOfUnderivableName.from_xml(fixture(:library)) assert nameless.novels.empty? end def test_tag_name assert_equal :dictionary, DictionaryOfTexts.tag_name dict = DictionaryOfTexts.from_xml(fixture(:dictionary_of_texts)) assert_equal :dictionary, dict.class.tag_name end def test_roxml_attrs assert_equal 'definition', DictionaryOfTexts.roxml_attrs.first.name assert_equal 'word', DictionaryOfTexts.roxml_attrs.first.hash.key.name assert_equal 'meaning', DictionaryOfTexts.roxml_attrs.first.hash.value.name end def test_xml_name_should_not_be_conventionalized_if_explicitly_set reference = ROXML::XMLTextRef.new(ROXML::Definition.new(:name, :from => 'georss:name'), WrapModule::InstanceStandin.new) assert_equal "georss:name", reference.name end def test_xml_name_not_screwed_up_by_xml_convention reference = ROXML::XMLTextRef.new(ROXML::Definition.new(:name, :in => './'), WrapModule::InstanceStandin.new) assert_equal "name value", reference.value_in(ROXML::XML.parse_string(%( name value )).root) end end module WrapModule class BaseClass include ROXML xml_convention :camelcase end class InstanceStandin < BaseClass xml_reader :name, :in => './' end endruby-roxml-3.3.1/test/unit/xml_namespace_test.rb000066400000000000000000000023341204356731700220060ustar00rootroot00000000000000require_relative './../test_helper' class TestDefaultXMLNamespaces < ActiveSupport::TestCase def setup @book = BookWithContributions.from_xml(fixture(:book_with_default_namespace)) end def test_default_namespace_doesnt_interfere_with_normal_operation assert_equal("Programming Ruby - 2nd Edition", @book.title) end def test_default_namespace_is_applied_to_in_element expected_authors = ["David Thomas","Andrew Hunt","Chad Fowler"] assert !@book.contributions.empty? @book.contributions.each do |contributor| assert expected_authors.include?(contributor.name) end end def test_default_namespace_on_root_node_should_be_found require 'libxml' xml = LibXML::XML::Parser.string( 'Yeah, contentAnother').parse assert_equal nil, xml.find_first('node') assert_equal "Yeah, content", xml.find_first('ns:node', 'ns:http://defaultnamespace.org').content assert_equal nil, xml.find_first('ns:node/subnode', 'ns:http://defaultnamespace.org') assert_equal "Another", xml.find_first('ns:node/ns:subnode', 'ns:http://defaultnamespace.org').content rescue LoadError end end ruby-roxml-3.3.1/test/unit/xml_object_test.rb000066400000000000000000000153421204356731700213230ustar00rootroot00000000000000# encoding: utf-8 require_relative './../test_helper' class EmptyCart include ROXML xml_reader :id def empty? true end end class CartHolder include ROXML xml_reader :cart, :as => EmptyCart, :required => true end class TestXMLObject < ActiveSupport::TestCase # Test book with text and attribute def test_book_author_text_attribute book = BookWithAuthorTextAttribute.from_xml(fixture(:book_text_with_attribute)) assert_equal("primary",book.author.role) assert_equal("David Thomas",book.author.text) end # Test XML object containing list of other XML objects (one-to-many) # In this case, book with contibutions def test_one_to_many_with_container expected_authors = ["David Thomas","Andrew Hunt","Chad Fowler"] book = BookWithContributions.from_xml(fixture(:book_with_contributions)) assert_equal("Programming Ruby - 2nd Edition", book.title) book.contributions.each do |contributor| assert expected_authors.include?(contributor.name) end end # Test XML object containing 1-n other XML objects without container (one-to-many) # In this case, book with contibutions def test_one_to_many_without_container expected_contributors = ["David Thomas","Andrew Hunt","Chad Fowler"] book = BookWithContributors.from_xml(fixture(:book_with_contributors)) assert_equal("Programming Ruby - 2nd Edition", book.title) book.contributors.each do |contributor| assert(expected_contributors.include?(contributor.name)) end end # when building objects that contain arrays, the second object seems to # inherit data from the first # def test_one_to_many_without_container_sequence contrib = WriteableContributor.new contrib.name = "David Thomas" book_one = WriteableBookWithContributors.new book_one.isbn = "9781843549161" book_one.title = "Anathem" book_one.description = "A new title from Neal Stephenson" book_one.contributors = [contrib] # this book should be completely empty book_two = WriteableBookWithContributors.new assert_equal(nil, book_two.isbn) assert_equal(nil, book_two.title) assert_equal(nil, book_two.description) assert_equal(nil, book_two.contributors) end # Test XML object containing one other XML object (one-to-one) # In this case, book with publisher def test_one_to_one book = BookWithPublisher.from_xml(fixture(:book_with_publisher)) assert_equal("Programming Ruby - 2nd Edition", book.title) assert_equal("Pragmatic Bookshelf", book.publisher.name) end # Test XML object containing type of self (self-reference) def test_self_reference book = BookPair.from_xml(fixture(:book_pair)) assert_equal("Programming Ruby - 2nd Edition", book.title) assert_equal("Agile Web Development with Rails", book.book.title) end # Test three-level composition (one-to-many-to-many) def test_one_to_many_to_many expected_contributors = ["David Thomas","Andrew Hunt","Chad Fowler", "David Heinemeier Hansson"] expected_books = ["Programming Ruby - 2nd Edition", "Agile Web Development with Rails"] library = Library.from_xml(fixture(:library)) assert_equal("Ruby library", library.name) assert !library.books.empty? library.books.each do |book| assert expected_books.include?(book.title) book.contributions.each do |contributor| assert(expected_contributors.include?(contributor.name)) end end end def test_without_needed_from assert_equal [], UppercaseLibrary.from_xml(fixture(:library)).books assert_equal [], Library.from_xml(fixture(:library_uppercase)).books end def test_with_needed_from assert Library.from_xml(fixture(:library)).books assert UppercaseLibrary.from_xml(fixture(:library_uppercase)).books end def test_with_recursion p = PersonWithMother.from_xml(fixture(:person_with_mothers)) assert_equal 'Ben Franklin', p.name assert_equal 'Abiah Folger', p.mother.name assert_equal 'Madeup Mother', p.mother.mother.name assert_equal nil, p.mother.mother.mother end class Node include ROXML xml_reader :name, :from => 'node_name' xml_reader :nodes, :as => [Node] end class Taxonomy include ROXML xml_reader :name, :from => 'taxonomy_name' xml_reader :nodes, :as => [Node] end class Taxonomies include ROXML xml_reader :taxonomies, :as => [Taxonomy] end def test_more_recursion taxonomies = Taxonomies.from_xml(< World Africa Algeria Algiers Ghardaïa El Oued Timimoun Annaba HERE assert_equal 1, taxonomies.taxonomies.size assert_equal 'World', taxonomies.taxonomies.first.name node = taxonomies.taxonomies.first.nodes.first assert_equal 'Africa', node.name assert_equal 'Algeria', node.nodes.first.name assert_equal ['Algiers', "Ghardaïa", 'El Oued', 'Timimoun', 'Annaba'], node.nodes.first.nodes.map(&:name) end def test_with_guarded_recursion p = PersonWithGuardedMother.from_xml(fixture(:person_with_guarded_mothers)) assert_equal 'Ben "Benji" Franklin', p.name assert_equal 'Abiah \'Abby\' Folger', p.mother.name assert_equal 'Madeup Mother < the third >', p.mother.mother.name assert_equal nil, p.mother.mother.mother end def test_recursive_with_default_initialization p = PersonWithMotherOrMissing.from_xml(fixture(:person_with_mothers)) assert_equal 'Unknown', p.mother.mother.mother.name assert_equal Person, p.mother.mother.mother.class end def test_defining_empty_on_object_doesnt_cause_it_to_be_seen_as_absent # absent means defaulting, failing required holder = CartHolder.from_xml(%{ 111111 }) assert_equal "111111", holder.cart.id end end ruby-roxml-3.3.1/test/unit/xml_required_test.rb000066400000000000000000000042521204356731700216730ustar00rootroot00000000000000require_relative './../test_helper' class TestXMLRequired < ActiveSupport::TestCase def setup @full_book = < This & that Johnny BOOK @book_missing_attr = < This & that Johnny BOOK @book_missing_text = < Johnny BOOK @book_missing_array = < This & that BOOK @book_missing_hash = < This & that Johnny BOOK end def test_required_passes_on_prescence BookWithRequired.from_xml(@full_book) end def test_required_throws_on_attr_absence assert_raise ROXML::RequiredElementMissing do BookWithRequired.from_xml(@book_missing_attr) end end def test_required_throws_on_text_absence assert_raise ROXML::RequiredElementMissing do BookWithRequired.from_xml(@book_missing_text) end end def test_required_throws_on_array_absence assert_raise ROXML::RequiredElementMissing do BookWithRequired.from_xml(@book_missing_array) end end def test_required_throws_on_hash_absence assert_raise ROXML::RequiredElementMissing do BookWithRequired.from_xml(@book_missing_hash) end end endruby-roxml-3.3.1/test/unit/xml_text_test.rb000066400000000000000000000042241204356731700210360ustar00rootroot00000000000000require_relative './../test_helper' class TestXMLText < ActiveSupport::TestCase # Test a simple mapping with no composition def test_valid_simple book = Book.from_xml(fixture(:book_valid)) assert_equal("The PickAxe", book.title) assert_equal("David Thomas, Andrew Hunt & Dave Thomas", book.author) assert_equal xml_fixture(:book_valid).to_s.gsub("\n", ''), book.to_xml.to_s.gsub("\n", '') end def test_without_needed_from assert !Library.from_xml(fixture(:library_uppercase)).name end def test_with_needed_from assert_equal "Ruby library", Library.from_xml(fixture(:library)).name assert_equal "Ruby library", UppercaseLibrary.from_xml(fixture(:library_uppercase)).name end def test_as_array assert_equal ["David Thomas","Andrew Hunt","Dave Thomas"].sort, BookWithAuthors.from_xml(fixture(:book_with_authors)).authors.sort end def test_empty_array_result_returned_properly empty_array = Class.new do include ROXML xml_reader :missing_array, :as => [], :from => 'missing' end obj = empty_array.from_xml('') assert_equal [], obj.missing_array end def test_text_modification person = Person.from_xml(fixture(:person)) assert_equal("Ben Franklin", person.name) person.name = "Fred" xml=person.to_xml.to_s assert(/Fred/=~xml) end def test_default_initialization person = PersonWithMotherOrMissing.from_xml(fixture(:nameless_ageless_youth)) assert_equal "Anonymous", person.name end def test_default_initialization_of_content person = Person.from_xml(fixture(:nameless_ageless_youth)) assert_equal "Unknown", person.name end def test_recursive_with_default_initialization p = PersonWithMotherOrMissing.from_xml(fixture(:person_with_mothers)) assert_equal 'Unknown', p.mother.mother.mother.name end def test_get_with_block p = Book.from_xml(fixture(:book_valid)) assert_equal 357, p.pages end def test_no_name_clashes n = NodeWithNameConflicts.from_xml(fixture(:node_with_name_conflicts)) assert_equal "Just junk... really", n.content assert_equal "Cartwheel", n.name end endruby-roxml-3.3.1/website/000077500000000000000000000000001204356731700153105ustar00rootroot00000000000000ruby-roxml-3.3.1/website/index.html000066400000000000000000000077141204356731700173160ustar00rootroot00000000000000 Empact/roxml @ GitHub Fork me on GitHub

roxml by Empact

ROXML is a module for binding Ruby classes to XML. It supports custom mapping and bidirectional marshaling between Ruby and XML using annotation-style class methods. ROXML supports the Nokogiri and LibXML XML processors.

We may not want to work with XML, but we don't always get to pick just how our data comes. If you do need to do serious work with XML, ROXML is here to make it nice. Use xpath-based xml declarations to map an XML response into an extensible object, use that object, and then ouput it back to xml as it came. Aside from the basics, ROXML has a lot of little goodies to make these definitions minimal and readable, which are worth digging in for. See the 'xml_convention' method for easily referencing xml which uses other naming conventions. See the handling of '?' in accessor names, the application of blocks and such for other manipulations. And finally, if you use this library, feel free to push code back my way. I'll be looking forward to it.

Dependencies

activesupport >= 2.1.0

Install

'gem install roxml' will install the latest stable rubyforge version

License

MIT License

Authors

Ben Woosley (ben.woosley@gmail.com)
Anders Engström (anders.engstrom@gnejs.net)
James Thompson (james@plainprograms.com)
James Healy (jimmy@deefa.com)
Zak Mandhro (mandhro@yahoo.com)
Russ Olsen (russell.olsen@gmail.com)

Contact

Ben Woosley (Ben.Woosley@gmail.com)

Download

You can download this project in either zip or tar formats.

You can also clone the project with Git by running:

$ git clone git://github.com/Empact/roxml