atom 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/atom.rb +171 -0
  2. data/lib/xmlmapping.rb +156 -0
  3. metadata +46 -0
@@ -0,0 +1,171 @@
1
+ #
2
+ # Copyright (c) 2006 Martin Traverso
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ require 'xmlmapping'
25
+ require 'time'
26
+
27
+ module Atom
28
+ NAMESPACE = 'http://www.w3.org/2005/Atom'
29
+
30
+ class Person
31
+ include XMLMapping
32
+
33
+ namespace NAMESPACE
34
+
35
+ has_one :name
36
+ has_one :email
37
+ has_one :uri
38
+
39
+ def to_s
40
+ name
41
+ end
42
+ end
43
+
44
+ class Generator
45
+ include XMLMapping
46
+
47
+ namespace NAMESPACE
48
+
49
+ has_attribute :uri
50
+ has_attribute :version
51
+ text :value
52
+
53
+ def to_s
54
+ value
55
+ end
56
+ end
57
+
58
+ class Link
59
+ include XMLMapping
60
+
61
+ namespace NAMESPACE
62
+
63
+ has_attribute :href
64
+ has_attribute :rel
65
+ has_attribute :type
66
+ has_attribute :hreflang
67
+ has_attribute :title
68
+ has_attribute :length
69
+
70
+ def to_s
71
+ href
72
+ end
73
+ end
74
+
75
+ class Category
76
+ include XMLMapping
77
+
78
+ namespace NAMESPACE
79
+
80
+ has_attribute :term
81
+ has_attribute :scheme
82
+ has_attribute :label
83
+
84
+ def to_s
85
+ term
86
+ end
87
+ end
88
+
89
+ class Content
90
+ include XMLMapping
91
+
92
+ namespace NAMESPACE
93
+
94
+ has_attribute :type
95
+ has_attribute :src
96
+ text :value
97
+
98
+ def to_s
99
+ value || src
100
+ end
101
+ end
102
+
103
+ class Source
104
+ include XMLMapping
105
+
106
+ namespace NAMESPACE
107
+
108
+ has_many :authors, :name => 'author', :type => Person
109
+ has_many :categories, :name => 'category', :type => Category
110
+ has_one :generator, :type => Generator
111
+ has_one :icon
112
+ has_many :links, :name => 'link', :type => Link
113
+ has_one :logo
114
+ has_one :rights
115
+ has_one :subtitle
116
+ has_one :title
117
+ has_one :updated, :transform => lambda { |t| Time.iso8601(t) }
118
+ end
119
+
120
+ class Entry
121
+ include XMLMapping
122
+
123
+ namespace NAMESPACE
124
+
125
+ has_one :id
126
+ has_one :title
127
+ has_one :summary
128
+ has_many :authors, :name => 'author', :type => Person
129
+ has_many :contributors, :name => 'contributor', :type => Person
130
+ has_one :published, :transform => lambda { |t| Time.iso8601(t) }
131
+ has_one :updated, :transform => lambda { |t| Time.iso8601(t) }
132
+ has_many :links, :name => 'link', :type => Link
133
+ has_many :category, :name => 'category', :type => Category
134
+ has_one :content, :type => Content
135
+ has_one :source, :type => Source
136
+ end
137
+
138
+ class Feed
139
+ include XMLMapping
140
+
141
+ namespace NAMESPACE
142
+
143
+ has_one :id
144
+ has_one :title
145
+ has_one :subtitle
146
+ has_many :authors, :name => 'author', :type => Person
147
+ has_many :contributors, :name => 'contributor', :type => Person
148
+ has_many :entries, :name => 'entry', :type => Entry
149
+ has_one :generator, :type => Generator
150
+ has_many :links, :name => 'link', :type => Link
151
+ has_one :updated, :transform => lambda { |t| Time.iso8601(t) }
152
+
153
+ has_one :rights
154
+ has_one :icon
155
+ has_one :logo
156
+ has_many :categories, :name => 'category', :type => Category
157
+ end
158
+ end
159
+
160
+
161
+ if $0 == __FILE__
162
+ require 'net/http'
163
+ require 'uri'
164
+
165
+ str = Net::HTTP::get(URI::parse('http://blog.ning.com/atom.xml'))
166
+ feed = Atom::Feed.new(str)
167
+
168
+ feed.entries.each { |entry|
169
+ puts "'#{entry.title}' by #{entry.authors[0].name} on #{entry.published.strftime('%m/%d/%Y')}"
170
+ }
171
+ end
@@ -0,0 +1,156 @@
1
+ #
2
+ # Copyright (c) 2006 Martin Traverso
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ require 'rexml/document'
25
+
26
+ module XMLMapping
27
+ def self.included(mod)
28
+ mod.extend(ClassMethods)
29
+ mod.instance_variable_set("@attributes", {})
30
+ mod.instance_variable_set("@elements", {})
31
+ mod.instance_variable_set("@text_attribute", nil)
32
+ end
33
+
34
+ def initialize(input)
35
+ if input.respond_to? :to_str
36
+ root = REXML::Document.new(input).root
37
+ elsif input.respond_to?(:node_type) && input.node_type == :document
38
+ root = input.root
39
+ elsif input.respond_to?(:node_type) && input.node_type == :element
40
+ root = input
41
+ else
42
+ raise "Invalid input: #{input}"
43
+ end
44
+
45
+ namespace = self.class.default_namespace
46
+ attributes = self.class.attributes
47
+ elements = self.class.elements
48
+ text_attribute = self.class.text_attribute
49
+
50
+ if !text_attribute.nil?
51
+ name = text_attribute[0]
52
+ options = text_attribute[1]
53
+ value = root.text
54
+
55
+ if options.has_key? :transform
56
+ value = options[:transform].call(value)
57
+ end
58
+
59
+ instance_variable_set("@#{name}", value)
60
+ else
61
+ # initialize :many attributes
62
+ elements.select { |k, v|
63
+ v[:cardinality] == :many
64
+ }.each { |k, v|
65
+ instance_variable_set("@#{v[:attribute]}", [])
66
+ }
67
+
68
+ root.each_element { |e|
69
+ if e.namespace == namespace && elements.has_key?(e.name.to_sym)
70
+ options = elements[e.name.to_sym]
71
+
72
+ if options.has_key? :type
73
+ value = options[:type].new(e)
74
+ else
75
+ value = e.text
76
+ end
77
+
78
+ if options.has_key? :transform
79
+ value = options[:transform].call(value)
80
+ end
81
+
82
+ attribute = options[:attribute]
83
+
84
+ existing = instance_variable_get("@#{attribute}")
85
+ case options[:cardinality]
86
+ when :one
87
+ raise "Found more than one #{e.name}" if !existing.nil?
88
+ instance_variable_set("@#{attribute}", value)
89
+ when :many
90
+ existing << value
91
+ end
92
+ end
93
+ }
94
+ end
95
+
96
+ root.attributes.each_attribute { |a|
97
+ if a.namespace == namespace && attributes.has_key?(a.name.to_sym)
98
+ options = attributes[a.name.to_sym]
99
+
100
+ value = a.value
101
+ if options.has_key? :transform
102
+ value = options[:transform].call(value)
103
+ end
104
+
105
+ instance_variable_set("@#{a.name}", value)
106
+ end
107
+ }
108
+ end
109
+
110
+ module ClassMethods
111
+ attr :attributes
112
+ attr :elements
113
+ attr :text_attribute
114
+ attr :default_namespace
115
+
116
+ def namespace(namespace)
117
+ @default_namespace = namespace
118
+ end
119
+
120
+ def has_one(attribute, options = {})
121
+ attr attribute
122
+ options[:cardinality] = :one
123
+ options[:attribute] = attribute
124
+
125
+ name = attribute
126
+ if options.has_key? :name
127
+ name = options[:name].to_sym
128
+ end
129
+
130
+ @elements[name] = options
131
+ end
132
+
133
+ def has_many(attribute, options = {})
134
+ attr attribute
135
+ options[:cardinality] = :many
136
+ options[:attribute] = attribute
137
+
138
+ name = attribute
139
+ if options.has_key? :name
140
+ name = options[:name].to_sym
141
+ end
142
+
143
+ @elements[name] = options
144
+ end
145
+
146
+ def has_attribute(attribute, options = {})
147
+ attr attribute
148
+ @attributes[attribute] = options
149
+ end
150
+
151
+ def text(attribute, options = {})
152
+ attr attribute
153
+ @text_attribute = [attribute, options]
154
+ end
155
+ end
156
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: atom
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.1"
7
+ date: 2006-04-06 00:00:00 -07:00
8
+ summary: Ruby library for working with the Atom syndication format
9
+ require_paths:
10
+ - lib
11
+ email: mtraverso@acm.org
12
+ homepage: http://http://rubyforge.org/projects/atom/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - Martin Traverso
30
+ files:
31
+ - lib/atom.rb
32
+ - lib/xmlmapping.rb
33
+ test_files: []
34
+
35
+ rdoc_options: []
36
+
37
+ extra_rdoc_files: []
38
+
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ requirements: []
44
+
45
+ dependencies: []
46
+