ess 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +448 -0
- data/Rakefile +5 -0
- data/ess.gemspec +21 -0
- data/lib/ess/dtd.rb +491 -0
- data/lib/ess/element.rb +266 -0
- data/lib/ess/ess.rb +8 -0
- data/lib/ess/examples.rb +432 -0
- data/lib/ess/helpers.rb +22 -0
- data/lib/ess/maker.rb +24 -0
- data/lib/ess/postprocessing.rb +69 -0
- data/lib/ess/pusher.rb +63 -0
- data/lib/ess/validation.rb +797 -0
- data/lib/ess/version.rb +3 -0
- data/lib/ess.rb +13 -0
- data/spec/ess/element_spec.rb +796 -0
- data/spec/ess/full_spec.rb +47 -0
- data/spec/ess/maker_spec.rb +30 -0
- data/spec/spec_helper.rb +5 -0
- metadata +88 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,448 @@
|
|
1
|
+
ruby-ess
|
2
|
+
========
|
3
|
+
|
4
|
+
#### https://github.com/essfeed/rails-ess
|
5
|
+
|
6
|
+
[](http://essfeed.org/)
|
7
|
+
|
8
|
+
Generate ESS XML feeds with Ruby
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'ess', '~> 0.9.1'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install ess -v 0.9.1
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
Producing your own ESS feeds is easy. Here is an example about how
|
27
|
+
it's done, with most of the available tags available in ESS:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
|
31
|
+
require 'ess'
|
32
|
+
|
33
|
+
ess = Maker.make do |ess|
|
34
|
+
ess.channel do |channel|
|
35
|
+
channel.title "National Stadium Football events"
|
36
|
+
channel.link "http://sample.com/feeds/sample.ess"
|
37
|
+
channel.id "ESSID:50b4b412-1ad4-a731-1c6a-2523ffa33f81"
|
38
|
+
channel.published "2012-12-13T08:29:29Z"
|
39
|
+
channel.updated "2012-12-13T18:30:02-08:00"
|
40
|
+
channel.rights "Copyright (c) 2013, John Doe"
|
41
|
+
|
42
|
+
channel.add_feed do |feed|
|
43
|
+
feed.title "Football match of saturday"
|
44
|
+
feed.uri "http://sample.com/events/specific-and-unique-event-page/"
|
45
|
+
feed.id "EVENTID:550b55b412-1ad4-a4731-155-2777fa37f866"
|
46
|
+
feed.published "2012-12-13T08:29:29Z"
|
47
|
+
feed.updated "2012-12-13T18:30:02-0800"
|
48
|
+
feed.access "PUBLIC"
|
49
|
+
feed.description("Welcome to my first football match event. " +
|
50
|
+
"This football match is very important. " +
|
51
|
+
"Our team is about to go up against our main league competitor.")
|
52
|
+
|
53
|
+
feed.tags do |tags|
|
54
|
+
tags.tag "Sport"
|
55
|
+
tags.tag "Footbal"
|
56
|
+
tags.tag "Soccer"
|
57
|
+
tags.tag "Match"
|
58
|
+
tags.tag "Game"
|
59
|
+
tags.tag "Team Sport"
|
60
|
+
tags.tag "Stadium"
|
61
|
+
end
|
62
|
+
|
63
|
+
feed.categories.add_item(:type => "competition") do |item|
|
64
|
+
item.name "Football"
|
65
|
+
item.id "C2AH"
|
66
|
+
end
|
67
|
+
|
68
|
+
feed.dates.add_item do |item|
|
69
|
+
item.type_attr "recurrent"
|
70
|
+
item.unit_attr "week"
|
71
|
+
item.limit_attr "4"
|
72
|
+
item.selected_day_attr "saturday,sunday"
|
73
|
+
|
74
|
+
item.name "Match Date"
|
75
|
+
item.start "2011-12-13T18:30:02Z"
|
76
|
+
item.duration "10800"
|
77
|
+
end
|
78
|
+
|
79
|
+
feed.places do |places|
|
80
|
+
places.add_item(:type => "fixed", :priority => 1) do |item|
|
81
|
+
item.name "Football Stade"
|
82
|
+
item.latitude "40.71675"
|
83
|
+
item.longitude "-74.00674"
|
84
|
+
item.address "Ave of Americas, 871"
|
85
|
+
item.city "New York"
|
86
|
+
item.zip "10001"
|
87
|
+
item.state_code "NY"
|
88
|
+
item.country_code "US"
|
89
|
+
end
|
90
|
+
|
91
|
+
places.add_item(:type => "fixed", :priority => 2) do |item|
|
92
|
+
item.name "Match direct on TV"
|
93
|
+
item.country_code "US"
|
94
|
+
item.medium_name "NBC super channel"
|
95
|
+
item.medium_type "television"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
feed.prices do |prices|
|
100
|
+
prices.add_item(:type => "standalone", :priority => 2) do |item|
|
101
|
+
item.mode_attr "invitation"
|
102
|
+
|
103
|
+
item.name "Free entrance"
|
104
|
+
item.value "0"
|
105
|
+
item.currency "USD"
|
106
|
+
end
|
107
|
+
|
108
|
+
prices.add_item(:type => "recurrent", :priority => 1) do |item|
|
109
|
+
item.unit_attr "month"
|
110
|
+
item.mode_attr "fixed"
|
111
|
+
item.limit_attr "12"
|
112
|
+
|
113
|
+
item.name "Subscribe monthly !"
|
114
|
+
item.value "17"
|
115
|
+
item.currency "USD"
|
116
|
+
item.start "2012-12-13T18:30:02Z"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
feed.media do |media|
|
121
|
+
media.add_item(:type => "image", :priority => 1) do |item|
|
122
|
+
item.name "Stade image"
|
123
|
+
item.uri "http://sample.com/small/image_1.png"
|
124
|
+
end
|
125
|
+
|
126
|
+
media.add_item(:type => "video", :priority => 3) do |item|
|
127
|
+
item.name "Stade video"
|
128
|
+
item.uri "http://sample.com/video/movie.mp4"
|
129
|
+
end
|
130
|
+
|
131
|
+
media.add_item(:type => "sound", :priority => 2) do |item|
|
132
|
+
item.name "Radio spot"
|
133
|
+
item.uri "http://sample.com/video/movie.mp3"
|
134
|
+
end
|
135
|
+
|
136
|
+
media.add_item(:type => "website", :priority => 4) do |item|
|
137
|
+
item.name "Football Stade website"
|
138
|
+
item.uri "http://my-football-website.com"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
feed.people do |people|
|
143
|
+
people.add_item(:type => "organizer") do |item|
|
144
|
+
item.id "THJP167:8URYRT24:BUEREBK:567TYEFGU:IPAAF"
|
145
|
+
item.uri "http://michaeldoe.com"
|
146
|
+
item.name "Michael Doe"
|
147
|
+
item.firstname "Michael"
|
148
|
+
item.lastname "Doe"
|
149
|
+
item.organization "Football club association"
|
150
|
+
item.address "80, 5th avenue / 45st E - #504"
|
151
|
+
item.city "New York"
|
152
|
+
item.zip "10001"
|
153
|
+
item.state "New York"
|
154
|
+
item.state_code "NY"
|
155
|
+
item.country "United States of America"
|
156
|
+
item.country_code "US"
|
157
|
+
item.logo "http://sample.com/logo_120x60.png"
|
158
|
+
item.icon "http://sample.com/icon_64x64.png"
|
159
|
+
item.email "contact@sample.com"
|
160
|
+
item.phone "+001 (646) 234-5566"
|
161
|
+
end
|
162
|
+
|
163
|
+
people.add_item(:type => "performer") do |item|
|
164
|
+
item.id "FDH56:G497D6:4564DD465:4F6S4S6"
|
165
|
+
item.uri "http://janettedoe.com"
|
166
|
+
item.name "Janette Doe"
|
167
|
+
end
|
168
|
+
|
169
|
+
people.add_item(:type => "attendee") do |item|
|
170
|
+
item.name "Attendees information:"
|
171
|
+
item.minpeople 0
|
172
|
+
item.maxpeople 500
|
173
|
+
item.minage 0
|
174
|
+
item.restriction "Smoking is not allowed in the stadium"
|
175
|
+
end
|
176
|
+
|
177
|
+
people.add_item(:type => "social") do |item|
|
178
|
+
item.name "Social network link to share or rate the event."
|
179
|
+
item.uri "http://social_network.com/my_events/my_friends/my_notes"
|
180
|
+
end
|
181
|
+
|
182
|
+
people.add_item(:type => "author") do |item|
|
183
|
+
item.name "Feed Powered by Event Promotion Tool"
|
184
|
+
item.uri "http://sample.com/my_events/"
|
185
|
+
item.logo "http://sample.com/logo_120x60.png"
|
186
|
+
item.icon "http://sample.com/icon_64x64.png"
|
187
|
+
end
|
188
|
+
|
189
|
+
people.add_item(:type => "contributor") do |item|
|
190
|
+
item.name "Jane Doe"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
feed.relations do |relations|
|
195
|
+
relations.add_item(:type => "alternative") do |item|
|
196
|
+
item.name "alternative event"
|
197
|
+
item.id "EVENTID:50412:1a904:a715731:1cera:25va33"
|
198
|
+
item.uri "http://sample.com/feed/event_2.ess"
|
199
|
+
end
|
200
|
+
|
201
|
+
relations.add_item(:type => "related") do |item|
|
202
|
+
item.name "related event title"
|
203
|
+
item.id "EVENTID:50b412:1a35d4:a731:1354c6a:225dg1"
|
204
|
+
item.uri "http://sample.com/feed/event_3.ess"
|
205
|
+
end
|
206
|
+
|
207
|
+
relations.add_item(:type => "enclosure") do |item|
|
208
|
+
item.name "nearby event"
|
209
|
+
item.id "EVENTID:50b12:3451d4:34f5a71:1cf6a:2ff81"
|
210
|
+
item.uri "http://sample.com/feed/event_5.ess"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
```
|
218
|
+
|
219
|
+
As can be seen, it's a very Builder-like DSL. The result of this code
|
220
|
+
will be an ESS feed with one item. To get XML from it, the 'to_xml!'
|
221
|
+
method ca be used.
|
222
|
+
|
223
|
+
More information on ESS and what tags and options are available can
|
224
|
+
be found on http://essfeed.org/ .
|
225
|
+
|
226
|
+
### Pushing feeds to aggregators
|
227
|
+
|
228
|
+
Once a feed is generated, it can be submitted to an aggregator easily.
|
229
|
+
To send it to the default aggregator service, which is Hypecal, just
|
230
|
+
add an option to the 'make' class method:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
|
234
|
+
ess = Maker.make(:push => true) do |ess|
|
235
|
+
|
236
|
+
...
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
```
|
241
|
+
|
242
|
+
Another way to do the same is to first generate the feed and assign
|
243
|
+
the result to a variable, like 'ess' in previous example, and call its
|
244
|
+
'push_to_aggregators' method. It accepts the same options and is
|
245
|
+
useful for example when the feed has to be submitted in a dalayed job.
|
246
|
+
|
247
|
+
In a Rails environment, if the feed is generated in response to a
|
248
|
+
request, providing the request object to the maker method could
|
249
|
+
provide the aggregator with more useful data:
|
250
|
+
|
251
|
+
```ruby
|
252
|
+
|
253
|
+
ess = Maker.make(:request => request) do |ess|
|
254
|
+
|
255
|
+
...
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
```
|
260
|
+
|
261
|
+
Should you want to provide a list of aggregator services yourself, it
|
262
|
+
can be done with the aggregators option:
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
|
266
|
+
ess = Maker.make(:aggregators => ['http://aggregator.example.com/api.json', ...]) do |ess|
|
267
|
+
|
268
|
+
...
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
```
|
273
|
+
|
274
|
+
Another option is to set a new default list of aggregator services
|
275
|
+
using the Pusher class:
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
|
279
|
+
ESS::Pusher.aggregators = ['http://aggregator.example.com/api.json', ...]
|
280
|
+
|
281
|
+
```
|
282
|
+
|
283
|
+
### Validation
|
284
|
+
|
285
|
+
When using the Maker class, the resulting feed is
|
286
|
+
validated automatically at the end of the block. That means that
|
287
|
+
before the block ends, the feed has to have all the mandatory
|
288
|
+
tags, with valid values. There is however an option to turn that
|
289
|
+
behavior off, but there should be a good reason to do that.
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
|
293
|
+
ess = Maker.make(:validate => false) do |ess|
|
294
|
+
|
295
|
+
...
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
```
|
300
|
+
|
301
|
+
The resulting object accepts the 'valid?' and 'validate' methods. The
|
302
|
+
former returns true or false, while the later raises an exception with
|
303
|
+
a message more useful for debugging.
|
304
|
+
|
305
|
+
### Working with tags
|
306
|
+
|
307
|
+
A tag with text can be specified like this:
|
308
|
+
|
309
|
+
```ruby
|
310
|
+
|
311
|
+
ess = Maker.make do |ess|
|
312
|
+
ess.channel do |channel|
|
313
|
+
|
314
|
+
channel.title "National Stadium Football events"
|
315
|
+
|
316
|
+
...
|
317
|
+
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
```
|
322
|
+
|
323
|
+
Each tag accepts method calls coresponding to child tag names. These
|
324
|
+
methods can accept a string argument, which will become the text of
|
325
|
+
the child tag, and/or a list of key/value pairs (options), which will
|
326
|
+
become tag attributes.
|
327
|
+
|
328
|
+
If there is also a block, it should expect one parameter which will
|
329
|
+
be a reference to the child tag.
|
330
|
+
|
331
|
+
For the case where a single tag can have multiple child tags with the
|
332
|
+
same name, the following construct can be used:
|
333
|
+
|
334
|
+
```ruby
|
335
|
+
|
336
|
+
ess = Maker.make do |ess|
|
337
|
+
ess.channel do |channel|
|
338
|
+
|
339
|
+
channel.add_feed do |feed|
|
340
|
+
|
341
|
+
...
|
342
|
+
|
343
|
+
end
|
344
|
+
|
345
|
+
channel.add_feed do |another_feed|
|
346
|
+
|
347
|
+
...
|
348
|
+
|
349
|
+
end
|
350
|
+
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
```
|
356
|
+
|
357
|
+
For every tag 'tag_name' its parent accepts an 'add_tag_name' method,
|
358
|
+
which accepts the same arguments as a 'tag_name' method.
|
359
|
+
|
360
|
+
Attributes have also their own methods for setting them, for example:
|
361
|
+
|
362
|
+
```ruby
|
363
|
+
|
364
|
+
ess = Maker.make do |ess|
|
365
|
+
ess.lang_attr "zu"
|
366
|
+
|
367
|
+
...
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
```
|
372
|
+
|
373
|
+
Here the 'lang' attribute of the ess tag is set to "zu". And there is
|
374
|
+
also a 'text!' method, which can be used to set a tags text:
|
375
|
+
|
376
|
+
```ruby
|
377
|
+
|
378
|
+
ess = Maker.make do |ess|
|
379
|
+
ess.channel do |channel|
|
380
|
+
|
381
|
+
channel.title do |title|
|
382
|
+
title.text! "National Stadium Football events"
|
383
|
+
end
|
384
|
+
|
385
|
+
...
|
386
|
+
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
```
|
391
|
+
|
392
|
+
Again, more information on ESS and what tags and options are available
|
393
|
+
can be found on http://essfeed.org/ .
|
394
|
+
|
395
|
+
### Valid tag and attribute values
|
396
|
+
|
397
|
+
Pretty much anything can be used as the value for a tag, as long as
|
398
|
+
it can be converted to a string with #to_s.
|
399
|
+
|
400
|
+
Tags that accept date or
|
401
|
+
time will accept Time objects too, which will be converted to the
|
402
|
+
corrent format, which is ISO-8601 for ESS. However, if the value is a
|
403
|
+
string, an attempt will be made to automatically convert the value
|
404
|
+
to the ISO-8601 format.
|
405
|
+
|
406
|
+
### IDs
|
407
|
+
|
408
|
+
The channel and feed ID tags can also be
|
409
|
+
computed automatically, they don't need to be set by hand. They are
|
410
|
+
automatically calculated and set the first time the TITLE or URI/LINK
|
411
|
+
tags are changed. Also, instead of using a valid ID value, any string
|
412
|
+
can be assigned to the ID tag of a channel or feed, and if it doesn't
|
413
|
+
start with "ESSID:" or "EVENTID:", it will be regenerated using that
|
414
|
+
string as the key.
|
415
|
+
|
416
|
+
## Contributing
|
417
|
+
|
418
|
+
1. Fork it
|
419
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
420
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
421
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
422
|
+
5. Create new Pull Request
|
423
|
+
|
424
|
+
# License
|
425
|
+
|
426
|
+
(The MIT License)
|
427
|
+
|
428
|
+
Copyright (c) 2013 Hypecal
|
429
|
+
|
430
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
431
|
+
a copy of this software and associated documentation files (the
|
432
|
+
'Software'), to deal in the Software without restriction, including
|
433
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
434
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
435
|
+
permit persons to whom the Software is furnished to do so, subject to
|
436
|
+
the following conditions:
|
437
|
+
|
438
|
+
The above copyright notice and this permission notice shall be
|
439
|
+
included in all copies or substantial portions of the Software.
|
440
|
+
|
441
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
442
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
443
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
444
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
445
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
446
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
447
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
448
|
+
|
data/Rakefile
ADDED
data/ess.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ess/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "ess"
|
8
|
+
gem.version = ESS::VERSION
|
9
|
+
gem.authors = ["Marjan Povolni","Brice Pissard"]
|
10
|
+
gem.email = ["marian.povolny@gmail.com"]
|
11
|
+
gem.description = %q{Helper classes and methods for creating ESS XML feeds with Ruby.}
|
12
|
+
gem.summary = %q{Generate ESS XML feeds with Ruby}
|
13
|
+
gem.homepage = "https://github.com/essfeed/ruby-ess"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_runtime_dependency "builder"
|
21
|
+
end
|