Initial commit

This commit is contained in:
xeals 2018-10-10 23:15:08 +11:00
commit 0c08823178
17 changed files with 1150 additions and 0 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*.cr]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
/docs/
/lib/
/bin/
/.shards/
*.dwarf
# Libraries don't need dependency lock
# Dependencies will be locked in application that uses them
/shard.lock

202
LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

41
README.md Normal file
View File

@ -0,0 +1,41 @@
# cryss
`cryss` is a light wrapper around `XML` for the W3 RSS 2.0 standard.
## Installation
Add this to your application's `shard.yml`:
```yaml
dependencies:
cryss:
github: xeals/cryss
```
## Usage
```crystal
require "cryss"
```
TODO: Write usage instructions here
## Development
TODO: Write development instructions here
## Contributing
1. Fork it (<https://github.com/xeals/cryss/fork>)
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request
## Contributors
- [xeals](https://github.com/xeals) - creator, maintainer
## License
cryss is licensed under the [Apache-2.0 license](LICENSE).

9
shard.yml Normal file
View File

@ -0,0 +1,9 @@
name: cryss
version: 0.1.0
authors:
- xeals <xeals@pm.me>
crystal: 0.26.1
license: Apache-2.0

89
spec/cryss_spec.cr Normal file
View File

@ -0,0 +1,89 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
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
ex_enclosure.to_s.strip.should eq w3
end
it "builds cloud" do
w3 = HEADER + CLOUD_TEST
ex_cloud.to_s.strip.should eq w3
end
it "builds item" do
item = RSS::Item.new title: "Venice Film Festival Tries to Quit Sinking"
item.link = URI.parse "http://www.nytimes.com/2002/09/07/movies/07FEST.html"
item.description = "Some of the most heated chatter at the Venice Film Festival this week was about the way that the arrival of the stars at the Palazzo del Cinema was being staged."
item.author = "oprah@oxygen.net"
item.category = RSS::Category.new "Simpsons Characters"
item.comments = URI.parse "http://www.myblog.org/cgi-local/mt/mt-comments.cgi?entry_id=290"
item.enclosure = ex_enclosure
item.guid = URI.parse "http://inessential.com/2002/09/01.php#a2"
item.pub_date = Time.parse_iso8601 "2002-05-19T15:21:36Z"
item.source = "Quotes of the Day"
item.source_url = URI.parse "http://www.quotationspage.com/data/qotd.rss"
item.to_s.strip.should eq ITEM_TEST
end
it "builds channel" do
chan = base_channel
chan.language = "en-us"
chan.copyright = "Copyright 2002, Spartanburg Herald-Journal"
chan.managing_editor = "geo@herald.com (George Matesky)"
chan.webmaster = "betty@herald.com (Betty Guernsey)"
chan.pub_date = Time.parse_iso8601 "2002-09-07T00:00:01Z"
chan.last_build_date = Time.parse_iso8601 "2002-09-07T09:42:31Z"
chan.category = [RSS::Category.new "Newspapers"]
chan.generator = "MightyInHouse Content System v2.3"
chan.docs = URI.parse "http://backend.userland.com/rss"
chan.cloud = ex_cloud
chan.ttl = 60
chan.to_s.strip.should eq CHANNEL_TEST
end
it "skips days and hours" do
chan = base_channel
chan.skip_days = [RSS::Day::Monday, RSS::Day::Wednesday]
chan.skip_hours = [2, 6, 18, 22]
end
end

78
spec/spec_helper.cr Normal file
View File

@ -0,0 +1,78 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "spec"
require "../src/cryss"
HEADER = "<?xml version=\"1.0\"?>\n"
CLOUD_TEST = "<cloud domain=\"rpc.sys.com\" port=\"80\" path=\"/RPC2\" registerProcedure=\"pingMe\" protocol=\"soap\"/>"
ENCLOSURE_TEST = "<enclosure url=\"http://live.curry.com/mp3/celebritySCms.mp3\" length=\"1069871\" type=\"audio/mpeg\"/>"
ITEM_TEST = HEADER + <<-XML
<item>
<title>Venice Film Festival Tries to Quit Sinking</title>
<link>http://www.nytimes.com/2002/09/07/movies/07FEST.html</link>
<description>Some of the most heated chatter at the Venice Film Festival this week was about the way that the arrival of the stars at the Palazzo del Cinema was being staged.</description>
<author>oprah@oxygen.net</author>
<category>Simpsons Characters</category>
<comments>http://www.myblog.org/cgi-local/mt/mt-comments.cgi?entry_id=290</comments>
#{ENCLOSURE_TEST}
<guid isPermaLink="true">http://inessential.com/2002/09/01.php#a2</guid>
<pubDate>Sun, 19 May 2002 15:21:36 +0000</pubDate>
<source url="http://www.quotationspage.com/data/qotd.rss">Quotes of the Day</source>
</item>
XML
CHANNEL_TEST = HEADER + <<-XML
<rss version="2.0">
<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>
<category>Newspapers</category>
#{CLOUD_TEST}
<copyright>Copyright 2002, Spartanburg Herald-Journal</copyright>
<docs>http://backend.userland.com/rss</docs>
<generator>MightyInHouse Content System v2.3</generator>
<language>en-us</language>
<lastBuildDate>Sat, 7 Sep 2002 09:42:31 +0000</lastBuildDate>
<managingEditor>geo@herald.com (George Matesky)</managingEditor>
<pubDate>Sat, 7 Sep 2002 00:00:01 +0000</pubDate>
<ttl>60</ttl>
<webMaster>betty@herald.com (Betty Guernsey)</webMaster>
</channel>
</rss>
XML
SKIP_DAY_TEST = HEADER + <<-XML
<rss version="2.0">
<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>
<skipHours>
<hour>2</hour>
<hour>6</hour>
<hour>18</hour>
<hour>22</hour>
</skipHours>
<skipDays>
<day>Monday</day>
<day>Wednesday</day>
</skipDays>
</channel>
</rss>
XML

17
src/cryss.cr Normal file
View File

@ -0,0 +1,17 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "./**"
# https://validator.w3.org/feed/docs/rss2.html

43
src/cryss/category.cr Normal file
View File

@ -0,0 +1,43 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "xml"
require "./element"
module RSS
class Category < Element
# Includes the item in one or more categories.
#
# The value of the element is a forward-slash-separated string that identifies a hierarchic
# location in the indicated taxonomy. Processors may establish conventions for the
# interpretation of categories. Two examples are provided below:
getter name : String
# Optional attribute that identifies a categorization taxonomy.
getter domain : URI?
def initialize(@name : String, domain : URI | String | Nil = nil)
@domain = domain.is_a?(String) ? URI.parse domain : domain
end
def to_xml(xml : XML::Builder)
if @domain
xml.element("category", domain: @domain) { xml.text name }
else
xml.element("category") { xml.text name }
end
end
end
end

207
src/cryss/channel.cr Normal file
View File

@ -0,0 +1,207 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "xml"
require "./cloud"
require "./day"
require "./element"
require "./image"
require "./item"
require "./text_input"
module RSS
# Contains information about an RSS channel (metadata) and its contents.
#
# For precise documentation, see <https://validator.w3.org/feed/docs/rss2.html>
class Channel < Element
# The name of the channel.
#
# It's how people refer to your service. If you have an HTML website that contains the same
# information as your RSS file, the title of your channel should be the same as the title of
# your website.
getter title : String
# The URL to the HTML website corresponding to the channel.
getter link : URI
# Phrase or sentence describing the channel.
getter description : String
# The language the channel is written in.
#
# This allows aggregators to group all Italian language sites, for example, on a single page. A
# list of allowable values for this element, as provided by Netscape, is
# [here](http://backend.userland.com/stories/storyReader$16). You may also use [values
# defined](http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes) by the W3C.
#
# Example: en-us
getter language : String?
# Copyright notice for content in the channel.
#
# Example: Copyright 2002, Spartanburg Herald-Journal
getter copyright : String?
# Email address for person responsible for editorial content.
#
# Example: geo@herald.com (George Matesky)
getter managing_editor : String?
# Email address for person responsible for technical issues relating to channel.
#
# Example: betty@herald.com (Betty Guernsey)
getter webmaster : String?
# The publication date for the content in the channel.
#
# For example, the New York Times publishes on a daily basis, the publication date flips once
# every 24 hours. That's when the pubDate of the channel changes. All date-times in RSS conform
# to the Date and Time Specification of [RFC 822](http://asg.web.cmu.edu/rfc/rfc822.html), with
# the exception that the year may be expressed with two characters or four characters (four
# preferred).
#
# Example: Sat, 07 Sep 2002 0:00:01 GMT
getter pub_date : Time?
# The last time the content of the channel changed.
#
# Example: Sat, 07 Sep 2002 9:42:31 GMT
getter last_build_date : Time?
# Specify one or more categories that the channel belongs to. Follows the same rules as the
# `Item`-level category element. More info.
getter category : Array(Category) = [] of Category
# A string indicating the program used to generate the channel.
getter generator : String = "cryss"
# A URL that points to the documentation for the format used in the RSS file.
#
# Defaults to the W3 RSS 2.0 specification. It's for people who might stumble across an RSS file
# on a Web server 25 years from now and wonder what it is.
getter docs : URI = URI.parse "https://validator.w3.org/feed/docs/rss2.html"
# Allows processes to register with a `Cloud` to be notified of updates to the channel,
# implementing a lightweight publish-subscribe protocol for RSS feeds. More info here.
getter cloud : Cloud?
# Time to live.
#
# It's a number of minutes that indicates how long a channel can be cached before refreshing
# from the source. More info here.
getter ttl : Int32?
# Specifies a GIF, JPEG or PNG image that can be displayed with the channel.
getter image : Image?
# Specifies a `TextInput` box that can be displayed with the channel.
getter text_input : TextInput?
# A hint for aggregators telling them which hours they can skip.
getter skip_days : Array(Day) = [] of Day
# A hint for aggregators telling them which days they can skip.
getter skip_hours : Array(Int32) = [] of Int32
setter title,
link,
description,
category,
cloud,
copyright,
docs,
generator,
image,
language,
last_build_date,
managing_editor,
pub_date,
skip_days,
skip_hours,
text_input,
ttl,
webmaster
# Contained elements of the channel.
getter items : Array(Item) = [] of Item
def initialize(link : URI | String, @title : String, @description : String)
@link = link.is_a?(URI) ? link : URI.parse link
end
def push(item : Item)
@items << item
end
def <<(item : Item)
push item
end
# Serialises the channel to the XML builder.
def to_xml(xml : XML::Builder)
xml.element("rss", version: "2.0") do
xml.element("channel") do
emit title
emit link
emit description
@category.each do |cat|
cat.to_xml xml
end
if cloud = @cloud
cloud.to_xml xml
end
emit copyright if @copyright
emit docs if @docs
emit generator if @generator
if image = @image
image.to_xml xml
end
emit language if @language
if lbd = @last_build_date
xml.element("lastBuildDate") { xml.text lbd.to_rfc2822 }
end
emit managing_editor, "managingEditor" if @managing_editor
if pub = @pub_date
xml.element("pubDate") { xml.text pub.to_rfc2822 }
end
emit text_input, "textInput" if @text_input
emit ttl if @ttl
emit webmaster, "webMaster" if @webmaster
# skips
if !@skip_hours.empty?
xml.element("skipHours") do
@skip_hours.each do |hour|
xml.element("hour") { xml.text hour.to_s }
end
end
end
if !@skip_days.empty?
xml.element("skipDays") do
@skip_days.each do |day|
xml.element("day") { xml.text day.to_s }
end
end
end
@items.each do |item|
item.to_xml xml
end
end
end
end
end
end

72
src/cryss/cloud.cr Normal file
View File

@ -0,0 +1,72 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "xml"
module RSS
# Optional sub-element of a channel.
#
# It specifies a web service that supports the rssCloud interface which can be implemented in
# HTTP-POST, XML-RPC or SOAP 1.1.
#
# Its purpose is to allow processes to register with a cloud to be notified of updates to the
# channel, implementing a lightweight publish-subscribe protocol for RSS feeds.
#
# ```
# <cloud domain="radio.xmlstoragesystem.com" port="80" path="/RPC2" registerProcedure="xmlStorageSystem.rssPleaseNotify" protocol="xml-rpc" />
# ```
#
# In this example, to request notification on the channel it appears in, you would send an XML-RPC
# message to radio.xmlstoragesystem.com on port 80, with a path of /RPC2. The procedure to call is
# xmlStorageSystem.rssPleaseNotify.
#
# A full explanation of this element and the rssCloud interface is
# [here](http://www.thetwowayweb.com/soapmeetsrss#rsscloudInterface).
class Cloud < Element
getter domain : URI
getter port : Int32
getter path : String
getter register_procedure : String
getter protocol : String
setter domain,
port,
path,
register_procedure,
protocol
def initialize(domain : URI | String,
@port : Int32,
@path : String,
@register_procedure : String,
@protocol : String)
@domain = domain.is_a?(String) ? URI.parse domain : domain
end
def to_xml(xml : XML::Builder)
xml.element(
"cloud",
domain: @domain.to_s,
port: @port.to_s,
path: @path,
registerProcedure: @register_procedure,
protocol: @protocol
)
end
end
end

25
src/cryss/day.cr Normal file
View File

@ -0,0 +1,25 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module RSS
enum Day
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
end
end

41
src/cryss/element.cr Normal file
View File

@ -0,0 +1,41 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "xml"
module RSS
abstract class Element
def to_s(io : IO)
to_xml(io)
end
# Writes the generated XML to the provided *io*.
def to_xml(io : IO)
XML.build(io, version: "1.0", indent: " ") do |xml|
to_xml(xml)
end
end
# Writes the generated XML to the provided *xml* builder.
abstract def to_xml(xml : XML::Builder)
private macro emit(elem)
xml.element("{{elem}}") { xml.text @{{elem}}.to_s }
end
private macro emit(elem, name)
xml.element({{name}}) { xml.text @{{elem}}.to_s }
end
end
end

39
src/cryss/enclosure.cr Normal file
View File

@ -0,0 +1,39 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module RSS
# Describes a media object that is attached to an item.
class Enclosure < Element
# Where the enclosure is located.
getter url : URI
# Size in bytes.
getter length : Int32
# MIME type of the media.
getter type : String
setter url,
length,
type
def initialize(url : URI | String, @length : Int32, @type : String)
@url = url.is_a?(URI) ? url : URI.parse url
end
def to_xml(xml : XML::Builder)
xml.element("enclosure", url: @url, length: @length, type: @type)
end
end
end

77
src/cryss/image.cr Normal file
View File

@ -0,0 +1,77 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "xml"
require "uri"
require "./element"
module RSS
class Image < Element
# URL of a GIF, JPEG or PNG image that represents the channel.
getter image : URI
# Describes the image.
#
# Used in the ALT attribute of the HTML <img> tag when the channel is rendered in HTML.
getter title : String
# URL of the site, when the channel is rendered, the image is a link to the site. (Note, in
# practice the image <title> and <link> should have the same value as the channel's <title> and
# <link>.
getter link : URI
# Width of the image in pixels. Default is 88. Maximum of 144.
getter width : Float32 = 88
# Height of the image in pixels. Default is 31. Maximum of 400.
getter height : Float32 = 31
# Description contains text that is included in the TITLE attribute of the link formed around
# the image in the HTML rendering.
getter description : String?
setter image,
title,
link,
description
def initialize(image : URI | String, @title : String, link : URI | String)
@image = image.is_a?(URI) ? image : URI.parse image
@link = link.is_a?(URI) ? link : URI.parse link
end
def width=(width : Float32)
raise Exception.new "maximum width is 144" if width > 144
@width = width
end
def height=(height : Float32)
raise Exception.new "maximum height is 400" if height > 400
@height = height
end
# Serialises the image to the XML builder.
def to_xml(xml : XML::Builder)
xml.element("image") do
emit image
emit title
emit link
emit width if @width
emit height if @height
emit description if @description
end
end
end
end

141
src/cryss/item.cr Normal file
View File

@ -0,0 +1,141 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "xml"
require "./category"
require "./element"
require "./enclosure"
module RSS
# A channel may contain any number of `Item`s. An item may represent a "story" -- much like a
# story in a newspaper or magazine; if so its description is a synopsis of the story, and the link
# points to the full story. An item may also be complete in itself, if so, the description
# contains the text (entity-encoded HTML is allowed), and the link and title may be omitted. All
# elements of an item are optional, however at least one of title or description must be present.
class Item < Element
# The title of the item.
getter title : String?
# The URL of the item.
getter link : URI?
# The item synopsis.
getter description : String?
# Email address of the author of the item.
getter author : String?
# Includes the item in one or more categories.
#
# The value of the element is a forward-slash-separated string that identifies a hierarchic
# location in the indicated taxonomy. Processors may establish conventions for the
# interpretation of categories. Two examples are provided below:
# getter category : String?
getter category : Category?
# Optional <category> attribute that identifies a categorization taxonomy.
# getter category_domain : URI?
# Optional URL of the comments page for the item.
#
# ```
# <comments>http://rateyourmusic.com/yaccs/commentsn/blogId=705245&itemId=271</comments>
# ```
getter comments : URI?
# Describes a media object that is attached to the item.
getter enclosure : Enclosure?
# Optional globally unique identifier.
#
# It's a string that uniquely identifies the item. When present, an aggregator may choose to use
# this string to determine if an item is new.
#
# ```
# <guid>http://some.server.com/weblogItem3207<guid>
# ```
#
# There are no rules for the syntax of a guid. Aggregators must view them as a string. It's up
# to the source of the feed to establish the uniqueness of the string.
#
# If the guid element has an attribute named "isPermaLink" with a value of true, the reader may
# assume that it is a permalink to the item, that is, a url that can be opened in a Web browser,
# that points to the full item described by the <item> element. An example:
#
# ```
# <guid isPermaLink="true">http://inessential.com/2002/09/01.php#a2</guid>
# ```
#
# *is_perma_link* is optional and defaults to true. If its value is false, the guid may not be
# assumed to be a url, or a url to anything in particular.
getter guid : URI?
# See `#guid`.
getter guid_is_perma_link : Bool = true
# <pubDate> is an optional sub-element of <item>.
#
# Its value is a date, indicating when the item was published. If it's a date in the future,
# aggregators may choose to not display the item until that date.
getter pub_date : Time?
# The RSS channel that the item came from.
getter source : String?
# Required if *source* is non-nil.
getter source_url : URI?
setter title,
link,
description,
author,
category,
comments,
enclosure,
guid,
guid_is_perma_link,
pub_date,
source,
source_url
def initialize(@title = nil, @description = nil)
raise Exception.new "either title or description are required for RSS item" if !(@title || @description)
end
# Serialises the item to the XML builder.
def to_xml(xml : XML::Builder)
raise Exception.new "source_url is required if source is non-nil for item" if @source && !@source_url
xml.element("item") do
emit title if @title
emit link if @link
emit description if @description
emit author if @author
if category = @category
category.to_xml xml
end
emit comments if @comments
if enc = @enclosure
enc.to_xml xml
end
xml.element("guid", isPermaLink: @guid_is_perma_link) { xml.text @guid.to_s } if @guid
if pub = @pub_date
xml.element("pubDate") { xml.text pub.to_rfc2822 }
end
xml.element("source", url: @source_url.to_s) { xml.text @source.to_s } if @source
end
end
end
end

51
src/cryss/text_input.cr Normal file
View File

@ -0,0 +1,51 @@
# Copyright 2018 Alex Smith
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "xml"
module RSS
# The purpose of the <textInput> element is something of a mystery. You can use it to specify a
# search engine box. Or to allow a reader to provide feedback. Most aggregators ignore it.
class TextInput < Element
# The label of the Submit button in the text input area.
getter title : String
# Explains the text input area.
getter description : String
# The name of the text object in the text input area.
getter name : String
# The URL of the CGI script that processes text input requests.
getter link : URI
setter title,
description,
name,
link
def initialize(@title : String, @description : String, @name : String, link : URI | String)
@link = link.is_a?(URI) ? link : URI.parse link
end
def to_xml(xml : XML::Builder)
xml.element("textInput") do
emit title
emit description
emit name
emit link
end
end
end
end