ruby-smugmug 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README.md +37 -0
- data/Rakefile +12 -0
- data/lib/ruby-smugmug.rb +8 -0
- data/lib/smugmug/api_category.rb +12 -0
- data/lib/smugmug/api_methods.rb +18 -0
- data/lib/smugmug/client.rb +85 -0
- data/lib/smugmug/exceptions.rb +41 -0
- data/lib/smugmug/http.rb +160 -0
- data/lib/smugmug/version.rb +3 -0
- metadata +87 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2011 Placester, Inc
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
Overview
|
2
|
+
===
|
3
|
+
Library for interacting with the SmugMug 1.3.0 API using OAuth authentication. This does not do any OAuth authorization or setup, it's assumed you're using another gem such as omniauth-oauth that handles that part.
|
4
|
+
|
5
|
+
Compability
|
6
|
+
-
|
7
|
+
Tested against Ruby 1.8.7, 1.9.2, 2.0.0 and JRuby, build history is available [here](http://travis-ci.org/zanker/ruby-smugmug).
|
8
|
+
|
9
|
+
<img src="https://secure.travis-ci.org/zanker/ruby-smugmug.png?branch=master&.png"/>
|
10
|
+
|
11
|
+
Examples
|
12
|
+
-
|
13
|
+
This is just a thin wrapper around the [SmugMug 1.3.0 API](http://wiki.smugmug.net/display/API/API+1.3.0), it's a 1:1 wrapper, so all of the documentation on the SmugMug page applies to this library. You can use any arguments that the SmugMug 1.3.0 documentation shows under the OAuth option.
|
14
|
+
|
15
|
+
client = SmugMug::Client.new(:api_key => "1234-api", :oauth_secret => "4321-secret", :user => {:token => "abcd-token", :secret => "abcd-secret"})
|
16
|
+
|
17
|
+
data = client.users.getStats(:Month => 2, :Year => 2012)
|
18
|
+
puts data # {"Bytes"=>0, "Hits"=>0, "Large"=>0, "Medium"=>0, "Small"=>0, "Video110"=>0, "Video200"=>0, "Video320"=>0, "Video640"=>0, "X2Large"=>0, "X3Large"=>0, "XLarge"=>0}
|
19
|
+
|
20
|
+
data = client.styles.getTemplates
|
21
|
+
puts data # [{"id"=>0, "Name"=>"Viewer Controlled"}, {"id"=>3, "Name"=>"SmugMug"}, {"id"=>4, "Name"=>"Traditional"}, {"id"=>7, "Name"=>"All Thumbs"}, {"id"=>8, "Name"=>"Slideshow"}, {"id"=>9, "Name"=>"Journal (Old)"}, {"id"=>10, "Name"=>"SmugMug Small"}, {"id"=>11, "Name"=>"Filmstrip"}, {"id"=>12, "Name"=>"Critique"}, {"id"=>16, "Name"=>"Journal"}, {"id"=>17, "Name"=>"Thumbnails"}]
|
22
|
+
|
23
|
+
|
24
|
+
Because uploading is a special case and not under the same group of APIs, it's called slightly differently. See http://wiki.smugmug.net/display/API/Uploading for more information or the documentation linked below for a list of arguments.
|
25
|
+
|
26
|
+
client = SmugMug::Client.new(:api_key => "1234-api", :oauth_secret => "4321-secret", :user => {:token => "abcd-token", :secret => "abcd-secret"})
|
27
|
+
data = client.upload_media(:file => File.new("/Users/foobar/Desktop/image.jpeg", :AlbumID => 51343)
|
28
|
+
puts data # {"id"=>1970029991, "Key"=>"rnSfAak", "URL"=>"http://foobar.smugmug.com/Other/Foo/51343_k8W1aR#1970029991_rnSfAak"}
|
29
|
+
|
30
|
+
|
31
|
+
Documentation
|
32
|
+
-
|
33
|
+
See http://rubydoc.info/github/zanker/ruby-smugmug/master/frames for full documentation.
|
34
|
+
|
35
|
+
License
|
36
|
+
-
|
37
|
+
Available under the MIT license, see LICENSE for more information.
|
data/Rakefile
ADDED
data/lib/ruby-smugmug.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module SmugMug
|
2
|
+
class ApiCategory
|
3
|
+
def initialize(http, category)
|
4
|
+
@http, @category = http, category
|
5
|
+
end
|
6
|
+
|
7
|
+
def method_missing(method, *args)
|
8
|
+
return super unless SmugMug::API_METHODS[@category][method.to_s]
|
9
|
+
@http.request("#{@category}.#{method}", args.pop || {})
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SmugMug
|
2
|
+
API_METHODS = {
|
3
|
+
"accounts" => {"browse" => true},
|
4
|
+
"albums" => {"applyWatermark" => true, "browse" => true, "changeSettings" => true, "comments" => true, "create" => true, "delete" => true, "get" => true, "getInfo" => true, "getStats" => true, "removeWatermark" => true, "reSort" => true},
|
5
|
+
"albumtemplates" => {"changeSettings" => true, "create" => true, "delete" => true, "get" => true}, "auth" => {"checkAccessToken" => true, "getAccessToken" => true, "getRequestToken" => true},
|
6
|
+
"categories" => {"create" => true, "delete" => true, "get" => true, "rename" => true}, "communities" => {"get" => true}, "coupons" => {"create" => true, "get" => true, "getInfo" => true, "modify" => true, "restrictions" => true},
|
7
|
+
"family" => {"add" => true, "get" => true, "remove" => true, "removeAll" => true}, "fans" => {"get" => true}, "featured" => {"albums" => true}, "friends" => {"add" => true, "get" => true, "remove" => true, "removeAll" => true},
|
8
|
+
"images" => {"applyWatermark" => true, "changePosition" => true, "changeSettings" => true, "collect" => true, "comments" => true, "crop" => true, "delete" => true, "get" => true, "getEXIF" => true, "getInfo" => true, "getStats" => true, "getURLs" => true, "removeWatermark" => true, "rotate" => true, "uploadFromURL" => true, "zoomThumbnail" => true},
|
9
|
+
"printmarks" => {"create" => true, "delete" => true, "get" => true, "getInfo" => true, "modify" => true},
|
10
|
+
"service" => {"ping" => true},
|
11
|
+
"sharegroups" => {"albums" => true, "browse" => true, "create" => true, "delete" => true, "get" => true, "getInfo" => true, "modify" => true},
|
12
|
+
"styles" => {"getTemplates" => true},
|
13
|
+
"subcategories" => {"create" => true, "delete" => true, "get" => true, "getAll" => true, "rename" => true},
|
14
|
+
"themes" => {"get" => true},
|
15
|
+
"users" => {"getInfo" => true, "getStats" => true, "getTree" => true},
|
16
|
+
"watermarks" => {"changeSettings" => true, "create" => true, "delete" => true, "get" => true, "getInfo" => true}
|
17
|
+
}
|
18
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module SmugMug
|
2
|
+
class Client
|
3
|
+
##
|
4
|
+
# Creates a new client instance that can be used to access the SMugMug API
|
5
|
+
# @param [Hash] args
|
6
|
+
# @option args [String] :api_key Your SmugMug API key
|
7
|
+
# @option args [String] :oauth_secret Your SmugMug OAuth secret key
|
8
|
+
# @option args [Hash] :user Configuration for the user you are requesting/updating data for
|
9
|
+
# * :token [String] OAuth token for the user
|
10
|
+
# * :secret [String] OAuth secret token for the user
|
11
|
+
# @option args [String, Optional :user_agent Helps SmugMug identify API calls
|
12
|
+
# @option args [Hash, Optional] :http Additional configuration for the HTTP requests
|
13
|
+
# * :verify_mode [Integer, Optional] How to verify the SSL certificate when connecting through HTTPS, either OpenSSL::SSL::VERIFY_PEER or OpenSSL::SSL::VERIFY_NONE, defaults to OpenSSL::SSL::VERIFY_NONE
|
14
|
+
# * :ca_file [String, Optional] Path to the CA certification file in PEM format
|
15
|
+
# * :ca_path [String, Optional] Path to the directory containing CA certifications in PEM format
|
16
|
+
#
|
17
|
+
# @raise [ArgumentError]
|
18
|
+
def initialize(args)
|
19
|
+
raise ArgumentError, "API Key required" unless args.has_key?(:api_key)
|
20
|
+
raise ArgumentError, "API OAuth secret required" unless args.has_key?(:oauth_secret)
|
21
|
+
raise ArgumentError, "Must specify the users OAuth datA" unless args[:user].is_a?(Hash)
|
22
|
+
raise ArgumentError, "Users OAuth token required" unless args[:user][:token]
|
23
|
+
raise ArgumentError, "Users OAuth secret token required" unless args[:user][:secret]
|
24
|
+
|
25
|
+
@http = HTTP.new(args)
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Uploading media files to SmugMug, see http://wiki.smugmug.net/display/API/Uploading for more information
|
30
|
+
# @param [Hash] args
|
31
|
+
# @option args [File] :file File or stream that can have the content read to upload
|
32
|
+
# @option args [String] :file Binary contents of the file to upload
|
33
|
+
# @option args [String] :FileName What the file name is, only required when passing :file as a string
|
34
|
+
# @option args [Integer] :AlbumID SmugMug Album ID to upload the media to
|
35
|
+
# @option args [Integer, Optional] :ImageID Image ID to replace if reuploading media rather than adding new
|
36
|
+
# @option args [String, Optional] :Caption The caption for the media
|
37
|
+
# @option args [Boolean, Optional] :Hidden Whether the media should be visible
|
38
|
+
# @option args [String, Optional] :Keywords Keywords to tag the media as
|
39
|
+
# @option args [Integer, Optional] :Altitude Altitude the media was taken at
|
40
|
+
# @option args [Float, Optional] :Latitude Latitude the media was taken at
|
41
|
+
# @option args [Float, Optional] :Longitude Latitude the media was taken at
|
42
|
+
#
|
43
|
+
# @raise [SmugMug::OAuthError]
|
44
|
+
# @raise [SmugMug::HTTPError]
|
45
|
+
# @raise [SmugMug::RequestError]
|
46
|
+
# @raise [SmugMug::ReadonlyModeError]
|
47
|
+
# @raise [SmugMug::UnknownAPIError]
|
48
|
+
def upload_media(args)
|
49
|
+
raise ArgumentError, "File is required" unless args.has_key?(:file)
|
50
|
+
raise ArgumentError, "AlbumID is required" unless args.has_key?(:AlbumID)
|
51
|
+
|
52
|
+
if args[:file].is_a?(String)
|
53
|
+
args[:FileName] ||= File.basename(args[:file])
|
54
|
+
args[:content] = File.read(args[:file])
|
55
|
+
elsif args[:file].is_a?(File)
|
56
|
+
args[:FileName] ||= File.basename(args[:file].path)
|
57
|
+
args[:content] = args[:file].read
|
58
|
+
else
|
59
|
+
raise ArgumentError, "File must be a String or File"
|
60
|
+
end
|
61
|
+
|
62
|
+
args.delete(:file)
|
63
|
+
@http.request(:uploading, args)
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Direct mapping of SmugMug 1.3.0 API, either see http://wiki.smugmug.net/display/API/API+1.3.0 or the README for examples
|
68
|
+
#
|
69
|
+
# @raise [SmugMug::OAuthError]
|
70
|
+
# @raise [SmugMug::HTTPError]
|
71
|
+
# @raise [SmugMug::RequestError]
|
72
|
+
# @raise [SmugMug::ReadonlyModeError]
|
73
|
+
# @raise [SmugMug::UnknownAPIError]
|
74
|
+
def method_missing(method, *args)
|
75
|
+
api_cat = method.to_s
|
76
|
+
return super unless SmugMug::API_METHODS[api_cat]
|
77
|
+
|
78
|
+
if klass = self.instance_variable_get("@#{api_cat}_wrapper")
|
79
|
+
klass
|
80
|
+
else
|
81
|
+
self.instance_variable_set("@#{api_cat}_wrapper", SmugMug::ApiCategory.new(@http, api_cat))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SmugMug
|
2
|
+
##
|
3
|
+
# Generic module that provides access to the code and text separately of the exception
|
4
|
+
module ReplyErrors
|
5
|
+
attr_reader :reply_text, :reply_code
|
6
|
+
|
7
|
+
def initialize(msg, reply_code=nil, reply_text=nil)
|
8
|
+
super(msg)
|
9
|
+
@reply_code, @reply_text = reply_code, reply_text
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Errors specific to the OAuth request
|
15
|
+
class OAuthError < StandardError
|
16
|
+
include ReplyErrors
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# HTTP errors
|
21
|
+
class HTTPError < StandardError
|
22
|
+
include ReplyErrors
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Problem with the request
|
27
|
+
class RequestError < StandardError
|
28
|
+
include ReplyErrors
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# SmugMug is in read-only mode
|
34
|
+
class ReadonlyModeError < StandardError
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Trying to call an API that doesn't exist
|
39
|
+
class UnknownAPIError < StandardError
|
40
|
+
end
|
41
|
+
end
|
data/lib/smugmug/http.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "openssl"
|
3
|
+
require "base64"
|
4
|
+
require "net/http"
|
5
|
+
require "json"
|
6
|
+
|
7
|
+
module SmugMug
|
8
|
+
class HTTP
|
9
|
+
API_URI = URI("https://api.smugmug.com/services/api/json/1.3.0")
|
10
|
+
UPLOAD_URI = URI("http://upload.smugmug.com/")
|
11
|
+
UPLOAD_HEADERS = [:AlbumID, :Caption, :Altitude, :ImageID, :Keywords, :Latitude, :Longitude, :Hidden, :FileName]
|
12
|
+
OAUTH_ERRORS = {30 => true, 32 => true, 33 => true, 35 => true, 36 => true, 37 => true, 38 => true, 98 => true}
|
13
|
+
|
14
|
+
##
|
15
|
+
# Creates a new HTTP wrapper to handle the network portions of the API requests
|
16
|
+
# @param [Hash] args Same as [SmugMug::HTTP]
|
17
|
+
#
|
18
|
+
def initialize(args)
|
19
|
+
@config = args
|
20
|
+
@digest = OpenSSL::Digest::Digest.new("SHA1")
|
21
|
+
|
22
|
+
@headers = {"Accept-Encoding" => "gzip"}
|
23
|
+
if args[:user_agent]
|
24
|
+
@headers["User-Agent"] = "#{args.delete(:user_agent)} (ruby-smugmug v#{SmugMug::VERSION})"
|
25
|
+
else
|
26
|
+
@headers["User-Agent"] = "Ruby-SmugMug v#{SmugMug::VERSION}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def request(api, args)
|
31
|
+
uri = api == :uploading ? UPLOAD_URI : API_URI
|
32
|
+
args[:method] = "smugmug.#{api}" unless api == :uploading
|
33
|
+
|
34
|
+
http = ::Net::HTTP.new(uri.host, uri.port)
|
35
|
+
http.set_debug_output(@config[:debug_output]) if @config[:debug_output]
|
36
|
+
|
37
|
+
# Configure HTTPS if needed
|
38
|
+
if uri.scheme == "https"
|
39
|
+
http.use_ssl = true
|
40
|
+
|
41
|
+
if @config[:http] and @config[:http][:verify_mode]
|
42
|
+
http.verify_mode = @config[:http][:verify_mode]
|
43
|
+
http.ca_file = @config[:http][:ca_file]
|
44
|
+
http.ca_path = @config[:http][:ca_path]
|
45
|
+
else
|
46
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Upload request, which requires special handling
|
51
|
+
if api == :uploading
|
52
|
+
postdata = args.delete(:content)
|
53
|
+
headers = @headers.merge("Content-Length" => postdata.length.to_s, "Content-MD5" => Digest::MD5.hexdigest(postdata), "X-Smug-Version" => "1.3.0", "X-Smug-ResponseType" => "JSON")
|
54
|
+
|
55
|
+
UPLOAD_HEADERS.each do |key|
|
56
|
+
next unless args[key] and args[key] != ""
|
57
|
+
headers["X-Smug-#{key}"] = args[key].to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
oauth = self.sign_request("POST", uri, nil)
|
61
|
+
headers["Authorization"] = "OAuth oauth_consumer_key=\"#{oauth["oauth_consumer_key"]}\", oauth_nonce=\"#{oauth["oauth_nonce"]}\", oauth_signature_method=\"#{oauth["oauth_signature_method"]}\", oauth_signature=\"#{oauth["oauth_signature"]}\", oauth_timestamp=\"#{oauth["oauth_timestamp"]}\", oauth_version=\"#{oauth["oauth_version"]}\", oauth_token=\"#{oauth["oauth_token"]}\""
|
62
|
+
|
63
|
+
# Normal API method
|
64
|
+
else
|
65
|
+
postdata = self.sign_request("POST", uri, args)
|
66
|
+
headers = @headers
|
67
|
+
end
|
68
|
+
|
69
|
+
response = http.request_post(uri.request_uri, postdata, headers)
|
70
|
+
if response.code == "204"
|
71
|
+
return nil
|
72
|
+
elsif response.code != "200"
|
73
|
+
raise SmugMug::HTTPError.new("HTTP #{response.code}, #{response.message}", response.code, response.message)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Check for GZIP encoding
|
77
|
+
if response.header["content-encoding"] == "gzip"
|
78
|
+
begin
|
79
|
+
body = Zlib::GzipReader.new(StringIO.new(response.body)).read
|
80
|
+
rescue Zlib::GzipFile::Error
|
81
|
+
raise
|
82
|
+
end
|
83
|
+
else
|
84
|
+
body = response.body
|
85
|
+
end
|
86
|
+
|
87
|
+
return nil if body == ""
|
88
|
+
|
89
|
+
data = JSON.parse(body)
|
90
|
+
|
91
|
+
if data["stat"] == "fail"
|
92
|
+
# Special casing for SmugMug being in Read only mode
|
93
|
+
if data["code"] == 99
|
94
|
+
raise SmugMug::ReadonlyModeError.new("SmugMug is currently in read only mode, try again later")
|
95
|
+
end
|
96
|
+
|
97
|
+
klass = OAUTH_ERRORS[data["code"]] ? SmugMug::OAuthError : SmugMug::RequestError
|
98
|
+
raise klass.new("Error ##{data["code"]}, #{data["message"]}", data["code"], data["message"])
|
99
|
+
end
|
100
|
+
|
101
|
+
data.delete("stat")
|
102
|
+
data.delete("method")
|
103
|
+
|
104
|
+
# smugmug.albums.changeSettings at the least doesn't return any data
|
105
|
+
return nil if data.length == 0
|
106
|
+
|
107
|
+
# It seems all smugmug APIs only return one hash of data, so this should be fine and not cause issues
|
108
|
+
data.each do |_, value|
|
109
|
+
return value
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Generates an OAuth signature and updates the args with the required fields
|
115
|
+
# @param [String] method HTTP method that the request is sent as
|
116
|
+
# @param [String] uri Full URL of the request
|
117
|
+
# @param [Hash] form_args Args to be passed to the server
|
118
|
+
def sign_request(method, uri, form_args)
|
119
|
+
# Convert non-string keys to strings so the sort works
|
120
|
+
args = {}
|
121
|
+
if form_args
|
122
|
+
form_args.each do |key, value|
|
123
|
+
next unless value and value != ""
|
124
|
+
|
125
|
+
key = key.to_s unless key.is_a?(String)
|
126
|
+
args[key] = value
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Add the necessary OAuth args
|
131
|
+
args["oauth_version"] = "1.0"
|
132
|
+
args["oauth_consumer_key"] = @config[:api_key]
|
133
|
+
args["oauth_nonce"] = Digest::MD5.hexdigest("#{Time.now.to_f}#{rand(10 ** 30)}")
|
134
|
+
args["oauth_signature_method"] = "HMAC-SHA1"
|
135
|
+
args["oauth_timestamp"] = Time.now.utc.to_i
|
136
|
+
args["oauth_token"] = @config[:user][:token]
|
137
|
+
|
138
|
+
# Sort the params
|
139
|
+
sorted_args = []
|
140
|
+
args.sort.each do |key, value|
|
141
|
+
sorted_args.push("#{key.to_s}=#{CGI::escape(value.to_s)}")
|
142
|
+
end
|
143
|
+
|
144
|
+
postdata = sorted_args.join("&")
|
145
|
+
|
146
|
+
# Final string to hash
|
147
|
+
sig_base = "#{method}&#{CGI::escape("#{uri.scheme}://#{uri.host}#{uri.path}")}&#{CGI::escape(postdata)}"
|
148
|
+
|
149
|
+
signature = OpenSSL::HMAC.digest(@digest, "#{@config[:oauth_secret]}&#{@config[:user][:secret]}", sig_base)
|
150
|
+
signature = CGI::escape(Base64.encode64(signature).chomp)
|
151
|
+
|
152
|
+
if uri == API_URI
|
153
|
+
"#{postdata}&oauth_signature=#{signature}"
|
154
|
+
else
|
155
|
+
args["oauth_signature"] = signature
|
156
|
+
args
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-smugmug
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Zachary Anker
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.7.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.7.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.8.0
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.8.0
|
46
|
+
description: Gem for reading and writing data from the SmugMug 1.3.0 API.
|
47
|
+
email:
|
48
|
+
- zach.anker@gmail.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- lib/ruby-smugmug.rb
|
54
|
+
- lib/smugmug/api_category.rb
|
55
|
+
- lib/smugmug/api_methods.rb
|
56
|
+
- lib/smugmug/client.rb
|
57
|
+
- lib/smugmug/exceptions.rb
|
58
|
+
- lib/smugmug/http.rb
|
59
|
+
- lib/smugmug/version.rb
|
60
|
+
- LICENSE
|
61
|
+
- README.md
|
62
|
+
- Rakefile
|
63
|
+
homepage: http://github.com/zanker/ruby-smugmug
|
64
|
+
licenses: []
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ! '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 1.3.6
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project: ruby-smugmug
|
83
|
+
rubygems_version: 1.8.23
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: SmugMug 1.3.0 API gem
|
87
|
+
test_files: []
|