atom-tools 1.0.0 → 2.0.0

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.
metadata CHANGED
@@ -1,39 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
4
2
  name: atom-tools
5
3
  version: !ruby/object:Gem::Version
6
- version: 1.0.0
7
- date: 2007-11-10 00:00:00 -07:00
8
- summary: Tools for working with Atom Entries, Feeds and Collections
9
- require_paths:
10
- - lib
11
- email:
12
- homepage:
13
- rubyforge_project:
14
- description:
15
- autorequire:
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 2.0.0
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Brendan Taylor
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-03-28 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email:
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
31
24
  files:
32
25
  - COPYING
33
26
  - README
34
27
  - Rakefile
35
28
  - setup.rb
36
- - bin/atom-client.rb
29
+ - bin/atom-grep
30
+ - bin/atom-post
31
+ - bin/atom-purge
32
+ - bin/atom-cp
37
33
  - test/test_constructs.rb
38
34
  - test/runtests.rb
39
35
  - test/test_feed.rb
@@ -48,26 +44,40 @@ files:
48
44
  - test/test_http.rb
49
45
  - test/test_general.rb
50
46
  - lib/atom
51
- - lib/atom/yaml.rb
47
+ - lib/atom/cache.rb
52
48
  - lib/atom/feed.rb
53
49
  - lib/atom/text.rb
54
50
  - lib/atom/collection.rb
55
51
  - lib/atom/service.rb
56
52
  - lib/atom/entry.rb
57
- - lib/atom/xml.rb
53
+ - lib/atom/tools.rb
58
54
  - lib/atom/element.rb
59
55
  - lib/atom/http.rb
60
- test_files:
61
- - test/runtests.rb
56
+ has_rdoc: true
57
+ homepage:
58
+ post_install_message:
62
59
  rdoc_options: []
63
60
 
64
- extra_rdoc_files:
65
- - README
66
- executables: []
67
-
68
- extensions: []
69
-
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
70
75
  requirements: []
71
76
 
72
- dependencies: []
73
-
77
+ rubyforge_project:
78
+ rubygems_version: 1.0.1
79
+ signing_key:
80
+ specification_version: 2
81
+ summary: Tools for working with Atom Entries, Feeds and Collections
82
+ test_files:
83
+ - test/runtests.rb
data/bin/atom-client.rb DELETED
@@ -1,275 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- require "optparse"
4
-
5
- options = {}
6
-
7
- OptionParser.new do |opts|
8
- opts.banner = "Usage: #{$0} [options]"
9
-
10
- opts.on("-c", "--coll-url [URL]", "URL of the collection you would like to manipulate") do |url|
11
- options[:url] = url
12
- end
13
-
14
- opts.on("-u", "--user [USERNAME]", "Username to authenticate with") do |user|
15
- options[:user] = user
16
- end
17
-
18
- opts.on("-p", "--password [PASSWORD]", "Password to authenticate with") do |pass|
19
- options[:pass] = pass
20
- end
21
-
22
- opts.on_tail("-h", "--help", "Show this message") do
23
- puts opts
24
- exit
25
- end
26
- end.parse!
27
-
28
- require "tempfile"
29
-
30
- require "atom/yaml"
31
- require "atom/service"
32
- require "atom/http"
33
-
34
- require "rubygems"
35
- require "bluecloth"
36
-
37
- require "time"
38
-
39
- require 'yaml'
40
-
41
- class Tempfile
42
- def edit_externally
43
- self.close
44
-
45
- system("#{EDITOR} #{self.path}")
46
-
47
- self.open
48
- end
49
- end
50
-
51
- class String
52
- def edit_externally
53
- tempfile = Tempfile.new("entry")
54
- tempfile.puts self
55
-
56
- tempfile.edit_externally
57
-
58
- ret = tempfile.read
59
- tempfile.delete
60
-
61
- ret
62
- end
63
- end
64
-
65
- class Atom::Entry
66
- def prepare_for_output
67
- filter_hook
68
-
69
- updated!
70
- end
71
-
72
- def filter_hook
73
- # so much for actual text content...
74
- if @content and @content["type"] == "text"
75
- self.content = BlueCloth.new( @content.to_s ).to_html
76
- @content["type"] = "xhtml"
77
- end
78
- end
79
-
80
- def edit
81
- yaml = YAML.load(self.to_yaml)
82
-
83
- # human readability
84
- yaml.delete "id"
85
-
86
- if yaml["links"]
87
- yaml["links"].find_all { |l| l["rel"] == "alternate" or l["rel"] == "edit" }.each { |l| yaml["links"].delete(l) }
88
- yaml.delete("links") if yaml["links"].empty?
89
- end
90
-
91
- new_yaml, entry = write_entry(yaml.to_yaml)
92
-
93
- entry.id = self.id
94
-
95
- [new_yaml["slug"], entry]
96
- end
97
- end
98
-
99
- # maybe this should handle displaying the list too.
100
- def choose_from list
101
- item = nil
102
- itemno = nil
103
-
104
- # oh wow this is pathetic
105
- until item
106
- if itemno
107
- puts "try picking a number on the list."
108
- end
109
-
110
- print "? "
111
- itemno = $stdin.gets.chomp
112
-
113
- item = list[itemno.to_i]
114
- end
115
-
116
- item
117
- end
118
-
119
- def choose_entry_url coll
120
- puts "which entry?"
121
-
122
- coll.entries.each_with_index do |entry, index|
123
- puts "#{index}: #{entry.title}"
124
- end
125
-
126
- entry = choose_from coll.entries
127
-
128
- edit_link = entry.links.find do |link|
129
- link["rel"] = "edit"
130
- end
131
-
132
- edit_link["href"]
133
- end
134
-
135
- def write_entry(editstring = "")
136
- begin
137
- edited = editstring.edit_externally
138
-
139
- if edited == editstring
140
- puts "You didn't edit anything, aborting."
141
- exit
142
- end
143
-
144
- yaml = YAML.load(edited)
145
-
146
- entry = Atom::Entry.from_yaml yaml
147
-
148
- entry.prepare_for_output
149
-
150
- # XXX disabled until the APP WG can decide what a valid entry is
151
- =begin
152
- valid, message = entry.valid?
153
- unless valid
154
- print "entry is invalid (#{message}). post anyway? (y/n)? "
155
- (gets.chomp == "y") || (raise Atom::InvalidEntry.new)
156
- end
157
- =end
158
-
159
- # this has to be here ATM to we can detect malformed atom:content
160
- puts entry.to_s
161
- rescue ArgumentError,REXML::ParseException => e
162
- puts e
163
-
164
- puts "press enter to edit again..."
165
- $stdin.gets
166
-
167
- editstring = edited
168
-
169
- retry
170
- rescue Atom::InvalidEntry
171
- editstring = edited
172
- retry
173
- end
174
-
175
- [yaml, entry]
176
- end
177
-
178
- module Atom
179
- class InvalidEntry < RuntimeError; end
180
- end
181
-
182
- EDITOR = ENV["EDITOR"] || "env vim"
183
-
184
- http = Atom::HTTP.new
185
-
186
- url = if options[:url]
187
- options[:url]
188
- else
189
- yaml = YAML.load(File.read("#{ENV["HOME"]}/.atom-client"))
190
- collections = yaml["collections"]
191
-
192
- puts "which collection?"
193
-
194
- collections.keys.each_with_index do |name,index|
195
- puts "#{index}: #{name}"
196
- end
197
-
198
- tmp = choose_from collections.values
199
-
200
- http.user = tmp["user"] if tmp["user"]
201
- http.pass = tmp["pass"] if tmp["pass"]
202
-
203
- tmp["url"]
204
- end
205
-
206
- http.user = options[:user] if options[:user]
207
- http.pass = options[:pass] if options[:pass]
208
-
209
- # this is where all the Atom stuff starts
210
-
211
- coll = Atom::Collection.new(url, http)
212
-
213
- # XXX generate a real id
214
- CLIENT_ID = "http://necronomicorp.com/nil"
215
-
216
- new = lambda do
217
- entry = Atom::Entry.new
218
-
219
- entry.title = ""
220
- entry.content = ""
221
-
222
- slug, entry = entry.edit
223
-
224
- entry.id = CLIENT_ID
225
- entry.published = Time.now.iso8601
226
-
227
- res = coll.post! entry, slug
228
-
229
- # XXX error recovery here, lost updates suck
230
- puts res.body
231
- end
232
-
233
- edit = lambda do
234
- coll.update!
235
-
236
- coll.entries.each_with_index do |entry,idx|
237
- puts "#{idx}: #{entry.title}"
238
- end
239
-
240
- entry = choose_from(coll.entries) { |entry| entry.title }
241
-
242
- url = entry.edit_url
243
-
244
- raise "this entry has no edit link" unless url
245
-
246
- entry = http.get_atom_entry url
247
-
248
- slug, new_entry = entry.edit
249
-
250
- res = coll.put! new_entry, url
251
-
252
- # XXX error recovery here, lost updates suck
253
- puts res.body
254
- end
255
-
256
- delete = lambda do
257
- coll.update!
258
-
259
- coll.entries.each_with_index do |entry,idx|
260
- puts "#{idx} #{entry.title}"
261
- end
262
-
263
- entry = choose_from(coll.entries)
264
- res = coll.delete! entry
265
-
266
- puts res.body
267
- end
268
-
269
- actions = [ new, edit, delete ]
270
-
271
- puts "0: new entry"
272
- puts "1: edit entry"
273
- puts "2: delete entry"
274
-
275
- choose_from(actions).call
data/lib/atom/xml.rb DELETED
@@ -1,213 +0,0 @@
1
- require "atom/entry"
2
- require "atom/feed"
3
- require "uri"
4
-
5
- class Atom::ParseError < StandardError; end
6
-
7
- # Two big, interrelated problems:
8
- #
9
- # * I probably shouldn't be playing around in REXML's namespace
10
- # * REXML isn't a great parser, and other options would be nice
11
- #
12
- # This shouldn't be hard to do, it's just tedious and non-critical
13
- module REXML # :nodoc: all
14
- class Document
15
- def to_atom_entry base = ""
16
- raise Atom::ParseError unless self.root
17
- self.root.to_atom_entry base
18
- end
19
- def to_atom_feed base = ""
20
- raise Atom::ParseError unless self.root
21
- self.root.to_atom_feed base
22
- end
23
- end
24
- class Element
25
- def get_atom_element name
26
- XPath.first(self, "./atom:#{name}", { "atom" => Atom::NS })
27
- end
28
-
29
- def each_atom_element name
30
- XPath.each(self, "./atom:#{name}", { "atom" => Atom::NS }) do |elem|
31
- yield elem
32
- end
33
- end
34
-
35
- def copy_extensions(coll)
36
- # XXX also look for attributes
37
- children.find_all do |child|
38
- child.respond_to? :namespace and child.namespace != Atom::NS
39
- end.each do |elem|
40
- e = elem.dup
41
-
42
- # because namespaces might be defined on parents
43
- unless e.prefix.empty?
44
- e.add_namespace e.prefix, e.namespace
45
- end
46
-
47
- coll << e
48
- end
49
- end
50
-
51
- # get the text content of a descendant element in the Atom namespace
52
- def get_atom_text name
53
- elem = get_atom_element name
54
- if elem
55
- elem.text
56
- else
57
- nil
58
- end
59
- end
60
-
61
- # a workaround for the odd way in which REXML handles namespaces
62
- # returns the value of the attribute +name+ that's in the same namespace as this element
63
- def ns_attr name
64
- if not self.prefix.empty?
65
- attr = self.prefix + ":" + name
66
- else
67
- attr = name
68
- end
69
-
70
- self.attributes[attr]
71
- end
72
-
73
- def fill_text_construct(entry, name)
74
- text = get_atom_element(name)
75
- if text
76
- type = text.ns_attr("type")
77
- src = text.ns_attr("src")
78
-
79
- if src and name == :content
80
- # the only content is out of line
81
- entry.send( "#{name}=".to_sym, "")
82
- entry.send(name.to_sym)["src"] = src
83
- elsif type == "xhtml"
84
- div = XPath.first(text, "./xhtml:div", { "xhtml" => XHTML::NS })
85
- unless div
86
- raise Atom::ParseError, "Refusing to parse type='xhtml' with no <div/> wrapper"
87
- end
88
-
89
- # content is the serialized content of the <div> wrapper
90
- entry.send( "#{name}=".to_sym, div )
91
- else
92
- raw = text.text || ""
93
- entry.send( "#{name}=", raw )
94
- end
95
-
96
- if text.attributes["xml:base"]
97
- entry.send(name.to_sym).base = text.attributes["xml:base"]
98
- end
99
-
100
- if type and type != "text"
101
- entry.send(name.to_sym)["type"] = type
102
- end
103
- end
104
- end
105
-
106
- def fill_elem_element(top, kind)
107
- each_atom_element(kind) do |elem|
108
- person = top.send("#{kind}s".to_sym).new
109
-
110
- ["name", "uri", "email"].each do |name|
111
- person.send("#{name}=".to_sym, elem.get_atom_text(name))
112
- end
113
- end
114
- end
115
-
116
- def fill_attr_element(top, array, kind)
117
- each_atom_element(kind) do |elem|
118
- thing = array.new
119
-
120
- thing.class.attrs.each do |name,req|
121
- value = elem.ns_attr name.to_s
122
- if value and name == :href
123
- begin
124
- thing[name.to_s] = (top.base.to_uri + value).to_s
125
- rescue URI::BadURIError
126
- raise "Document contains relative URIs and no xml:base. You must pass a base URI to #parse()"
127
- end
128
- elsif value
129
- thing[name.to_s] = value
130
- end
131
- end
132
- end
133
- end
134
-
135
- # 'base' is the URI that you fetched this document from.
136
- def to_atom_entry base = ""
137
- unless self.name == "entry" and self.namespace == Atom::NS
138
- raise Atom::ParseError, "this isn't an atom:entry! (name: #{self.name}, ns: #{self.namespace})"
139
- end
140
-
141
- entry = Atom::Entry.new
142
-
143
- entry.base = if attributes["xml:base"]
144
- (URI.parse(base) + attributes["xml:base"]).to_s
145
- else
146
- # go with the URL we were passed in
147
- base
148
- end
149
-
150
- # Text constructs
151
- entry.class.elements.find_all { |n,k,r| k.ancestors.member? Atom::Text }.each do |n,k,r|
152
- fill_text_construct(entry, n)
153
- end
154
-
155
- ["id", "published", "updated"].each do |name|
156
- entry.send("#{name}=".to_sym, get_atom_text(name))
157
- end
158
-
159
- ["author", "contributor"].each do |type|
160
- fill_elem_element(entry, type)
161
- end
162
-
163
- {"link" => entry.links, "category" => entry.categories}.each do |k,v|
164
- fill_attr_element(entry, v, k)
165
- end
166
-
167
- copy_extensions(entry.extensions)
168
-
169
- entry
170
- end
171
-
172
- # 'base' is the URI that you fetched this document from.
173
- def to_atom_feed base = ""
174
- unless self.name == "feed" and self.namespace == Atom::NS
175
- raise Atom::ParseError, "this isn't an atom:feed! (name: #{self.name}, ns: #{self.namespace})"
176
- end
177
-
178
- feed = Atom::Feed.new
179
-
180
- feed.base = if attributes["xml:base"]
181
- (URI.parse(base) + attributes["xml:base"]).to_s
182
- else
183
- # go with the URL we were passed in
184
- base
185
- end
186
-
187
- # Text constructs
188
- feed.class.elements.find_all { |n,k,r| k.ancestors.member? Atom::Text }.each do |n,k,r|
189
- fill_text_construct(feed, n)
190
- end
191
-
192
- ["id", "updated", "generator", "icon", "logo"].each do |name|
193
- feed.send("#{name}=".to_sym, get_atom_text(name))
194
- end
195
-
196
- ["author", "contributor"].each do |type|
197
- fill_elem_element(feed, type)
198
- end
199
-
200
- {"link" => feed.links, "category" => feed.categories}.each do |k,v|
201
- fill_attr_element(feed, v, k)
202
- end
203
-
204
- each_atom_element("entry") do |elem|
205
- feed << elem.to_atom_entry(feed.base)
206
- end
207
-
208
- copy_extensions(feed.extensions)
209
-
210
- feed
211
- end
212
- end
213
- end