fireeagle 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +0 -0
- data/License.txt +20 -0
- data/Manifest.txt +19 -0
- data/README.txt +20 -0
- data/Rakefile +123 -0
- data/lib/fireeagle.rb +65 -0
- data/lib/fireeagle/apibase.rb +6 -0
- data/lib/fireeagle/application.rb +29 -0
- data/lib/fireeagle/base.rb +89 -0
- data/lib/fireeagle/location.rb +74 -0
- data/lib/fireeagle/user.rb +39 -0
- data/lib/fireeagle/version.rb +9 -0
- data/scripts/txt2html +67 -0
- data/setup.rb +1585 -0
- data/test/test_fireeagle.rb +30 -0
- data/test/test_fireeagle_application.rb +46 -0
- data/test/test_fireeagle_location.rb +97 -0
- data/test/test_fireeagle_user.rb +103 -0
- data/test/test_helper.rb +14 -0
- metadata +80 -0
data/History.txt
ADDED
File without changes
|
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Jesse Newland
|
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,19 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
lib/fireeagle.rb
|
7
|
+
lib/fireeagle/application.rb
|
8
|
+
lib/fireeagle/apibase.rb
|
9
|
+
lib/fireeagle/base.rb
|
10
|
+
lib/fireeagle/location.rb
|
11
|
+
lib/fireeagle/user.rb
|
12
|
+
lib/fireeagle/version.rb
|
13
|
+
scripts/txt2html
|
14
|
+
setup.rb
|
15
|
+
test/test_fireeagle.rb
|
16
|
+
test/test_fireeagle_application.rb
|
17
|
+
test/test_fireeagle_location.rb
|
18
|
+
test/test_fireeagle_user.rb
|
19
|
+
test/test_helper.rb
|
data/README.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
FireEagle[http://fireeagle.research.yahoo.com/] (FE) is a system providing centralized management of user location information. FE allows 3rd party developers to update and/or access user's location data.
|
2
|
+
|
3
|
+
== Installation
|
4
|
+
|
5
|
+
gem install fireeagle
|
6
|
+
|
7
|
+
== Usage
|
8
|
+
|
9
|
+
require 'fireeagle'
|
10
|
+
f = FireEagle.new(:token => "foo", :secret => "bar")
|
11
|
+
user = FireEagle::User.new(f,"token")
|
12
|
+
l = FireEagle::Location.new(:country => "Belize")
|
13
|
+
user.location = l
|
14
|
+
user.location
|
15
|
+
=> #<FireEagle::Location:0x15ba0d0 @details={:country=>"Belize"}>
|
16
|
+
|
17
|
+
Rubyforge Project Page:: http://rubyforge.org/projects/fireeagle
|
18
|
+
Author:: Jesse Newland (http://soylentfoo.jnewland.com) (jnewland@gmail.com[mailto:jnewland@gmail.com])
|
19
|
+
Copyright:: Copyright (c) 2007 Jesse Newland
|
20
|
+
License:: Distributes under the same terms as Ruby
|
data/Rakefile
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/packagetask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'rake/rdoctask'
|
8
|
+
require 'rake/contrib/rubyforgepublisher'
|
9
|
+
require 'fileutils'
|
10
|
+
require 'hoe'
|
11
|
+
|
12
|
+
include FileUtils
|
13
|
+
require File.join(File.dirname(__FILE__), 'lib', 'fireeagle', 'version')
|
14
|
+
|
15
|
+
AUTHOR = 'Jesse Newland' # can also be an array of Authors
|
16
|
+
EMAIL = "jnewland@gmail.com"
|
17
|
+
DESCRIPTION = "Fire Eagle is a site that keeps track of your current location and helps you share it with other sites and services safely. There are hundreds of potential applications. This gem exposes the FireEagle API as Ruby Classes"
|
18
|
+
GEM_NAME = 'fireeagle' # what ppl will type to install your gem
|
19
|
+
|
20
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
21
|
+
@config = nil
|
22
|
+
def rubyforge_username
|
23
|
+
unless @config
|
24
|
+
begin
|
25
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
26
|
+
rescue
|
27
|
+
puts <<-EOS
|
28
|
+
ERROR: No rubyforge config file found: #{@config_file}"
|
29
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
30
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
31
|
+
EOS
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
end
|
35
|
+
@rubyforge_username ||= @config["username"]
|
36
|
+
end
|
37
|
+
|
38
|
+
RUBYFORGE_PROJECT = 'fireeagle' # The unix name for your project
|
39
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
40
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
41
|
+
|
42
|
+
NAME = "fireeagle"
|
43
|
+
REV = nil
|
44
|
+
# UNCOMMENT IF REQUIRED:
|
45
|
+
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
46
|
+
VERS = FireEagle::VERSION::STRING + (REV ? ".#{REV}" : "")
|
47
|
+
CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
|
48
|
+
RDOC_OPTS = ['--quiet', '--title', 'fireeagle documentation',
|
49
|
+
"--opname", "index.html",
|
50
|
+
"--line-numbers",
|
51
|
+
"--main", "README",
|
52
|
+
"--inline-source"]
|
53
|
+
|
54
|
+
class Hoe
|
55
|
+
def extra_deps
|
56
|
+
@extra_deps.reject { |x| Array(x).first == 'hoe' }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Generate all the Rake tasks
|
61
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
62
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
63
|
+
p.author = AUTHOR
|
64
|
+
p.description = DESCRIPTION
|
65
|
+
p.email = EMAIL
|
66
|
+
p.summary = DESCRIPTION
|
67
|
+
p.url = HOMEPATH
|
68
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
69
|
+
p.test_globs = ["test/**/test_*.rb"]
|
70
|
+
p.clean_globs |= CLEAN #An array of file patterns to delete on clean.
|
71
|
+
|
72
|
+
# == Optional
|
73
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
74
|
+
p.extra_deps = [['hpricot', '>= 0.5.145'] ] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
75
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
76
|
+
end
|
77
|
+
|
78
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\n\n")
|
79
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
80
|
+
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
81
|
+
|
82
|
+
desc 'Generate website files'
|
83
|
+
task :website_generate do
|
84
|
+
Dir['website/**/*.txt'].each do |txt|
|
85
|
+
sh %{ ruby scripts/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
desc 'Upload website files to rubyforge'
|
90
|
+
task :website_upload do
|
91
|
+
host = "#{rubyforge_username}@rubyforge.org"
|
92
|
+
remote_dir = "/var/www/gforge-projects/#{PATH}/"
|
93
|
+
local_dir = 'website'
|
94
|
+
sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
|
95
|
+
end
|
96
|
+
|
97
|
+
desc 'Generate and upload website files'
|
98
|
+
task :website => [:website_generate, :website_upload, :publish_docs]
|
99
|
+
|
100
|
+
desc 'Release the website and new gem version'
|
101
|
+
task :deploy => [:check_version, :website, :release] do
|
102
|
+
puts "Remember to create SVN tag:"
|
103
|
+
puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
|
104
|
+
"svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
|
105
|
+
puts "Suggested comment:"
|
106
|
+
puts "Tagging release #{CHANGES}"
|
107
|
+
end
|
108
|
+
|
109
|
+
desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
|
110
|
+
task :local_deploy => [:website_generate, :install_gem]
|
111
|
+
|
112
|
+
task :check_version do
|
113
|
+
unless ENV['VERSION']
|
114
|
+
puts 'Must pass a VERSION=x.y.z release version'
|
115
|
+
exit
|
116
|
+
end
|
117
|
+
unless ENV['VERSION'] == VERS
|
118
|
+
puts "Please update your version.rb to match the release version, currently #{VERS}"
|
119
|
+
exit
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
|
data/lib/fireeagle.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
%w[ cgi digest/sha1 net/http hpricot time ].each { |f| require f }
|
2
|
+
|
3
|
+
class FireEagle#:nodoc:
|
4
|
+
API_DOMAIN = "fireeagle.research.yahoo.com"
|
5
|
+
API_PATH = "/api/"
|
6
|
+
DEBUG = false
|
7
|
+
|
8
|
+
class Error < RuntimeError #:nodoc:
|
9
|
+
end
|
10
|
+
|
11
|
+
class ArgumentError < Error #:nodoc:
|
12
|
+
end
|
13
|
+
|
14
|
+
class FireEagleException < Error #:nodoc:
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'fireeagle/base'
|
19
|
+
require 'fireeagle/apibase'
|
20
|
+
require 'fireeagle/application'
|
21
|
+
require 'fireeagle/user'
|
22
|
+
require 'fireeagle/location'
|
23
|
+
require 'fireeagle/version'
|
24
|
+
|
25
|
+
#FireEagle additions to the <code>Hash</code> class
|
26
|
+
class Hash
|
27
|
+
#Returns <code>true</code> if the ALL or NONE of the given keys are present in <i>hsh</i>.
|
28
|
+
def has_all_or_none_keys?(*my_keys)
|
29
|
+
size = my_keys.length
|
30
|
+
false_count = 0
|
31
|
+
my_keys.each do |k|
|
32
|
+
false_count += 1 unless keys.include?(k)
|
33
|
+
end
|
34
|
+
false_count == 0 or false_count == size
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
#FireEagle additions to the <code>Object</code> class
|
40
|
+
class Object
|
41
|
+
# A Ruby-ized realization of the K combinator, courtesy of Mikael Brockman.
|
42
|
+
#
|
43
|
+
# def foo
|
44
|
+
# returning values = [] do
|
45
|
+
# values << 'bar'
|
46
|
+
# values << 'baz'
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# foo # => ['bar', 'baz']
|
51
|
+
#
|
52
|
+
# def foo
|
53
|
+
# returning [] do |values|
|
54
|
+
# values << 'bar'
|
55
|
+
# values << 'baz'
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# foo # => ['bar', 'baz']
|
60
|
+
#
|
61
|
+
def returning(value)
|
62
|
+
yield(value)
|
63
|
+
value
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class FireEagle::Application < FireEagle::APIBase
|
2
|
+
#A user must authorize (or grant permissions to) an application before the application can write or read the user's location. This authorization process begins by directing a user to the authorization page, where the user logs in and chooses which permissions to grant to the requesting application. The authorization page generates a user token, specific to the requesting application, which can be returned to the requesting application in several ways:
|
3
|
+
#
|
4
|
+
#1. User token passed back to requesting application via callback URL (if the callback parameter is supplied)
|
5
|
+
#2. User token displayed onscreen (this is good for testing, but will likely be phased out or modified in the future)
|
6
|
+
#3. User token is exchanged at a later time (good for mobile devices where a user may not want to enter their Yahoo! username/password)
|
7
|
+
#
|
8
|
+
def authorize_url(callback_url = "")
|
9
|
+
"http://#{FireEagle::API_DOMAIN}/authorize.php?appid=#{@fireeagle.token}&callback=#{CGI::escape(callback_url)}"
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
#Applications which do not maintain a user repository (for example, a lightweight mobile application) may not wish to use the callback mechanism described above. These applications still must send users to authorize.php, but do not expect an immediate response (though at the moment, the authorize page will display the user token for easy testing and debugging). After the user has authorized an application, the application can later retrieve the user token in exchange for a short code obtained by the user from the Fire Eagle site. The user would retrieve a short code from the FE site and enter the code into the application which would then use the exchangeToken.php to exchange the short code for a full user token.
|
14
|
+
#
|
15
|
+
#To obtain a short code users visit http://fireeagle.research.yahoo.com/displayToken.php?appid=TOKEN, where app token is the application token.
|
16
|
+
#
|
17
|
+
#Returnes an instance of FireEagle::User
|
18
|
+
def exchange_token(shortcode = nil)
|
19
|
+
raise FireEagle::ArgumentError, "Shortcode required" if shortcode.nil?
|
20
|
+
request("exchangeToken", :shortcode => shortcode.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def parse_response(doc)
|
26
|
+
raise FireEagle::FireEagleException, doc.at("/resultset/errormessage").innerText unless doc.at("/resultset").nil?
|
27
|
+
FireEagle::User.new_from_xml(@fireeagle, doc)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#The base class for interfacing w/ FireEagle
|
2
|
+
#
|
3
|
+
# @fireeagle = Fireagle::Base.new(:token => "foo", :secret => "bar")
|
4
|
+
#
|
5
|
+
#Fire Eagle (FE) is a system providing centralized management of user location information. FE allows 3rd party developers to update and/or access user's location data.
|
6
|
+
#
|
7
|
+
#There are 3 data entities at Fire Eagle's core:
|
8
|
+
#
|
9
|
+
#* User: Users can grant 3rd party applications privileges to read or write the user's location data. Users identify themselves to the FE system with their Yahoo! username/password. Applications identify a user with an application-specific user token (referred to in the API as a userid) generated by FE.
|
10
|
+
#* Application: An application is identified by system-wide application token. Applications use this token (referred to in the API as an appid) and an application-specific secret to identify themselves to FE when reading or writing user location data.
|
11
|
+
#* Location: FE stores the most recent location supplied by each application for each user. Applications can specify location in a number of ways: e.g. a latitude/longitude pair, a postal code, a street address, a GSM cell tower identifier, or an identifier from an external system (Plazes, Upcoming.org, etc.). See the Update API section for all possible location input options.
|
12
|
+
#
|
13
|
+
#Only one location per user-application pair is stored, thus FE provides access only to a user's current location, not a location history of where the user has been. When a user's location is requested FE combines location info from one or more applications into a current best guess location record which is returned in XML format -- see the Query API Response section, below for details.
|
14
|
+
class FireEagle::Base
|
15
|
+
|
16
|
+
attr_reader :token, :secret
|
17
|
+
|
18
|
+
#Create a new FireEagle::Base object.
|
19
|
+
#
|
20
|
+
# @fireeagle = Fireagle::Base.new(:token => "foo", :secret => "bar")
|
21
|
+
def initialize(options = {})
|
22
|
+
options = { :token => nil, :secret => nil }.merge(options)
|
23
|
+
raise FireEagle::ArgumentError, "Token and Secret required" if options[:token].nil? || options[:secret].nil?
|
24
|
+
@token = options[:token]
|
25
|
+
@secret = options[:secret]
|
26
|
+
@fireeagle = self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return an instance of FireEagle::Application
|
30
|
+
def application() @application ||= FireEagle::Application.new(self) end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# do the required api signing
|
35
|
+
def encode_and_sign(params = {})
|
36
|
+
|
37
|
+
#check for the params
|
38
|
+
raise ArgumentError, "Params required" if params == {} || !params.is_a?(Hash)
|
39
|
+
|
40
|
+
#remove any provided sig
|
41
|
+
params.delete(:sig)
|
42
|
+
|
43
|
+
#add the app token id
|
44
|
+
params[:appid] = @fireeagle.token
|
45
|
+
|
46
|
+
#sort and URL encode the params
|
47
|
+
normalized_params = {}
|
48
|
+
params.each_pair { |name, value| normalized_params[name.to_s] = value.to_s }
|
49
|
+
|
50
|
+
#build the string to sign
|
51
|
+
sig = "#{@fireeagle.secret}"
|
52
|
+
normalized_params.sort.each { |name, value| sig << "#{name}#{value}" }
|
53
|
+
|
54
|
+
#sign it
|
55
|
+
normalized_params['sig'] = Digest::SHA1.hexdigest(sig)
|
56
|
+
|
57
|
+
#create and return the request string
|
58
|
+
request_string = "?" + normalized_params.sort.collect { |name, value| "#{name}=#{CGI::escape(value)}" }.join('&')
|
59
|
+
end
|
60
|
+
|
61
|
+
# request method which is used by all public methods
|
62
|
+
def request(action = nil,params = {})
|
63
|
+
raise ArgumentError, "Action name required" if action.nil?
|
64
|
+
|
65
|
+
#reject crap
|
66
|
+
params.reject { |key, value| value.nil? or (value.is_a?(String) and value.empty?)}
|
67
|
+
#merge timestamp
|
68
|
+
params.merge!( { :timestamp => Time.now.to_i } )
|
69
|
+
|
70
|
+
path = "#{FireEagle::API_PATH}#{action}.php#{encode_and_sign(params)}"
|
71
|
+
|
72
|
+
puts path if FireEagle::DEBUG
|
73
|
+
|
74
|
+
response = Net::HTTP.get_response(FireEagle::API_DOMAIN, path)
|
75
|
+
|
76
|
+
parse_response(Hpricot(response.body))
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_response(doc)
|
80
|
+
raise FireEagleException, doc.at("/resultset/errormessage").innerText unless !doc.at("/resultset").nil? and doc.at("/resultset/error").innerText.to_i == "0"
|
81
|
+
doc.at("/result")
|
82
|
+
end
|
83
|
+
|
84
|
+
def fireeagle
|
85
|
+
fireeagle
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#Describes a location
|
2
|
+
class FireEagle::Location
|
3
|
+
|
4
|
+
DETAILS = :locale, :quality, :updatetime, :latitute, :longitude, :offsetlat, :offsetlon,
|
5
|
+
:radius, :boundinglatnorth, :boundinglatsouth, :boundinglateast, :boundinglatwest,
|
6
|
+
:name, :line1, :line2, :line3, :line4, :house, :street, :xstreet, :unittype, :unit,
|
7
|
+
:neighborhood, :city, :county, :state, :country, :coutrycode, :statecode, :countrycode,
|
8
|
+
:timezone,
|
9
|
+
# attributes used only on update
|
10
|
+
:source, :addr, :mcn, :mcc, :lac, :cellid, :loc, :name, :woeid, :plazesid,
|
11
|
+
:upvenueid, :street1, :street2
|
12
|
+
|
13
|
+
attr_reader :details
|
14
|
+
|
15
|
+
#Create an instance of FireEagle::Location. There are some specific requirements for combinations of elements in the <code>options</code> Hash:
|
16
|
+
#
|
17
|
+
#* Requires all or none of :lat, :long
|
18
|
+
#* Requires all or none of :mnc, :mcc, :lac, :cellid
|
19
|
+
#* Requires all or none of :street1, :street2
|
20
|
+
#* Requires :postal or :city with :street1 and :street2
|
21
|
+
#* Requires :city or :postal with :addr
|
22
|
+
#* Requires :state, :country, or :postal with :city
|
23
|
+
#* Requires :country with :postal if not in US
|
24
|
+
def initialize(options = {}, verify_attributes = true)
|
25
|
+
option = options.reject { |key, value| DETAILS.include?(key) }
|
26
|
+
|
27
|
+
if verify_attributes
|
28
|
+
raise FireEagle::ArgumentError, "Requires all or none of :lat, :long" unless options.has_all_or_none_keys?(:lat, :long)
|
29
|
+
raise FireEagle::ArgumentError, "Requires all or none of :mnc, :mcc, :lac, :cellid" unless options.has_all_or_none_keys?(:mnc, :mcc, :lac, :cellid)
|
30
|
+
raise FireEagle::ArgumentError, "Requires all or none of :street1, :street2" unless options.has_all_or_none_keys?(:street1, :street2)
|
31
|
+
raise FireEagle::ArgumentError, "Requires :postal or :city with :street1 and :street2" if (options.has_key?(:street1) and options.has_key?(:street2)) and !(options.has_key?(:city) or options.has_key?(:postal))
|
32
|
+
raise FireEagle::ArgumentError, "Requires :city or :postal with :addr" if options.has_key?(:addr) and !(options.has_key?(:city) or options.has_key?(:postal))
|
33
|
+
raise FireEagle::ArgumentError, "Requires :state, :country, or :postal with :city" if options.has_key?(:city) and !(options.has_key?(:state) or options.has_key?(:country) or options.has_key?(:postal))
|
34
|
+
raise FireEagle::ArgumentError, "Requires :country with :postal if not in US" if (options.has_key?(:postal) and options.has_key?(:country)) and (options[:country] != "US")
|
35
|
+
end
|
36
|
+
|
37
|
+
@details = options
|
38
|
+
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
#Create a new instance of FireEagle::Location from the XML returned from Yahoo!
|
42
|
+
def new_from_xml(doc)
|
43
|
+
#build the massive hash needed for a location
|
44
|
+
options = { }
|
45
|
+
doc = doc.at("/resultset")
|
46
|
+
options[:locale] = doc.at("locale").innerText unless doc.at("locale").nil?
|
47
|
+
# quick parse of the xml
|
48
|
+
puts doc if FireEagle::DEBUG
|
49
|
+
doc.at("result").containers.each do |attribute|
|
50
|
+
options[attribute.xpath.split("/")[-1].to_sym] = attribute.inner_text unless attribute.nil?
|
51
|
+
end
|
52
|
+
#fixup types
|
53
|
+
options[:updatetime] = Time.parse(options[:updatetime])
|
54
|
+
options[:radius] = options[:radius].to_i
|
55
|
+
options[:quality] = options[:radius].to_i
|
56
|
+
%w(latitude longitude offsetlat offsetlon :boundinglatnorth boundinglatsouth boundinglateast boundinglatwest).each do |attribute|
|
57
|
+
options[attribute.to_sym].nil? || options[attribute.to_sym].empty? ? (options[attribute.to_sym] = '') : (options[attribute.to_sym] = options[attribute.to_sym].to_f)
|
58
|
+
end
|
59
|
+
|
60
|
+
FireEagle::Location.new(options, false)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def verify_attribute_combination(options, *args)
|
67
|
+
args.each do |a|
|
68
|
+
return false unless options.include?(a)
|
69
|
+
end
|
70
|
+
return true
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
end
|