xommelier 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/Guardfile CHANGED
@@ -4,7 +4,8 @@ guard 'bundler' do
4
4
  end
5
5
 
6
6
  guard 'rspec', :version => 2 do
7
+ watch(%r{^spec/fixtures/.+$})
7
8
  watch(%r{^spec/.+_spec\.rb$})
8
9
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
9
- watch('spec/spec_helper.rb') { "spec" }
10
+ watch('spec/spec_helper.rb') { 'spec' }
10
11
  end
data/README.md CHANGED
@@ -4,18 +4,109 @@
4
4
 
5
5
  Xommelier is an XML Object Mapper. You could describe some namespace (e.g. Atom) in ruby DSL and use it for parsing XML to Ruby objects or for building XML from Ruby objects.
6
6
 
7
- Look into {Xommelier::Atom} module for implementation of http://www.w3.org/2005/Atom namespace
7
+ Look into {Xommelier::Atom} and {Xommelier::Atom::Thread} module for implementation of http://www.w3.org/2005/Atom namespace and Atom Threading extension
8
8
 
9
9
  Xommelier is work in progress: [![Build Status](https://secure.travis-ci.org/alsemyonov/xommelier.png?branch=master)](http://travis-ci.org/alsemyonov/xommelier)
10
10
 
11
- ## Examples
11
+ ## Examples with Atom
12
12
 
13
- You can see example code in examples/ folder.
13
+ ```ruby
14
+ require 'xommelier/atom'
15
+ require 'xommelier/atom/thread'
16
+ ```
17
+
18
+ ### Reading a feed
19
+
20
+ ```ruby
21
+ feed = Xommelier::Atom::Feed.parse(open('spec/fixtures/feed.atom.xml'))
22
+ puts feed.id, feed.title, feed.updated
23
+
24
+ feed.entries do |entry|
25
+ puts feed.id, feed.title, feed.published, feed.updated
26
+ puts feed.content || feed.summary
27
+ end
28
+ ```
29
+
30
+ ### Building a feed
31
+
32
+ ```ruby
33
+ feed = Xommelier::Atom::Feed.new
34
+ feed.id = 'http://example.com/blog'
35
+ feed.title = 'Example.com blog'
36
+
37
+ entry = feed.entry = Xommelier::Atom::Entry.new(
38
+ id: 'http://example.com/blog/2012/03/05',
39
+ title: "Happy Xommelier's day!",
40
+ updated: 5.days.ago
41
+ ).tap do |entry|
42
+ entry.link = Xommelier::Atom::Link.new(
43
+ href: entry.id,
44
+ rel: 'alternate',
45
+ type: 'text/html'
46
+ )
47
+ entry.links << Xommelier::Atom::Link.new(
48
+ href: "#{entry.id}/comments.atom",
49
+ rel: 'replies',
50
+ type: 'application/atom+xml',
51
+ count: 5
52
+ )
53
+ end
54
+
55
+ # Add Comments
56
+ 3.times do |i|
57
+ feed.entries << Xommelier::Atom::Entry.new(
58
+ id: "http://example.com/blog/2012/03/05#comment_#{i}",
59
+ title: ('Hooray! ' * (i + 1)).strip,
60
+ updated: (5 - i).days.ago
61
+ ).tap do |comment|
62
+ comment.in_reply_to = Xommelier::Atom::Thread::InReplyTo.new(
63
+ ref: entry.id,
64
+ href: entry.link.href
65
+ )
66
+ end
67
+ end
68
+
69
+ puts feed.to_xml
70
+ ```
71
+
72
+ will output:
73
+
74
+ ```xml
75
+ <?xml version="1.0" encoding="utf-8"?>
76
+ <feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0">
77
+ <id>http://example.com/blog</id>
78
+ <title>Example.com blog</title>
79
+ <entry>
80
+ <id>http://example.com/blog/2012/03/05</id>
81
+ <title>Happy Xommelier's day!</title>
82
+ <updated>2012-02-29T07:52:51+04:00</updated>
83
+ <link href="http://example.com/blog/2012/03/05" rel="alternate" type="text/html"/>
84
+ <link href="http://example.com/blog/2012/03/05/comments.atom" rel="replies" type="application/atom+xml" thr:count="5"/>
85
+ </entry>
86
+ <entry>
87
+ <id>http://example.com/blog/2012/03/05#comment_0</id>
88
+ <title>Hooray!</title>
89
+ <updated>2012-02-29T07:52:51+04:00</updated>
90
+ <thr:in-reply-to ref="http://example.com/blog/2012/03/05" href="http://example.com/blog/2012/03/05"/>
91
+ </entry>
92
+ <entry>
93
+ <id>http://example.com/blog/2012/03/05#comment_1</id>
94
+ <title>Hooray! Hooray!</title>
95
+ <updated>2012-03-01T07:52:51+04:00</updated>
96
+ <thr:in-reply-to ref="http://example.com/blog/2012/03/05" href="http://example.com/blog/2012/03/05"/>
97
+ </entry>
98
+ <entry>
99
+ <id>http://example.com/blog/2012/03/05#comment_2</id>
100
+ <title>Hooray! Hooray! Hooray!</title>
101
+ <updated>2012-03-02T07:52:51+04:00</updated>
102
+ <thr:in-reply-to ref="http://example.com/blog/2012/03/05" href="http://example.com/blog/2012/03/05"/>
103
+ </entry>
104
+ </feed>
105
+ ```
14
106
 
15
107
  ## TODO
16
108
 
17
109
  * Validating built XML against RelaxNG and XML Schema
18
- * Implementation that support more than one namespace in XML class
19
110
  * Converting XML Schema, RelaxNG, RelaxNG Compact and DTD into Xommelier Ruby DSL
20
111
  * ActiveRecord-like automatic loading of XML Schema, RelaxNG, RelaxNG Compact and DTD without needing to write it down into ruby code
21
112
 
data/console CHANGED
@@ -1,7 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'bundler/setup'
3
3
  require 'xommelier'
4
+ require 'nokogiri'
4
5
  require 'ripl'
5
6
  require 'pp'
6
7
 
8
+ SPEC_ROOT = File.expand_path('..', __FILE__)
9
+
10
+ Dir[File.join(SPEC_ROOT, 'spec/support/**/*.rb')].each {|f| require f}
11
+
7
12
  Ripl.start
data/examples/atom.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  require 'xommelier/atom'
2
+ require 'xommelier/atom/thread'
2
3
  require 'active_support/core_ext'
3
4
 
4
5
  # Reading a feed
5
- feed = Xommelier::Atom::Feed.parse(open('spec/fixtures/feed.atom'))
6
+ feed = Xommelier::Atom::Feed.parse(open('spec/fixtures/feed.atom.xml'))
6
7
  puts feed.id, feed.title, feed.updated
7
8
 
8
9
  feed.entries do |entry|
@@ -15,13 +16,24 @@ feed = Xommelier::Atom::Feed.new
15
16
  feed.id = 'http://example.com/blog'
16
17
  feed.title = 'Example.com blog'
17
18
 
18
- 5.times do |i|
19
- entry = Xommelier::Atom::Entry.new
20
- entry.id = "http://example.com/blog/#{i}"
21
- entry.title = "Example.com blog entry #{i}"
22
- entry.updated = (5 - i).days.ago
19
+ entry = feed.entry = Xommelier::Atom::Entry.new(
20
+ id: 'http://example.com/blog/2012/03/05',
21
+ title: "Happy Xommelier's day!",
22
+ updated: 5.days.ago
23
+ ).tap do |entry|
24
+ entry.link = Xommelier::Atom::Link.new(href: entry.id, rel: 'alternate', type: 'text/html')
25
+ entry.links << Xommelier::Atom::Link.new(href: "#{entry.id}/comments.atom", rel: 'replies', type: 'application/atom+xml', count: 5)
26
+ end
23
27
 
24
- feed.entries << entry
28
+ # Add Comments
29
+ 5.times do |i|
30
+ feed.entries << Xommelier::Atom::Entry.new(
31
+ id: "http://example.com/blog/2012/03/05#comment_#{i}",
32
+ title: ('Hooray! ' * (i + 1)).strip,
33
+ updated: (5 - i).days.ago
34
+ ).tap do |comment|
35
+ comment.in_reply_to = Xommelier::Atom::Thread::InReplyTo.new(ref: entry.id, href: entry.link.href)
36
+ end
25
37
  end
26
38
 
27
39
  puts feed.to_xml
@@ -9,9 +9,8 @@ module Xommelier
9
9
 
10
10
  class InReplyTo < Xml::Element
11
11
  element_name 'in-reply-to'
12
- #method_name :in_reply_to
13
12
 
14
- attribute :href
13
+ attribute :ref
15
14
 
16
15
  may do
17
16
  attribute :href, type: Uri
@@ -24,7 +23,7 @@ module Xommelier
24
23
  # Extends Atom elements
25
24
  class Entry
26
25
  may do
27
- element :in_reply_to, ns: Thread.xmlns
26
+ element :in_reply_to, type: Thread::InReplyTo, as: Thread::InReplyTo.element_name
28
27
  element :total, type: Integer, ns: Thread.xmlns
29
28
  end
30
29
  end
@@ -32,6 +31,7 @@ module Xommelier
32
31
  class Link
33
32
  may do
34
33
  attribute :count, type: Integer, ns: Thread.xmlns
34
+ attribute :updated, type: Time, ns: Thread.xmlns
35
35
  end
36
36
  end
37
37
  end
@@ -1,3 +1,3 @@
1
1
  module Xommelier
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require 'xommelier/xml/element'
2
2
  require 'active_support/concern'
3
+ require 'active_support/core_ext/object/blank'
3
4
  require 'nokogiri'
4
5
 
5
6
  module Xommelier
@@ -28,7 +29,8 @@ module Xommelier
28
29
 
29
30
  def xmlns_xpath(xml_document = nil)
30
31
  if xml_document
31
- xml_document.namespaces.key(xmlns.uri)
32
+ prefix = xml_document.namespaces.key(xmlns.uri)
33
+ (prefix =~ /:/) ? prefix[6..-1] : prefix
32
34
  else
33
35
  xmlns.as
34
36
  end
@@ -62,21 +64,32 @@ module Xommelier
62
64
  if options[:builder] # Non-root element
63
65
  builder = options.delete(:builder)
64
66
  attribute_values = {}
67
+ prefix = builder.doc.namespaces.key(xmlns.uri)[6..-1].presence
65
68
  else # Root element
66
69
  builder = Nokogiri::XML::Builder.new(options)
67
- attribute_values = {xmlns: xmlns.to_s}
70
+ attribute_values = children_namespaces.inject({xmlns: xmlns.uri}) do |hash, ns|
71
+ hash["xmlns:#{ns.as}"] = ns.uri
72
+ hash
73
+ end
74
+ attribute_values.delete("xmlns:#{xmlns.as.to_s}")
75
+ prefix = nil
68
76
  end
77
+ current_xmlns = builder.doc.namespaces[prefix ? "xmlns:#{prefix}" : 'xmlns']
69
78
  attributes.each do |name, value|
79
+ if (ns = self.class.attributes[name][:ns]).uri != current_xmlns && attr_prefix = builder.doc.namespaces.key(ns.uri).try(:[], 6..-1).presence
80
+ name = "#{attr_prefix}:#{name}"
81
+ end
70
82
  serialize_attribute(name, value, attribute_values)
71
83
  end
72
- builder.send(element_name, attribute_values) do |xml|
73
- elements.each do |name, value|
74
- serialize_element(name, value, xml)
84
+ (prefix ? builder[prefix] : builder).
85
+ send(element_name, attribute_values) do |xml|
86
+ elements.each do |name, value|
87
+ serialize_element(name, value, xml)
88
+ end
89
+ if respond_to?(:text)
90
+ xml.text @text
91
+ end
75
92
  end
76
- if respond_to?(:text)
77
- xml.text @text
78
- end
79
- end
80
93
  builder.to_xml
81
94
  end
82
95
  alias_method :to_xommelier, :to_xml
@@ -87,6 +100,17 @@ module Xommelier
87
100
  self.class.element_xpath(xmldoc, name)
88
101
  end
89
102
 
103
+ def children_namespaces(namespaces = Set[xmlns])
104
+ elements.inject(namespaces) do |result, (name, children)|
105
+ element_options = self.class.elements[name]
106
+ result << element_options[:ns]
107
+ if element_options[:type] < Xml::Element
108
+ Array(children).each { |child| result += child.children_namespaces }
109
+ end
110
+ result
111
+ end
112
+ end
113
+
90
114
  def xml_document
91
115
  @_xml_node.document
92
116
  end
@@ -102,12 +126,7 @@ module Xommelier
102
126
  def deserialize_element(name, options = nil)
103
127
  options ||= self.element_options(name)
104
128
  type = options[:type]
105
- xpath = if type < Xommelier::Xml::Element
106
- type.element_xpath(xml_document, name)
107
- else
108
- element_xpath(xml_document, name)
109
- end
110
- nodes = @_xml_node.xpath("./#{xpath}")
129
+ nodes = @_xml_node.xpath("./#{options[:ns].as}:#{options[:element_name]}", options[:ns].to_hash)
111
130
  if nodes.any?
112
131
  case options[:count]
113
132
  when :any, :many
@@ -136,9 +155,9 @@ module Xommelier
136
155
  else
137
156
  case value
138
157
  when Xommelier::Xml::Element
139
- value.to_xommelier(builder: xml, element_name: name)
158
+ value.to_xommelier(builder: xml, element_name: options[:element_name])
140
159
  else
141
- xml.send(name) { xml.text value.to_xommelier }
160
+ xml.send(options[:element_name]) { xml.text value.to_xommelier }
142
161
  end
143
162
  end
144
163
  end
@@ -1,6 +1,7 @@
1
1
  require 'xommelier/xml/element'
2
2
  require 'active_support/core_ext/module/delegation'
3
3
  require 'active_support/core_ext/object/with_options'
4
+ require 'active_support/core_ext/object/try'
4
5
  require 'active_support/core_ext/string/inflections'
5
6
  require 'active_support/inflections'
6
7
 
@@ -70,15 +71,21 @@ module Xommelier
70
71
 
71
72
  # Defines containing element
72
73
  # @example
73
- # element :author, class_name: 'Xommelier::Atom::Person'
74
+ # element :author, type: Xommelier::Atom::Person
74
75
  def element(name, options = {})
75
- options[:element_name] = name
76
+ options[:element_name] = options.delete(:as) { name }
77
+ options[:ns] ||= if options[:type].try(:<, Xml::Element)
78
+ options[:ns] = options[:type].xmlns
79
+ else
80
+ xmlns
81
+ end
76
82
  elements[name] = DEFAULT_ELEMENT_OPTIONS.merge(options)
77
83
  define_element_accessors(name)
78
84
  end
79
85
 
80
86
  # Defines containing attribute
81
87
  def attribute(name, options = {})
88
+ options[:ns] ||= xmlns
82
89
  attributes[name] = DEFAULT_OPTIONS.merge(options)
83
90
  define_attribute_accessors(name)
84
91
  end
@@ -141,8 +148,6 @@ module Xommelier
141
148
  end
142
149
  end
143
150
 
144
- protected
145
-
146
151
  def define_attribute_accessors(name)
147
152
  define_method(name) do |*args|
148
153
  if args[0]
@@ -59,6 +59,10 @@ module Xommelier
59
59
  end
60
60
  end
61
61
 
62
+ def to_hash
63
+ {as.to_s => uri.to_s}
64
+ end
65
+
62
66
  def inspect
63
67
  %(xmlns:#{as}="#{uri}")
64
68
  end
@@ -1,8 +1,8 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
- <feed xmlns="http://www.w3.org/2005/Atom">
2
+ <feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0">
3
3
  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
4
4
  <title type="text">Example Feed</title>
5
- <updated>2003-12-13T18:30:02Z</updated>
5
+ <updated>2003-12-13T18:30:20Z</updated>
6
6
  <subtitle type="html">A &lt;em&gt;lot&lt;/em&gt; of effort went into making this effortless</subtitle>
7
7
  <link rel="alternate" type="text/html" href="http://example.ru/" />
8
8
  <link rel="self" type="application/atom+xml" href="http://example.ru/feed.atom" />
@@ -18,6 +18,7 @@
18
18
  <published>2003-12-13T08:29:29-04:00</published>
19
19
  <link rel="alternate" type="text/html" href="http://example.ru/2003/12/13/atom03"/>
20
20
  <link rel="enclosure" type="audio/mpeg" href="http://example.org/audio/ph34r_my_podcast.mp3" length="1337"/>
21
+ <link rel="replies" type="application/atom+xml" href="http://example.ru/2003/12/13/atom03/comments.atom" thr:count="1" thr:updated="2003-12-13T18:30:20Z" />
21
22
  <author>
22
23
  <name>Mark Pilgrim</name>
23
24
  <uri>http://example.org/</uri>
@@ -35,5 +36,13 @@
35
36
  <p><i>[Update: The Atom draft is finished.]</i></p>
36
37
  </div>
37
38
  </content>
39
+ <thr:total>1</thr:total>
40
+ </entry>
41
+ <entry>
42
+ <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6b</id>
43
+ <title type="text">First comment</title>
44
+ <updated>2003-12-13T18:30:20Z</updated>
45
+ <thr:in-reply-to ref="urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a" href="http://example.ru/2003/12/13/atom03#comment_1" type="text/html" />
46
+ <content>This is first comment.</content>
38
47
  </entry>
39
48
  </feed>
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0">
3
+ <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
4
+ <title>Example Feed</title>
5
+ <link href="http://example.org/"/>
6
+ <updated>2003-12-13T18:30:02Z</updated>
7
+ <author>
8
+ <name>John Doe</name>
9
+ </author>
10
+ <entry>
11
+ <title>Atom-Powered Robots Run Amok</title>
12
+ <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
13
+ <updated>2003-12-13T18:30:02Z</updated>
14
+ <summary>Some text.</summary>
15
+ <link href="http://example.org/2003/12/13/atom03"/>
16
+ <link href="http://example.org/2003/12/13/atom03.atom" rel="replies" thr:count="1"/>
17
+ </entry>
18
+ <entry>
19
+ <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6b</id>
20
+ <title>Comment</title>
21
+ <updated>2003-12-13T18:30:02Z</updated>
22
+ <thr:in-reply-to ref="urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a"/>
23
+ </entry>
24
+ </feed>
@@ -1,6 +1,7 @@
1
1
  # coding: utf-8
2
2
  require 'spec_helper'
3
3
  require 'active_support/core_ext/numeric/time'
4
+ require 'xommelier/atom/thread'
4
5
 
5
6
  describe 'Atom feed' do
6
7
  describe 'parsing' do
@@ -13,7 +14,7 @@ describe 'Atom feed' do
13
14
 
14
15
  its(:id) { should == 'urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6' }
15
16
  its(:title) { should == 'Example Feed' }
16
- its(:updated) { should == Time.utc(2003, 12, 13, 18, 30, 02) }
17
+ its(:updated) { should == Time.utc(2003, 12, 13, 18, 30, 20) }
17
18
  its(:subtitle) { should == 'A <em>lot</em> of effort went into making this effortless' }
18
19
 
19
20
  it { should have(2).links }
@@ -40,9 +41,9 @@ describe 'Atom feed' do
40
41
  its(:author) { should be_instance_of(Xommelier::Atom::Person) }
41
42
  it { feed.author.name.should == 'John Doe' }
42
43
 
43
- it { feed.should have(1).entries }
44
+ it { feed.should have(2).entries }
44
45
  describe 'Entry' do
45
- let(:entry) { feed.entry }
46
+ let(:entry) { feed.entries[0] }
46
47
  subject { entry }
47
48
 
48
49
  its(:id) { should == 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a' }
@@ -50,7 +51,7 @@ describe 'Atom feed' do
50
51
  its(:updated) { should == Time.utc(2003, 12, 13, 18, 30, 02) }
51
52
  its(:published) { should == Time.utc(2003, 12, 13, 8, 29, 29) + 4.hours }
52
53
 
53
- it { should have(2).links }
54
+ it { should have(3).links }
54
55
  its(:link) { should be_instance_of(Xommelier::Atom::Link) }
55
56
  it { entry.links[0].href.should == URI.parse('http://example.ru/2003/12/13/atom03') }
56
57
  it { entry.links[0].rel.should == 'alternate' }
@@ -59,6 +60,11 @@ describe 'Atom feed' do
59
60
  it { entry.links[1].rel.should == 'enclosure' }
60
61
  it { entry.links[1].type.should == 'audio/mpeg' }
61
62
  it { entry.links[1].length.should == 1337 }
63
+ it { entry.links[2].href.should == URI.parse('http://example.ru/2003/12/13/atom03/comments.atom') }
64
+ it { entry.links[2].rel.should == 'replies' }
65
+ it { entry.links[2].type.should == 'application/atom+xml' }
66
+ it { entry.links[2].count.should == 1 }
67
+ it { entry.links[2].updated.should == Time.utc(2003, 12, 13, 18, 30, 20) }
62
68
 
63
69
  it { should have(1).authors }
64
70
 
@@ -79,7 +85,24 @@ describe 'Atom feed' do
79
85
  its(:type) { should == 'xhtml' }
80
86
  its(:lang) { should == 'en' }
81
87
  its(:base) { should == 'http://diveintomark.org/' }
82
- its(:content) { should ~ /#{Regexp.escape('<p><i>[Update: The Atom draft is fiished.]</i></p>')}/ }
88
+ its(:content) { should ~ Regexp.new(Regexp.escape('<p><i>[Update: The Atom draft is fiished.]</i></p>')) }
89
+ end
90
+ its(:total) { should == 1 }
91
+
92
+ describe 'Comment' do
93
+ let(:comment) { feed.entries[1] }
94
+ subject { comment }
95
+
96
+ its(:id) { should == 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6b' }
97
+ its(:title) { should == 'First comment' }
98
+ its(:updated) { should == Time.utc(2003, 12, 13, 18, 30, 20) }
99
+
100
+ describe 'in-reply-to' do
101
+ subject { comment.in_reply_to }
102
+ its(:ref) { should == 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a' }
103
+ its(:href) { should == URI.parse('http://example.ru/2003/12/13/atom03#comment_1') }
104
+ its(:type) { should == 'text/html' }
105
+ end
83
106
  end
84
107
  end
85
108
  end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'xommelier/atom/thread'
3
+
4
+ describe 'Atom feed building' do
5
+ let(:feed) do
6
+ Xommelier::Atom::Feed.new.tap do |feed|
7
+ feed.id = 'urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6'
8
+ feed.title = 'Example Feed'
9
+ feed.link = Xommelier::Atom::Link.new(href: 'http://example.org/')
10
+ feed.updated = Time.utc(2003, 12, 13, 18, 30, 02)
11
+ feed.author = Xommelier::Atom::Person.new(name: 'John Doe')
12
+ feed.entry = Xommelier::Atom::Entry.new(
13
+ title: 'Atom-Powered Robots Run Amok',
14
+ id: 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a',
15
+ updated: Time.utc(2003, 12, 13, 18, 30, 02),
16
+ summary: 'Some text.',
17
+ ).tap do |entry|
18
+ entry.link = Xommelier::Atom::Link.new(href: 'http://example.org/2003/12/13/atom03')
19
+ entry.links << Xommelier::Atom::Link.new(href: 'http://example.org/2003/12/13/atom03.atom', rel: 'replies', count: 1)
20
+ end
21
+ feed.entries << Xommelier::Atom::Entry.new(
22
+ id: 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6b',
23
+ title: 'Comment',
24
+ updated: Time.utc(2003, 12, 13, 18, 30, 02)
25
+ ).tap do |entry|
26
+ entry.in_reply_to = Xommelier::Atom::Thread::InReplyTo.new(ref: 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a')
27
+ end
28
+ end
29
+ end
30
+
31
+ let(:built_xml) { feed.to_xml }
32
+ let(:parsed_xml) { Nokogiri::XML(built_xml) }
33
+ let(:rng) { Nokogiri::XML::RelaxNG(load_xml_file('atom.rng')) }
34
+ let(:xsd) { Nokogiri::XML::Schema(load_xml_file('atom.xsd')) }
35
+
36
+ subject { built_xml }
37
+
38
+ it { should == load_xml_file('multi_namespace_feed.atom').read }
39
+ it('should conform to RelaxNG schema') { rng.valid?(parsed_xml).should == true }
40
+ end
@@ -6,21 +6,4 @@ describe Xommelier::Xml::Element::Serialization do
6
6
 
7
7
  it { should respond_to(:parse) }
8
8
  end
9
-
10
- describe 'parsing simple_feed' do
11
- let(:feed) { @feed = Xommelier::Atom::Feed.parse(load_xml_file('simple_feed.atom')) }
12
-
13
- it { feed.id.should == 'urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6' }
14
- it { feed.title.should == 'Example Feed' }
15
- it { feed.link.href.should == URI.parse('http://example.org/') }
16
- it { feed.updated.should == Time.utc(2003, 12, 13, 18, 30, 02) }
17
- it { feed.should have(1).authors }
18
- it { feed.author.name.should == 'John Doe' }
19
- it { feed.should have(1).entries }
20
- it { feed.entry.title.should == 'Atom-Powered Robots Run Amok' }
21
- it { feed.entry.link.href.should == URI.parse('http://example.org/2003/12/13/atom03') }
22
- it { feed.entry.id.should == 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a' }
23
- it { feed.entry.updated.should == Time.utc(2003, 12, 13, 18, 30, 02) }
24
- it { feed.entry.summary.should == 'Some text.' }
25
- end
26
9
  end
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Xommelier do
4
- it { Xommelier::VERSION.should == '0.1.1' }
4
+ it { Xommelier::VERSION.should == '0.1.2' }
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xommelier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-03-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
16
- requirement: &70096232577880 !ruby/object:Gem::Requirement
16
+ requirement: &70220266503160 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.5.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70096232577880
24
+ version_requirements: *70220266503160
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: activesupport
27
- requirement: &70096232577380 !ruby/object:Gem::Requirement
27
+ requirement: &70220266502660 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 3.2.0
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70096232577380
35
+ version_requirements: *70220266502660
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: activemodel
38
- requirement: &70096232576920 !ruby/object:Gem::Requirement
38
+ requirement: &70220266502200 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: 3.2.0
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70096232576920
46
+ version_requirements: *70220266502200
47
47
  description: XML-Object Mapper with many built-in XML formats supported
48
48
  email:
49
49
  - al@semyonov.us
@@ -93,9 +93,11 @@ files:
93
93
  - spec/fixtures/atom.rng.xml
94
94
  - spec/fixtures/atom.xsd.xml
95
95
  - spec/fixtures/feed.atom.xml
96
+ - spec/fixtures/multi_namespace_feed.atom.xml
96
97
  - spec/fixtures/simple_feed.atom.xml
97
98
  - spec/functional/atom_feed_building_spec.rb
98
99
  - spec/functional/atom_feed_parsing_spec.rb
100
+ - spec/functional/atom_feed_thread_building_spec.rb
99
101
  - spec/lib/xommelier/atom/entry_spec.rb
100
102
  - spec/lib/xommelier/xml/element/serialization_spec.rb
101
103
  - spec/lib/xommelier/xml/element/structure_spec.rb
@@ -134,9 +136,11 @@ test_files:
134
136
  - spec/fixtures/atom.rng.xml
135
137
  - spec/fixtures/atom.xsd.xml
136
138
  - spec/fixtures/feed.atom.xml
139
+ - spec/fixtures/multi_namespace_feed.atom.xml
137
140
  - spec/fixtures/simple_feed.atom.xml
138
141
  - spec/functional/atom_feed_building_spec.rb
139
142
  - spec/functional/atom_feed_parsing_spec.rb
143
+ - spec/functional/atom_feed_thread_building_spec.rb
140
144
  - spec/lib/xommelier/atom/entry_spec.rb
141
145
  - spec/lib/xommelier/xml/element/serialization_spec.rb
142
146
  - spec/lib/xommelier/xml/element/structure_spec.rb