atomutil 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2007-12-05
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Lyo Kato
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,35 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ config/hoe.rb
7
+ config/requirements.rb
8
+ lib/atomutil.rb
9
+ log/debug.log
10
+ script/destroy
11
+ script/generate
12
+ script/txt2html
13
+ setup.rb
14
+ spec/categories_spec.rb
15
+ spec/category_spec.rb
16
+ spec/content_spec.rb
17
+ spec/customfeed_spec.rb
18
+ spec/feed_spec.rb
19
+ spec/link_spec.rb
20
+ spec/namespace_spec.rb
21
+ spec/opensearch_spec.rb
22
+ spec/person_spec.rb
23
+ spec/samples/feed.atom
24
+ spec/spec.opts
25
+ spec/spec_helper.rb
26
+ spec/threading_spec.rb
27
+ tasks/deployment.rake
28
+ tasks/environment.rake
29
+ tasks/rspec.rake
30
+ tasks/website.rake
31
+ website/index.html
32
+ website/index.txt
33
+ website/javascripts/rounded_corners_lite.inc.js
34
+ website/stylesheets/screen.css
35
+ website/template.rhtml
data/README.txt ADDED
@@ -0,0 +1,632 @@
1
+ = Utilities for AtomPub / Atom Syndication Format
2
+
3
+ = SYNOPSIS
4
+
5
+ == Building or parsing XML with Atom Syndication Format
6
+
7
+ === How To Construct Each Atom Element
8
+
9
+ Create new object and setup with each accessor.
10
+
11
+ entry = Atom::Entry.new
12
+
13
+ entry.title = 'Title!'
14
+ entry.summary = 'Summary!'
15
+ entry.published = Time.now
16
+
17
+ Or you can do that at once with passing hash parameter to constructor
18
+
19
+ entry = Atom::Entry.new(
20
+ :title => 'Title!',
21
+ :summary => 'Summary',
22
+ :published => Time.now
23
+ )
24
+
25
+ And you also can setup new element within a block if you pass one.
26
+
27
+ entry = Atom::Entry.new(:title => 'New Entry') do |e|
28
+ e.summary = 'New Summary'
29
+ author = Atom::Author.new :name => 'John'
30
+ e.author = author
31
+ e.published = Time.now
32
+ end
33
+
34
+ And finally you can get xml-document from them.
35
+
36
+ xml_string = entry.to_s
37
+
38
+ If you pass false to to_s, it returns non-indented string
39
+
40
+ xml_string = entry.to_s(false)
41
+
42
+ === How To Parse Each Atom XML Document
43
+
44
+ xml_string = <<-EOS
45
+ <?xml version="1.0" encoding="UTF-8"?>
46
+ <entry xmlns="http://www.w3.org/2005/Atom">
47
+ <id>tag:example.org,2007-12-01:mybook</id>
48
+ <title>Title</title>
49
+ <summary>Summary</summary>
50
+ <author><name>John</name></author>
51
+ </entry>
52
+ EOS
53
+
54
+ Pass the xml-string to proper Atom Element Class with :stream key
55
+
56
+ entry = Atom::Entry.new :stream => xml_string
57
+ puts entry.title # Book
58
+ puts entry.summary # Summary
59
+ puts entry.author.name # John
60
+
61
+ Atom::Feed and Atom::Entry can be build from files
62
+
63
+ entry = Atom::Feed.new :file => 'my_feed.atom'
64
+
65
+ or from uri
66
+
67
+ entry = Atom::Feed.new :uri => 'http://example.com/feed.atom'
68
+
69
+ == How To Handle other Namespace
70
+
71
+ There are times when you want to extend your atom element
72
+ with other namespaces.
73
+ For example, in case you want to deal pagination with OpenSearch
74
+
75
+ xmlstring = <<-EOS
76
+ <feed xmlns="http://www.w3.org/2005/Atom"
77
+ xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">
78
+ <openSearch:totalResult>153</openSearch:totalResult>
79
+ <openSearch:startIndex>40</openSearch:startIndex>
80
+ <openSearch:itemsPerPage>20</openSearch:itemsPerPage>
81
+ ...
82
+ </feed>
83
+ EOS
84
+
85
+ How to get these values?
86
+ The answer is using 'get' method.
87
+ And then, just a reminder, you have to prepare Atom::Namespace object.
88
+ Pass the object and element name to the method.
89
+ And it returns REXML::Element object.
90
+
91
+ feed = Atom::Feed.new :stream => xmlstring
92
+ open_search_ns = Atom::Namespace.new(
93
+ :prefix => 'openSearch',
94
+ :uri => 'http://a9.com/-/spec/opensearchrss/1.1/')
95
+
96
+ total = feed.get(open_search_ns, 'totalResult').text.to_i
97
+ start = feed.get(open_search_ns, 'startIndex').text.to_i
98
+ per_page = feed.get(open_search_ns, 'itemsPerPage').text.to_i
99
+
100
+ And of cource, you also can 'set'
101
+
102
+ feed = Atom::Feed.new
103
+ feed.title = 'my new feed'
104
+ feed.set(open_search_ns, 'totalResult', 153)
105
+ feed.set(open_search_ns, 'startIndex', 40)
106
+ feed.set(open_search_ns, 'itemsPerPage', 20)
107
+
108
+ In this example, I take the 'openSearch' for pagination, but it's already implemented with
109
+ useful methods.
110
+
111
+ feed = Atom::Feed.new
112
+ feed.total_results = 35
113
+ feed.start_index = 1
114
+ feed.items_per_page = 20
115
+
116
+ puts feed.total_results
117
+ puts feed.start_index
118
+ puts feed.items_per_page
119
+
120
+ === Build a Service Document
121
+
122
+ Create root service element
123
+
124
+ service = Atom::Service.new
125
+
126
+ Create workspace element which the service appends.
127
+
128
+ blog_workspace = Atom::Workspace.new
129
+ blog_workspace.title = 'My Blog'
130
+
131
+ collection = Atom::Collection.new
132
+ collection.href = 'http://blog.example.org/feed'
133
+ collection.title = 'Sample Blog'
134
+
135
+ Create categories that your collection handles
136
+
137
+ cats = Atom::Categories.new
138
+ cats.fixed = 'no'
139
+
140
+ You can set each concrete categories here
141
+
142
+ category1 = Atom::Category.new
143
+ category1.term = 'technology'
144
+ category2 = Atom::Category.new
145
+ category2.term = 'music'
146
+ category3 = Atom::Category.new
147
+ category3.term = 'sport'
148
+ cats.add_category category1
149
+ cats.add_category category2
150
+ cats.add_category category3
151
+
152
+ Or set only href parameter that represents uri for Categories Document,
153
+ Instead of setting each categories here.
154
+ Then you should provides Categories Document at indicated uri.
155
+
156
+ cats.href = 'http://blog.example.org/categories'
157
+
158
+ collection.add_categories cats
159
+ blog_workspace.add_collection collection
160
+ service.add_workspace blog_workspace
161
+ service_document_xml_string = service.to_s
162
+
163
+ === Build a Categories Document
164
+
165
+ cats = Atom::Categories.new
166
+ category1 = Atom::Category.new
167
+ category1.term = 'technology'
168
+ category2 = Atom::Category.new
169
+ category2.term = 'music'
170
+ category3 = Atom::Category.new
171
+ category3.term = 'sport'
172
+ cats.add_category category1
173
+ cats.add_category category2
174
+ cats.add_category category3
175
+
176
+ categories_xml_string = cats.to_s
177
+
178
+ === Build an Entry
179
+
180
+ entry = Atom::Entry.new
181
+
182
+ * id
183
+ * title
184
+ * summary
185
+ * rights
186
+ * source
187
+
188
+ Simple text accessors
189
+
190
+ entry.id = 'tag:example.org,2007:example'
191
+ entry.title = 'My First Blog Post'
192
+ entry.summary = 'This is summary'
193
+ entry.rights = 'Copyright(c) 2007 Lyo Kato all rights reserved.'
194
+
195
+ * published
196
+ * updated
197
+
198
+ You can set them with Time class
199
+
200
+ entry.published = Time.now
201
+ entry.updated = Time.now
202
+
203
+ Or you can set with W3CDTF formatted string
204
+
205
+ entry.published = "2007-12-01T01:30:00Z"
206
+
207
+ And pick it up as Time object
208
+
209
+ published = entry.published
210
+ puts published.year
211
+ puts published.month
212
+
213
+ * author
214
+ * contributor
215
+
216
+ Set person construct with Atom::Person
217
+
218
+ person = Atom::Person.new
219
+ person.name = 'Lyo Kato'
220
+ person.email = 'lyo.kato atmark gmail.com'
221
+ person.uri = 'http://www.lyokato.net/'
222
+
223
+ entry.author = person.to_author
224
+ entry.contributor = person.to_contributor
225
+
226
+ Or Atom::Author, Atom::Contributor directly
227
+
228
+ cont = Atom::Contributor.new
229
+ cont.name = 'Lyo'
230
+ cont.email = 'lyo.kato atmark gmail.com'
231
+ entry.contributor = cont
232
+
233
+ To set multiple data
234
+
235
+ entry.add_author author1
236
+ entry.add_author author2
237
+ entry.add_contributor contributor1
238
+ entry.add_contributor contributor2
239
+
240
+ Get all authors and contributors
241
+
242
+ authors = entry.authors
243
+ contributors = entry.contributors
244
+
245
+ Get only first author and contributor
246
+
247
+ author = entry.author
248
+ contributor = entry.contributor
249
+
250
+ * link
251
+
252
+ Link Element Accessor
253
+
254
+ link = Atom::Link.new
255
+ link.href = 'http://example.org/entry/1'
256
+ link.rel = 'alternate'
257
+ link.type = 'text/html'
258
+ link.hreflang = 'fr'
259
+ link.length = '512'
260
+ link.title = 'My Blog Post'
261
+ entry.link = link
262
+
263
+ You can set multiple links
264
+
265
+ entry.add_link link1
266
+ entry.add_link link2
267
+
268
+ To get all links as an Array
269
+
270
+ links = entry.links
271
+
272
+ To get first one
273
+
274
+ link = entry.link
275
+ puts link.href
276
+ puts link.rel
277
+
278
+ Further more, useful methods are implemented for major 'rel' types.
279
+
280
+ entry.alternate_link = 'http://example.org/entry/1'
281
+
282
+ This is same as
283
+
284
+ link = Atom::Link.new
285
+ link.rel = 'alternate'
286
+ link.href = 'http://example.org/entry/1'
287
+ entry.add_link link
288
+
289
+ And
290
+
291
+ puts entry.alternate_link # http://example.org/entry1
292
+
293
+ This is same as
294
+
295
+ links = entry.links
296
+ alternate_link = links.select{ |l| l.rel == 'alternate' }.first
297
+ puts alternate_link.href
298
+
299
+ If it contains multiple 'alternate' links, to get all of them,
300
+
301
+ alternate_links = links.alternate_links
302
+
303
+ Like this, you can use following methods for each links
304
+
305
+ entry.self_link:: <link rel='self' href='...'/>
306
+ entry.edit_link:: <link rel='edit' href='...'/>
307
+ entry.edit_media_link:: <link rel='edit-media' href='...'/>
308
+ entry.enclosure_link:: <link rel='enclosure' href='...'/>
309
+ entry.related_link:: <link rel='related' href='...' />
310
+ entry.via_link:: <link rel='via' href='...' />
311
+ entry.first_link:: <link rel='first' href='...'/>
312
+ entry.previous_link:: <link rel='previous' href='...'/>
313
+ entry.next_link:: <link rel='next' href='...' />
314
+ entry.last_link:: <link rel='last' href='...' />
315
+
316
+ * category
317
+
318
+ Category Element Accessor
319
+
320
+ category = Atom::Category.new
321
+ category.term = 'music'
322
+ category.scheme = 'http://example.org/category/music'
323
+ category.label = 'My Music'
324
+ entry.category = category
325
+
326
+ You can set multiple categories
327
+
328
+ entry.add_category cat1
329
+ entry.add_category cat2
330
+
331
+ To get all categories as an Array
332
+
333
+ categories = entry.categories
334
+
335
+ To get first one
336
+
337
+ first_category = entry.category
338
+ puts first_category.term
339
+ puts first_category.scheme
340
+
341
+ * content
342
+
343
+ You can push it as a text
344
+
345
+ entry.content = 'This is a content'
346
+
347
+ Or an Atom::Content object
348
+
349
+ content = Atom::Content.new :body => 'This is a content'
350
+ entry.content = content
351
+
352
+ To pick it up
353
+
354
+ content = entry.content
355
+
356
+ puts content.type
357
+ puts content.body
358
+
359
+ * control
360
+
361
+ Control Element Accessor
362
+
363
+ control = Atom::Control.new
364
+ control.draft = 'yes'
365
+ entry.control = control
366
+
367
+ Then entry includes
368
+
369
+ <app:control xmlns:app='http://www.w3.org/2007/app'>
370
+ <app:draft>yes</app:draft>
371
+ </app:control>
372
+
373
+ * edited
374
+
375
+ Represents what time this entry was edited.
376
+
377
+ entry.edited = Time.now
378
+
379
+ Then entry includes
380
+
381
+ <app:edited>2007-09-01T00:00:00Z</app:edited>
382
+
383
+ To pick it up
384
+
385
+ edited = entry.edited
386
+ puts edited.year
387
+ puts edited.month
388
+
389
+ You also can handle Atom-Threading
390
+ (http://tools.ietf.org/html/rfc4685)
391
+
392
+ target = Atom::ReplyTarget.new
393
+ target.id = 'tag:example.org,2007:12:example'
394
+ target.href = 'http://example.org/blog/2007/12/archive01'
395
+ target.type = 'text/xhtml'
396
+
397
+ entry.in_reply_to target
398
+
399
+ Or you can set the target direclty with hash
400
+
401
+ entry.in_reply_to(
402
+ :id => 'tag:example.org,2007:12:example',
403
+ :href => 'http://example.org/blog/2007/12/archive01',
404
+ :type => 'text/xhtml'
405
+ )
406
+
407
+ And then entry includes xml
408
+
409
+ <thr:in-reply-to xmlns:thr='http://purl.org/syndication/thread/1.0'
410
+ ref='tag:example.org,2007:12:example'
411
+ href='http://example.org/blog/2007/12/archive01'
412
+ type='text/xhtml'/>
413
+
414
+ Pick it up from entry
415
+
416
+ target = entry.in_reply_to
417
+ puts target.id
418
+ puts target.href
419
+ puts target.type
420
+
421
+ Add a replies link
422
+
423
+ link = Atom::RepliesLink.new
424
+ link.href = 'http://example.org/entry/1/replies'
425
+ link.count = 10
426
+ link.updated = Time.now
427
+
428
+ entry.add_link link
429
+
430
+ Then entry includes
431
+
432
+ <link rel='replies' href='http://example.org/entry/1/replies'
433
+ thr:count='10' thr:updated='2007-01-01T00:00:00Z'>
434
+
435
+ Add total replies count
436
+
437
+ entry.total = 10
438
+
439
+ Then entry includes
440
+
441
+ <thr:total>10</thr:total>
442
+
443
+ === Build a Feed
444
+
445
+ feed = Atom::Feed.new
446
+
447
+ * id
448
+ * title
449
+ * subtitle
450
+ * rights
451
+ * icon
452
+ * logo
453
+ * language
454
+ * version
455
+
456
+ Simple text accessors
457
+
458
+ feed.id = 'tag:example.org,2007:example'
459
+ feed.title = 'Example Feed'
460
+ feed.subtitle = 'Subtitle of Example Feed'
461
+ feed.rights = 'Copyright(c) 2007 example.org all rights reserved'
462
+ feed.icon = 'http://example.org/icon.png'
463
+ feed.logo = 'http://example.org/logo.png'
464
+ feed.language = 'fr'
465
+ feed.version = '1.0'
466
+
467
+ * updated
468
+
469
+ Time accessor
470
+
471
+ feed.updated = Time.now
472
+ updated = feed.updated
473
+ puts updated.year
474
+ puts updated.month
475
+
476
+ * generator
477
+
478
+ You can set generator information
479
+
480
+ feed.generator = 'MyGenerator'
481
+
482
+ Or more in detail
483
+
484
+ generator = Atom::Generator.new(
485
+ :name => 'MyGenerator',
486
+ :uri => 'http://example.org/mygenerator',
487
+ :version => '1.0'
488
+ )
489
+ feed.generator = generator
490
+
491
+ generator = feed.generator
492
+ puts generator.name
493
+ puts generator.uri
494
+ puts generator.version
495
+
496
+ * link
497
+
498
+ You can set links like you do with entry
499
+
500
+ link1 = Atom::Link.new :href => 'http://example.org/entry/1', :rel => 'alternate'
501
+ feed.add_link link1
502
+
503
+ feed.edit_link = 'http://example.org/entry/1/edit'
504
+
505
+ * category
506
+
507
+ You can set categoryes like you do with entry
508
+
509
+ * author
510
+ * contributor
511
+
512
+ Person construct data.
513
+ You can set authors/contributors on same way for entry.
514
+
515
+ * entry
516
+
517
+ Entry Accessors
518
+
519
+ entry1 = Atom::Entry.new
520
+ entry1.title = 'Entry1'
521
+
522
+ entry2 = Atom::Entry.new
523
+ entry2.title = 'Entry2'
524
+
525
+ feed.add_entry entry1
526
+ feed.add_entry entry2
527
+
528
+ entries = feed.entries
529
+
530
+ OpenSeach Pagination Control
531
+
532
+ feed.total_results = 35
533
+ feed.items_per_page = 10
534
+ feed.start_index = 11
535
+
536
+ Then feed includes
537
+
538
+ <openSearch:totalResults>35</openSearch:totalResults>
539
+ <openSearch:itemsPerPage>10</openSearch:itemsPerPage>
540
+ <openSearch:startIndex>11</openSearch:startIndex>
541
+
542
+ == Using service that provides AtomPub API
543
+
544
+ At first, construct appropriate authorizer
545
+ At this time, let's assume that we're requried WSSE Authentication.
546
+ Of cource, you can choose other authorizer,
547
+ for example, Atom::Auth::Basic(Basic authentication),
548
+ and in future, Atom::Auth::OAuth, Atom::Auth::OpenID, and etc.
549
+
550
+ auth = Atompub::Auth::Wsse.new :username => 'myname', :password => 'mypass'
551
+
552
+ client = Atompub::Client.new :auth => auth
553
+
554
+ service = client.get_service( 'http://example/service/api/endpoint' )
555
+ collection = service.workspaces.first.collection.first
556
+ categories = client.get_categories( collection.categories.href )
557
+
558
+ categories.categories.each do |category|
559
+ puts category.label
560
+ puts category.scheme
561
+ puts category.term
562
+ end
563
+
564
+ feed = client.get_feed( collection.href )
565
+
566
+ puts feed.title # 'Example Feed'
567
+ puts feed.icon # http://example/icon.jpg
568
+ puts feed.logo # http://example/logo.jpg
569
+
570
+ entries = feed.entries
571
+ entries.each do |entry|
572
+ puts entry.id
573
+ puts entry.title
574
+ end
575
+
576
+ entry = entries.first
577
+ entry.title = 'Changed!'
578
+
579
+ client.update_entry( entry.edit_link, entry )
580
+
581
+ client.delete_entry( entries[2].edit_link )
582
+
583
+ new_entry = Atom::Entry.new
584
+ new_entry.title = 'New!'
585
+ new_entry.summary = 'New Entry for Example'
586
+ new_entry.published = Time.now
587
+
588
+ edit_uri = client.create_entry( collection.href, new_entry )
589
+
590
+ # you also can use 'slug'
591
+ slug = 'new-entry'
592
+ edit_uri = client.create_entry( collection.href, new_entry, slug )
593
+
594
+ media_collection = service.workspaces.first.collections[1]
595
+ media_collection_uri = media_collection.href
596
+
597
+ media_uri = client.create_media( media_collection_uri, '', 'image/jpeg')
598
+ # with slug
599
+ # client.create_media( media_collection_uri, 'foo.jpg', 'image/jpeg', 'new-image')
600
+
601
+ media_entry = client.get_entry( media_uri )
602
+ edit_media_link = media_entry.edit_media_link
603
+ client.update_media( edit_media_link, 'bar.jpg', 'image/jpeg' )
604
+ client.delete_media( edit_media_link )
605
+
606
+ feed_contains_media_entreis = client.get_feed( media_collection_uri )
607
+
608
+ = DESCRIPTION
609
+
610
+ This library allows you to handle AtomPub and Atom Syndication Format easily.
611
+ Most of the idea is from great Perl modules on CPAN.
612
+
613
+ = TO DO
614
+
615
+ * More document
616
+ * More tests (RSpec)
617
+ * Encoding control
618
+ * New Auth classes Atompub::Auth::OpenID and Atompub::Auth::OAuth
619
+
620
+ = SEE ALSO
621
+
622
+ AtomPub Spec(RFC):: http://atompub.org/rfc4287.html
623
+ Atom::XML(Perl):: http://search.cpan.org/perldoc?XML%3A%3AAtom
624
+ Atom::XML::Service(Perl):: http://search.cpan.org/perldoc?XML%3A%3AAtom%3A%3AService
625
+ Atompub(Perl):: http://search.cpan.org/perldoc?Atompub
626
+
627
+ = Author and License
628
+
629
+ Author:: Lyo Kato (lyo.kato atmark gmail.com)
630
+ Copyright:: Copyright (c) 2007, Lyo Kato All rights reserved.
631
+ License:: Ruby License
632
+
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }