ratom 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ == 0.5.0 2008-07-28
2
+
3
+ * Fix bug where processing instructions break parsing.
4
+ * Added Custom extension element classes. (Ignacio Carrera)
5
+
1
6
  == 0.4.2 2008-07-09
2
7
 
3
8
  * Update to libxml-ruby version 0.8.x
data/Manifest.txt CHANGED
@@ -36,6 +36,7 @@ spec/fixtures/created_entry.atom
36
36
  spec/fixtures/entry.atom
37
37
  spec/fixtures/multiple_entry.atom
38
38
  spec/fixtures/simple_single_entry.atom
39
+ spec/fixtures/with_stylesheet.atom
39
40
  spec/paging/first_paged_feed.atom
40
41
  spec/paging/last_paged_feed.atom
41
42
  spec/paging/middle_paged_feed.atom
data/README.txt CHANGED
@@ -181,6 +181,50 @@ You can then call to_xml and rAtom will serialize the extension elements into xm
181
181
  Notice that the output repeats the xmlns attribute for each of the extensions, this is semantically the same the input XML, just a bit
182
182
  ugly. It seems to be a limitation of the libxml-Ruby API. But if anyone knows a work around I'd gladly accept a patch (or even advice).
183
183
 
184
+ ==== Custom Extension Classes
185
+
186
+ As of version 0.5.0 you can also define your own classes for a extension elements. This is done by first creating an alias
187
+ for the namespace for the class and then using the +element+ method on the Atom::Feed or Atom::Entry class to tell rAtom
188
+ to use your custom class when it encounters the extension element.
189
+
190
+ For example, say we have the following piece Atom XML with a structured extension element:
191
+
192
+ <?xml version='1.0' encoding='UTF-8'?>
193
+ <entry xmlns='http://www.w3.org/2005/Atom' xmlns:custom='http://custom.namespace'>
194
+ <id>https://custom.namespace/id/1</id>
195
+ <link rel='self' type='application/atom+xml' href='https://custom.namespace/id/1'/>
196
+ <custom:property name='foo' value='bar'/>
197
+ <custom:property name='baz' value='bat'/>
198
+ </entry>
199
+
200
+ And we want the +custom:property+ elements to be parsed as our own custom class called Custom::Property that is
201
+ defined like this:
202
+
203
+ class Custom::Property
204
+ attr_accessor :name, :value
205
+ def initialize(xml)
206
+ # Custom XML handling
207
+ end
208
+ end
209
+
210
+ We can tell rAtom about our custom namespace and custom class using the following method calls:
211
+
212
+ Atom::Feed..add_extension_namespace :custom, "http://custom.namespace"
213
+ Atom::Entry.elements "custom:property", :class => Custom::Property
214
+
215
+ The first method call registers an alias for the "http://custom.namespace" namespace and the second method call
216
+ tell rAtom that when it encounters a custom:property element within a Feed it should create an instance of Custom::Property
217
+ and pass the XML Reader to the constructor of the instance. It is then up to the constructor to populate the objects attributes
218
+ from the XML.
219
+
220
+ The custom property will then be available as a method on the rAtom class. In the above example:
221
+
222
+ @feed.custom_property.size == 2
223
+ @feed.custom_property.first.name == 'foo'
224
+ @feed.custom_property.first.value == 'bar'
225
+
226
+ (Thanks to nachokb for this feature!!)
227
+
184
228
  === Basic Authentication
185
229
 
186
230
  All methods that involve HTTP requests now support HTTP Basic Authentication. Authentication credentials are passed
data/lib/atom/version.rb CHANGED
@@ -7,8 +7,8 @@
7
7
  module Atom #:nodoc:
8
8
  module VERSION #:nodoc:
9
9
  MAJOR = 0
10
- MINOR = 4
11
- TINY = 2
10
+ MINOR = 5
11
+ TINY = 0
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY].join('.')
14
14
  end
@@ -77,7 +77,7 @@ module Atom
77
77
  loop do
78
78
  case xml.node_type
79
79
  when XML::Reader::TYPE_ELEMENT
80
- if element_specs.include?(xml.local_name) && [Atom::NAMESPACE, Atom::Pub::NAMESPACE].include?(xml.namespace_uri)
80
+ if element_specs.include?(xml.local_name) && (self.class.known_namespaces + [Atom::NAMESPACE, Atom::Pub::NAMESPACE]).include?(xml.namespace_uri)
81
81
  element_specs[xml.local_name].parse(self, xml)
82
82
  elsif attributes.any?
83
83
  while (xml.move_to_next_attribute == 1)
@@ -98,7 +98,9 @@ module Atom
98
98
  end
99
99
 
100
100
  def next_node_is?(xml, element, ns = nil)
101
- xml.next == 1 && current_node_is?(xml, element, ns)
101
+ # Get to the next element
102
+ while xml.next == 1 && xml.node_type != XML::Reader::TYPE_ELEMENT; end
103
+ current_node_is?(xml, element, ns)
102
104
  end
103
105
 
104
106
  def current_node_is?(xml, element, ns = nil)
@@ -114,6 +116,9 @@ module Atom
114
116
  def ordered_element_specs; self.class.ordered_element_specs; end
115
117
  def attributes; self.class.attributes; end
116
118
  def o.namespace(ns = @namespace); @namespace = ns; end
119
+ def o.add_extension_namespace(ns, url); self.extensions_namespaces[ns.to_s] = url; end
120
+ def o.extensions_namespaces; @extensions_namespaces ||= {} end
121
+ def o.known_namespaces; @known_namespaces ||= [] end
117
122
  end
118
123
  o.send(:extend, DeclarationMethods)
119
124
  end
@@ -138,6 +143,9 @@ module Atom
138
143
  namespace_map = NamespaceMap.new(self.class.namespace) if namespace_map.nil?
139
144
  node = XML::Node.new(root_name)
140
145
  node['xmlns'] = self.class.namespace unless nodeonly || !self.class.respond_to?(:namespace)
146
+ self.class.extensions_namespaces.each do |ns_alias,uri|
147
+ node["xmlns:#{ns_alias}"] = uri
148
+ end
141
149
 
142
150
  self.class.ordered_element_specs.each do |spec|
143
151
  if spec.single?
@@ -210,8 +218,10 @@ module Atom
210
218
  options.merge!(names.pop) if names.last.is_a?(Hash)
211
219
 
212
220
  names.each do |name|
213
- attr_accessor name
214
- self.ordered_element_specs << self.element_specs[name.to_s] = ParseSpec.new(name, options)
221
+ attr_accessor name.to_s.sub(/:/, '_').to_sym
222
+ ns, local_name = name.to_s[/(.*):(.*)/,1], $2 || name
223
+ self.known_namespaces << self.extensions_namespaces[ns] if ns
224
+ self.ordered_element_specs << self.element_specs[local_name.to_s] = ParseSpec.new(name, options)
215
225
  end
216
226
  end
217
227
 
@@ -220,8 +230,16 @@ module Atom
220
230
  options.merge!(names.pop) if names.last.is_a?(Hash)
221
231
 
222
232
  names.each do |name|
223
- attr_accessor name
224
- self.ordered_element_specs << self.element_specs[name.to_s.singularize] = ParseSpec.new(name, options)
233
+ name_sym = name.to_s.sub(/:/, '_').to_sym
234
+ attr_writer name_sym
235
+ define_method name_sym do
236
+ ivar = :"@#{name_sym}"
237
+ self.instance_variable_set ivar, [] unless self.instance_variable_defined? ivar
238
+ self.instance_variable_get ivar
239
+ end
240
+ ns, local_name = name.to_s[/(.*):(.*)/,1], $2 || name
241
+ self.known_namespaces << self.extensions_namespaces[ns] if ns
242
+ self.ordered_element_specs << self.element_specs[local_name.to_s.singularize] = ParseSpec.new(name, options)
225
243
  end
226
244
  end
227
245
 
@@ -314,7 +332,9 @@ module Atom
314
332
  when :single
315
333
  target.send("#{@attribute}=".to_sym, build(target, xml))
316
334
  when :collection
317
- target.send("#{@attribute}") << build(target, xml)
335
+ collection = target.send(@attribute.to_s)
336
+ element = build(target, xml)
337
+ collection << element
318
338
  end
319
339
  end
320
340
 
data/spec/atom_spec.rb CHANGED
@@ -8,6 +8,7 @@
8
8
  require File.dirname(__FILE__) + '/spec_helper.rb'
9
9
  require 'net/http'
10
10
  require 'time'
11
+ require 'spec/property'
11
12
 
12
13
  shared_examples_for 'simple_single_entry.atom attributes' do
13
14
  it "should parse title" do
@@ -183,6 +184,12 @@ describe Atom do
183
184
  it_should_behave_like "simple_single_entry.atom attributes"
184
185
  end
185
186
 
187
+ describe 'FeedWithStyleSheet' do
188
+ it "should load without failure" do
189
+ lambda { feed = Atom::Feed.load_feed(File.open('spec/fixtures/with_stylesheet.atom')) }.should_not raise_error
190
+ end
191
+ end
192
+
186
193
  describe 'ComplexFeed' do
187
194
  before(:all) do
188
195
  @feed = Atom::Feed.load_feed(File.open('spec/fixtures/complex_single_entry.atom'))
@@ -1045,6 +1052,43 @@ describe Atom do
1045
1052
  end
1046
1053
  end
1047
1054
 
1055
+ describe 'custom_extensions' do
1056
+ before(:all) do
1057
+ Atom::Entry.add_extension_namespace :ns_alias, "http://custom.namespace"
1058
+ Atom::Entry.elements "ns_alias:property", :class => Atom::Extensions::Property
1059
+ @entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry_with_custom_extensions.atom'))
1060
+ end
1061
+
1062
+ it "should_load_custom_extensions_for_entry" do
1063
+ @entry.ns_alias_property.should_not == []
1064
+ end
1065
+
1066
+ it "should_load_2_custom_extensions_for_entry" do
1067
+ @entry.ns_alias_property.size.should == 2
1068
+ end
1069
+
1070
+ it "should load correct_data_for_custom_extensions_for_entry" do
1071
+ @entry.ns_alias_property.map { |x| [x.name, x.value] }.should == [['foo', 'bar'], ['baz', 'bat']]
1072
+ end
1073
+ end
1074
+
1075
+ describe 'single custom_extensions' do
1076
+ before(:all) do
1077
+ Atom::Entry.add_extension_namespace :custom, "http://custom.namespace"
1078
+ Atom::Entry.element "custom:property", :class => Atom::Extensions::Property
1079
+ @entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry_with_single_custom_extension.atom'))
1080
+ end
1081
+
1082
+ it "should load single custom extensions for entry" do
1083
+ @entry.custom_property.should_not be_nil
1084
+ end
1085
+
1086
+ it "should load correct data for custom extensions for entry" do
1087
+ @entry.custom_property.name.should == 'foo'
1088
+ @entry.custom_property.value.should == 'bar'
1089
+ end
1090
+ end
1091
+
1048
1092
  describe Atom::Link do
1049
1093
  before(:each) do
1050
1094
  @href = 'http://example.org/next'
@@ -0,0 +1,8 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+ <?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?>
3
+ <feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'>
4
+ <id>tag:blogger.com,1999:blog-3343849602113720282</id>
5
+ <updated>2008-07-26T09:01:19.322+01:00</updated>
6
+ <title type='text'>Blockstack.tv</title>
7
+ <link rel='alternate' type='text/html' href='http://blockstack.blogspot.com/'/>
8
+ </feed>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ratom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peerworks
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2008-07-23 00:00:00 +09:30
13
+ date: 2008-07-28 00:00:00 +09:30
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -84,6 +84,7 @@ files:
84
84
  - spec/fixtures/entry.atom
85
85
  - spec/fixtures/multiple_entry.atom
86
86
  - spec/fixtures/simple_single_entry.atom
87
+ - spec/fixtures/with_stylesheet.atom
87
88
  - spec/paging/first_paged_feed.atom
88
89
  - spec/paging/last_paged_feed.atom
89
90
  - spec/paging/middle_paged_feed.atom