Skip to content

Commit

Permalink
Extract atomizer gem
Browse files Browse the repository at this point in the history
  • Loading branch information
mutle committed Mar 1, 2011
1 parent 0fa9db7 commit ed0252d
Show file tree
Hide file tree
Showing 24 changed files with 594 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Gemfile
@@ -1,4 +1,6 @@
source "http://rubygems.org"

gem "rake"

# Specify your gem's dependencies in atomizer.gemspec
gemspec
20 changes: 20 additions & 0 deletions LICENSE
@@ -0,0 +1,20 @@
Copyright (c) 2011 Mutwin Kraus

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.
18 changes: 18 additions & 0 deletions README.md
@@ -0,0 +1,18 @@
Atomizer
--------

Atomizer is a Ruby library for parsing and generating Atom feeds.


Installation
============

$ gem install atomizer


Copyright
=========

Copyright (c) 2011 Mutwin Kraus

Atomizer is licensed under the [MIT License](https://github.com/mutle/atomizer/blob/master/LICENSE).
9 changes: 9 additions & 0 deletions Rakefile
@@ -1,2 +1,11 @@
require 'bundler'
Bundler::GemHelper.install_tasks

require 'rake/testtask'

namespace :test do
Rake::TestTask.new(:units) do |t|
t.libs << "test"
t.pattern = 'test/unit/**/*_test.rb'
end
end
17 changes: 17 additions & 0 deletions lib/atomizer.rb
@@ -1,2 +1,19 @@
require 'nokogiri'

module Atomizer
autoload :Author, 'atomizer/author'
autoload :Builder, 'atomizer/builder'
autoload :Buildable,'atomizer/buildable'
autoload :Collection,'atomizer/collection'
autoload :Content,'atomizer/content'
autoload :Contributor,'atomizer/contributor'
autoload :Entry,'atomizer/entry'
autoload :Feed,'atomizer/feed'
autoload :Generator,'atomizer/generator'
autoload :FeedItem, 'atomizer/feed_item'
autoload :Link,'atomizer/link'
autoload :Service,'atomizer/service'
autoload :Text,'atomizer/text'
autoload :Time,'atomizer/time'
autoload :Workspace,'atomizer/workspace'
end
7 changes: 7 additions & 0 deletions lib/atomizer/author.rb
@@ -0,0 +1,7 @@
module Atomizer
class Author < FeedItem
feed_tag_name "author"
feed_attributes :name, :uri, :email
feed_no_collection_group_tag!
end
end
9 changes: 9 additions & 0 deletions lib/atomizer/buildable.rb
@@ -0,0 +1,9 @@
module Atomizer
module Buildable
def to_atom
builder = Builder.new
builder.to_atom(self)
end
end
end

10 changes: 10 additions & 0 deletions lib/atomizer/builder.rb
@@ -0,0 +1,10 @@
module Atomizer
class Builder
def to_atom(object)
builder = Nokogiri::XML::Builder.new do |xml|
object.to_xml(xml)
end
builder.to_xml
end
end
end
19 changes: 19 additions & 0 deletions lib/atomizer/collection.rb
@@ -0,0 +1,19 @@
module Atomizer
class Collection < FeedItem
feed_attributes :href, :title, :accepts, :categories

def initialize
@accepts = []
@categories = []
end

def to_xml(xml)
xml.collection :href => href do
xml['atom'].title title if title
accepts.each do |accept|
xml.accept accept
end
end
end
end
end
10 changes: 10 additions & 0 deletions lib/atomizer/content.rb
@@ -0,0 +1,10 @@
module Atomizer
class Content < FeedItem
feed_tag_name "content"
feed_attributes :body, :type, :xml_lang, :xml_base

def to_xml(xml)
xml.content(@body, :type => type, "xml:lang" => @xml_lang, "xml:base" => @xml_base)
end
end
end
8 changes: 8 additions & 0 deletions lib/atomizer/contributor.rb
@@ -0,0 +1,8 @@
module Atomizer
class Contributor < Author
feed_tag_name "contributor"
feed_attributes :name, :uri, :email
feed_no_collection_group_tag!
end
end

13 changes: 13 additions & 0 deletions lib/atomizer/entry.rb
@@ -0,0 +1,13 @@
module Atomizer
class Entry < FeedItem
feed_tag_name "entry"
feed_attributes :id, :title, :links, :updated, :published, :authors, :contributors, :content
feed_no_collection_group_tag!

def initialize(*attrs)
super(*attrs)
@content_type ||= "html"
@links ||= []
end
end
end
97 changes: 97 additions & 0 deletions lib/atomizer/feed.rb
@@ -0,0 +1,97 @@
module Atomizer
class Feed < FeedItem

feed_attributes :id, :title, :subtitle, :updated, :published, :links, :rights, :generator, :generator_uri, :generator_version, :entries, :authors, :contributors

class << self
def parse(xml)
doc = Nokogiri::XML(xml)
feed = new
feed.id = text(doc, "feed>id")
feed.title = text(doc, "feed>title")
feed.subtitle = text(doc, "feed>subtitle")
feed.updated = parse_time text(doc, "feed>updated")
feed.rights = text(doc, "feed>rights")
generator = text(doc, "feed>generator")
if generator
feed.generator = Generator.new(:name => text(doc, "feed>generator"), :uri => attribute_text(doc, "feed>generator", "uri"), :version => attribute_text(doc, "feed>generator", "version"))
end
feed.links = parse_links(doc.css("feed>link"))

doc.css("entry").each do |e|
entry = Entry.new
entry.id = text(e, "id")
entry.title = text(e, "title")
entry.content = parse_content e.css("content")
entry.updated = parse_time(text(e, "updated"))
entry.published = parse_time(text(e, "published"))
entry.authors = parse_authors e.css("author"), Author
entry.contributors = parse_authors e.css("contributor"), Contributor
entry.links = parse_links(e.css("link"))
feed.entries << entry
end

feed
end

private

def text(element, selector)
Text.new(element.css(selector).first.text, element.css(selector).first.attributes)
end

def attribute_text(element, selector, attribute)
Text.new(element.css(selector).attr(attribute).text)
end

def parse_time(text)
Atomizer::Time.parse(text)
end

def parse_content(content)
Content.new(:body => content.inner_html, :type => content.attr("type").to_s, :xml_lang => content.attr("lang").to_s, :xml_base => content.attr("base").to_s)
end

def parse_links(link)
links = []
if link
link.each do |l|
rel = l.attr("rel").to_s
type = l.attr("type").to_s
hreflang = l.attr("hreflang").to_s
href = l.attr("href").to_s
length = l.attr("length").to_s
links << Atomizer::Link.new(:rel => rel, :type => type, :hreflang => hreflang, :href => href, :length => length)
end
end
links
end

def parse_authors(author, author_class)
authors = []
if author
author.each do |a|
name = a.css("name").text
uri = a.css("uri").text
email = a.css("email").text
authors << author_class.new(:name => name, :uri => uri, :email => email)
end
end
authors
end
end

def initialize
@authors = []
@contributors = []
@entries = []
@links = []
end

def to_xml(xml, root_element=true)
xml.feed :xmlns => "http://www.w3.org/2005/Atom" do
super(xml, false)
end
end
end
end
84 changes: 84 additions & 0 deletions lib/atomizer/feed_item.rb
@@ -0,0 +1,84 @@
module Atomizer
class FeedItem
include Buildable

class << self

def feed_tag_name(tag_name=nil)
@feed_tag_name = tag_name.to_s if tag_name
@feed_tag_name
end

def feed_attributes(*attrs)
@attributes ||= []
if attrs && attrs.size > 0
@attributes.push(*attrs)
attrs.each do |a|
attr_accessor a
end
end
@attributes
end

def feed_no_collection_group_tag!
@feed_no_collection_group_tag = true
end

def feed_no_collection_group_tag
@feed_no_collection_group_tag || false
end
end

def initialize(options={})
self.class.feed_attributes.each do |a|
if v = (options[a.to_sym] || options[a.to_s])
meth = "#{a}="
send(meth, v) if respond_to?(meth) && v && v != ""
end
end
end

def to_xml(xml, root_element=true)
if root_element
xml.send(self.class.feed_tag_name) do |child_xml|
feed_attributes_to_xml(child_xml)
end
else
feed_attributes_to_xml(xml)
end
end

private

def feed_attributes_to_xml(xml)
self.class.feed_attributes.each do |a|
v = send(a) if respond_to?(a)
next if !v || v == ""
a = "#{a}_" if a.to_s == "id"
if v.is_a?(Array)
next if v.size == 0
if v.first.class.feed_no_collection_group_tag
v.each do |obj|
obj.to_xml xml
end
else
xml.send(a.to_s) do |child_xml|
v.each do |obj|
obj.to_xml child_xml
end
end
end
elsif v.respond_to?(:to_xml)
v.to_xml(xml)
elsif v.respond_to?(:attributes)
xml.send(a.to_s, v.attributes) do
xml.text v
end
else
xml.send(a.to_s, v.to_s)
end
end
end

end
end
10 changes: 10 additions & 0 deletions lib/atomizer/generator.rb
@@ -0,0 +1,10 @@
module Atomizer
class Generator < FeedItem
feed_tag_name "generator"
feed_attributes :name, :uri, :version

def to_xml(xml)
xml.generator @name, :uri => @uri, :version => @version
end
end
end
11 changes: 11 additions & 0 deletions lib/atomizer/link.rb
@@ -0,0 +1,11 @@
module Atomizer
class Link < FeedItem
feed_tag_name "link"
feed_attributes :rel, :type, :length, :href
feed_no_collection_group_tag!

def to_xml(xml)
xml.link :rel => @rel, :type => @type, :length => @length, :href => @href
end
end
end
25 changes: 25 additions & 0 deletions lib/atomizer/service.rb
@@ -0,0 +1,25 @@
module Atomizer
class Service < FeedItem
feed_tag_name "service"
feed_attributes :workspaces

def initialize(*attrs)
super(*attrs)
@workspaces ||= []
end

def to_xml(xml)
xml.service :xmlns => "http://www.w3.org/2007/app", :"xmlns:atom" => "http://www.w3.org/2005/Atom" do
workspaces.each do |workspace|
workspace.to_xml xml
end
end
end

def setup_workspace(collection=nil)
workspace = Workspace.new
workspace.collections << collection if collection
self.workspaces << workspace
end
end
end

0 comments on commit ed0252d

Please sign in to comment.