mapsqueak 0.0.1
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.
- data/bin/squeak.rb +105 -0
- data/lib/mapsqueak.rb +246 -0
- metadata +57 -0
data/bin/squeak.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# squeak.rb - update mapsqueak.heroku.com with a lat/long and a message (a squeak)
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift File.dirname($PROGRAM_NAME)
|
6
|
+
$LOAD_PATH.unshift File.dirname($PROGRAM_NAME) + "/../lib"
|
7
|
+
|
8
|
+
require 'opt_simple'
|
9
|
+
require 'mapsqueak'
|
10
|
+
|
11
|
+
defaults = {
|
12
|
+
:host => 'http://mapsqueak.heroku.com' # http://localhost:3000
|
13
|
+
}
|
14
|
+
|
15
|
+
opts = OptSimple.new(defaults).parse_opts! do
|
16
|
+
argument "--latitude", "Latitude in decimal degrees","LAT"
|
17
|
+
argument "--longitude", "Longitude in decimal degrees","LONG"
|
18
|
+
argument %w[-t --text], "Squeak text", "TEXT"
|
19
|
+
argument %w[-d --duration], "Duration in hours","DURATION" do | arg |
|
20
|
+
dur = arg.to_f
|
21
|
+
if dur > 0.0 and dur <= 24.0
|
22
|
+
set_opt dur
|
23
|
+
else
|
24
|
+
error "Duration must be between 0 and 24 hours"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
option "--host", "MapSqueak host","URL"
|
28
|
+
option %w[--access-token], "Facebook access token to post mapsqueak","TOKEN"
|
29
|
+
flag %w[--facebook-test-user], "Create a Facebook test user using Mapsqueak's app token"
|
30
|
+
end
|
31
|
+
puts opts
|
32
|
+
|
33
|
+
|
34
|
+
# TODO: add signin capability
|
35
|
+
# TODO: re-add the facebook functionality
|
36
|
+
m = MapSqueakSession.new
|
37
|
+
|
38
|
+
m.post_squeak({
|
39
|
+
:latitude => opts.latitude.dup.gsub("\\",''),
|
40
|
+
:longitude =>opts.longitude.dup.gsub("\\",''),
|
41
|
+
:text =>opts.text.dup,
|
42
|
+
:duration => opts.duration
|
43
|
+
})
|
44
|
+
|
45
|
+
__END__
|
46
|
+
|
47
|
+
|
48
|
+
puts "Auto confirming squeak ..."
|
49
|
+
|
50
|
+
update = {:squeak => Hash.new}
|
51
|
+
update[:squeak][:latitude] = initial_return_hash['squeak']['latitude']
|
52
|
+
update[:squeak][:longitude] = initial_return_hash['squeak']['longitude']
|
53
|
+
|
54
|
+
# PUT /squeaks/:id(.:format) {:action=>"update", :controller=>"squeaks"}
|
55
|
+
confirmation_curl_str = "curl -v --request PUT --data #{update.to_json} #{opts.host}/squeaks/#{initial_return_hash['squeak']['id']}.json -H \"Content-Type: application/json\" 2>> ruby_err.html"
|
56
|
+
|
57
|
+
puts confirmation_curl_str
|
58
|
+
|
59
|
+
confirmation_return = `#{confirmation_curl_str}`
|
60
|
+
puts "Confirmed."
|
61
|
+
confirmation_return_hash = JSON.parse(confirmation_return)
|
62
|
+
# Mapsqueak is all set, now update facebook if desired
|
63
|
+
user = nil
|
64
|
+
login_url = nil
|
65
|
+
if opts.include?('access-token')
|
66
|
+
user = Koala::Facebook::API.new(opts.access_token)
|
67
|
+
elsif(opts.include?('facebook-test-user'))
|
68
|
+
test_users = Koala::Facebook::TestUsers.new(:app_id => '107582139349630', :secret => "ca16bbd5834ab7d4b012ec5e84a0d003")
|
69
|
+
user_info = test_users.create(true, "offline_access,read_stream,manage_pages,publish_stream")
|
70
|
+
login_url = user_info['login_url']
|
71
|
+
user = Koala::Facebook::API.new(user_info['access_token'])
|
72
|
+
end
|
73
|
+
|
74
|
+
unless user.nil?
|
75
|
+
puts "Using the following facebook user: #{user.inspect}"
|
76
|
+
|
77
|
+
picture_url = "http://maps.googleapis.com/maps/api/staticmap?center=#{update[:latitude]},#{update[:longitude]}&zoom=13&size=200x200&maptype=roadmap&markers=color:blue%7Clabel:M%7C#{update[:latitude]},#{update[:longitude]}&sensor=true"
|
78
|
+
|
79
|
+
puts "Google image url: #{picture_url}"
|
80
|
+
|
81
|
+
# Use google's static map api to get an image for the squeak
|
82
|
+
id = user.put_wall_post("MapSqueak update at #{Time.now.strftime('')}",{:name => 'squeak name',
|
83
|
+
:link => "#{opts.host}/squeaks/#{confirmation_return_hash['squeak']['id']}",
|
84
|
+
:caption => opts.text,
|
85
|
+
:description => "the description of the squeak, TBD",
|
86
|
+
:picture => picture_url})
|
87
|
+
puts "Updated facebook with id: #{id}"
|
88
|
+
puts "Visit #{login_url} to see it ..." unless login_url.nil?
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
__END__
|
93
|
+
|
94
|
+
# To update the squeak using POST params, similar to the web client
|
95
|
+
#curl_str = "curl -v -F squeak[latitude]=#{opts.latitude} -F squeak[longitude]=#{opts.longitude} -F squeak[text]=\'#{opts.text}\' -F duration=#{opts.duration} #{opts.host}/squeaks/ 2> ruby_err.html"
|
96
|
+
# TODO: make this work.
|
97
|
+
class MapSqueak
|
98
|
+
include HTTParty
|
99
|
+
format :json
|
100
|
+
def self.squeak(host,params)
|
101
|
+
post("#{host}/squeaks/",:body=>params)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
$stderr.puts params.to_json
|
105
|
+
MapSqueak.squeak(opts.host,params.to_json)
|
data/lib/mapsqueak.rb
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
|
3
|
+
= mapsqueak - a reference implementation for MapSqueak clients
|
4
|
+
|
5
|
+
=end
|
6
|
+
|
7
|
+
require 'json'
|
8
|
+
require 'koala'
|
9
|
+
require 'rexml/document'
|
10
|
+
include REXML
|
11
|
+
|
12
|
+
module XmlHelpers
|
13
|
+
def xml_element(tag,text=nil)
|
14
|
+
e = Element.new(tag)
|
15
|
+
e << Text.new(text) unless text.nil?
|
16
|
+
e
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# MapSqueakSession - an class that encapsulates a session with the mapsqueak server.
|
21
|
+
#
|
22
|
+
class MapSqueakSession
|
23
|
+
include XmlHelpers
|
24
|
+
attr_accessor :host, :facebook_token
|
25
|
+
attr_reader :session_cookie
|
26
|
+
|
27
|
+
def initialize(host = 'http://mapsqueak.heroku.com', username=nil,password=nil)
|
28
|
+
@host = host
|
29
|
+
@cookie_file = 'anonymous@anaonymous.com.cookies'
|
30
|
+
end
|
31
|
+
|
32
|
+
# sign in by email/password.
|
33
|
+
# note that a remember_token will be saved in a cookie file
|
34
|
+
def sign_in(email,password)
|
35
|
+
signin_xml = Document.new
|
36
|
+
signin_xml.add_element('session')
|
37
|
+
signin_xml.root << xml_element('email',email)
|
38
|
+
signin_xml.root << xml_element('password',password)
|
39
|
+
puts signin_xml.to_s
|
40
|
+
|
41
|
+
@cookie_file = "#{email}.cookies"
|
42
|
+
|
43
|
+
curl_str = "curl --data \'#{signin_xml.to_s}\' #{self.host}/sessions.xml -H \"Content-Type: application/xml\" --cookie-jar #{@cookie_file}"
|
44
|
+
|
45
|
+
result = `#{curl_str}`
|
46
|
+
puts result
|
47
|
+
doc = Document.new(result)
|
48
|
+
@user_id = XPath.first(doc,"hash/user-id").text
|
49
|
+
end
|
50
|
+
|
51
|
+
# sign the current user out.
|
52
|
+
# note that the cookie file will be deleted.
|
53
|
+
def sign_out
|
54
|
+
curl_str = "curl #{self.host}/sessions --request DELETE --cookie #{@cookie_file}"
|
55
|
+
puts curl_str
|
56
|
+
`#{curl_str}`
|
57
|
+
File.unlink(@cookie_file)
|
58
|
+
end
|
59
|
+
|
60
|
+
# post a new squeak. the squeak can either be whatever the ClientSqueak constructor accepts -
|
61
|
+
# a String of json or xml, or a hash, or it can be a ClientSqueak object. Talk about flexibility!
|
62
|
+
# the send_format must be :xml or :json
|
63
|
+
def post_squeak(squeak,send_format = :xml)
|
64
|
+
s = nil
|
65
|
+
case squeak
|
66
|
+
when ClientSqueak
|
67
|
+
s = squeak
|
68
|
+
when Hash
|
69
|
+
s = ClientSqueak.new(squeak)
|
70
|
+
end
|
71
|
+
unless [:json, :xml].include?(send_format)
|
72
|
+
$stderr.puts "Error: send_format must be in json or xml"
|
73
|
+
end
|
74
|
+
format_str = send_format.to_s
|
75
|
+
data = s.send("to_#{format_str}")
|
76
|
+
curl_str = "curl --data \'#{data}\' #{self.host}/squeaks.#{format_str} -H \"Content-Type: application/#{format_str}\" --cookie #{@cookie_file}"
|
77
|
+
|
78
|
+
# execute the curl command
|
79
|
+
`#{curl_str}`
|
80
|
+
end
|
81
|
+
|
82
|
+
# get a list of no more than max squeaks closest to the given center_latitude/centerlongitude
|
83
|
+
# The format must either be :json or :xml.
|
84
|
+
# TODO: create a list of ClientSqueak objects, or make a get_squeak_objects function
|
85
|
+
def get_squeaks(center_latitude,center_longitude,max = 100,format=:json)
|
86
|
+
# curl "http://192.168.0.2:3000/squeaks.xml?num_squeaks=3¢er_latitude=50.0¢er_longitude=-1.8"
|
87
|
+
unless [:json, :xml].include?(format)
|
88
|
+
$stderr.puts "Error: must be in json or xml"
|
89
|
+
end
|
90
|
+
|
91
|
+
squeaks = `curl #{self.host}/squeaks.#{format.to_s}?num_squeaks=#{max}¢er_latitude=#{center_latitude}¢er_longitude=#{center_longitude}`
|
92
|
+
|
93
|
+
# TODO: parse these appropriately
|
94
|
+
end
|
95
|
+
|
96
|
+
# return all of my squeaks in a specified format, either :xml or :json
|
97
|
+
def get_my_squeaks(format=:json)
|
98
|
+
unless [:json, :xml].include?(format)
|
99
|
+
$stderr.puts "Error: must be in json or xml"
|
100
|
+
end
|
101
|
+
# TODO: add a hash based on the parameters requested and use session token
|
102
|
+
# T
|
103
|
+
`curl #{self.host}/users/#{@user_id}.#{format.to_s} --cookie #{@cookie_file}`
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# ClientSqueak - a class that encapsulates a client side squeak
|
108
|
+
# Note that if I am not the owner of a squeak, I will not know the user
|
109
|
+
class ClientSqueak
|
110
|
+
include XmlHelpers
|
111
|
+
attr_accessor :latitude, :longitude, :text, :duration, :expires, :username
|
112
|
+
|
113
|
+
@@mandatory_parameters = %w[latitude longitude text duration]
|
114
|
+
@@min_latitude = -90.0
|
115
|
+
@@max_latitude = 90.0
|
116
|
+
@@min_longitude = -180.0
|
117
|
+
@@max_longitude = 180.0
|
118
|
+
@@min_duration = 0.0
|
119
|
+
@@max_duration = 24.0
|
120
|
+
@@max_text_length = 140
|
121
|
+
|
122
|
+
# Initialize a new squeak which must be in an allowable format:
|
123
|
+
# json - a String representation of a JSON object
|
124
|
+
# e.g. {\"squeak\":{\"latitude\":\"54.1\",\"longitude\":\"-1.7\",\"duration\":\"2\",\"text\":\"Another squeak!\"}}
|
125
|
+
# xml - a String representation of an XML blob
|
126
|
+
# e.g. <squeak><latitude>54.1</latitude><longitude>-1.7</longitude><text>Another squeak!</text><duration>2</duration></squeak>
|
127
|
+
# hash - a hash representation of a squeak
|
128
|
+
# e.g. {:squeak => {:latitude=> 54.1, :longitude=>-1.69, :text => "Another squeak!", :duration => 2}}
|
129
|
+
# OR if you are lazy (like me) you can just specify the inner hash:
|
130
|
+
# e.g. {:latitude=> 54.1, :longitude=>-1.69, :text => "Another squeak!", :duration => 2}
|
131
|
+
def initialize(squeak)
|
132
|
+
@original_squeak = squeak
|
133
|
+
temp_hash = {:squeak => {}}
|
134
|
+
case squeak
|
135
|
+
when Hash
|
136
|
+
# just to be nice, we won't force the user to specify the outer wrapping
|
137
|
+
if squeak.has_key? 'squeak'
|
138
|
+
temp_hash = squeak.dup
|
139
|
+
else
|
140
|
+
temp_hash = {:squeak => squeak}
|
141
|
+
end
|
142
|
+
|
143
|
+
when String
|
144
|
+
begin
|
145
|
+
temp_hash = JSON.parse(squeak)
|
146
|
+
rescue Exception => e
|
147
|
+
begin
|
148
|
+
doc = Document.new(squeak)
|
149
|
+
# a nice flexible way to parse the XML. as long as the XML
|
150
|
+
# is only one level deep
|
151
|
+
doc.elements.each('squeak/') do | el |
|
152
|
+
el.each do |child|
|
153
|
+
temp_hash[:squeak][child.name.to_sym] = child.text
|
154
|
+
end
|
155
|
+
end
|
156
|
+
rescue Exception => e2
|
157
|
+
raise "Can't parse squeak text: #{squeak}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
t = temp_hash['squeak'] || temp_hash[:squeak]
|
163
|
+
parms_set = []
|
164
|
+
t.keys.each do | k |
|
165
|
+
# this will set and validate the parameters
|
166
|
+
self.send("#{k.to_s}=",t[k])
|
167
|
+
parms_set << k.to_s
|
168
|
+
end
|
169
|
+
|
170
|
+
# but we need to make sure that all of the mandatory parameters are defined
|
171
|
+
unless (@@mandatory_parameters - parms_set).empty?
|
172
|
+
raise "Must have duration, lat and long and text"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# convert the squeak to XML format
|
177
|
+
# e.g. <squeak><latitude>54.1</latitude><longitude>-1.7</longitude><text>Another squeak!</text><duration>2</duration></squeak>
|
178
|
+
def to_xml
|
179
|
+
params_xml = Document.new
|
180
|
+
params_xml.add_element('squeak')
|
181
|
+
params_xml.root << xml_element('latitude',self.latitude.to_s)
|
182
|
+
params_xml.root << xml_element('longitude',self.longitude.to_s)
|
183
|
+
params_xml.root << xml_element('text',self.text)
|
184
|
+
params_xml.root << xml_element('duration',self.duration.to_s)
|
185
|
+
params_xml
|
186
|
+
end
|
187
|
+
|
188
|
+
# convert the squeak to JSON format
|
189
|
+
# e.g. {\"squeak\":{\"latitude\":\"54.1\",\"longitude\":\"-1.7\",\"duration\":\"2\",\"text\":\"Another squeak!\"}}
|
190
|
+
def to_json
|
191
|
+
self.to_hash.to_json
|
192
|
+
end
|
193
|
+
|
194
|
+
# convert the squeak to a Hash
|
195
|
+
def to_hash
|
196
|
+
{
|
197
|
+
:squeak=> {
|
198
|
+
:latitude => self.latitude.to_s,
|
199
|
+
:longitude => self.longitude.to_s,
|
200
|
+
:duration => self.duration.to_s,
|
201
|
+
:text => self.text
|
202
|
+
}
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
# set the latitude for the squeak
|
207
|
+
# must be between @@min_latitude and @@max_latitude
|
208
|
+
def latitude=(latitude)
|
209
|
+
lat = latitude.to_f
|
210
|
+
raise "Bad latitude" if lat < @@min_latitude
|
211
|
+
raise "Bad latitude" if lat > @@max_latitude
|
212
|
+
@latitude = lat
|
213
|
+
end
|
214
|
+
|
215
|
+
# set the longitude for the squeak
|
216
|
+
# must be between @@min_longitude and @@max_longitude
|
217
|
+
def longitude=(longitude)
|
218
|
+
long = longitude.to_f
|
219
|
+
raise "Bad longitude" if long < @@min_longitude
|
220
|
+
raise "Bad longitude" if long > @@max_longitude
|
221
|
+
@longitude = long
|
222
|
+
end
|
223
|
+
|
224
|
+
# set the time to live for the squeak
|
225
|
+
# must be between @@min_duration and @@max_duration
|
226
|
+
def duration=(duration)
|
227
|
+
dur = duration.to_f
|
228
|
+
raise "Bad duration" if dur < @@min_duration
|
229
|
+
raise "Bad duration" if dur > @@max_duration
|
230
|
+
@duration = dur
|
231
|
+
end
|
232
|
+
|
233
|
+
# set the message portion of the squeak
|
234
|
+
# length can't exceed @@max_text_length
|
235
|
+
def text=(txt)
|
236
|
+
raise "Bad text length" unless txt.length <= @@max_text_length
|
237
|
+
@text = txt.dup
|
238
|
+
end
|
239
|
+
|
240
|
+
# simply use to_s on the Hash representation
|
241
|
+
def to_s
|
242
|
+
self.to_hash.to_s
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mapsqueak
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ethan Stryker
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-12-03 00:00:00 +00:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: " A REST client for MapSqueak, a mobile enabled web app. \n"
|
18
|
+
email: e.stryker@gmail.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- lib/mapsqueak.rb
|
27
|
+
- bin/squeak.rb
|
28
|
+
has_rdoc: true
|
29
|
+
homepage: http://mapsqueak.rubyforge.org/
|
30
|
+
licenses: []
|
31
|
+
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
rubyforge_project: mapsqueak
|
52
|
+
rubygems_version: 1.6.2
|
53
|
+
signing_key:
|
54
|
+
specification_version: 3
|
55
|
+
summary: a REST client for MapSqueak
|
56
|
+
test_files: []
|
57
|
+
|