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 +2 -1
- data/README.md +95 -4
- data/console +5 -0
- data/examples/atom.rb +19 -7
- data/lib/xommelier/atom/thread.rb +3 -3
- data/lib/xommelier/version.rb +1 -1
- data/lib/xommelier/xml/element/serialization.rb +36 -17
- data/lib/xommelier/xml/element/structure.rb +9 -4
- data/lib/xommelier/xml/namespace.rb +4 -0
- data/spec/fixtures/feed.atom.xml +11 -2
- data/spec/fixtures/multi_namespace_feed.atom.xml +24 -0
- data/spec/functional/atom_feed_parsing_spec.rb +28 -5
- data/spec/functional/atom_feed_thread_building_spec.rb +40 -0
- data/spec/lib/xommelier/xml/element/serialization_spec.rb +0 -17
- data/spec/lib/xommelier_spec.rb +1 -1
- metadata +11 -7
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') {
|
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
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
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 :
|
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,
|
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
|
data/lib/xommelier/version.rb
CHANGED
@@ -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.
|
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
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
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:
|
158
|
+
value.to_xommelier(builder: xml, element_name: options[:element_name])
|
140
159
|
else
|
141
|
-
xml.send(
|
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,
|
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]
|
data/spec/fixtures/feed.atom.xml
CHANGED
@@ -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:
|
5
|
+
<updated>2003-12-13T18:30:20Z</updated>
|
6
6
|
<subtitle type="html">A <em>lot</em> 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,
|
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(
|
44
|
+
it { feed.should have(2).entries }
|
44
45
|
describe 'Entry' do
|
45
|
-
let(:entry) { feed.
|
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(
|
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 ~
|
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
|
data/spec/lib/xommelier_spec.rb
CHANGED
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.
|
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: &
|
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: *
|
24
|
+
version_requirements: *70220266503160
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activesupport
|
27
|
-
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: *
|
35
|
+
version_requirements: *70220266502660
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: activemodel
|
38
|
-
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: *
|
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
|