roxml-4.0.0/0000755000004100000410000000000013211325252012700 5ustar www-datawww-dataroxml-4.0.0/Rakefile0000644000004100000410000000531513211325252014351 0ustar www-datawww-datarequire 'rake' ENV['RUBY_FLAGS'] = '-W1' # Generate all the Rake tasks # Run 'rake -T' to see list of generated tasks (from gem root directory) require 'juwelier' Juwelier::Tasks.new do |gem| gem.name = '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" Rake::TestTask.new do |t| t.test_files = FileList['test/**/*_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 roxml-4.0.0/Gemfile.lock0000644000004100000410000000441013211325252015121 0ustar www-datawww-dataGEM remote: http://rubygems.org/ specs: activemodel (5.1.4) activesupport (= 5.1.4) activerecord (5.1.4) activemodel (= 5.1.4) activesupport (= 5.1.4) arel (~> 8.0) activesupport (5.1.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (~> 0.7) minitest (~> 5.1) tzinfo (~> 1.1) addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) arel (8.0.0) builder (3.2.3) concurrent-ruby (1.0.5) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.3) equivalent-xml (0.6.0) nokogiri (>= 1.4.3) faraday (0.12.2) multipart-post (>= 1.2, < 3) git (1.3.0) github_api (0.18.2) addressable (~> 2.4) descendants_tracker (~> 0.0.4) faraday (~> 0.8) hashie (~> 3.5, >= 3.5.2) oauth2 (~> 1.0) hashie (3.5.6) highline (1.7.10) i18n (0.9.1) concurrent-ruby (~> 1.0) juwelier (2.4.7) builder bundler git github_api highline kamelcase (~> 0) nokogiri psych rake rdoc semver2 jwt (1.5.6) kamelcase (0.0.1) semver2 (~> 3) mini_portile2 (2.3.0) minitest (5.10.3) multi_json (1.12.2) multi_xml (0.6.0) multipart-post (2.0.0) nokogiri (1.8.1) mini_portile2 (~> 2.3.0) oauth2 (1.4.0) faraday (>= 0.8, < 0.13) jwt (~> 1.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) psych (3.0.0) public_suffix (3.0.1) rack (1.6.8) rake (0.9.6) rdoc (5.1.0) rspec (3.7.0) rspec-core (~> 3.7.0) rspec-expectations (~> 3.7.0) rspec-mocks (~> 3.7.0) rspec-core (3.7.0) rspec-support (~> 3.7.0) rspec-expectations (3.7.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.7.0) rspec-mocks (3.7.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.7.0) rspec-support (3.7.0) semver2 (3.4.2) sqlite3 (1.3.13) thread_safe (0.3.6) tzinfo (1.2.4) thread_safe (~> 0.1) PLATFORMS ruby DEPENDENCIES activerecord (>= 4.0) activesupport (>= 4.0) equivalent-xml (>= 0.6.0) juwelier minitest nokogiri (>= 1.3.3) rack (< 2.0.0) rake (~> 0.9) rspec (~> 3.7.0) sqlite3 (>= 1.2.4) BUNDLED WITH 1.16.0 roxml-4.0.0/Gemfile0000644000004100000410000000050213211325252014170 0ustar www-datawww-datasource "http://rubygems.org" gem 'activesupport', '>= 4.0' gem 'nokogiri', '>= 1.3.3' group :development, :test do gem 'rake', '~> 0.9' gem 'juwelier' gem 'minitest' gem 'rspec', '~> 3.7.0' gem 'sqlite3', '>= 1.2.4' gem 'activerecord', '>= 4.0' gem 'rack', '< 2.0.0' gem 'equivalent-xml', '>= 0.6.0' end roxml-4.0.0/examples/0000755000004100000410000000000013211325252014516 5ustar www-datawww-dataroxml-4.0.0/examples/search_query.rb0000644000004100000410000000051013211325252017531 0ustar www-datawww-data#!/usr/bin/env ruby require_relative './../spec/spec_helper' class SearchQuery include ROXML xml_accessor :query xml_accessor :max_results, :else => 20, :as => Integer xml_accessor :language, :else => 'EN' end unless defined?(RSpec) q = SearchQuery.new q.query = "Some random query string." puts q.to_xml.to_s end roxml-4.0.0/examples/posts.rb0000755000004100000410000000113713211325252016220 0ustar www-datawww-data#!/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 endroxml-4.0.0/examples/current_weather.rb0000755000004100000410000000150113211325252020244 0ustar www-datawww-data#!/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 endroxml-4.0.0/examples/amazon.rb0000755000004100000410000000202513211325252016332 0ustar www-datawww-data#!/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 endroxml-4.0.0/examples/dashed_elements.rb0000755000004100000410000000065013211325252020173 0ustar www-datawww-data#!/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, '' endroxml-4.0.0/examples/library_with_fines.rb0000644000004100000410000000036413211325252020731 0ustar www-datawww-dataclass LibraryWithFines include ROXML xml_name 'library' xml_accessor :name xml_accessor :fines, :as => { :key => 'name', :value => 'desc' }, :from => 'fine', :in => 'policy/fines' endroxml-4.0.0/examples/person.rb0000755000004100000410000000124613211325252016357 0ustar www-datawww-data#!/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 endroxml-4.0.0/examples/xml/0000755000004100000410000000000013211325252015316 5ustar www-datawww-dataroxml-4.0.0/examples/xml/posts.xml0000644000004100000410000001633613211325252017221 0ustar www-datawww-data roxml-4.0.0/examples/xml/twitter.xml0000644000004100000410000004452413211325252017553 0ustar www-datawww-data 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 roxml-4.0.0/examples/xml/amazon.xml0000644000004100000410000001363013211325252017330 0ustar www-datawww-data
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)
roxml-4.0.0/examples/xml/current_weather.xml0000644000004100000410000001032713211325252021244 0ustar www-datawww-data 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 roxml-4.0.0/examples/xml/person.xml0000644000004100000410000000046213211325252017350 0ustar www-datawww-data John Doe 40.715224 -74.005966
Evergreen Terrace Springfield 2342
roxml-4.0.0/examples/xml/dashed_elements.xml0000644000004100000410000000266713211325252021177 0ustar www-datawww-data 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 roxml-4.0.0/examples/xml/library_with_fines.xml0000644000004100000410000000067313211325252021731 0ustar www-datawww-data 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. roxml-4.0.0/examples/xml/active_record.xml0000644000004100000410000000422313211325252020652 0ustar www-datawww-data 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 roxml-4.0.0/examples/twitter.rb0000755000004100000410000000144013211325252016547 0ustar www-datawww-data#!/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] endroxml-4.0.0/examples/library.rb0000644000004100000410000000167513211325252016520 0ustar www-datawww-dataclass 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 roxml-4.0.0/examples/rails.rb0000644000004100000410000000302713211325252016157 0ustar www-datawww-data#!/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 endroxml-4.0.0/.rspec0000644000004100000410000000001013211325252014004 0ustar www-datawww-data--colourroxml-4.0.0/History.txt0000644000004100000410000003324513211325252015111 0ustar www-datawww-dataSee github releases for versions > 3.3.1 https://github.com/Empact/roxml/releases == 3.3.1 (February 10, 2012) * bug fix * Fix reading of VERSION file - Jari Bakken (jarib) == 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] roxml-4.0.0/spec/0000755000004100000410000000000013211325252013632 5ustar www-datawww-dataroxml-4.0.0/spec/examples/0000755000004100000410000000000013211325252015450 5ustar www-datawww-dataroxml-4.0.0/spec/examples/active_record_spec.rb0000644000004100000410000000207713211325252021626 0ustar www-datawww-datarequire '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 expect(@route).to_not eq(nil) expect(@route).to be_an_instance_of(Route) end describe "xml attributes" do it "should extract xml attributes" do expect(@route.totalHg).to eq("640") expect(@route.lonlatx).to eq("357865") expect(@route.lonlaty).to eq("271635") expect(@route.grcenter).to eq("SH 71635 57865") expect(@route.totalMins).to eq("235.75000000000003") expect(@route.totalDist).to eq("11185.321521477119") end end describe "xml sub-objects" do it "should extract xml sub-objects" do expect(@route.waypoints.size).to eq(6) @route.waypoints.each {|waypoint| expect(waypoint).to be_an_instance_of(Waypoint)} end it "should be usable as a ActiveRecord object" do expect(Waypoint.count).to eq(0) @route.save! expect(Waypoint.count).to eq(6) end end end roxml-4.0.0/spec/examples/amazon_spec.rb0000644000004100000410000000311713211325252020276 0ustar www-datawww-datarequire '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 expect(@response.total_results).to be > 0 end end describe "#total_pages" do it "should be parsed as a number" do expect(@response.total_pages).to be > 0 end end describe "#items" do it "should return a collection of items" do expect(@response.items).to be_an_instance_of(Array) expect(@response.items.size).to be > 0 @response.items.each {|item| expect(item).to be_an_instance_of(PITA::Item) } end it "should have the some number less than or equal to #total_results" do expect(@response.items.size).to be > 0 expect(@response.items.size).to be <= @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| expect(item.asin).to be_an_instance_of(String) } @items.each {|item| expect(item.asin).to_not be_empty } end it "should extract detail_page_url" do @items.each {|item| expect(item.detail_page_url).to be_an_instance_of(String) } @items.each {|item| expect(item.detail_page_url).to_not be_empty } end it "should extract manufacturer" do @items.each {|item| expect(item.manufacturer).to be_an_instance_of(String) } @items.each {|item| expect(item.manufacturer).to_not be_empty } end endroxml-4.0.0/spec/examples/library_with_fines_spec.rb0000644000004100000410000000207513211325252022676 0ustar www-datawww-datarequire_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 expect(library.fines).to be_a(Hash) library.fines.size == 3 expect(library.fines).to have_key('talking') expect(library.fines['talking']).to 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 expect(xml_out.remove_whitespace).to eq(xml.remove_whitespace) end it "should write two children of library: name and policy" do expect(library.to_xml.children.map{|e| e.name }).to eq(['name', 'policy']) end it "should be re-parsable via .from_xml" do lib_reparsed = LibraryWithFines.from_xml(library.to_xml.to_s) expect(lib_reparsed.name).to eq(library.name) expect(lib_reparsed.fines).to eq(library.fines) end end roxml-4.0.0/spec/examples/dashed_elements_spec.rb0000644000004100000410000000070013211325252022130 0ustar www-datawww-datarequire '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 expect(@commit.committed_date).to be_an_instance_of(Date) end it "should extract url" do expect(@commit.url).to_not be_empty end it "should extract id" do expect(@commit.id).to_not be_empty end endroxml-4.0.0/spec/examples/person_spec.rb0000644000004100000410000000172313211325252020320 0ustar www-datawww-datarequire '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 expect(ROXML::XML.search(@person.to_xml, 'location').count).to eq(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(' ') expect(xml_file).to eq(@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(' ') expect(xml_roundtrip).to eq(@xml_generated) end end endroxml-4.0.0/spec/examples/post_spec.rb0000644000004100000410000000111213211325252017767 0ustar www-datawww-datarequire '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| expect(post.description).to_not be_empty } end it "should extract href" do @posts.each {|post| expect(post.href).to_not be_empty } end it "should extract extended" do @posts.each {|post| expect(post.extended).to_not be_empty } end it "should extract time" do @posts.each {|post| expect(post.created_at).to be_an_instance_of(DateTime) } end endroxml-4.0.0/spec/examples/current_weather_spec.rb0000644000004100000410000000170613211325252022214 0ustar www-datawww-datarequire '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 expect(@weather.observation).to 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 expect(@observation.temperature).to be > 0 end it "should extract feels_like" do expect(@observation.feels_like).to be > 0 end describe "#current_condition" do it "should extract current_condition" do expect(@observation.current_condition).to_not be_empty end it "should extract icon attribute" do skip "need to think options through for HappyMapper-style :attributes extensions" expect(@observation.current_condition.icon).to_not be_empty end end endroxml-4.0.0/spec/examples/library_spec.rb0000644000004100000410000000353113211325252020455 0ustar www-datawww-datarequire '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 expect(@lib.to_xml.to_s).to eq(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 expect(ROXML::XML.parse_string(File.read(@path)).to_s).to eq(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| expect(Library.from_xml(file)).to eq(@lib) end end end end end roxml-4.0.0/spec/examples/search_query_spec.rb0000644000004100000410000000134413211325252021503 0ustar www-datawww-datarequire 'spec_helper' require_relative './../../examples/search_query' describe SearchQuery do before do @search = SearchQuery.new @search.query = 'This is a random search query.' @saved_search = SearchQuery.from_xml("Search for something") end it 'should return the default value for all attributes where no value is set' do expect(@search.language).to eq('EN') @search.max_results == 20 end it 'should return the same object for the default value' do expect(@search.language.object_id).to eq(@search.language.object_id) end it 'should respect the defaults when loading from xml' do expect(@saved_search.language).to eq('EN') @saved_search.max_results == 20 end end roxml-4.0.0/spec/examples/twitter_spec.rb0000644000004100000410000000140013211325252020504 0ustar www-datawww-datarequire '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| expect(status.text).to_not be_empty } end it "should extract source" do @statuses.each {|status| expect(status.source).to_not be_empty } end describe User do before do @users = @statuses.map(&:user) end it "should extract name" do @users.each {|user| expect(user.name).to eq("John Nunemaker") } end it "should extract screen_name" do @users.each {|user| expect(user.screen_name).to eq("jnunemaker") } end end end endroxml-4.0.0/spec/roxml_spec.rb0000644000004100000410000002327113211325252016337 0ustar www-datawww-datarequire_relative './spec_helper' describe ROXML do describe "::VERSION" do it "should be equal to the VERSION file contents" do expect(ROXML::VERSION).to eq(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) expect(book.title).to eq("Programming Ruby - 2nd Edition") expect(book.contributors.map(&:name)).to eq(["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 expect do Class.new do include ROXML xml_reader :id xml_accessor :id end end.to 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 #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) expect(book.pages).to eq(@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 expect(@frozen.writable.frozen?).to be_falsey expect(@frozen.readonly.frozen?).to be_truthy expect(@unfrozen.writable.frozen?).to be_falsey expect(@unfrozen.readonly.frozen?).to be_truthy 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 expect(@frozen.all?(&:frozen?)).to be_truthy expect(@unfrozen.any?(&:frozen?)).to be_falsey 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 }) expect(book.contributors.map(&:name).sort).to eq(["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 expect(@frozen.keys.all?(&:frozen?)).to be_truthy expect(@unfrozen.keys.all?(&:frozen?)).to be_truthy end it "should apply :frozen to the constituent values" do expect(@frozen.values.all?(&:frozen?)).to be_truthy expect(@unfrozen.values.any?(&:frozen?)).to be_falsey 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 expect(@child.isbn).to eq("0201710897") expect(@child.title).to eq("The PickAxe") expect(@child.description).to eq("Probably the best Ruby book out there") expect(@child.author).to eq('David Thomas, Andrew Hunt, Dave Thomas') expect(@child.pages).to eq(nil) end it "should not include its child's attributes" do expect(@parent).to_not respond_to(:depth) end end describe "child" do it "should include its parent's attributes" do expect(@child.isbn).to eq(@parent.isbn) expect(@child.title).to eq(@parent.title) expect(@child.description).to eq(@parent.description) expect(@child.author).to eq(@parent.author) expect(@child.pages).to eq(@parent.pages) end it "should include its attributes" do expect(@child.depth.to_s).to eq('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) expect(book.publisher).to eq("Pragmattic Programmers") end end end roxml-4.0.0/spec/shared_specs.rb0000644000004100000410000000056013211325252016623 0ustar www-datawww-dataif defined?(shared_examples_for) shared_examples_for "freezable xml reference" do describe "with :frozen option" do it "should be frozen" do expect(@frozen.frozen?).to be_truthy end end describe "without :frozen option" do it "should not be frozen" do expect(@unfrozen.frozen?).to be_falsey end end end end roxml-4.0.0/spec/spec_helper.rb0000644000004100000410000000131613211325252016451 0ustar www-datawww-datarequire 'ostruct' require 'rubygems' require 'pathname' require 'ostruct' require 'rspec/matchers' # req by equivalent-xml custom matcher `be_equivalent_to` require 'equivalent-xml' 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 roxml-4.0.0/spec/regression_spec.rb0000644000004100000410000000120513211325252017347 0ustar www-datawww-datarequire 'spec_helper' describe ROXML do describe 'frozen nils' do subject { nil } # Prior to ruby-2.2, nil was not frozen. This test watches for # a regression in previous versions of roxml that caused nil to # become frozen. FIXME: remove after ruby-2.1 support is removed. if RUBY_VERSION < "2.2" context 'before unmarshalling an XML document' do it { is_expected.to_not be_frozen } end context 'after unmarshalling an XML document' do before do lib = Library.from_xml(fixture(:library)) end it { is_expected.to_not be_frozen } end end end end roxml-4.0.0/spec/xml/0000755000004100000410000000000013211325252014432 5ustar www-datawww-dataroxml-4.0.0/spec/xml/text_spec.rb0000644000004100000410000000376613211325252016771 0ustar www-datawww-datarequire '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 expect(@ref.value_in(@xml)).to eq("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 expect(@ref.value_in(@xml)).to eq(["first", "second", "third"]) end it "should output all instances" do xml = ROXML::XML.new_node('myxml') @ref.update_xml(xml, ["first", "second", "third"]) expect(xml.to_s.squeeze(' ')).to eq(@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 expect(@ref.value_in(@xml)).to eq(["first", "second", "third"]) end it "should output all instances with namespaces" do skip "Full namespace write support" xml = ROXML::XML.new_node('myxml') @ref.update_xml(xml, ["first", "second", "third"]) expect(xml).to eq(@xml.root) end end end endroxml-4.0.0/spec/xml/encoding_spec.rb0000644000004100000410000000334313211325252017562 0ustar www-datawww-data# 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 expect(if defined?(Nokogiri) doc.at('message').inner_text else doc.find_first('message').inner_xml end).to eq("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 expect(if defined?(Nokogiri) doc.at('message').inner_text else doc.find_first('message').inner_xml end).to eq("sadfk одловыа jjklsd ") end it "should allow override via the document" do res = TestResult.from_xml("sadfk одловыа jjklsd ") expect(if defined?(Nokogiri) xml = res.to_xml doc = xml.document doc.root = xml doc.encoding = 'ISO-8859-1' expect(doc.to_s).to 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 skip "Libxml bug" expect(doc.to_s).to include('ISO-8859-1') doc.find_first('message').inner_xml end).to eq("sadfk одловыа jjklsd ") end end end roxml-4.0.0/spec/xml/parser_spec.rb0000644000004100000410000000105413211325252017265 0ustar www-datawww-datarequire_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, " < > ' \" & ") expect(node.to_s).to eq(" < > ' \" & ") end it "should esape invalid characters for attribute name" do node = ROXML::XML.new_node("attr_holder") ROXML::XML.set_attribute(node, "entities", "\"'<>&") expect(node.to_s).to eq(%{}) end end roxml-4.0.0/spec/xml/attributes_spec.rb0000644000004100000410000000403213211325252020156 0ustar www-datawww-datarequire '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 expect(@ref.value_in(@xml)).to eq("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 expect(@ref.value_in(@xml)).to eq(["first", "second", "third"]) end it "should output all instances" do xml = ROXML::XML.new_node('myxml') @ref.update_xml(xml, ["first", "second", "third"]) expect(xml.to_s.squeeze(' ')).to eq(@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 skip "Test bug?" expect(@ref.value_in(@xml)).to eq(["first", "second", "third"]) end it "should output all instances with namespaces" do skip "Full namespace write support" xml = ROXML::XML.new_node('result') @ref.update_xml(xml, ["first", "second", "third"]) expect(xml).to eq(@xml.root) end end end endroxml-4.0.0/spec/xml/namespaces_spec.rb0000644000004100000410000000410313211325252020106 0ustar www-datawww-datarequire_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 expect(Tires.from_xml(@xml).car_tires).to match_array(['super slick racing tire', 'all weather tire']) end it "should remap prefix namespaces" do expect(Tires.from_xml(@xml).bike_tires).to eq(['skinny street']) end context "with namespace-indifferent option" do it "should return all tires" do expect(Tires.from_xml(@xml).tires).to match_array(['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 endroxml-4.0.0/spec/xml/object_spec.rb0000644000004100000410000000455413211325252017247 0ustar www-datawww-datarequire '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 expect(@ref.value_in(@xml).value).to eq("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 expect(@ref.value_in(@xml).map(&:value)).to eq(["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) }) expect(xml.to_s.squeeze(' ')).to eq(@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 skip "Test bug?" expect(@ref.value_in(@xml).map(&:value)).to eq(["first", "second", "third"]) end it "should output all instances with namespaces" do skip "Full namespace write support" xml = ROXML::XML.new_node('myxml') @ref.update_xml(xml, ["first", "second", "third"].map {|value| SubObject.new(value) }) expect(xml).to eq(@xml.root) end end end endroxml-4.0.0/spec/xml/namespace_spec.rb0000644000004100000410000003256113211325252017734 0ustar www-datawww-datarequire_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 => [], :from => 'gronk:error' 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(:namespaces => {'vmw' => "http://foo.example.com", 'gronk' => "http://gronk.example.com"}) expect(ROXML::XML.parse_string(output.to_s)).to be_equivalent_to(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 expect 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.to raise_error(ROXML::ContradictoryNamespaces) end end context "and :namespace => false" do it "should raise" do expect 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.to 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 expect(@instance.default_namespace).to eq('default namespace node') end context "and :namespace => false" do it "should find the namespace-less node" do expect(@instance.default_namespace_with_namespace_false).to eq('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 expect(@instance.default_namespace_with_namespaceless_from).to eq('default namespace node') end context "and :namespace => false" do it "should find the namespace-less node" do expect(@instance.default_namespace_with_namespaceless_from_and_namespace_false).to eq('namespaceless node') end end context "and an explicit :namespace" do it "should use the explicit namespace" do expect(@instance.default_namespace_with_namespaceless_from_and_explicit_namespace).to eq('explicit namespace node') end end end context "with a namespacey :from" do it "should use the :from namespace" do expect(@instance.default_namespace_with_namespacey_from).to eq('namespacey node') end end context "with an namespacey XPath :from" do it "should use the given namespace" do expect(@instance.default_namespace_with_namespacey_xpath_from).to eq('namespacey xpath node') end end context "with an XPath :from" do it "should use the default namespace" do expect(@instance.default_namespace_with_xpath_from).to eq('default namespace with xpath 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' xml_reader :default_namespace_with_namespacey_xpath_from, :from => 'xpath/namespacey:default_namespace' xml_reader :default_namespace_with_xpath_from, :from => 'xpath/default_namespace' # 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 namespacey xpath node default namespace with xpath 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' xml_reader :default_namespace_with_namespacey_xpath_from, :from => 'xpath/namespacey:default_namespace' xml_reader :default_namespace_with_xpath_from, :from => 'xpath/default_namespace' # 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 namespacey xpath node default namespace with xpath 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 expect(@instance.no_default_namespace).to eq('namespaceless node') end context "with :namespace => false" do it "should find the namespace-less node" do expect(@instance.no_default_namespace_with_namespace_false).to eq('namespaceless node') end end context "with an explicit :namespace" do it "should use the explicit namespace" do expect(@instance.no_default_but_an_explicit_namespace).to eq('explicit namespace node') end end context "with a namespace-less :from" do it "should find the namespace-less node" do expect(@instance.no_default_namespace_with_namespaceless_from).to eq('namespaceless node') end context "and an explicit :namespace" do it "should use the explicit namespace" do expect(@instance.no_default_namespace_with_namespaceless_from_and_explicit_namespace).to eq('explicit namespace node') end end context "with :namespace => false" do it "should find the namespace-less node" do expect(@instance.no_default_namespace_with_namespaceless_from_and_namespace_false).to eq('namespaceless node') end end end context "with a namespacey :from" do it "should use the :from namespace" do expect(@instance.no_default_namespace_with_namespacey_from).to eq('namespacey node') end end end end roxml-4.0.0/spec/xml/array_spec.rb0000644000004100000410000000140713211325252017111 0ustar www-datawww-datarequire '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 expect(ArraySpec::MyXml.from_xml(%( 1first book 2second book 3third book )).store.books.size).to eq(3) end end end roxml-4.0.0/spec/support/0000755000004100000410000000000013211325252015346 5ustar www-datawww-dataroxml-4.0.0/spec/support/libxml.rb0000644000004100000410000000005113211325252017156 0ustar www-datawww-datamodule ROXML XML_PARSER = 'libxml' end roxml-4.0.0/spec/support/nokogiri.rb0000644000004100000410000000005313211325252017512 0ustar www-datawww-datamodule ROXML XML_PARSER = 'nokogiri' end roxml-4.0.0/spec/reference_spec.rb0000644000004100000410000000136213211325252017131 0ustar www-datawww-data# 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 expect(reference).to be_a(ROXML::XMLHashRef) xml = ROXML::XML.new_node('org').tap do |root| reference.update_xml(root, org.fines) end expect(xml_path( xml )).to eq(%w{org policy fines fine name}) end end roxml-4.0.0/spec/definition_spec.rb0000644000004100000410000003753113211325252017332 0ustar www-datawww-data# encoding: utf-8 require_relative './spec_helper' describe ROXML::Definition do describe "#name_explicit?" do it "should indicate whether from option is present" do expect(ROXML::Definition.new(:element, :from => 'somewhere').name_explicit?).to be_truthy expect(ROXML::Definition.new(:element).name_explicit?).to be_falsey end it "should not consider name proxies as explicit" do expect(ROXML::Definition.new(:element, :from => :attr).name_explicit?).to be_falsey expect(ROXML::Definition.new(:element, :from => :content).name_explicit?).to be_falsey end end shared_examples_for "DateTime reference" do it "should return nil on empty string" do expect(@subject.blocks.first.call(" ")).to 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 expect(@subject.blocks.first.call(["12:05pm, September 3rd, 1970", "3:00pm, May 22, 1700"]).map(&:to_s)).to eq(["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 expect(@subject.blocks.first.call(" ")).to 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 expect(@subject.blocks.first.call(["September 3rd, 1970", "1776-07-04"]).map(&:to_s)).to eq(["1970-09-03", "1776-07-04"]) end end end it "should unescape xml entities" do expect(ROXML::Definition.new(:questions, :as => []).to_ref(RoxmlObject.new).value_in(%{ "Wickard & Filburn" > < McCulloch & Maryland? })).to eq(["\"Wickard & Filburn\" >", " < McCulloch & Maryland?"]) end it "should unescape utf characters in xml" do expect(ROXML::Definition.new(:questions, :as => []).to_ref(RoxmlObject.new).value_in(%{ ROXML\342\204\242 })).to eq(["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 => []) expect(opts.array?).to be_truthy expect(opts.sought_type).to eq(:text) end end describe "=> RoxmlClass" do class RoxmlClass include ROXML end it "should store type" do opts = ROXML::Definition.new(:name, :as => RoxmlClass) expect(opts.sought_type).to eq(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) expect(opts.sought_type).to eq(OctalInteger) end end describe "=> NonRoxmlClass" do it "should fail with a warning" do expect { ROXML::Definition.new(:authors, :as => Module) }.to raise_error(ArgumentError) end end describe "=> [NonRoxmlClass]" do it "should raise" do expect { ROXML::Definition.new(:authors, :as => [Module]) }.to raise_error(ArgumentError) end end describe "=> {}" do shared_examples_for "hash options declaration" do it "should represent a hash" do expect(@opts.hash?).to be_truthy end it "should have hash definition" do expect({@opts.hash.key.sought_type => @opts.hash.key.name}).to eq(@hash_args[:key]) expect({@opts.hash.value.sought_type => @opts.hash.value.name}).to eq(@hash_args[:value]) end it "should not represent an array" do expect(@opts.array?).to be_falsey 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 expect(@opts.array?).to be_truthy end it "should be normal otherwise" do expect(@opts.sought_type).to eq(:text) expect(@opts.blocks.size).to eq(1) end end it "should have no blocks without a shorthand" do expect(ROXML::Definition.new(:count).blocks).to be_empty end it "should raise on unknown :as" do expect { ROXML::Definition.new(:count, :as => :bogus) }.to raise_error(ArgumentError) expect { ROXML::Definition.new(:count, :as => :foat) }.to raise_error(ArgumentError) end shared_examples_for "block shorthand type declaration" do it "should translate nil to nil" do expect(@definition.blocks.first.call(nil)).to be_nil end it "should translate empty strings to nil" do expect(@definition.blocks.first.call("")).to be_nil expect(@definition.blocks.first.call(" ")).to 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 expect(@definition.blocks.first['3']).to eq(3) expect(@definition.blocks.first['792']).to eq(792) expect(@definition.blocks.first['08']).to eq(8) expect(@definition.blocks.first['279.23']).to eq(279) end it "should extract whatever is possible and fall back to 0" do expect(@definition.blocks.first['junk 11']).to eql(0) expect(@definition.blocks.first['.?sttf']).to eql(0) expect(@definition.blocks.first['11sttf']).to eql(11) end context "when passed an array" do it "should translate the array elements to integer" do expect(@definition.blocks.first.call(["792", "12", "328"])).to eq([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 expect(@definition.blocks.first['3']).to eq(3.0) expect(@definition.blocks.first['12.7']).to eq(12.7) end it "should raise on non-float values" do expect { @definition.blocks.first['junk 11.3'] }.to raise_error(ArgumentError) expect { @definition.blocks.first['11.1sttf'] }.to raise_error(ArgumentError) end context "when passed an array" do it "should translate the array elements to integer" do expect(@definition.blocks.first.call(["792.13", "240", "3.14"])).to eq([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 expect(@definition.blocks.first['3']).to eq(BigDecimal.new("3.0")) expect(@definition.blocks.first['0.3']).to eq(BigDecimal.new("0.3")) end # Ruby behavior of BigDecimal changed in 2.4, this test is not valid on older rubies if RUBY_VERSION >= "2.4" it "should raise on non-decimal values" do expect { @definition.blocks.first['junk 11'] }.to raise_error(ArgumentError) end end it "should extract what it can" do expect(@definition.blocks.first['11sttf']).to eql(BigDecimal.new("11.0")) end context "when passed an array" do it "should translate the array elements to integer" do expect(@definition.blocks.first.call(["12.1", "328.2"])).to eq([BigDecimal.new("12.1"), BigDecimal.new("328.2")]) end end end describe ":bool" do it "should boolify individual values" do expect(ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("1")).to be_truthy expect(ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("True")).to be_truthy expect(ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("Yes")).to be_truthy end context "when an array is passed in" do it "should boolify arrays of values" do expect(ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("0")).to be_falsey expect(ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("false")).to be_falsey expect(ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("nO")).to be_falsey end end context "when no value is detected" do it "should return nil" do expect(ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("junk")).to 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 expect(ROXML::Definition.new(:floatvalue, :as => Time).blocks.first.call(" ")).to be_nil end it "should return a time version of the string" do expect(ROXML::Definition.new(:datevalue, :as => Time).blocks.first.call("12:31am").min).to eq(31) end context "when passed an array of values" do it "should timify all of them" do expect(ROXML::Definition.new(:datevalue, :as => Time).blocks.first.call(["12:31am", "3:00pm", "11:59pm"]).map(&:min)).to eq([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 expect { ROXML::Definition.new(:count, :as => [Float, Integer]) }.to raise_error(ArgumentError) end it "should stack block shorthands with explicit blocks" do expect(ROXML::Definition.new(:count, :as => Integer) {|val| val.to_i }.blocks.size).to eq(2) expect(ROXML::Definition.new(:count, :as => Float) {|val| val.object_id }.blocks.size).to eq(2) end end end describe ":from" do shared_examples_for "attribute reference" do it "should be interpreted as :attr" do expect(@opts.sought_type).to eq(:attr) end it "should strip '@' from name" do expect(@opts.name).to eq('attr_name') end it "should unescape xml entities" do expect(@opts.to_ref(RoxmlObject.new).value_in(%{ })).to eq("\"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 expect(ROXML::Definition.new(:author).content?).to be_falsey expect(ROXML::Definition.new(:author, :from => :content).content?).to eq(true) end it "should be equivalent to :from => '.'" do expect(ROXML::Definition.new(:author, :from => '.').content?).to eq(true) end end end describe ":in" do context "as xpath" do it "should pass through as wrapper" do expect(ROXML::Definition.new(:manufacturer, :in => './').wrapper).to eq('./') end end context "as xpath" do it "should pass through as wrapper" do expect(ROXML::Definition.new(:manufacturer, :in => 'wrapper').wrapper).to eq('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}?") expect(ROXML::Definition.new(:author, :from => :content, @option => true).send(:"#{@option}?")).to be_truthy expect(ROXML::Definition.new(:author, :from => :content, @option => false).send(:"#{@option}?")).to be_falsey end it "should default to false" do expect(ROXML::Definition.new(:author, :from => :content).send(:"#{@option}?")).to be_falsey 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 expect { ROXML::Definition.new(:author, :from => :content, :required => true, :else => 'Johnny') }.to raise_error(ArgumentError) expect { ROXML::Definition.new(:author, :from => :content, :required => false, :else => 'Johnny') }.to_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 roxml-4.0.0/README.rdoc0000644000004100000410000001313413211325252014510 0ustar www-datawww-dataROXML Ruby Object to XML mapping library. {Build Status}[https://travis-ci.org/Empact/roxml] For more information visit: http://rdoc.info/projects/Empact/roxml http://empact.github.com/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. roxml-4.0.0/.travis.yml0000644000004100000410000000011413211325252015005 0ustar www-datawww-datasudo: false language: ruby rvm: - 2.2.8 - 2.3.5 - 2.4.2 - ruby-head roxml-4.0.0/lib/0000755000004100000410000000000013211325252013446 5ustar www-datawww-dataroxml-4.0.0/lib/roxml.rb0000644000004100000410000005053613211325252015145 0ustar www-datawww-datarequire '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 if params[:namespaces] params[:namespaces].each { |prefix, url| root.add_namespace_definition(prefix, url) } 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, 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 (or it's there but its contents are blank) 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 if instance_variable_get(attr.instance_variable_name).nil? instance_variable_set(attr.instance_variable_name, attr.default) end 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 roxml-4.0.0/lib/roxml/0000755000004100000410000000000013211325252014607 5ustar www-datawww-dataroxml-4.0.0/lib/roxml/hash_definition.rb0000644000004100000410000000114113211325252020264 0ustar www-datawww-datamodule 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 endroxml-4.0.0/lib/roxml/xml.rb0000644000004100000410000000165013211325252015736 0ustar www-datawww-datamodule 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' roxml-4.0.0/lib/roxml/definition.rb0000644000004100000410000001432313211325252017267 0ustar www-datawww-datarequire '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| v.to_i unless v.blank? end end, Float => lambda do |val| all(val) do |v| Float(v) 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 roxml-4.0.0/lib/roxml/xml/0000755000004100000410000000000013211325252015407 5ustar www-datawww-dataroxml-4.0.0/lib/roxml/xml/references.rb0000644000004100000410000001730513211325252020063 0ustar www-datawww-datarequire "rexml/xpath_parser" module ROXML class RequiredElementMissing < ArgumentError # :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) xml = XML::Node.from(xml) value = fetch_value(xml) value = default if default && (value.nil? || value.to_s.empty?) 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? && opts.namespace != false && ns = [opts.namespace, @instance.class.roxml_namespace, @default_namespace].compact.map(&:to_s).first parser = REXML::Parsers::XPathParser.new parsed = parser.parse what parsed.each_cons(4).with_index.each do |a,i| if a[0..2] == [:child, :qname, ""] if ns == "*" parsed[i+1,3] = [:any, :predicate, [:eq, [:function, "local-name", []], [:literal, a[3]]]] if a[3] != "*" else a[2].replace ns end end end parser.abbreviate parsed else what end 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 roxml-4.0.0/lib/roxml/xml/parsers/0000755000004100000410000000000013211325252017066 5ustar www-datawww-dataroxml-4.0.0/lib/roxml/xml/parsers/libxml.rb0000644000004100000410000000306413211325252020705 0ustar www-datawww-datarequire '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 roxml-4.0.0/lib/roxml/xml/parsers/nokogiri.rb0000644000004100000410000000307013211325252021234 0ustar www-datawww-datarequire '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 roxml-4.0.0/test/0000755000004100000410000000000013211325252013657 5ustar www-datawww-dataroxml-4.0.0/test/fixtures/0000755000004100000410000000000013211325252015530 5ustar www-datawww-dataroxml-4.0.0/test/fixtures/person_with_guarded_mothers.xml0000644000004100000410000000043613211325252024052 0ustar www-datawww-data Ben "Benji" Franklin Abiah 'Abby' Folger Madeup Mother < the third > roxml-4.0.0/test/fixtures/book_with_wrapped_attr.xml0000644000004100000410000000005213211325252023010 0ustar www-datawww-data roxml-4.0.0/test/fixtures/library.xml0000644000004100000410000000164113211325252017720 0ustar www-datawww-data 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 roxml-4.0.0/test/fixtures/book_pair.xml0000644000004100000410000000046513211325252020224 0ustar www-datawww-data Programming Ruby - 2nd Edition Second edition of the great book out there Agile Web Development with Rails Jolt winning original Ruby on Rails book roxml-4.0.0/test/fixtures/muffins.xml0000644000004100000410000000006713211325252017724 0ustar www-datawww-data 3 roxml-4.0.0/test/fixtures/dictionary_of_texts.xml0000644000004100000410000000051313211325252022331 0ustar www-datawww-data quaquaversally adjective: (of a geological formation) sloping downward from the center in all directions. tergiversate To use evasions or ambiguities; equivocate. roxml-4.0.0/test/fixtures/library_uppercase.xml0000644000004100000410000000164113211325252021767 0ustar www-datawww-data 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 roxml-4.0.0/test/fixtures/book_with_contributions.xml0000644000004100000410000000064313211325252023224 0ustar www-datawww-data Programming Ruby - 2nd Edition Second edition of the great book out there David Thomas Andrew Hunt Chad Fowler roxml-4.0.0/test/fixtures/dictionary_of_name_clashes.xml0000644000004100000410000000051313211325252023604 0ustar www-datawww-data quaquaversally adjective: (of a geological formation) sloping downward from the center in all directions. tergiversate To use evasions or ambiguities; equivocate. roxml-4.0.0/test/fixtures/book_text_with_attribute.xml0000644000004100000410000000027313211325252023370 0ustar www-datawww-data The PickAxe David Thomas roxml-4.0.0/test/fixtures/dictionary_of_mixeds.xml0000644000004100000410000000040113211325252022447 0ustar www-datawww-data adjective: (of a geological formation) sloping downward from the center in all directions. To use evasions or ambiguities; equivocate. roxml-4.0.0/test/fixtures/book_with_octal_pages.xml0000644000004100000410000000010113211325252022570 0ustar www-datawww-data 0357 roxml-4.0.0/test/fixtures/book_with_publisher.xml0000644000004100000410000000033113211325252022311 0ustar www-datawww-data Programming Ruby - 2nd Edition Second edition of the great book out there Pragmatic Bookshelf roxml-4.0.0/test/fixtures/person.xml0000644000004100000410000000003613211325252017557 0ustar www-datawww-dataBen Franklin roxml-4.0.0/test/fixtures/dictionary_of_attrs.xml0000644000004100000410000000043013211325252022315 0ustar www-datawww-data roxml-4.0.0/test/fixtures/book_with_authors.xml0000644000004100000410000000035213211325252022004 0ustar www-datawww-data The PickAxe David Thomas Andrew Hunt Dave Thomas roxml-4.0.0/test/fixtures/book_with_default_namespace.xml0000644000004100000410000000070713211325252023763 0ustar www-datawww-data Programming Ruby - 2nd Edition Second edition of the great book out there David Thomas Andrew Hunt Chad Fowler roxml-4.0.0/test/fixtures/dictionary_of_names.xml0000644000004100000410000000034313211325252022266 0ustar www-datawww-data adjective: (of a geological formation) sloping downward from the center in all directions. To use evasions or ambiguities; equivocate. roxml-4.0.0/test/fixtures/book_valid.xml0000644000004100000410000000034713211325252020367 0ustar www-datawww-data The PickAxe David Thomas, Andrew Hunt & Dave Thomas 357roxml-4.0.0/test/fixtures/book_with_contributors_attrs.xml0000644000004100000410000000051313211325252024270 0ustar www-datawww-data Programming Ruby - 2nd Edition Second edition of the great book out there roxml-4.0.0/test/fixtures/book_malformed.xml0000644000004100000410000000030513211325252021230 0ustar www-datawww-data The PickAxe<title> <description><![CDATA[Probably the best Ruby book out there]]></description> <author>David Thomas, Andrew Hunt, Dave Thomas</author> </book>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������roxml-4.0.0/test/fixtures/person_with_mothers.xml���������������������������������������������������0000644�0000041�0000041�00000000241�13211325252�022351� 0����������������������������������������������������������������������������������������������������ustar �www-data������������������������www-data���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<person> <name>Ben Franklin</name> <mother> <name>Abiah Folger</name> <mother> <name>Madeup Mother</name> </mother> </mother> </person> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������roxml-4.0.0/test/fixtures/book_with_contributors.xml������������������������������������������������0000644�0000041�0000041�00000000576�13211325252�023064� 0����������������������������������������������������������������������������������������������������ustar �www-data������������������������www-data���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<book isbn="0974514055"> <title>Programming Ruby - 2nd Edition Second edition of the great book out there David Thomas Andrew Hunt Chad Fowler roxml-4.0.0/test/fixtures/dictionary_of_attr_name_clashes.xml0000644000004100000410000000046713211325252024646 0ustar www-datawww-data adjective: (of a geological formation) sloping downward from the center in all directions. To use evasions or ambiguities; equivocate. roxml-4.0.0/test/fixtures/book_with_depth.xml0000644000004100000410000000036613211325252021430 0ustar www-datawww-data The PickAxe David Thomas, Andrew Hunt, Dave Thomas 1130 roxml-4.0.0/test/fixtures/node_with_name_conflicts.xml0000644000004100000410000000012013211325252023267 0ustar www-datawww-data Just junk... really Cartwheel roxml-4.0.0/test/fixtures/numerology.xml0000644000004100000410000000020313211325252020445 0ustar www-datawww-data roxml-4.0.0/test/fixtures/node_with_attr_name_conflicts.xml0000644000004100000410000000006713211325252024333 0ustar www-datawww-dataroxml-4.0.0/test/fixtures/nameless_ageless_youth.xml0000644000004100000410000000002213211325252023006 0ustar www-datawww-data roxml-4.0.0/test/fixtures/dictionary_of_guarded_names.xml0000644000004100000410000000041013211325252023754 0ustar www-datawww-data adjective: (of a geological formation) sloping downward from the center in all directions. To use evasions or ambiguities; equivocate. roxml-4.0.0/test/test_helper.rb0000644000004100000410000000157613211325252016533 0ustar www-datawww-datarequire 'rubygems' 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 end roxml-4.0.0/test/mocks/0000755000004100000410000000000013211325252014773 5ustar www-datawww-dataroxml-4.0.0/test/mocks/mocks.rb0000644000004100000410000001252313211325252016437 0ustar www-datawww-datarequire_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 endroxml-4.0.0/test/mocks/dictionaries.rb0000644000004100000410000000245613211325252020004 0ustar www-datawww-datarequire_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 endroxml-4.0.0/test/unit/0000755000004100000410000000000013211325252014636 5ustar www-datawww-dataroxml-4.0.0/test/unit/xml_attribute_test.rb0000644000004100000410000000227413211325252021112 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' class TestXMLAttribute < Minitest::Test 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 end roxml-4.0.0/test/unit/xml_hash_test.rb0000644000004100000410000000636513211325252020037 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' class BookWithContributorHash include ROXML xml_reader :contributors, :as => {:key => '@role', :value => 'name'} end class TestXMLHash < Minitest::Test 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_raises 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_raises 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 end roxml-4.0.0/test/unit/xml_initialize_test.rb0000644000004100000410000000270713211325252021251 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' 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 < Minitest::Test 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_raises 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 end roxml-4.0.0/test/unit/xml_bool_test.rb0000644000004100000410000000636113211325252020043 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' 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 < Minitest::Test 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_nil x.missing? end def test_unexpected_value_results_in_nil x = XmlBoolUnexpected.from_xml(UNEXPECTED_VALUE_XML) assert_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 XmlBoolRequired.from_xml(PRESENT) assert_raises 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 end roxml-4.0.0/test/unit/xml_namespace_test.rb0000644000004100000410000000234013211325252021035 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' class TestDefaultXMLNamespaces < Minitest::Test 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_nil xml.find_first('node') assert_equal "Yeah, content", xml.find_first('ns:node', 'ns:http://defaultnamespace.org').content assert_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 roxml-4.0.0/test/unit/xml_required_test.rb0000644000004100000410000000430113211325252020720 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' class TestXMLRequired < Minitest::Test 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_raises ROXML::RequiredElementMissing do BookWithRequired.from_xml(@book_missing_attr) end end def test_required_throws_on_text_absence assert_raises ROXML::RequiredElementMissing do BookWithRequired.from_xml(@book_missing_text) end end def test_required_throws_on_array_absence assert_raises ROXML::RequiredElementMissing do BookWithRequired.from_xml(@book_missing_array) end end def test_required_throws_on_hash_absence assert_raises ROXML::RequiredElementMissing do BookWithRequired.from_xml(@book_missing_hash) end end end roxml-4.0.0/test/unit/xml_convention_test.rb0000644000004100000410000000751713211325252021276 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' 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 < Minitest::Test # 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_raises 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 end roxml-4.0.0/test/unit/deprecations_test.rb0000644000004100000410000000235513211325252020707 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' require 'active_support/testing/deprecation' class TestDeprecation < Minitest::Test include ActiveSupport::Testing::Deprecation 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 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 def test_multiple_shorthands_raises assert_raises ArgumentError do assert_deprecated do ROXML::Definition.new(:count, :as => [Float, Integer]) end end end end roxml-4.0.0/test/unit/xml_object_test.rb0000644000004100000410000001531513211325252020355 0ustar www-datawww-data# encoding: utf-8 require_relative './../test_helper' require 'minitest/autorun' 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 < Minitest::Test # 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_nil book_two.isbn assert_nil book_two.title assert_nil book_two.description assert_equal [], 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_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_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 roxml-4.0.0/test/unit/xml_name_test.rb0000644000004100000410000000756013211325252020032 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' # 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 < Minitest::Test 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 end roxml-4.0.0/test/unit/definition_test.rb0000644000004100000410000002203613211325252020355 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' class TestDefinition < Minitest::Test 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_raises ArgumentError do ROXML::Definition.new(:author, :required => true, :else => 'Johnny') end ROXML::Definition.new(:author, :required => false, :else => 'Johnny') end def test_hash_of_attrs opts = ROXML::Definition.new(:attributes, :as => {:key => '@name', :value => '@value'}) assert_hash(opts, :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 => '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 => '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_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_nil ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call(" ") assert_equal 792, ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call("792") assert_equal 792, ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call("792.13") 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_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_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_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_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_for_missing_element_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_for_empty_element_works opts = ROXML::Definition.new(:age, :else => 25) assert_equal 25, opts.to_ref(RoxmlObject.new).value_in(ROXML::XML.parse_string('')) end def test_empty_element_works_without_default opts = ROXML::Definition.new(:age) assert_equal '', 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 < Minitest::Test 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 end roxml-4.0.0/test/unit/xml_text_test.rb0000644000004100000410000000424713211325252020075 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' class TestXMLText < Minitest::Test # 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 end roxml-4.0.0/test/unit/to_xml_test.rb0000644000004100000410000000416713211325252017534 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' class TestHashToXml < Minitest::Test 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 < Minitest::Test 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 < Minitest::Test 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 < Minitest::Test 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, :as => OctalInteger, :required => true end class TestToXmlWithOverriddenOutput < Minitest::Test to_xml_test :book_with_octal_pages end roxml-4.0.0/test/unit/xml_block_test.rb0000644000004100000410000000362713211325252020204 0ustar www-datawww-datarequire_relative './../test_helper' require 'minitest/autorun' 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 < Minitest::Test 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 end roxml-4.0.0/test/support/0000755000004100000410000000000013211325252015373 5ustar www-datawww-dataroxml-4.0.0/test/support/fixtures.rb0000644000004100000410000000027413211325252017574 0ustar www-datawww-datadef 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 roxml-4.0.0/roxml.gemspec0000644000004100000410000001576413211325252015423 0ustar www-datawww-data# Generated by juwelier # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- # stub: roxml 4.0.0 ruby lib Gem::Specification.new do |s| s.name = "roxml".freeze s.version = "4.0.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Ben Woosley".freeze, "Zak Mandhro".freeze, "Anders Engstrom".freeze, "Russ Olsen".freeze] s.date = "2017-12-01" 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".freeze s.email = "ben.woosley@gmail.com".freeze s.extra_rdoc_files = [ "History.txt", "README.rdoc" ] s.files = [ ".gitmodules", ".rspec", ".travis.yml", "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/search_query.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/search_query_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 = "https://github.com/Empact/roxml".freeze s.rubygems_version = "2.6.11".freeze s.summary = "Ruby Object to XML mapping library".freeze if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q.freeze, [">= 4.0"]) s.add_runtime_dependency(%q.freeze, [">= 1.3.3"]) s.add_development_dependency(%q.freeze, ["~> 0.9"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["~> 3.7.0"]) s.add_development_dependency(%q.freeze, [">= 1.2.4"]) s.add_development_dependency(%q.freeze, [">= 4.0"]) s.add_development_dependency(%q.freeze, ["< 2.0.0"]) s.add_development_dependency(%q.freeze, [">= 0.6.0"]) else s.add_dependency(%q.freeze, [">= 4.0"]) s.add_dependency(%q.freeze, [">= 1.3.3"]) s.add_dependency(%q.freeze, ["~> 0.9"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 3.7.0"]) s.add_dependency(%q.freeze, [">= 1.2.4"]) s.add_dependency(%q.freeze, [">= 4.0"]) s.add_dependency(%q.freeze, ["< 2.0.0"]) s.add_dependency(%q.freeze, [">= 0.6.0"]) end else s.add_dependency(%q.freeze, [">= 4.0"]) s.add_dependency(%q.freeze, [">= 1.3.3"]) s.add_dependency(%q.freeze, ["~> 0.9"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 3.7.0"]) s.add_dependency(%q.freeze, [">= 1.2.4"]) s.add_dependency(%q.freeze, [">= 4.0"]) s.add_dependency(%q.freeze, ["< 2.0.0"]) s.add_dependency(%q.freeze, [">= 0.6.0"]) end end roxml-4.0.0/LICENSE0000644000004100000410000000210513211325252013703 0ustar www-datawww-dataCopyright (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. roxml-4.0.0/VERSION0000644000004100000410000000000513211325252013743 0ustar www-datawww-data4.0.0roxml-4.0.0/TODO0000644000004100000410000000206313211325252013371 0ustar www-datawww-dataPlanned: 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 roxml-4.0.0/website/0000755000004100000410000000000013211325252014342 5ustar www-datawww-dataroxml-4.0.0/website/index.html0000644000004100000410000000751413211325252016346 0ustar www-datawww-data 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 >= 4.0

Install

'gem install roxml'

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

roxml-4.0.0/.gitmodules0000644000004100000410000000020013211325252015045 0ustar www-datawww-data[submodule "vendor/override_rake_task"] path = vendor/override_rake_task url = git://github.com/Empact/override_rake_task.git