spacer 0.5.0

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/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.5.0 / 2008-02-09
2
+
3
+ * Initial release
4
+ * Birthday!
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2008 Shane Vitarana <shanev@gmail.com>, CrimsonJet LLC
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.
21
+
data/Manifest.txt ADDED
@@ -0,0 +1,34 @@
1
+ History.txt
2
+ MIT-LICENSE
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/spacer
7
+ lib/spacer.rb
8
+ lib/spacer/auth.rb
9
+ lib/spacer/client.rb
10
+ lib/spacer/model.rb
11
+ lib/spacer/models/album.rb
12
+ lib/spacer/models/details.rb
13
+ lib/spacer/models/group.rb
14
+ lib/spacer/models/interest.rb
15
+ lib/spacer/models/mood.rb
16
+ lib/spacer/models/photo.rb
17
+ lib/spacer/models/profile.rb
18
+ lib/spacer/models/status.rb
19
+ lib/spacer/models/user.rb
20
+ lib/spacer/models/video.rb
21
+ tasks/annotations.rake
22
+ tasks/doc.rake
23
+ tasks/gem.rake
24
+ tasks/manifest.rake
25
+ tasks/post_load.rake
26
+ tasks/rubyforge.rake
27
+ tasks/setup.rb
28
+ tasks/spec.rake
29
+ tasks/svn.rake
30
+ tasks/test.rake
31
+ test/test_client.rb
32
+ test/test_helper.rb
33
+ test/test_spacer.rb
34
+ test/test_user.rb
data/README.txt ADDED
@@ -0,0 +1,54 @@
1
+ spacer
2
+ by Shane Vitarana
3
+ http://shanesbrain.net
4
+
5
+ == DESCRIPTION:
6
+
7
+ Ruby API for the MySpace Platform REST API
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * Implements v1.0 of the MySpace Platform REST API
12
+ * Uses JSON for minimal transport footprint
13
+
14
+ == SYNOPSIS:
15
+
16
+ @myspace = Spacer::Client.new(api_key, secret_key)
17
+ user = @myspace.user('3454354')
18
+ puts user.interests.music
19
+ puts user.photos.first.caption
20
+
21
+ == REQUIREMENTS:
22
+
23
+ * OAuth
24
+ * ActiveSupport
25
+ * Mocha (for testing)
26
+
27
+ == INSTALL:
28
+
29
+ * sudo gem install spacer
30
+
31
+ == LICENSE:
32
+
33
+ (The MIT License)
34
+
35
+ Copyright (c) 2008 Shane Vitarana <shanev@gmail.com>, CrimsonJet LLC
36
+
37
+ Permission is hereby granted, free of charge, to any person obtaining
38
+ a copy of this software and associated documentation files (the
39
+ 'Software'), to deal in the Software without restriction, including
40
+ without limitation the rights to use, copy, modify, merge, publish,
41
+ distribute, sublicense, and/or sell copies of the Software, and to
42
+ permit persons to whom the Software is furnished to do so, subject to
43
+ the following conditions:
44
+
45
+ The above copyright notice and this permission notice shall be
46
+ included in all copies or substantial portions of the Software.
47
+
48
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
49
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
50
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
51
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
52
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
53
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
54
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ load 'tasks/setup.rb'
6
+
7
+ ensure_in_path 'lib'
8
+ require 'spacer'
9
+
10
+ task :default => 'test:run'
11
+
12
+ PROJ.name = 'spacer'
13
+ PROJ.authors = 'Shane Vitarana'
14
+ PROJ.email = 'shanev@gmail.com'
15
+ PROJ.url = 'http://shanesbrain.net'
16
+ PROJ.rubyforge_name = 'spacer'
17
+
18
+ PROJ.spec_opts << '--color'
19
+
20
+ # EOF
data/bin/spacer ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), '..', 'lib', 'spacer'))
5
+
6
+ # Put your code here
7
+
8
+ # EOF
data/lib/spacer.rb ADDED
@@ -0,0 +1,63 @@
1
+ # $Id$
2
+
3
+ # Equivalent to a header guard in C/C++
4
+ # Used to prevent the class/module from being loaded more than once
5
+ unless defined? Spacer
6
+
7
+ require 'rubygems'
8
+ require 'oauth/consumer'
9
+ require 'activesupport'
10
+ require 'spacer/model'
11
+
12
+ module Spacer
13
+
14
+ # :stopdoc:
15
+ VERSION = '0.5.0'
16
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
17
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
18
+ # :startdoc:
19
+
20
+ # Returns the version string for the library.
21
+ #
22
+ def self.version
23
+ VERSION
24
+ end
25
+
26
+ # Returns the library path for the module. If any arguments are given,
27
+ # they will be joined to the end of the libray path using
28
+ # <tt>File.join</tt>.
29
+ #
30
+ def self.libpath( *args )
31
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, *args)
32
+ end
33
+
34
+ # Returns the lpath for the module. If any arguments are given,
35
+ # they will be joined to the end of the path using
36
+ # <tt>File.join</tt>.
37
+ #
38
+ def self.path( *args )
39
+ args.empty? ? PATH : ::File.join(PATH, *args)
40
+ end
41
+
42
+ # Utility method used to rquire all files ending in .rb that lie in the
43
+ # directory below this file that has the same name as the filename passed
44
+ # in. Optionally, a specific _directory_ name can be passed in such that
45
+ # the _filename_ does not have to be equivalent to the directory.
46
+ #
47
+ def self.require_all_libs_relative_to( fname, dir = nil )
48
+ dir ||= ::File.basename(fname, '.*')
49
+ search_me = ::File.expand_path(
50
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
51
+
52
+ Dir.glob(search_me).sort.each do |rb|
53
+ require rb
54
+ end
55
+ end
56
+
57
+ end # module Spacer
58
+
59
+ Spacer.require_all_libs_relative_to __FILE__
60
+
61
+ end # unless defined?
62
+
63
+ # EOF
@@ -0,0 +1,23 @@
1
+ module Spacer
2
+
3
+ class Authentication
4
+ def initialize(api_key, secret_key)
5
+ @oauth_consumer = OAuth::Consumer.new(CGI.escape(api_key), secret_key)
6
+ end
7
+
8
+ def process_request(http, request)
9
+ request.oauth!(http, @oauth_consumer, nil, { :scheme => :query_string, :nonce => nonce, :timestamp => timestamp })
10
+ request
11
+ end
12
+
13
+ private
14
+ def nonce
15
+ rand(2**128).to_s
16
+ end
17
+
18
+ def timestamp
19
+ Time.new.to_i.to_s
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,141 @@
1
+ module Spacer
2
+ class Client
3
+
4
+ SERVER = 'api.msappspace.com'
5
+ VERSION = 'v1'
6
+ FORMAT = :json
7
+ LOG_LEVEL = Logger::INFO
8
+
9
+ def initialize(api_key, secret_key, logger=nil)
10
+ @auth = Authentication.new(api_key, secret_key)
11
+
12
+ if logger
13
+ @log = logger
14
+ else
15
+ @log = Logger.new(STDOUT)
16
+ @log.level = LOG_LEVEL
17
+ end
18
+ end
19
+
20
+ def user(user_id)
21
+ response = do_request "users/#{user_id}"
22
+ @user = User.from_hash_with_client(response, self)
23
+ end
24
+
25
+ def profile(user_id)
26
+ response = do_request "users/#{user_id}/profile"
27
+ @profile = Profile.from_hash(response)
28
+ end
29
+
30
+ def friends(user_id, page=nil, page_size=nil, list=nil)
31
+ response = do_request "users/#{user_id}/friends.#{FORMAT.to_s}?page=#{page}&page_size=#{page_size}&list=#{list}"
32
+ @friends = response['friends'].map do |friend|
33
+ User.from_hash_with_client(friend, self)
34
+ end
35
+ end
36
+
37
+ def albums(user_id)
38
+ response = do_request "users/#{user_id}/albums"
39
+ @albums = response['albums'].map do |album|
40
+ Album.from_hash(album)
41
+ end
42
+ end
43
+
44
+ def album(user_id, album_id)
45
+ response = do_request "users/#{user_id}/albums/#{album_id}"
46
+ @album = Album.from_hash(response)
47
+ end
48
+
49
+ def photos_for_album(user_id, album_id)
50
+ response = do_request "users/#{user_id}/albums/#{album_id}/photos"
51
+ @photos = response['photos'].map do |photo|
52
+ Photo.from_hash(photo)
53
+ end
54
+ end
55
+
56
+ def photos(user_id)
57
+ response = do_request "users/#{user_id}/photos"
58
+ @photos = response['photos'].map do |photo|
59
+ Photo.from_hash(photo)
60
+ end
61
+ end
62
+
63
+ def interests(user_id)
64
+ response = do_request "users/#{user_id}/interests"
65
+ @interests = Interest.from_hash(response)
66
+ end
67
+
68
+ def details(user_id)
69
+ response = do_request "users/#{user_id}/details"
70
+ @details = Details.from_hash(response)
71
+ end
72
+
73
+ def videos(user_id)
74
+ response = do_request "users/#{user_id}/videos"
75
+ @videos = response['videos'].map do |video|
76
+ Video.from_hash(video)
77
+ end
78
+ end
79
+
80
+ def video(user_id, video_id)
81
+ response = do_request "users/#{user_id}/videos/#{video_id}"
82
+ @video = Video.from_hash(response)
83
+ end
84
+
85
+ def photo(user_id, photo_id)
86
+ response = do_request "users/#{user_id}/photos/#{photo_id}"
87
+ @photo = Photo.from_hash(response)
88
+ end
89
+
90
+ def status(user_id)
91
+ response = do_request "users/#{user_id}/status"
92
+ @status = Status.from_hash(response)
93
+ end
94
+
95
+ def mood(user_id)
96
+ response = do_request "users/#{user_id}/mood"
97
+ @mood = Mood.from_hash(response)
98
+ end
99
+
100
+ def friendship?(user_id, friend_ids)
101
+ multiple_friends = friend_ids.is_a?(Array)
102
+
103
+ friend_ids = friend_ids.join(';') if multiple_friends
104
+ response = do_request "users/#{user_id}/friends/#{friend_ids}"
105
+
106
+ if multiple_friends
107
+ @friendships = response['friendship'].map do |friendship|
108
+ friendship['areFriends']
109
+ end
110
+ else
111
+ response['friendship'].first['areFriends']
112
+ end
113
+ end
114
+
115
+ def groups(user_id)
116
+ response = do_request "users/#{user_id}/groups"
117
+ @groups = response['Groups'].map do |group|
118
+ Group.from_hash(group)
119
+ end
120
+ end
121
+
122
+ private
123
+ def do_request(query)
124
+ request_uri = request_uri(query)
125
+
126
+ http = Net::HTTP.new(request_uri.host, request_uri.port)
127
+ request = Net::HTTP::Get.new(request_uri.path)
128
+ request = @auth.process_request(http, request)
129
+ @log.debug "REQUEST PATH: #{request.path}"
130
+
131
+ response = http.request(request)
132
+ @log.debug "RESPONSE BODY: #{response.body}\n"
133
+
134
+ ActiveSupport::JSON.decode(response.body)
135
+ end
136
+
137
+ def request_uri(query)
138
+ URI.parse("http://#{SERVER}/#{VERSION}/#{query}.#{FORMAT.to_s}")
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,124 @@
1
+ ## Graciously stolen from Facebooker
2
+ #
3
+ # Copyright (c) 2007 Chad Fowler <chad@infoether.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in the
7
+ # Software without restriction, including without limitation the rights to use,
8
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
9
+ # Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19
+ # AN ACTION 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.
21
+
22
+ module Spacer
23
+ ##
24
+ # helper methods primarily supporting the management of Ruby objects which are populatable via Hashes.
25
+ # Since most Facebook API calls accept and return hashes of data (as XML), the Model module allows us to
26
+ # directly populate a model's attributes given a Hash with matching key names.
27
+ module Model
28
+ class UnboundSessionException < Exception; end
29
+ def self.included(includer)
30
+ includer.extend ClassMethods
31
+ end
32
+ module ClassMethods
33
+ ##
34
+ # Instantiate a new instance of the class into which we are included and populate that instance's
35
+ # attributes given the provided Hash. Key names in the Hash should map to attribute names on the model.
36
+ def from_hash(hash)
37
+ instance = new(hash)
38
+ yield instance if block_given?
39
+ instance
40
+ end
41
+
42
+ ##
43
+ # Create a standard attr_writer and a populating_attr_reader
44
+ def populating_attr_accessor(*symbols)
45
+ attr_writer *symbols
46
+ populating_attr_reader *symbols
47
+ end
48
+
49
+ ##
50
+ # Create a reader that will attempt to populate the model if it has not already been populated
51
+ def populating_attr_reader(*symbols)
52
+ symbols.each do |symbol|
53
+ define_method(symbol) do
54
+ populate unless populated?
55
+ instance_variable_get("@#{symbol}")
56
+ end
57
+ end
58
+ end
59
+
60
+ def populating_hash_settable_accessor(symbol, klass)
61
+ populating_attr_reader symbol
62
+ hash_settable_writer(symbol, klass)
63
+ end
64
+
65
+ def populating_hash_settable_list_accessor(symbol, klass)
66
+ populating_attr_reader symbol
67
+ hash_settable_list_writer(symbol, klass)
68
+ end
69
+
70
+ #
71
+ # Declares an attribute named ::symbol:: which can be set with either an instance of ::klass::
72
+ # or a Hash which will be used to populate a new instance of ::klass::.
73
+ def hash_settable_accessor(symbol, klass)
74
+ attr_reader symbol
75
+ hash_settable_writer(symbol, klass)
76
+ end
77
+
78
+ def hash_settable_writer(symbol, klass)
79
+ define_method("#{symbol}=") do |value|
80
+ instance_variable_set("@#{symbol}", value.kind_of?(Hash) ? klass.from_hash(value) : value)
81
+ end
82
+ end
83
+
84
+ #
85
+ # Declares an attribute named ::symbol:: which can be set with either a list of instances of ::klass::
86
+ # or a list of Hashes which will be used to populate a new instance of ::klass::.
87
+ def hash_settable_list_accessor(symbol, klass)
88
+ attr_reader symbol
89
+ hash_settable_list_writer(symbol, klass)
90
+ end
91
+
92
+ def hash_settable_list_writer(symbol, klass)
93
+ define_method("#{symbol}=") do |list|
94
+ instance_variable_set("@#{symbol}", list.map do |item|
95
+ item.kind_of?(Hash) ? klass.from_hash(item) : item
96
+ end)
97
+ end
98
+ end
99
+ end
100
+
101
+ def initialize(hash = {})
102
+ populate_from_hash!(hash)
103
+ end
104
+
105
+ def populate
106
+ raise NotImplementedError, "#{self.class} included me and should have overriden me"
107
+ end
108
+
109
+ def populated?
110
+ !@populated.nil?
111
+ end
112
+
113
+ ##
114
+ # Set model's attributes via Hash. Keys should map directly to the model's attribute names.
115
+ def populate_from_hash!(hash)
116
+ unless hash.empty?
117
+ hash.each do |key, value|
118
+ self.__send__("#{key}=", value)
119
+ end
120
+ @populated = true
121
+ end
122
+ end
123
+ end
124
+ end