tagalus 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ === 0.5.0 / 2009-03-26
2
+
3
+ * 1st Release
4
+
5
+ * Full API access
6
+ * Swappable XML parsers
7
+
@@ -0,0 +1,7 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/tagalus.rb
6
+ lib/xmlstruct.rb
7
+ test/test_tagalus.rb
@@ -0,0 +1,65 @@
1
+ = tagalus
2
+
3
+ * http://www.carboni.ca/projects/tagalus/
4
+
5
+ == DESCRIPTION:
6
+
7
+ This module encapsulates the API for tagal.us, a site which helps users
8
+ define tags on twitter or other websites. The basic elements are tags,
9
+ definitions, and comments - and these 3 objects can be written and read
10
+ to/from tagal.us using this gem.
11
+
12
+ There's just 6 useful methods - 3 that read, and 3 that write.
13
+
14
+ This module uses the Carboni.ca XML base, which means you can set which
15
+ XML parser it will use - simply use
16
+ Tagalus.parser = :nokogiri # can be :nokogiri, :hpricot, :rexml, or :libxml
17
+ to change the parser.
18
+
19
+ == FEATURES/PROBLEMS:
20
+
21
+ * Full access to the Tagul.us API
22
+ * Swap out XML parsers - nokogiri, hpricot, rexml, and libxml-ruby are supported
23
+
24
+ == SYNOPSIS:
25
+
26
+ Exmaple usage:
27
+ acc = Tagalus::Account.new("1290185015890")
28
+ acc.define("apisandbox") #=> <Definition>
29
+ acc.comments("apisandbox").each do |comm|
30
+ puts comm.text+"\n"
31
+ end
32
+ acc.post_comment "apisandbox", "Testing, 1,2,3!" #=> <Comment>
33
+
34
+ == REQUIREMENTS:
35
+
36
+ * none, though an XML parser other than REXML will make it run quicker
37
+
38
+ == INSTALL:
39
+
40
+ * sudo gem install tagalus
41
+
42
+ == LICENSE:
43
+
44
+ (The MIT License)
45
+
46
+ Copyright (c) 2009 Michael J. Edgar
47
+
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of this software and associated documentation files (the
50
+ 'Software'), to deal in the Software without restriction, including
51
+ without limitation the rights to use, copy, modify, merge, publish,
52
+ distribute, sublicense, and/or sell copies of the Software, and to
53
+ permit persons to whom the Software is furnished to do so, subject to
54
+ the following conditions:
55
+
56
+ The above copyright notice and this permission notice shall be
57
+ included in all copies or substantial portions of the Software.
58
+
59
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
60
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
61
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
62
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
63
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
64
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
65
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/tagalus.rb'
6
+
7
+ Hoe.new('tagalus', Tagalus::VERSION) do |p|
8
+ p.rubyforge_name = 'carbonica' # if different than lowercase project name
9
+ p.developer('Michael J. Edgar', 'adgar@carboni.ca')
10
+
11
+ desc 'Post your blog announcement to blogger.'
12
+ task :post_blogger do
13
+ require 'blogger'
14
+ p.with_config do |config, path|
15
+ break unless config['blogs']
16
+ subject, title, body, urls = p.announcement
17
+
18
+ config['blogs'].each do |site|
19
+ next unless site['url'] =~ /www\.blogger\.com/
20
+ acc = Blogger::Account.new(site['user'],site['password'])
21
+ post = Blogger::Post.new(:title => title, :content => body, :categories => p.blog_categories, :formatter => :rdiscount)
22
+ acc.post(site['blog_id'], post)
23
+
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ # vim: syntax=Ruby
@@ -0,0 +1,222 @@
1
+ require 'net/http'
2
+ require 'time'
3
+ require File.dirname(__FILE__)+"/xmlstruct.rb"
4
+ # = tagalus
5
+ #
6
+ # This module encapsulates the API for tagal.us, a site which helps users
7
+ # define tags on twitter or other websites. The basic elements are tags,
8
+ # definitions, and comments - and these 3 objects can be written and read
9
+ # to/from tagal.us using this gem.
10
+ #
11
+ # There's just 6 useful methods - 3 that read, and 3 that write.
12
+ #
13
+ # Exmaple usage:
14
+ # acc = tagalus::Account.new("1290185015890")
15
+ # acc.define("apisandbox") #=> <Definition>
16
+ # acc.comments("apisandbox").each do |comm|
17
+ # puts comm.text+"\n"
18
+ # end
19
+ # acc.post_comment "apisandbox", "Testing, 1,2,3!" #=> <Comment>
20
+ #
21
+ # This module uses the Carboni.ca XML base, which means you can set which
22
+ # XML parser it will use - simply use
23
+ # tagalus.parser = :nokogiri # can be :nokogiri, :hpricot, :rexml, or :libxml
24
+ # to change the parser.
25
+ #
26
+ module Tagalus
27
+ VERSION = '0.5.0'
28
+
29
+ API_ROOT = 'api.tagal.us'
30
+
31
+ class TagalusError < StandardError; end
32
+
33
+ # The list of parsers you are allowed to use with the tagalus module.
34
+ AVAILABLE_PARSERS = [:nokogiri, :hpricot, :rexml, :libxml]
35
+ # Sets which XML parser to use. Must be in AVAILABLE_PARSERS
36
+ def self.parser=(val)
37
+ raise UnsupportedParserError.new("An unsupported parser was provided: #{val}") unless AVAILABLE_PARSERS.include? val
38
+ @@parser = val
39
+ case @@parser
40
+ when :nokogiri
41
+ require 'nokogiri'
42
+ when :hpricot
43
+ require 'hpricot'
44
+ when :rexml
45
+ require 'rexml/document'
46
+ when :libxml
47
+ require 'libxml'
48
+ end
49
+ end
50
+ Tagalus.parser = :rexml
51
+ def self.parser
52
+ @@parser
53
+ end
54
+
55
+ # = Account
56
+ #
57
+ # Encapsulates a user's account on tagal.us. Currently the tagal.us API is rather
58
+ # limited, but it is fully supported. Example usage:
59
+ #
60
+ # acc = tagalus::Account.new("1290185015890")
61
+ # acc.define("apisandbox") #=> <Definition>
62
+ # acc.post_comment "apisandbox", "Testing, 1,2,3!" #=> <Comment>
63
+ #
64
+ class Account
65
+
66
+ include CanParse
67
+
68
+ # Creates a new Account object, with API Key +key+. This key is necessary to
69
+ # create tags, definitions, and comments on the server. Read-only operations don't
70
+ # require a key.
71
+ def initialize(key="")
72
+ @api_key = key
73
+ end
74
+
75
+ # Retrieves the most authoritative definition of the tag with name or id +tag+
76
+ def define tag
77
+ path = "/tag/#{tag}/show.xml"
78
+ doc = http_get path
79
+ Definition.new(:xml => xpath(doc,"//definition").first)
80
+ end
81
+
82
+ # Retrieves all the definitions for the tag with name or id +tag+
83
+ def all_definitions tag
84
+ path = "/definition/#{tag}/show.xml"
85
+ doc = http_get path
86
+
87
+ definitions = []
88
+ xpath(doc,"//definition").each do |entry|
89
+ definitions << Definition.new(:xml => entry)
90
+ end
91
+ definitions
92
+ end
93
+
94
+ # Retrieves all the comments for the tag with name or id +tag+
95
+ def comments tag
96
+ path = "/comment/#{tag}/show.xml"
97
+ doc = http_get path
98
+
99
+ comments = []
100
+ xpath(doc, "//comment").each do |entry|
101
+ comments << Comment.new(:xml => entry)
102
+ end
103
+ comments
104
+ end
105
+
106
+ # creates a comment on tagal.us. The tag must have already been created, or an error will be
107
+ # thrown. +comment+ is a string. +tag+ can be either a tagalus::Tag, String, or Fixnum.
108
+ def post_comment tag, comment
109
+ tag_params = (tag.is_a? String) ? { :the_tag => tag } : {:tag_id => (tag.is_a? Tag) ? tag.id : tag }
110
+ tag_params.merge! :the_comment => comment
111
+ path = "/comment/create.xml"
112
+ doc = http_post path, tag_params
113
+ Comment.new(:xml => doc)
114
+ end
115
+
116
+ # defines a tag on tagal.us. The tag must have already been created, or an error will be
117
+ # thrown. +definition+ is a string. +tag+ can be either a tagalus::Tag, String, or Fixnum.
118
+ def post_definition tag, definition
119
+ tag_params = (tag.is_a? String) ? { :the_tag => tag } : {:tag_id => (tag.is_a? Tag) ? tag.id : tag }
120
+ tag_params.merge! :the_definition => definition
121
+ path = "/definition/create.xml"
122
+ doc = http_post path, tag_params
123
+ puts doc.to_s
124
+ Definition.new(:xml => doc)
125
+ end
126
+
127
+ # creates a tag on tagal.us. The tag must not have already been created, or an error will be
128
+ # thrown. +tag+ and +definition+ are both strings.
129
+ def create_tag tag, definition
130
+ tag_params = { :the_tag => tag, :the_definition => definition }
131
+ path = "/tag/create.xml"
132
+ doc = http_post path, tag_params
133
+
134
+ definition = Definition.new(:xml => xpath(doc,"//definition").first)
135
+ result = Tag.new(:xml => doc)
136
+ result.definitions = [definition]
137
+ result
138
+ end
139
+
140
+ # Helper method for retrieving URLs via GET while escaping parameters and including API-specific
141
+ # parameters
142
+ def http_get(path, query_params = {})
143
+ query_params.merge!(:api_key => @api_key, :api_version => "0001")
144
+ http = Net::HTTP.new API_ROOT
145
+ path = path + "?" + URI.escape(query_params.map {|k,v| "#{k}=#{v}"}.join("&"), /[^-_!~*'()a-zA-Z\d;\/?:@&=+$,\[\]]/n)
146
+ resp = http.get(path)
147
+ raise tagalus::tagalusError.new("Error while querying the path #{path}") if resp.body =~ /something went wrong/
148
+ xml_doc(resp.body)
149
+ end
150
+
151
+ # Helper method for retrieving URLs via POST while escaping parameters and including API-specific
152
+ # parameters
153
+ def http_post(path, query_params = {})
154
+ query_params.merge!(:api_key => @api_key, :api_version => "0001")
155
+ http = Net::HTTP.new API_ROOT
156
+ data = URI.escape(query_params.map {|k,v| "#{k}=#{v}"}.join("&"), /[^-_!~*'()a-zA-Z\d;\/?:@&=+$,\[\]]/n)
157
+ resp = http.post(path, data)
158
+ xml_doc(resp.body)
159
+ end
160
+ end
161
+
162
+ # = Tag
163
+ # Represents a tag retrieved or posted to tagal.us. Fields available:
164
+ # [:id] - the ID of the definition
165
+ # [:tag] - the name of the tag being defined
166
+ # [:updated_at] - When the comment was last updated
167
+ # [:created_at] - When the comment was initially created
168
+ class Tag < XMLStruct
169
+ attr_accessor :definitions
170
+ field :tag, :node, "//the-tag"
171
+ field :id, :node, "//id"
172
+ field :updated_at, :proc, lambda { |entry| Time.xmlschema(xml_content(xpath(entry,"//updated-at").first)) }
173
+ field :created_at, :proc, lambda { |entry| Time.xmlschema(xml_content(xpath(entry,"//created-at").first)) }
174
+ def post_initialize; @id = @id.to_i; end
175
+ end
176
+
177
+ # = Definition
178
+ # Represents a definition retrieved or posted on tagal.us. Fields available:
179
+ # [:id] - the ID of the definition
180
+ # [:meta_info] - no idea what this is, seems to always be empty
181
+ # [:tag_id] - the ID of the tag being defined
182
+ # [:text] - the text of the definition
183
+ # [:user_id] - the ID of the user posting the comment
184
+ # [:updated_at] - When the comment was last updated
185
+ # [:created_at] - When the comment was initially created
186
+ # [:authority] - The number of up-votes minus the number of down-votes.
187
+ class Definition < XMLStruct
188
+ field :text, :node, ".//the-definition"
189
+ field :tag_id, :node, ".//tag-id"
190
+ field :id, :node, ".//id"
191
+ field :authority, :node, ".//authority"
192
+ field :user_id, :node, ".//user-id"
193
+ field :meta_info, :node, ".//meta-info"
194
+ field :updated_at, :proc, lambda { |entry| Time.xmlschema(xml_content(xpath(entry,".//updated-at").first)) }
195
+ field :created_at, :proc, lambda { |entry| Time.xmlschema(xml_content(xpath(entry,".//created-at").first)) }
196
+ def post_initialize
197
+ @tag_id = @tag_id.to_i; @id = @id.to_i; @user_id = @user_id.to_i
198
+ end
199
+ end
200
+
201
+ # = Comment
202
+ # Represents a comment retrieved from tagal.us. Fields available:
203
+ # [:id] - the ID of the comment
204
+ # [:meta_info] - no idea what this is, seems to always be empty
205
+ # [:tag_id] - the ID of the tag
206
+ # [:text] - the text of the comment
207
+ # [:user_id] - the ID of the user posting the comment
208
+ # [:updated_at] - When the comment was last updated
209
+ # [:created_at] - When the comment was initially created
210
+ class Comment < XMLStruct
211
+ field :id, :node, "id"
212
+ field :meta_info, :node, "meta_info"
213
+ field :tag_id, :node, "tag-id"
214
+ field :text, :node, "the-comment"
215
+ field :user_id, :node, "user-id"
216
+ field :updated_at, :proc, lambda { |entry| Time.xmlschema(xml_content(xpath(entry,"//updated-at").first)) }
217
+ field :created_at, :proc, lambda { |entry| Time.xmlschema(xml_content(xpath(entry,"//created-at").first)) }
218
+ def post_initialize #:nodoc:
219
+ @tag_id = @tag_id.to_i; @id = @id.to_i; @user_id = @user_id.to_i
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,111 @@
1
+ # Methods for parser-agnostic parsing
2
+ module CanParse
3
+ # Helper method that encapsulates a string into an XML document
4
+ def xml_doc(body)
5
+ case Tagalus.parser
6
+ when :nokogiri
7
+ Nokogiri::XML(body)
8
+ when :hpricot
9
+ Hpricot(body)
10
+ when :rexml
11
+ REXML::Document.new(body)
12
+ when :libxml
13
+ LibXML::XML::Parser.string(body).parse
14
+ end
15
+ end
16
+
17
+ def xpath(element,path)
18
+ case Tagalus.parser
19
+ when :nokogiri
20
+ element.xpath(path)
21
+ when :hpricot
22
+ puts "in hpricot"
23
+ element/path #force the //
24
+ when :rexml
25
+ REXML::XPath.match(element,path)
26
+ when :libxml
27
+ element.find(path)
28
+ end
29
+ end
30
+
31
+ def xml_content(element)
32
+ case Tagalus.parser
33
+ when :nokogiri
34
+ element.content
35
+ when :hpricot
36
+ element.inner_text
37
+ when :rexml
38
+ element.text
39
+ when :libxml
40
+ element.content
41
+ end
42
+ end
43
+
44
+ def xml_attribute(element,attribute)
45
+ case Tagalus.parser
46
+ when :nokogiri
47
+ element[attribute]
48
+ when :hpricot
49
+ element.get_attribute(attribute)
50
+ when :rexml
51
+ element.attributes[attribute]
52
+ when :nokogiri
53
+ element.attributes[attribute]
54
+ end
55
+ end
56
+ end
57
+
58
+ # Generic XML Structure
59
+ class XMLStruct
60
+
61
+ include CanParse
62
+ extend CanParse
63
+
64
+ class << self
65
+
66
+ attr_accessor :fields
67
+
68
+ def field(name, type, getter, path="")
69
+ @fields ||= {}
70
+ if type == :attribute
71
+ @fields[name.to_sym] = {:type => type, :getter => getter, :path => path}
72
+ else
73
+ @fields[name.to_sym] = {:type => type, :getter => getter}
74
+ end
75
+ attr_accessor name
76
+
77
+ end
78
+ end
79
+
80
+ def post_initialize; end
81
+
82
+ def initialize(opts = {})
83
+ if opts[:xml]
84
+ parse_xml opts[:xml]
85
+ else
86
+ opts.each do |key, value|
87
+ instance_variable_set("@#{key}".to_sym, value)
88
+ end
89
+ end
90
+ post_initialize
91
+ self
92
+ end
93
+
94
+ def parse_xml(entry)
95
+ myfields = self.class.fields
96
+ myfields.each do |k,v|
97
+ if v[:getter].is_a?(String) || v[:getter].is_a?(Symbol)
98
+ if v[:type] == :attribute
99
+ instance_variable_set("@#{k}".to_sym, xml_attribute(xpath(entry,v[:path]).first, v[:getter].to_s))
100
+ elsif v[:type] == :node
101
+ node = xpath(entry, v[:getter].to_s).first
102
+ if node
103
+ instance_variable_set "@#{k}".to_sym, xml_content(node)
104
+ end
105
+ end
106
+ elsif v[:getter].is_a?(Proc)
107
+ instance_variable_set "@#{k}".to_sym, v[:getter].call(entry)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,8 @@
1
+ require "test/unit"
2
+ require "tagalus"
3
+
4
+ class TestTagalus < Test::Unit::TestCase
5
+ def test_sanity
6
+ flunk "write tests or I will kneecap you"
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tagalus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael J. Edgar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-27 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.11.0
24
+ version:
25
+ description: "This module encapsulates the API for tagal.us, a site which helps users define tags on twitter or other websites. The basic elements are tags, definitions, and comments - and these 3 objects can be written and read to/from tagal.us using this gem. There's just 6 useful methods - 3 that read, and 3 that write. This module uses the Carboni.ca XML base, which means you can set which XML parser it will use - simply use Tagalus.parser = :nokogiri # can be :nokogiri, :hpricot, :rexml, or :libxml to change the parser."
26
+ email:
27
+ - adgar@carboni.ca
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - History.txt
34
+ - Manifest.txt
35
+ - README.txt
36
+ files:
37
+ - History.txt
38
+ - Manifest.txt
39
+ - README.txt
40
+ - Rakefile
41
+ - lib/tagalus.rb
42
+ - lib/xmlstruct.rb
43
+ - test/test_tagalus.rb
44
+ has_rdoc: true
45
+ homepage: http://www.carboni.ca/projects/tagalus/
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --main
49
+ - README.txt
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project: carbonica
67
+ rubygems_version: 1.3.1
68
+ signing_key:
69
+ specification_version: 2
70
+ summary: This module encapsulates the API for tagal.us, a site which helps users define tags on twitter or other websites
71
+ test_files:
72
+ - test/test_tagalus.rb