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.
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
+