Support namespace addons

This commit is contained in:
xeals 2018-10-11 00:04:26 +11:00
parent 0c08823178
commit b6aab1edb5
6 changed files with 125 additions and 20 deletions

View File

@ -15,26 +15,6 @@
require "./spec_helper"
describe RSS do
ex_cloud = RSS::Cloud.new(
domain: "rpc.sys.com",
port: 80,
path: "/RPC2",
register_procedure: "pingMe",
protocol: "soap"
)
ex_enclosure = RSS::Enclosure.new(
url: "http://live.curry.com/mp3/celebritySCms.mp3",
length: 1069871,
type: "audio/mpeg"
)
base_channel = RSS::Channel.new(
link: "http://www.goupstate.com/",
title: "GoUpstate.com News Headlines",
description: "The latest news from GoUpstate.com, a Spartanburg Herald-Journal Web site."
)
it "builds enclosure" do
w3 = HEADER + ENCLOSURE_TEST
@ -85,5 +65,23 @@ describe RSS do
chan = base_channel
chan.skip_days = [RSS::Day::Monday, RSS::Day::Wednesday]
chan.skip_hours = [2, 6, 18, 22]
chan.to_s.strip.should eq SKIP_DAY_TEST
end
it "adds namespace" do
chan = base_channel
chan.add_ns(dc: "http://purl.org/dc/elements/1.1")
chan.ns("dc") do |dc|
dc["rights"] = "Copyright 2002"
end
item = RSS::Item.new(title: "New item")
item.ns("dc") do |dc|
dc["subject"] = "CSS"
end
chan << item
chan.to_s.strip.should eq NAMESPACE_TEST
end
end

View File

@ -15,6 +15,32 @@
require "spec"
require "../src/cryss"
def ex_cloud
RSS::Cloud.new(
domain: "rpc.sys.com",
port: 80,
path: "/RPC2",
register_procedure: "pingMe",
protocol: "soap"
)
end
def ex_enclosure
RSS::Enclosure.new(
url: "http://live.curry.com/mp3/celebritySCms.mp3",
length: 1069871,
type: "audio/mpeg"
)
end
def base_channel
RSS::Channel.new(
link: "http://www.goupstate.com/",
title: "GoUpstate.com News Headlines",
description: "The latest news from GoUpstate.com, a Spartanburg Herald-Journal Web site."
)
end
HEADER = "<?xml version=\"1.0\"?>\n"
CLOUD_TEST = "<cloud domain=\"rpc.sys.com\" port=\"80\" path=\"/RPC2\" registerProcedure=\"pingMe\" protocol=\"soap\"/>"
@ -63,6 +89,8 @@ SKIP_DAY_TEST = HEADER + <<-XML
<title>GoUpstate.com News Headlines</title>
<link>http://www.goupstate.com/</link>
<description>The latest news from GoUpstate.com, a Spartanburg Herald-Journal Web site.</description>
<docs>https://validator.w3.org/feed/docs/rss2.html</docs>
<generator>cryss</generator>
<skipHours>
<hour>2</hour>
<hour>6</hour>
@ -76,3 +104,20 @@ SKIP_DAY_TEST = HEADER + <<-XML
</channel>
</rss>
XML
NAMESPACE_TEST = HEADER + <<-XML
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1">
<channel>
<title>GoUpstate.com News Headlines</title>
<link>http://www.goupstate.com/</link>
<description>The latest news from GoUpstate.com, a Spartanburg Herald-Journal Web site.</description>
<docs>https://validator.w3.org/feed/docs/rss2.html</docs>
<generator>cryss</generator>
<dc:rights>Copyright 2002</dc:rights>
<item>
<title>New item</title>
<dc:subject>CSS</dc:subject>
</item>
</channel>
</rss>
XML

View File

@ -137,6 +137,8 @@ module RSS
# Contained elements of the channel.
getter items : Array(Item) = [] of Item
@namespaces = {} of String => String
def initialize(link : URI | String, @title : String, @description : String)
@link = link.is_a?(URI) ? link : URI.parse link
end
@ -149,9 +151,21 @@ module RSS
push item
end
def add_ns(name : String | Symbol,
url : URI | String)
@namespaces["xmlns:#{name.to_s}"] = url.to_s
end
def add_ns(**ns)
ns.each do |k, v|
add_ns(k, v)
end
end
# Serialises the channel to the XML builder.
def to_xml(xml : XML::Builder)
xml.element("rss", version: "2.0") do
xml.attributes(@namespaces)
xml.element("channel") do
emit title
emit link
@ -197,6 +211,8 @@ module RSS
end
end
emit_custom xml
@items.each do |item|
item.to_xml xml
end

View File

@ -16,6 +16,8 @@ require "xml"
module RSS
abstract class Element
@custom = {} of String => Hash(String, String)
def to_s(io : IO)
to_xml(io)
end
@ -27,6 +29,38 @@ module RSS
end
end
# Adds a non-standard namespaced element to the component.
#
# Yields access to a set of namespaced elements and their values.
#
# Examples taken from [here](http://static.userland.com/gems/backend/rssMarkPilgrimExample.xml).
#
# ```crystal
# channel = RSS::Channel.new(/* ... */)
# channel.add_ns(dc: "http://purl.org/dc/elements/1.1")
# channel.ns("dc") do |dc|
# dc["rights"] = "Copyright 2002"
# end
#
# item = RSS::Item.new(title: "New item")
# item.ns("dc") do |dc|
# dc["subject"] = "CSS"
# end
#
# channel << item
# ```
#
# If the namespace already exists, it will yield access to the already existing namespace rather
# than overwriting it. Duplicate keys inside that namespace will overwrite, however.
#
# Note that no sanity checking is (currently) done before serializing an element with a custom
# namespaced element, as only the top-level element (a `Channel`) has access to specifying the
# namespace imports.
def ns(name : String, &block)
@custom[name] = {} of String => String if @custom[name]?.nil?
yield @custom[name]
end
# Writes the generated XML to the provided *xml* builder.
abstract def to_xml(xml : XML::Builder)
@ -37,5 +71,13 @@ module RSS
private macro emit(elem, name)
xml.element({{name}}) { xml.text @{{elem}}.to_s }
end
private def emit_custom(xml)
@custom.each do |ns, content|
content.each do |key, val|
xml.element("#{ns}:#{key}") { xml.text val }
end
end
end
end
end

View File

@ -71,6 +71,8 @@ module RSS
emit width if @width
emit height if @height
emit description if @description
emit_custom xml
end
end
end

View File

@ -135,6 +135,8 @@ module RSS
xml.element("pubDate") { xml.text pub.to_rfc2822 }
end
xml.element("source", url: @source_url.to_s) { xml.text @source.to_s } if @source
emit_custom xml
end
end
end