mapsqueak 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/bin/squeak.rb +105 -0
  2. data/lib/mapsqueak.rb +246 -0
  3. 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&center_latitude=50.0&center_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}&center_latitude=#{center_latitude}&center_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
+