placemaker 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -0
- data/Gemfile.lock +14 -0
- data/LICENSE +20 -0
- data/README.rdoc +76 -0
- data/Rakefile +28 -0
- data/lib/placemaker/client.rb +75 -0
- data/lib/placemaker/coordinates.rb +13 -0
- data/lib/placemaker/document.rb +44 -0
- data/lib/placemaker/extents.rb +25 -0
- data/lib/placemaker/location.rb +35 -0
- data/lib/placemaker/place_details.rb +28 -0
- data/lib/placemaker/reference.rb +34 -0
- data/lib/placemaker/xml_helper.rb +14 -0
- data/lib/placemaker/xml_parser.rb +33 -0
- data/lib/placemaker.rb +9 -0
- data/spec/fixtures/xml_rss_feed_result.xml +636 -0
- data/spec/placemaker/client_spec.rb +48 -0
- data/spec/placemaker/coordinates_spec.rb +14 -0
- data/spec/placemaker/document_spec.rb +51 -0
- data/spec/placemaker/extents_spec.rb +56 -0
- data/spec/placemaker/location_spec.rb +44 -0
- data/spec/placemaker/place_details_spec.rb +28 -0
- data/spec/placemaker/reference_spec.rb +40 -0
- data/spec/placemaker/xml_parser_spec.rb +36 -0
- data/spec/spec_helper.rb +14 -0
- metadata +130 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Justin S. Leitgeb
|
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/README.rdoc
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
= Description
|
2
|
+
|
3
|
+
Yahoo! Placemaker is a freely available geoparsing Web service. It helps developers make their applications location-aware by
|
4
|
+
identifying places in unstructured and atomic content - feeds, web pages, news, status updates - and returning geographic metadata
|
5
|
+
for geographic indexing and markup.
|
6
|
+
|
7
|
+
This library is a Ruby interface for accessing the {Yahoo PlaceMaker API}[http://developer.yahoo.com/geo/placemaker/].
|
8
|
+
|
9
|
+
= Installation
|
10
|
+
|
11
|
+
Assuming that you've set up your ruby environment to pull gems from GitHub
|
12
|
+
(see {the GitHub instructions if you haven't yet done this}[http://gems.github.com]),
|
13
|
+
install placemaker with the following command:
|
14
|
+
|
15
|
+
sudo gem install jsl-placemaker
|
16
|
+
|
17
|
+
= Usage
|
18
|
+
|
19
|
+
The following is an example of using the Placemaker gem to read places in a standard feed. You'll have to get a Yahoo App ID first if you haven't
|
20
|
+
already done so.
|
21
|
+
|
22
|
+
require 'placemaker'
|
23
|
+
p = Placemaker::Client.new(:appid => YOUR_APP_ID, :document_url => 'http://feeds.feedburner.com/wooster', :document_type => 'text/xml')
|
24
|
+
p.fetch!
|
25
|
+
|
26
|
+
This will make a call to the Placemaker service and populate the Placemaker::Client object with data about the places in the content that you
|
27
|
+
sent to Yahoo. The information that you'll be interested in may be divided into "documents" and "meta-data."
|
28
|
+
|
29
|
+
You can also use placemaker with a document that you upload. Use +document_content+ in the configuration options instead of +document_url+, and
|
30
|
+
make sure to set the appropriate value for +document_type+. Acceptable mime types are text/plain, text/html, text/xml, text/rss, application/xml,
|
31
|
+
and application/rss+xml. The following is an example of using jsl-placemaker to encode content that you upload:
|
32
|
+
|
33
|
+
p = Placemaker::Client.new(:appid => YOUR_APP_ID, :document_content => 'railsconf was in las vegas this year', :document_type => 'text/plain')
|
34
|
+
p.fetch!
|
35
|
+
|
36
|
+
Afterwards, you have access to the same Placemaker::Client methods as if you had pointed placemaker to a +document_url+.
|
37
|
+
|
38
|
+
== Documents
|
39
|
+
|
40
|
+
Once you've run the +fetch!+ method on the Placemaker::Client, you may invoke the method +documents+ which will return a set of Placemaker::Document
|
41
|
+
objects corresponding to each of the entries in the feed given to the placemaker service. For example, if you gave a +document_url+ pointing
|
42
|
+
to a feed containing 15 entries, there will be 15 documents in the resulting client object.
|
43
|
+
|
44
|
+
The following are methods that you may invoke on each of the Placemaker::Document objects to find out more about the place information that
|
45
|
+
Yahoo was able to glean from the input document:
|
46
|
+
|
47
|
+
* place_details - Returns a Placemaker::Location object that is a container for one named place mentioned in the document
|
48
|
+
* administrative_scope - Returns a Placemaker::Location object that is a container for the smallest administrative place that best describes the document
|
49
|
+
* geographic_scope - Returns a Placemaker::Location object that is a container for the smallest place that best describes the document
|
50
|
+
* extents - Returns a Placemaker::Extents object that is a container for the the map extents covering the places mentioned in the document
|
51
|
+
|
52
|
+
Below is a summary of the methods that these objects respond to. You may wish to browse the Placemaker rdoc files for these classes to see
|
53
|
+
for more details.
|
54
|
+
|
55
|
+
=== Placemaker::Location
|
56
|
+
|
57
|
+
Placemaker::Location objects contain a woe_id, name, location_type and centroid.
|
58
|
+
|
59
|
+
* woe_id - permanent identifier for the place
|
60
|
+
* name - fully qualified name for the place
|
61
|
+
* location_type - type name for the place
|
62
|
+
* centroid - centroid for the place, responds to +lat+ and +lng+
|
63
|
+
|
64
|
+
=== Placemaker::Extents
|
65
|
+
|
66
|
+
Placemaker::Extents are bounding boxes for an area of interest. They respond to methods for +center+, +south_west+ and +north_east+. In
|
67
|
+
all of these cases, they return a Placemaker::Coordinates object responding to +lat+ and +lng+.
|
68
|
+
|
69
|
+
== Meta-data
|
70
|
+
|
71
|
+
The request to the Yahoo place coding service returns information about the request. You may invoke the methods +processing_time+,
|
72
|
+
+version+, and +document_length+ to find out more about the request.
|
73
|
+
|
74
|
+
= Author
|
75
|
+
|
76
|
+
Justin S. Leitgeb, justin@phq.org
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
|
8
|
+
require 'lib/placemaker'
|
9
|
+
|
10
|
+
desc 'Test the plugin.'
|
11
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
12
|
+
t.spec_opts = ["--format", "progress", "--colour"]
|
13
|
+
t.libs << 'lib'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run all the tests"
|
18
|
+
task :default => :spec
|
19
|
+
|
20
|
+
desc 'Generate documentation'
|
21
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
22
|
+
rdoc.rdoc_dir = 'rdoc'
|
23
|
+
rdoc.title = 'Placemaker'
|
24
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
25
|
+
rdoc.rdoc_files.include('README.rdoc')
|
26
|
+
rdoc.rdoc_files.include('lib/placemaker/**/*.rb')
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'placemaker/xml_parser'
|
2
|
+
|
3
|
+
module Placemaker
|
4
|
+
|
5
|
+
# Main interface to the Placemaker API.
|
6
|
+
class Client
|
7
|
+
POST_FIELDS = %w[ appid document_content document_url document_type document_title
|
8
|
+
auto_disambiguate focus_woe_id input_language output_type ].map{|f| f.to_sym}
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options
|
12
|
+
@options[:appid] ||= ENV['PLACEMAKER_APPID']
|
13
|
+
|
14
|
+
@xml_parser = Placemaker::XmlParser.new('NODOC')
|
15
|
+
|
16
|
+
verify_content_set
|
17
|
+
verify_document_type_set
|
18
|
+
end
|
19
|
+
|
20
|
+
# Fetches the place information for input parameters from the Yahoo Placemaker service
|
21
|
+
def fetch!
|
22
|
+
fields = POST_FIELDS.reject{|f| @options[f].nil? }.map do |f|
|
23
|
+
# Change ruby-form fields to url type, e.g., document_content => documentContent
|
24
|
+
cgi_param = f.to_s.gsub(/\_(.)/) {|s| s.upcase}.gsub('_', '').sub(/url/i, 'URL')
|
25
|
+
Curl::PostField.content(cgi_param, @options[f])
|
26
|
+
end
|
27
|
+
|
28
|
+
res = Curl::Easy.http_post('http://wherein.yahooapis.com/v1/document', *fields)
|
29
|
+
@xml_parser = Placemaker::XmlParser.new(res.body_str)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a collection of Placemaker::Document items as containers for content location information
|
33
|
+
def documents
|
34
|
+
@xml_parser.documents
|
35
|
+
end
|
36
|
+
|
37
|
+
# time in seconds to process the document
|
38
|
+
def processing_time
|
39
|
+
@xml_parser.processing_time
|
40
|
+
end
|
41
|
+
|
42
|
+
# version of the software used to process the document
|
43
|
+
def version
|
44
|
+
@xml_parser.version
|
45
|
+
end
|
46
|
+
|
47
|
+
# length in bytes of the document
|
48
|
+
def document_length
|
49
|
+
@xml_parser.document_length
|
50
|
+
end
|
51
|
+
|
52
|
+
# Create convenience methods to access post fields from the @options hash, mostly for testing.
|
53
|
+
POST_FIELDS.each do |f|
|
54
|
+
define_method(f) do # def appid
|
55
|
+
@options[f] # @options[:appid]
|
56
|
+
end # end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def verify_document_type_set
|
62
|
+
valid_types = %w[
|
63
|
+
text/plain
|
64
|
+
text/html text/xml text/rss
|
65
|
+
application/xml application/rss+xml
|
66
|
+
]
|
67
|
+
|
68
|
+
raise ArgumentError, "Document type must be in #{valid_types.join(', ')}" unless valid_types.include?(@options[:document_type])
|
69
|
+
end
|
70
|
+
|
71
|
+
def verify_content_set
|
72
|
+
raise ArgumentError, "Either document_url or document_content must be set" if (@options[:document_content].nil? && @options[:document_url].nil?)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Placemaker
|
2
|
+
class Coordinates
|
3
|
+
include Placemaker::XmlHelper
|
4
|
+
|
5
|
+
def lat
|
6
|
+
@nodeset.search('.//xmlns:latitude', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').inner_text.to_f
|
7
|
+
end
|
8
|
+
|
9
|
+
def lng
|
10
|
+
@nodeset.search('.//xmlns:longitude', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').inner_text.to_f
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'placemaker/xml_helper'
|
2
|
+
require 'placemaker/place_details'
|
3
|
+
require 'placemaker/location'
|
4
|
+
require 'placemaker/extents'
|
5
|
+
require 'placemaker/reference'
|
6
|
+
|
7
|
+
module Placemaker
|
8
|
+
|
9
|
+
class Document
|
10
|
+
include Placemaker::XmlHelper
|
11
|
+
|
12
|
+
# Returns a Placemaker::Location object that is a container for one named place mentioned in the document
|
13
|
+
def place_details
|
14
|
+
@nodeset.search('.//xmlns:placeDetails', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').map do |p|
|
15
|
+
Placemaker::PlaceDetails.new(p)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a Placemaker::Location object that is a container for the smallest administrative place that best describes the document
|
20
|
+
def administrative_scope
|
21
|
+
as = @nodeset.search('.//xmlns:administrativeScope', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').first
|
22
|
+
Placemaker::Location.new(as) unless as.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns a Placemaker::Location object that is a container for the smallest place that best describes the document
|
26
|
+
def geographic_scope
|
27
|
+
gs = @nodeset.search('.//xmlns:geographicScope', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').first
|
28
|
+
Placemaker::Location.new(gs) unless gs.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a Placemaker::Extents object that is a container for the the map extents covering the places mentioned in the document
|
32
|
+
def extents
|
33
|
+
extents = @nodeset.search('.//xmlns:extents', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').first
|
34
|
+
Placemaker::Extents.new(extents) unless extents.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def reference_list
|
38
|
+
@nodeset.search('.//xmlns:referenceList[1]/xmlns:reference', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').map do |reference|
|
39
|
+
Placemaker::Reference.new(reference)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'placemaker/coordinates'
|
2
|
+
|
3
|
+
module Placemaker
|
4
|
+
|
5
|
+
# container for the the map extents covering the places mentioned in the document
|
6
|
+
class Extents
|
7
|
+
include Placemaker::XmlHelper
|
8
|
+
|
9
|
+
# coordinates of center (WGS84)
|
10
|
+
def center
|
11
|
+
Placemaker::Coordinates.new(@nodeset.search('.//xmlns:center', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema'))
|
12
|
+
end
|
13
|
+
|
14
|
+
# coordinates of southwest corner of bounding box (WGS84)
|
15
|
+
def south_west
|
16
|
+
Placemaker::Coordinates.new(@nodeset.search('.//xmlns:southWest', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema'))
|
17
|
+
end
|
18
|
+
|
19
|
+
# coordinates of northeast corner of bounding box (WGS84)
|
20
|
+
def north_east
|
21
|
+
Placemaker::Coordinates.new(@nodeset.search('.//xmlns:northEast', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema'))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'placemaker/coordinates'
|
2
|
+
|
3
|
+
module Placemaker
|
4
|
+
|
5
|
+
# Parses and contains data for +place+, +administrative scope+ and +geographic scope+ elements.
|
6
|
+
class Location
|
7
|
+
include Placemaker::XmlHelper
|
8
|
+
|
9
|
+
# permanent identifier for the place
|
10
|
+
def woe_id
|
11
|
+
nested_node('woeId').to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
# fully qualified name for the place
|
15
|
+
def name
|
16
|
+
nested_node('name')
|
17
|
+
end
|
18
|
+
|
19
|
+
# place type name for the place
|
20
|
+
def location_type
|
21
|
+
nested_node('type')
|
22
|
+
end
|
23
|
+
|
24
|
+
# centroid for the place
|
25
|
+
def centroid
|
26
|
+
Placemaker::Coordinates.new(@nodeset.search('.//xmlns:centroid', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema'))
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def nested_node(name)
|
32
|
+
@nodeset.search(".//xmlns:#{name}", 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').inner_text
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Placemaker
|
2
|
+
|
3
|
+
# container for one named place mentioned in the document
|
4
|
+
class PlaceDetails
|
5
|
+
include Placemaker::XmlHelper
|
6
|
+
|
7
|
+
# Returns a Placemaker::Location object as a container for place information.
|
8
|
+
def place
|
9
|
+
Placemaker::Location.new(@nodeset.search('.//xmlns:place', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema'))
|
10
|
+
end
|
11
|
+
|
12
|
+
# type of match (0=text or text and coordinates, 1=coordinates only)
|
13
|
+
def match_type
|
14
|
+
nested_node('matchType').to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
# relative weight of the place within the document (range 1-100)
|
18
|
+
def weight
|
19
|
+
nested_node('weight').to_i
|
20
|
+
end
|
21
|
+
|
22
|
+
# confidence that the document mentions the place (range 1-10)
|
23
|
+
def confidence
|
24
|
+
nested_node('confidence').to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Placemaker
|
2
|
+
|
3
|
+
class Reference
|
4
|
+
include Placemaker::XmlHelper
|
5
|
+
|
6
|
+
def woe_ids
|
7
|
+
nested_node('woeIds')
|
8
|
+
end
|
9
|
+
|
10
|
+
def start
|
11
|
+
nested_node('start')
|
12
|
+
end
|
13
|
+
|
14
|
+
def end
|
15
|
+
nested_node('end')
|
16
|
+
end
|
17
|
+
|
18
|
+
def is_plain_text_marker
|
19
|
+
nested_node('isPlainTextMarker')
|
20
|
+
end
|
21
|
+
|
22
|
+
def text
|
23
|
+
nested_node('text')
|
24
|
+
end
|
25
|
+
|
26
|
+
def type
|
27
|
+
nested_node('type')
|
28
|
+
end
|
29
|
+
|
30
|
+
def xpath
|
31
|
+
nested_node('xpath')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Placemaker
|
2
|
+
module XmlHelper
|
3
|
+
def initialize(nodeset)
|
4
|
+
@nodeset = nodeset
|
5
|
+
end
|
6
|
+
|
7
|
+
# Returns the inner text of a node with the given name under the current @nodeset
|
8
|
+
def nested_node(name)
|
9
|
+
@nodeset.search(".//xmlns:#{name}", 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').inner_text
|
10
|
+
end
|
11
|
+
|
12
|
+
private :nested_node
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'placemaker/document'
|
2
|
+
|
3
|
+
module Placemaker
|
4
|
+
class XmlParser
|
5
|
+
def initialize(xml_body)
|
6
|
+
@body = xml_body
|
7
|
+
@xml = Nokogiri::XML(xml_body)
|
8
|
+
end
|
9
|
+
|
10
|
+
# time in seconds to process the document
|
11
|
+
def processing_time
|
12
|
+
@xml.xpath('.//xmlns:processingTime', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').inner_text.to_f
|
13
|
+
end
|
14
|
+
|
15
|
+
# version of the software used to process the document
|
16
|
+
def version
|
17
|
+
@xml.xpath('.//xmlns:version', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').inner_text.strip
|
18
|
+
end
|
19
|
+
|
20
|
+
# length in bytes of the document
|
21
|
+
def document_length
|
22
|
+
@xml.xpath('.//xmlns:documentLength', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').inner_text.to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns a set of Placemaker::Document objects as containers for content location information
|
26
|
+
def documents
|
27
|
+
@xml.xpath('//xmlns:document', 'xmlns' => 'http://wherein.yahooapis.com/v1/schema').map do |d|
|
28
|
+
Placemaker::Document.new(d)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|